From 30fa682a4670e1699952595728199f3ba30ab9a0 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Wed, 5 Jun 2024 15:31:49 +0200 Subject: [PATCH 01/35] refs #423. Create new datatables organizational_unit --- migrations/Version20240605094344.php | 32 +++++++++++ migrations/Version20240605100013.php | 33 ++++++++++++ src/Entity/OrganizationalUnit.php | 76 +++++++++++++++++++++++++++ src/Model/OrganizationalUnitTypes.php | 8 +++ 4 files changed, 149 insertions(+) create mode 100644 migrations/Version20240605094344.php create mode 100644 migrations/Version20240605100013.php create mode 100644 src/Model/OrganizationalUnitTypes.php diff --git a/migrations/Version20240605094344.php b/migrations/Version20240605094344.php new file mode 100644 index 0000000..5f6de70 --- /dev/null +++ b/migrations/Version20240605094344.php @@ -0,0 +1,32 @@ +addSql('ALTER TABLE organizational_unit ADD type VARCHAR(255) NOT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE organizational_unit DROP type'); + } +} diff --git a/migrations/Version20240605100013.php b/migrations/Version20240605100013.php new file mode 100644 index 0000000..4d24099 --- /dev/null +++ b/migrations/Version20240605100013.php @@ -0,0 +1,33 @@ +addSql('ALTER TABLE organizational_unit ADD network_settings VARCHAR(255) DEFAULT NULL, ADD location VARCHAR(255) DEFAULT NULL, ADD projector TINYINT(1) DEFAULT NULL, ADD board TINYINT(1) DEFAULT NULL, CHANGE network_settings_id capacity INT DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE organizational_unit DROP network_settings, DROP location, DROP projector, DROP board, CHANGE capacity network_settings_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D9B9A36D0 FOREIGN KEY (network_settings_id) REFERENCES network_settings (id)'); + $this->addSql('CREATE INDEX IDX_749AEB2D9B9A36D0 ON organizational_unit (network_settings_id)'); + } +} diff --git a/src/Entity/OrganizationalUnit.php b/src/Entity/OrganizationalUnit.php index 6e58c7f..2bb01b8 100644 --- a/src/Entity/OrganizationalUnit.php +++ b/src/Entity/OrganizationalUnit.php @@ -45,6 +45,7 @@ class OrganizationalUnit extends AbstractEntity private Collection $organizationalUnits; #[ORM\ManyToOne(inversedBy: 'organizationalUnits')] + #[ORM\Column(nullable: true)] private ?NetworkSettings $networkSettings = null; /** @@ -59,6 +60,21 @@ class OrganizationalUnit extends AbstractEntity #[ORM\OneToMany(mappedBy: 'organizationalUnit', targetEntity: Client::class)] private Collection $clients; + #[ORM\Column(length: 255)] + private ?string $type = null; + + #[ORM\Column(length: 255, nullable: true)] + private ?string $location = null; + + #[ORM\Column(nullable: true)] + private ?bool $projector = null; + + #[ORM\Column(nullable: true)] + private ?bool $board = null; + + #[ORM\Column(nullable: true)] + private ?int $capacity = null; + public function __construct() { parent::__construct(); @@ -236,4 +252,64 @@ class OrganizationalUnit extends AbstractEntity return $this; } + + public function getType(): ?string + { + return $this->type; + } + + public function setType(string $type): static + { + $this->type = $type; + + return $this; + } + + public function getLocation(): ?string + { + return $this->location; + } + + public function setLocation(?string $location): static + { + $this->location = $location; + + return $this; + } + + public function isProjector(): ?bool + { + return $this->projector; + } + + public function setProjector(?bool $projector): static + { + $this->projector = $projector; + + return $this; + } + + public function isBoard(): ?bool + { + return $this->board; + } + + public function setBoard(?bool $board): static + { + $this->board = $board; + + return $this; + } + + public function getCapacity(): ?int + { + return $this->capacity; + } + + public function setCapacity(?int $capacity): static + { + $this->capacity = $capacity; + + return $this; + } } diff --git a/src/Model/OrganizationalUnitTypes.php b/src/Model/OrganizationalUnitTypes.php new file mode 100644 index 0000000..28b39e8 --- /dev/null +++ b/src/Model/OrganizationalUnitTypes.php @@ -0,0 +1,8 @@ + Date: Wed, 5 Jun 2024 15:32:46 +0200 Subject: [PATCH 02/35] refs #427. New endpoints created organizational-units --- config/api_platform/OrganizationalUnit.yaml | 30 +++++++- .../OrganizationalUnitClassroomGroupInput.php | 53 ++++++++++++++ .../OrganizationalUnitClassroomInput.php | 73 +++++++++++++++++++ .../OrganizationalUnitClientGroupInput.php | 53 ++++++++++++++ ...ut.php => OrganizationalUnitRootInput.php} | 14 +++- src/Dto/Output/OrganizationalUnitOutput.php | 12 +++ src/Model/OrganizationalUnitTypes.php | 27 ++++++- .../Processor/OrganizationalUnitProcessor.php | 17 ++++- 8 files changed, 271 insertions(+), 8 deletions(-) create mode 100644 src/Dto/Input/OrganizationalUnitClassroomGroupInput.php create mode 100644 src/Dto/Input/OrganizationalUnitClassroomInput.php create mode 100644 src/Dto/Input/OrganizationalUnitClientGroupInput.php rename src/Dto/Input/{OrganizationalUnitInput.php => OrganizationalUnitRootInput.php} (57%) diff --git a/config/api_platform/OrganizationalUnit.yaml b/config/api_platform/OrganizationalUnit.yaml index 577b80a..26fb903 100644 --- a/config/api_platform/OrganizationalUnit.yaml +++ b/config/api_platform/OrganizationalUnit.yaml @@ -1,8 +1,6 @@ resources: App\Entity\OrganizationalUnit: processor: App\State\Processor\OrganizationalUnitProcessor - input: App\Dto\Input\OrganizationalUnitInput - output: App\Dto\Output\OrganizationalUnitOutput normalization_context: groups: ['default', 'organizational-unit:read'] denormalization_context: @@ -16,8 +14,34 @@ resources: provider: App\State\Provider\OrganizationalUnitProvider ApiPlatform\Metadata\Patch: provider: App\State\Provider\OrganizationalUnitProvider - ApiPlatform\Metadata\Post: ~ ApiPlatform\Metadata\Delete: ~ + organizational_unit_root: + class: ApiPlatform\Metadata\Post + method: POST + uriTemplate: /organizational-units/root + input: App\Dto\Input\OrganizationalUnitRootInput + output: App\Dto\Output\OrganizationalUnitOutput + + organizational_unit_classroom_group: + class: ApiPlatform\Metadata\Post + method: POST + uriTemplate: /organizational-units/classroom-group + input: App\Dto\Input\OrganizationalUnitClassroomGroupInput + output: App\Dto\Output\OrganizationalUnitOutput + + organizational_unit_classroom: + class: ApiPlatform\Metadata\Post + method: POST + uriTemplate: /organizational-units/classroom + input: App\Dto\Input\OrganizationalUnitClassroomInput + output: App\Dto\Output\OrganizationalUnitOutput + + organizational_unit_client_group: + class: ApiPlatform\Metadata\Post + method: POST + uriTemplate: /organizational-units/client-group + input: App\Dto\Input\OrganizationalUnitClientGroupInput + output: App\Dto\Output\OrganizationalUnitOutput properties: App\Entity\OrganizationalUnit: diff --git a/src/Dto/Input/OrganizationalUnitClassroomGroupInput.php b/src/Dto/Input/OrganizationalUnitClassroomGroupInput.php new file mode 100644 index 0000000..3d1aee5 --- /dev/null +++ b/src/Dto/Input/OrganizationalUnitClassroomGroupInput.php @@ -0,0 +1,53 @@ +name = $organizationalUnit->getName(); + $this->parent = $organizationalUnit->getParent(); + $this->description = $organizationalUnit->getDescription(); + $this->comments = $organizationalUnit->getComments(); + } + + public function createOrUpdateEntity(?OrganizationalUnit $organizationalUnit = null): OrganizationalUnit + { + if (!$organizationalUnit) { + $organizationalUnit = new OrganizationalUnit(); + } + + $organizationalUnit->setName($this->name); + $organizationalUnit->setParent($this->parent->getEntity()); + $organizationalUnit->setType(OrganizationalUnitTypes::CLASSROOMS_GROUP); + $organizationalUnit->setDescription($this->description); + $organizationalUnit->setComments($this->comments); + + return $organizationalUnit; + } +} \ No newline at end of file diff --git a/src/Dto/Input/OrganizationalUnitClassroomInput.php b/src/Dto/Input/OrganizationalUnitClassroomInput.php new file mode 100644 index 0000000..1bdf977 --- /dev/null +++ b/src/Dto/Input/OrganizationalUnitClassroomInput.php @@ -0,0 +1,73 @@ +name = $organizationalUnit->getName(); + $this->parent = $organizationalUnit->getParent(); + $this->description = $organizationalUnit->getDescription(); + $this->comments = $organizationalUnit->getComments(); + $this->location = $organizationalUnit->getLocation(); + $this->projector = $organizationalUnit->isProjector(); + $this->board = $organizationalUnit->isBoard(); + $this->capacity = $organizationalUnit->getCapacity(); + } + + public function createOrUpdateEntity(?OrganizationalUnit $organizationalUnit = null): OrganizationalUnit + { + if (!$organizationalUnit) { + $organizationalUnit = new OrganizationalUnit(); + } + + $organizationalUnit->setName($this->name); + $organizationalUnit->setType(OrganizationalUnitTypes::CLASSROOM); + $organizationalUnit->setParent($this->parent->getEntity()); + $organizationalUnit->setDescription($this->description); + $organizationalUnit->setComments($this->comments); + $organizationalUnit->setLocation($this->location); + $organizationalUnit->setProjector($this->projector); + $organizationalUnit->setBoard($this->board); + $organizationalUnit->setCapacity($this->capacity); + + return $organizationalUnit; + } +} \ No newline at end of file diff --git a/src/Dto/Input/OrganizationalUnitClientGroupInput.php b/src/Dto/Input/OrganizationalUnitClientGroupInput.php new file mode 100644 index 0000000..9ef1742 --- /dev/null +++ b/src/Dto/Input/OrganizationalUnitClientGroupInput.php @@ -0,0 +1,53 @@ +name = $organizationalUnit->getName(); + $this->parent = $organizationalUnit->getParent(); + $this->description = $organizationalUnit->getDescription(); + $this->comments = $organizationalUnit->getComments(); + } + + public function createOrUpdateEntity(?OrganizationalUnit $organizationalUnit = null): OrganizationalUnit + { + if (!$organizationalUnit) { + $organizationalUnit = new OrganizationalUnit(); + } + + $organizationalUnit->setName($this->name); + $organizationalUnit->setParent($this->parent->getEntity()); + $organizationalUnit->setType(OrganizationalUnitTypes::CLIENTS_GROUP); + $organizationalUnit->setDescription($this->description); + $organizationalUnit->setComments($this->comments); + + return $organizationalUnit; + } +} \ No newline at end of file diff --git a/src/Dto/Input/OrganizationalUnitInput.php b/src/Dto/Input/OrganizationalUnitRootInput.php similarity index 57% rename from src/Dto/Input/OrganizationalUnitInput.php rename to src/Dto/Input/OrganizationalUnitRootInput.php index 53f8d40..27a36f3 100644 --- a/src/Dto/Input/OrganizationalUnitInput.php +++ b/src/Dto/Input/OrganizationalUnitRootInput.php @@ -3,15 +3,22 @@ namespace App\Dto\Input; use App\Entity\OrganizationalUnit; +use App\Model\OrganizationalUnitTypes; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; -final class OrganizationalUnitInput +final class OrganizationalUnitRootInput { #[Assert\NotBlank] #[Groups(['organizational-unit:write'])] public ?string $name = null; + #[Groups(['organizational-unit:write'])] + public ?string $description = null; + + #[Groups(['organizational-unit:write'])] + public ?string $comments = null; + public function __construct(?OrganizationalUnit $organizationalUnit = null) { if (!$organizationalUnit) { @@ -19,6 +26,8 @@ final class OrganizationalUnitInput } $this->name = $organizationalUnit->getName(); + $this->description = $organizationalUnit->getDescription(); + $this->comments = $organizationalUnit->getComments(); } public function createOrUpdateEntity(?OrganizationalUnit $organizationalUnit = null): OrganizationalUnit @@ -28,6 +37,9 @@ final class OrganizationalUnitInput } $organizationalUnit->setName($this->name); + $organizationalUnit->setType(OrganizationalUnitTypes::ORGANIZATIONAL_UNIT); + $organizationalUnit->setDescription($this->description); + $organizationalUnit->setComments($this->comments); return $organizationalUnit; } diff --git a/src/Dto/Output/OrganizationalUnitOutput.php b/src/Dto/Output/OrganizationalUnitOutput.php index 1b8bf80..923b2f0 100644 --- a/src/Dto/Output/OrganizationalUnitOutput.php +++ b/src/Dto/Output/OrganizationalUnitOutput.php @@ -12,6 +12,15 @@ final class OrganizationalUnitOutput extends AbstractOutput #[Groups(['organizational-unit:read'])] public string $name; + #[Groups(['organizational-unit:read'])] + public string $type; + + #[Groups(['organizational-unit:read'])] + public ?OrganizationalUnit $parent = null; + + #[Groups(['organizational-unit:read'])] + public string $path; + #[Groups(['organizational-unit:read'])] public \DateTime $createAt; @@ -23,6 +32,9 @@ final class OrganizationalUnitOutput extends AbstractOutput parent::__construct($organizationalUnit); $this->name = $organizationalUnit->getName(); + $this->type = $organizationalUnit->getType(); + $this->parent = $organizationalUnit->getParent(); + $this->path = $organizationalUnit->getPath(); $this->createAt = $organizationalUnit->getCreatedAt(); $this->createBy = $organizationalUnit->getCreatedBy(); } diff --git a/src/Model/OrganizationalUnitTypes.php b/src/Model/OrganizationalUnitTypes.php index 28b39e8..2472da0 100644 --- a/src/Model/OrganizationalUnitTypes.php +++ b/src/Model/OrganizationalUnitTypes.php @@ -2,7 +2,32 @@ namespace App\Model; -class OrganizationalUnitTypes +final class OrganizationalUnitTypes { + public const ORGANIZATIONAL_UNIT = 'ORGANIZATIONAL_UNIT'; + public const CLASSROOMS_GROUP = 'CLASSROOMS_GROUP'; + public const CLASSROOM = 'CLASSROOM'; + public const CLIENTS_GROUP = 'CLIENTS_GROUP'; + private const ORGANIZATIONAL_UNIT_TYPES = [ + self::ORGANIZATIONAL_UNIT => 'Unidad Organizativa', + self::CLASSROOMS_GROUP => 'Grupo de aulas', + self::CLASSROOM => 'Aula', + self::CLIENTS_GROUP => 'Grupo de ordenadores', + ]; + + public static function getOrganizationalUnitTypes(): array + { + return self::ORGANIZATIONAL_UNIT_TYPES; + } + + public static function getOrganizationalUnitType(string $organizationalUnit): ?string + { + return self::ORGANIZATIONAL_UNIT_TYPES[$organizationalUnit] ?? null; + } + + public static function getOrganizationalUnitTypeKeys(): array + { + return array_keys(self::ORGANIZATIONAL_UNIT_TYPES); + } } \ No newline at end of file diff --git a/src/State/Processor/OrganizationalUnitProcessor.php b/src/State/Processor/OrganizationalUnitProcessor.php index 4dd6aac..5bd3c99 100644 --- a/src/State/Processor/OrganizationalUnitProcessor.php +++ b/src/State/Processor/OrganizationalUnitProcessor.php @@ -9,7 +9,10 @@ use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Put; use ApiPlatform\State\ProcessorInterface; use ApiPlatform\Validator\ValidatorInterface; -use App\Dto\Input\OrganizationalUnitInput; +use App\Dto\Input\OrganizationalUnitClassroomGroupInput; +use App\Dto\Input\OrganizationalUnitClassroomInput; +use App\Dto\Input\OrganizationalUnitClientGroupInput; +use App\Dto\Input\OrganizationalUnitRootInput; use App\Dto\Output\OrganizationalUnitOutput; use App\Repository\OrganizationalUnitRepository; @@ -42,8 +45,16 @@ class OrganizationalUnitProcessor implements ProcessorInterface */ private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): OrganizationalUnitOutput { - if (!($data instanceof OrganizationalUnitOutput)) { - throw new \Exception(sprintf('data is not instance of %s', OrganizationalUnitInput::class)); + if (!($data instanceof OrganizationalUnitRootInput) && + !($data instanceof OrganizationalUnitClassroomInput) && + !($data instanceof OrganizationalUnitClientGroupInput) && + !($data instanceof OrganizationalUnitClassroomGroupInput)) { + throw new \Exception(sprintf('data is not an instance of %s, %s, %s, or %s', + OrganizationalUnitRootInput::class, + OrganizationalUnitClassroomInput::class, + OrganizationalUnitClientGroupInput::class, + OrganizationalUnitClassroomGroupInput::class + )); } $entity = null; From 80606388093f38aea6b13995506189ff7db5f841 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Fri, 7 Jun 2024 15:39:47 +0200 Subject: [PATCH 03/35] refs #423. New tables hardware and hardware-profile --- config/api_platform/Client.yaml | 0 config/api_platform/Hardware.yaml | 0 config/api_platform/HardwareProfile.yaml | 0 docker/xdebug.ini | 0 migrations/Version20240529131520.php | 34 ----- migrations/Version20240605094344.php | 32 ----- migrations/Version20240605100013.php | 33 ----- ...28093352.php => Version20240606081620.php} | 6 +- migrations/Version20240606102152.php | 47 ++++++ src/Dto/Input/ClientInput.php | 8 ++ src/Dto/Input/HardwareInput.php | 8 ++ src/Dto/Output/ClientOutput.php | 8 ++ src/Dto/Output/HardwareOutput.php | 8 ++ src/Dto/Output/NetworkSettingsOutput.php | 8 ++ src/Entity/Client.php | 17 ++- src/Entity/Hardware.php | 89 ++++++++++++ src/Entity/HardwareProfile.php | 136 ++++++++++++++++++ src/Entity/NetworkSettings.php | 7 +- src/Entity/OrganizationalUnit.php | 41 +++++- src/Repository/ClientRepository.php | 27 +--- src/Repository/HardwareProfileRepository.php | 43 ++++++ src/Repository/HardwareRepository.php | 18 +++ src/State/Processor/ClientProcessor.php | 8 ++ src/State/Processor/HardwareProcessor.php | 8 ++ src/State/Provider/ClientProvider.php | 8 ++ src/State/Provider/HardwareProvider.php | 8 ++ 26 files changed, 470 insertions(+), 132 deletions(-) create mode 100644 config/api_platform/Client.yaml create mode 100644 config/api_platform/Hardware.yaml create mode 100644 config/api_platform/HardwareProfile.yaml create mode 100644 docker/xdebug.ini delete mode 100644 migrations/Version20240529131520.php delete mode 100644 migrations/Version20240605094344.php delete mode 100644 migrations/Version20240605100013.php rename migrations/{Version20240528093352.php => Version20240606081620.php} (94%) create mode 100644 migrations/Version20240606102152.php create mode 100644 src/Dto/Input/ClientInput.php create mode 100644 src/Dto/Input/HardwareInput.php create mode 100644 src/Dto/Output/ClientOutput.php create mode 100644 src/Dto/Output/HardwareOutput.php create mode 100644 src/Dto/Output/NetworkSettingsOutput.php create mode 100644 src/Entity/Hardware.php create mode 100644 src/Entity/HardwareProfile.php create mode 100644 src/Repository/HardwareProfileRepository.php create mode 100644 src/Repository/HardwareRepository.php create mode 100644 src/State/Processor/ClientProcessor.php create mode 100644 src/State/Processor/HardwareProcessor.php create mode 100644 src/State/Provider/ClientProvider.php create mode 100644 src/State/Provider/HardwareProvider.php diff --git a/config/api_platform/Client.yaml b/config/api_platform/Client.yaml new file mode 100644 index 0000000..e69de29 diff --git a/config/api_platform/Hardware.yaml b/config/api_platform/Hardware.yaml new file mode 100644 index 0000000..e69de29 diff --git a/config/api_platform/HardwareProfile.yaml b/config/api_platform/HardwareProfile.yaml new file mode 100644 index 0000000..e69de29 diff --git a/docker/xdebug.ini b/docker/xdebug.ini new file mode 100644 index 0000000..e69de29 diff --git a/migrations/Version20240529131520.php b/migrations/Version20240529131520.php deleted file mode 100644 index b596cab..0000000 --- a/migrations/Version20240529131520.php +++ /dev/null @@ -1,34 +0,0 @@ -addSql('ALTER TABLE organizational_unit DROP FOREIGN KEY FK_749AEB2D727ACA70'); - $this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D727ACA70 FOREIGN KEY (parent_id) REFERENCES organizational_unit (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 organizational_unit DROP FOREIGN KEY FK_749AEB2D727ACA70'); - $this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D727ACA70 FOREIGN KEY (parent_id) REFERENCES organizational_unit (id)'); - } -} diff --git a/migrations/Version20240605094344.php b/migrations/Version20240605094344.php deleted file mode 100644 index 5f6de70..0000000 --- a/migrations/Version20240605094344.php +++ /dev/null @@ -1,32 +0,0 @@ -addSql('ALTER TABLE organizational_unit ADD type VARCHAR(255) NOT NULL'); - } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql('ALTER TABLE organizational_unit DROP type'); - } -} diff --git a/migrations/Version20240605100013.php b/migrations/Version20240605100013.php deleted file mode 100644 index 4d24099..0000000 --- a/migrations/Version20240605100013.php +++ /dev/null @@ -1,33 +0,0 @@ -addSql('ALTER TABLE organizational_unit ADD network_settings VARCHAR(255) DEFAULT NULL, ADD location VARCHAR(255) DEFAULT NULL, ADD projector TINYINT(1) DEFAULT NULL, ADD board TINYINT(1) DEFAULT NULL, CHANGE network_settings_id capacity INT DEFAULT NULL'); - } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql('ALTER TABLE organizational_unit DROP network_settings, DROP location, DROP projector, DROP board, CHANGE capacity network_settings_id INT DEFAULT NULL'); - $this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D9B9A36D0 FOREIGN KEY (network_settings_id) REFERENCES network_settings (id)'); - $this->addSql('CREATE INDEX IDX_749AEB2D9B9A36D0 ON organizational_unit (network_settings_id)'); - } -} diff --git a/migrations/Version20240528093352.php b/migrations/Version20240606081620.php similarity index 94% rename from migrations/Version20240528093352.php rename to migrations/Version20240606081620.php index 60ec26a..498f6b2 100644 --- a/migrations/Version20240528093352.php +++ b/migrations/Version20240606081620.php @@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration; /** * Auto-generated Migration: Please modify to your needs! */ -final class Version20240528093352 extends AbstractMigration +final class Version20240606081620 extends AbstractMigration { public function getDescription(): string { @@ -26,14 +26,14 @@ final class Version20240528093352 extends AbstractMigration $this->addSql('CREATE TABLE gruposordenadores (idgrupo INT AUTO_INCREMENT NOT NULL, nombregrupoordenador VARCHAR(255) NOT NULL, idaula VARCHAR(255) NOT NULL, grupoid VARCHAR(255) NOT NULL, comentarios VARCHAR(255) NOT NULL, PRIMARY KEY(idgrupo)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE network_settings (id INT AUTO_INCREMENT 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, proxy VARCHAR(255) DEFAULT NULL, dns VARCHAR(255) DEFAULT NULL, netmask VARCHAR(255) DEFAULT NULL, router VARCHAR(255) DEFAULT NULL, ntp VARCHAR(255) DEFAULT NULL, p2p_time INT DEFAULT NULL, p2p_mode VARCHAR(255) DEFAULT NULL, mcast_ip VARCHAR(255) DEFAULT NULL, mcast_speed INT NOT NULL, mcast_mode VARCHAR(255) DEFAULT NULL, mcast_port INT DEFAULT NULL, UNIQUE INDEX UNIQ_48869B54D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE ordenadores (idordenador INT AUTO_INCREMENT NOT NULL, PRIMARY KEY(idordenador)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('CREATE TABLE organizational_unit (id INT AUTO_INCREMENT NOT NULL, parent_id INT DEFAULT NULL, network_settings_id INT DEFAULT 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, description VARCHAR(255) DEFAULT NULL, comments VARCHAR(255) DEFAULT NULL, path VARCHAR(255) DEFAULT NULL, level INT DEFAULT NULL, slug VARCHAR(255) DEFAULT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_749AEB2DD17F50A6 (uuid), INDEX IDX_749AEB2D727ACA70 (parent_id), INDEX IDX_749AEB2D9B9A36D0 (network_settings_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE organizational_unit (id INT AUTO_INCREMENT NOT NULL, parent_id INT DEFAULT NULL, network_settings_id INT DEFAULT 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, description VARCHAR(255) DEFAULT NULL, comments VARCHAR(255) DEFAULT NULL, path VARCHAR(255) DEFAULT NULL, level INT DEFAULT NULL, slug VARCHAR(255) DEFAULT NULL, type VARCHAR(255) NOT NULL, location VARCHAR(255) DEFAULT NULL, projector TINYINT(1) DEFAULT NULL, board TINYINT(1) DEFAULT NULL, capacity INT DEFAULT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_749AEB2DD17F50A6 (uuid), INDEX IDX_749AEB2D727ACA70 (parent_id), INDEX IDX_749AEB2D9B9A36D0 (network_settings_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE refresh_tokens (id INT AUTO_INCREMENT NOT NULL, refresh_token VARCHAR(128) NOT NULL, username VARCHAR(255) NOT NULL, valid DATETIME NOT NULL, UNIQUE INDEX UNIQ_9BACE7E1C74F2195 (refresh_token), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE user (id INT AUTO_INCREMENT 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, username VARCHAR(180) NOT NULL, roles JSON NOT NULL COMMENT \'(DC2Type:json)\', password VARCHAR(255) NOT NULL, enabled TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_8D93D649D17F50A6 (uuid), UNIQUE INDEX UNIQ_IDENTIFIER_USERNAME (username), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE user_organizational_unit (user_id INT NOT NULL, organizational_unit_id INT NOT NULL, INDEX IDX_5E59845FA76ED395 (user_id), INDEX IDX_5E59845FFB84408A (organizational_unit_id), PRIMARY KEY(user_id, organizational_unit_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE user_group (id INT AUTO_INCREMENT 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, permissions JSON NOT NULL COMMENT \'(DC2Type:json)\', name VARCHAR(255) NOT NULL, enabled TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_8F02BF9DD17F50A6 (uuid), UNIQUE INDEX UNIQ_IDENTIFIER_NAME (name), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE user_group_user (user_group_id INT NOT NULL, user_id INT NOT NULL, INDEX IDX_3AE4BD51ED93D47 (user_group_id), INDEX IDX_3AE4BD5A76ED395 (user_id), PRIMARY KEY(user_group_id, user_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455FB84408A FOREIGN KEY (organizational_unit_id) REFERENCES organizational_unit (id)'); - $this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D727ACA70 FOREIGN KEY (parent_id) REFERENCES organizational_unit (id)'); + $this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D727ACA70 FOREIGN KEY (parent_id) REFERENCES organizational_unit (id) ON DELETE SET NULL'); $this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D9B9A36D0 FOREIGN KEY (network_settings_id) REFERENCES network_settings (id)'); $this->addSql('ALTER TABLE user_organizational_unit ADD CONSTRAINT FK_5E59845FA76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE'); $this->addSql('ALTER TABLE user_organizational_unit ADD CONSTRAINT FK_5E59845FFB84408A FOREIGN KEY (organizational_unit_id) REFERENCES organizational_unit (id) ON DELETE CASCADE'); diff --git a/migrations/Version20240606102152.php b/migrations/Version20240606102152.php new file mode 100644 index 0000000..3415b95 --- /dev/null +++ b/migrations/Version20240606102152.php @@ -0,0 +1,47 @@ +addSql('CREATE TABLE hardware (id INT AUTO_INCREMENT 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, description VARCHAR(255) DEFAULT NULL, type VARCHAR(255) DEFAULT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_FE99E9E0D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE hardware_profile (id INT AUTO_INCREMENT NOT NULL, organizational_unit_id INT DEFAULT 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, description VARCHAR(255) DEFAULT NULL, comments VARCHAR(255) DEFAULT NULL, UNIQUE INDEX UNIQ_2D9A2460D17F50A6 (uuid), INDEX IDX_2D9A2460FB84408A (organizational_unit_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE hardware_profile_hardware (hardware_profile_id INT NOT NULL, hardware_id INT NOT NULL, INDEX IDX_18C7E12CFA495C1 (hardware_profile_id), INDEX IDX_18C7E12C9CC762B (hardware_id), PRIMARY KEY(hardware_profile_id, hardware_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE hardware_profile ADD CONSTRAINT FK_2D9A2460FB84408A FOREIGN KEY (organizational_unit_id) REFERENCES organizational_unit (id)'); + $this->addSql('ALTER TABLE hardware_profile_hardware ADD CONSTRAINT FK_18C7E12CFA495C1 FOREIGN KEY (hardware_profile_id) REFERENCES hardware_profile (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE hardware_profile_hardware ADD CONSTRAINT FK_18C7E12C9CC762B FOREIGN KEY (hardware_id) REFERENCES hardware (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE client ADD hardware_profile_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455CFA495C1 FOREIGN KEY (hardware_profile_id) REFERENCES hardware_profile (id)'); + $this->addSql('CREATE INDEX IDX_C7440455CFA495C1 ON client (hardware_profile_id)'); + } + + 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_C7440455CFA495C1'); + $this->addSql('ALTER TABLE hardware_profile DROP FOREIGN KEY FK_2D9A2460FB84408A'); + $this->addSql('ALTER TABLE hardware_profile_hardware DROP FOREIGN KEY FK_18C7E12CFA495C1'); + $this->addSql('ALTER TABLE hardware_profile_hardware DROP FOREIGN KEY FK_18C7E12C9CC762B'); + $this->addSql('DROP TABLE hardware'); + $this->addSql('DROP TABLE hardware_profile'); + $this->addSql('DROP TABLE hardware_profile_hardware'); + $this->addSql('DROP INDEX IDX_C7440455CFA495C1 ON client'); + $this->addSql('ALTER TABLE client DROP hardware_profile_id'); + } +} diff --git a/src/Dto/Input/ClientInput.php b/src/Dto/Input/ClientInput.php new file mode 100644 index 0000000..c3af412 --- /dev/null +++ b/src/Dto/Input/ClientInput.php @@ -0,0 +1,8 @@ +netDriver; } - public function setNetDriver(string $netDriver): static + public function setNetDriver(?string $netDriver): static { $this->netDriver = $netDriver; @@ -128,4 +131,16 @@ class Client extends AbstractEntity return $this; } + + public function getHardwareProfile(): ?HardwareProfile + { + return $this->hardwareProfile; + } + + public function setHardwareProfile(?HardwareProfile $hardwareProfile): static + { + $this->hardwareProfile = $hardwareProfile; + + return $this; + } } diff --git a/src/Entity/Hardware.php b/src/Entity/Hardware.php new file mode 100644 index 0000000..5a1ba19 --- /dev/null +++ b/src/Entity/Hardware.php @@ -0,0 +1,89 @@ + + */ + #[ORM\ManyToMany(targetEntity: HardwareProfile::class, mappedBy: 'hardwareCollection')] + private Collection $hardwareProfiles; + + public function __construct() + { + parent::__Construct(); + + $this->hardwareProfiles = new ArrayCollection(); + } + + public function getId(): ?int + { + return $this->id; + } + + public function getDescription(): ?string + { + return $this->description; + } + + public function setDescription(?string $description): static + { + $this->description = $description; + + return $this; + } + + public function getType(): ?string + { + return $this->type; + } + + public function setType(?string $type): static + { + $this->type = $type; + + return $this; + } + + /** + * @return Collection + */ + public function getHardwareProfiles(): Collection + { + return $this->hardwareProfiles; + } + + public function addHardwareProfile(HardwareProfile $hardwareProfile): static + { + if (!$this->hardwareProfiles->contains($hardwareProfile)) { + $this->hardwareProfiles->add($hardwareProfile); + $hardwareProfile->addHardwareCollection($this); + } + + return $this; + } + + public function removeHardwareProfile(HardwareProfile $hardwareProfile): static + { + if ($this->hardwareProfiles->removeElement($hardwareProfile)) { + $hardwareProfile->removeHardwareCollection($this); + } + + return $this; + } +} diff --git a/src/Entity/HardwareProfile.php b/src/Entity/HardwareProfile.php new file mode 100644 index 0000000..432eedf --- /dev/null +++ b/src/Entity/HardwareProfile.php @@ -0,0 +1,136 @@ + + */ + #[ORM\ManyToMany(targetEntity: Hardware::class, inversedBy: 'hardwareProfiles')] + private Collection $hardwareCollection; + + /** + * @var Collection + */ + #[ORM\OneToMany(mappedBy: 'hardwareProfile', targetEntity: Client::class)] + private Collection $clients; + + public function __construct() + { + parent::__construct(); + + $this->hardwareCollection = new ArrayCollection(); + $this->clients = new ArrayCollection(); + } + + public function getId(): ?int + { + return $this->id; + } + + public function getDescription(): ?string + { + return $this->description; + } + + public function setDescription(?string $description): static + { + $this->description = $description; + + return $this; + } + + public function getComments(): ?string + { + return $this->comments; + } + + public function setComments(?string $comments): static + { + $this->comments = $comments; + + return $this; + } + + public function getOrganizationalUnit(): ?OrganizationalUnit + { + return $this->organizationalUnit; + } + + public function setOrganizationalUnit(?OrganizationalUnit $organizationalUnit): static + { + $this->organizationalUnit = $organizationalUnit; + + return $this; + } + + /** + * @return Collection + */ + public function getHardwareCollection(): Collection + { + return $this->hardwareCollection; + } + + public function addHardwareCollection(Hardware $hardwareCollection): static + { + if (!$this->hardwareCollection->contains($hardwareCollection)) { + $this->hardwareCollection->add($hardwareCollection); + } + + return $this; + } + + public function removeHardwareCollection(Hardware $hardwareCollection): static + { + $this->hardwareCollection->removeElement($hardwareCollection); + + return $this; + } + + /** + * @return Collection + */ + public function getClients(): Collection + { + return $this->clients; + } + + public function addClient(Client $client): static + { + if (!$this->clients->contains($client)) { + $this->clients->add($client); + $client->setHardwareProfile($this); + } + + return $this; + } + + public function removeClient(Client $client): static + { + if ($this->clients->removeElement($client)) { + // set the owning side to null (unless already changed) + if ($client->getHardwareProfile() === $this) { + $client->setHardwareProfile(null); + } + } + + return $this; + } +} diff --git a/src/Entity/NetworkSettings.php b/src/Entity/NetworkSettings.php index 7f36461..e229208 100644 --- a/src/Entity/NetworkSettings.php +++ b/src/Entity/NetworkSettings.php @@ -46,7 +46,7 @@ class NetworkSettings extends AbstractEntity /** * @var Collection */ - #[ORM\OneToMany(targetEntity: OrganizationalUnit::class, mappedBy: 'networkSettings')] + #[ORM\OneToMany(mappedBy: 'networkSettings', targetEntity: OrganizationalUnit::class)] private Collection $organizationalUnits; public function __construct() @@ -221,4 +221,9 @@ class NetworkSettings extends AbstractEntity return $this; } + + public function __toString(): string + { + return $this->getId() ? (string) $this->getId() : ''; + } } diff --git a/src/Entity/OrganizationalUnit.php b/src/Entity/OrganizationalUnit.php index 2bb01b8..6a66d38 100644 --- a/src/Entity/OrganizationalUnit.php +++ b/src/Entity/OrganizationalUnit.php @@ -44,8 +44,8 @@ class OrganizationalUnit extends AbstractEntity #[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)] private Collection $organizationalUnits; - #[ORM\ManyToOne(inversedBy: 'organizationalUnits')] - #[ORM\Column(nullable: true)] + #[ORM\ManyToOne(targetEntity: NetworkSettings::class, inversedBy: 'organizationalUnits')] + #[ORM\JoinColumn(nullable: true)] private ?NetworkSettings $networkSettings = null; /** @@ -75,12 +75,19 @@ class OrganizationalUnit extends AbstractEntity #[ORM\Column(nullable: true)] private ?int $capacity = null; + /** + * @var Collection + */ + #[ORM\OneToMany(mappedBy: 'organizationalUnit', targetEntity: HardwareProfile::class)] + private Collection $hardwareProfiles; + public function __construct() { parent::__construct(); $this->organizationalUnits = new ArrayCollection(); $this->users = new ArrayCollection(); $this->clients = new ArrayCollection(); + $this->hardwareProfiles = new ArrayCollection(); } public function getDescription(): ?string @@ -312,4 +319,34 @@ class OrganizationalUnit extends AbstractEntity return $this; } + + /** + * @return Collection + */ + public function getHardwareProfiles(): Collection + { + return $this->hardwareProfiles; + } + + public function addHardwareProfile(HardwareProfile $hardwareProfile): static + { + if (!$this->hardwareProfiles->contains($hardwareProfile)) { + $this->hardwareProfiles->add($hardwareProfile); + $hardwareProfile->setOrganizationalUnit($this); + } + + return $this; + } + + public function removeHardwareProfile(HardwareProfile $hardwareProfile): static + { + if ($this->hardwareProfiles->removeElement($hardwareProfile)) { + // set the owning side to null (unless already changed) + if ($hardwareProfile->getOrganizationalUnit() === $this) { + $hardwareProfile->setOrganizationalUnit(null); + } + } + + return $this; + } } diff --git a/src/Repository/ClientRepository.php b/src/Repository/ClientRepository.php index 81c3e7f..6ec469d 100644 --- a/src/Repository/ClientRepository.php +++ b/src/Repository/ClientRepository.php @@ -9,35 +9,10 @@ use Doctrine\Persistence\ManagerRegistry; /** * @extends ServiceEntityRepository */ -class ClientRepository extends ServiceEntityRepository +class ClientRepository extends AbstractRepository { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, Client::class); } - - // /** - // * @return Client[] Returns an array of Client objects - // */ - // public function findByExampleField($value): array - // { - // return $this->createQueryBuilder('c') - // ->andWhere('c.exampleField = :val') - // ->setParameter('val', $value) - // ->orderBy('c.id', 'ASC') - // ->setMaxResults(10) - // ->getQuery() - // ->getResult() - // ; - // } - - // public function findOneBySomeField($value): ?Client - // { - // return $this->createQueryBuilder('c') - // ->andWhere('c.exampleField = :val') - // ->setParameter('val', $value) - // ->getQuery() - // ->getOneOrNullResult() - // ; - // } } diff --git a/src/Repository/HardwareProfileRepository.php b/src/Repository/HardwareProfileRepository.php new file mode 100644 index 0000000..0e4ff1a --- /dev/null +++ b/src/Repository/HardwareProfileRepository.php @@ -0,0 +1,43 @@ + + */ +class HardwareProfileRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, HardwareProfile::class); + } + + // /** + // * @return HardwareProfile[] Returns an array of HardwareProfile objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('h') + // ->andWhere('h.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('h.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?HardwareProfile + // { + // return $this->createQueryBuilder('h') + // ->andWhere('h.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/src/Repository/HardwareRepository.php b/src/Repository/HardwareRepository.php new file mode 100644 index 0000000..21a1e2b --- /dev/null +++ b/src/Repository/HardwareRepository.php @@ -0,0 +1,18 @@ + + */ +class HardwareRepository extends AbstractRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Hardware::class); + } +} diff --git a/src/State/Processor/ClientProcessor.php b/src/State/Processor/ClientProcessor.php new file mode 100644 index 0000000..4f6e068 --- /dev/null +++ b/src/State/Processor/ClientProcessor.php @@ -0,0 +1,8 @@ + Date: Fri, 7 Jun 2024 15:40:51 +0200 Subject: [PATCH 04/35] refs #427. New endpoints, states, providers. CRUD OrganizationalUnit and CLient --- config/api_platform/Client.yaml | 33 ++++++++ config/api_platform/Hardware.yaml | 31 ++++++++ config/api_platform/OrganizationalUnit.yaml | 4 + config/api_platform/User.yaml | 1 - config/services.yaml | 10 +++ docker-compose.yaml | 2 + docker/Dockerfile-php | 10 +++ docker/xdebug.ini | 4 + src/DataFixtures/AppFixtures.php | 9 ++- src/Dto/Input/ClientInput.php | 75 ++++++++++++++++++- src/Dto/Input/HardwareInput.php | 45 ++++++++++- .../OrganizationalUnitClassroomGroupInput.php | 2 +- .../OrganizationalUnitClassroomInput.php | 72 +++++++++++++++++- .../OrganizationalUnitClientGroupInput.php | 2 +- src/Dto/Output/ClientOutput.php | 38 +++++++++- src/Dto/Output/HardwareOutput.php | 33 +++++++- src/Dto/Output/NetworkSettingsOutput.php | 61 ++++++++++++++- src/Dto/Output/OrganizationalUnitOutput.php | 26 +++++-- src/State/Processor/ClientProcessor.php | 67 ++++++++++++++++- src/State/Processor/HardwareProcessor.php | 68 ++++++++++++++++- .../Processor/OrganizationalUnitProcessor.php | 6 +- src/State/Provider/ClientProvider.php | 69 ++++++++++++++++- src/State/Provider/HardwareProvider.php | 71 +++++++++++++++++- .../Provider/OrganizationalUnitProvider.php | 28 ++++++- 24 files changed, 725 insertions(+), 42 deletions(-) diff --git a/config/api_platform/Client.yaml b/config/api_platform/Client.yaml index e69de29..196c658 100644 --- a/config/api_platform/Client.yaml +++ b/config/api_platform/Client.yaml @@ -0,0 +1,33 @@ +resources: + App\Entity\Client: + processor: App\State\Processor\ClientProcessor + input: App\Dto\Input\ClientInput + output: App\Dto\Output\ClientOutput + normalization_context: + groups: ['default', 'client:read'] + denormalization_context: + groups: ['client:write'] + operations: + ApiPlatform\Metadata\GetCollection: + provider: App\State\Provider\ClientProvider + filters: + - 'api_platform.filter.client.order' + - 'api_platform.filter.client.search' + - 'api_platform.filter.client.boolean' + ApiPlatform\Metadata\Get: + provider: App\State\Provider\ClientProvider + ApiPlatform\Metadata\Put: + provider: App\State\Provider\ClientProvider + ApiPlatform\Metadata\Patch: + provider: App\State\Provider\ClientProvider + validationContext: + groups: [ 'client:patch' ] + ApiPlatform\Metadata\Post: ~ + ApiPlatform\Metadata\Delete: ~ + +properties: + App\Entity\Client: + id: + identifier: false + uuid: + identifier: true \ No newline at end of file diff --git a/config/api_platform/Hardware.yaml b/config/api_platform/Hardware.yaml index e69de29..3e81cc6 100644 --- a/config/api_platform/Hardware.yaml +++ b/config/api_platform/Hardware.yaml @@ -0,0 +1,31 @@ +resources: + App\Entity\Hardware: + processor: App\State\Processor\HardwareProcessor + input: App\Dto\Input\HardwareInput + output: App\Dto\Output\HardwareOutput + normalization_context: + groups: ['default', 'hardware:read'] + denormalization_context: + groups: ['hardware:write'] + operations: + ApiPlatform\Metadata\GetCollection: + provider: App\State\Provider\HardwareProvider + filters: + - 'api_platform.filter.hardware.order' + - 'api_platform.filter.hardware.search' + - 'api_platform.filter.hardware.boolean' + ApiPlatform\Metadata\Get: + provider: App\State\Provider\HardwareProvider + ApiPlatform\Metadata\Put: + provider: App\State\Provider\HardwareProvider + ApiPlatform\Metadata\Patch: + provider: App\State\Provider\HardwareProvider + ApiPlatform\Metadata\Post: ~ + ApiPlatform\Metadata\Delete: ~ + +properties: + App\Entity\Hardware: + id: + identifier: false + uuid: + identifier: true \ No newline at end of file diff --git a/config/api_platform/OrganizationalUnit.yaml b/config/api_platform/OrganizationalUnit.yaml index 26fb903..2b7e137 100644 --- a/config/api_platform/OrganizationalUnit.yaml +++ b/config/api_platform/OrganizationalUnit.yaml @@ -1,6 +1,7 @@ resources: App\Entity\OrganizationalUnit: processor: App\State\Processor\OrganizationalUnitProcessor + output: App\Dto\Output\OrganizationalUnitOutput normalization_context: groups: ['default', 'organizational-unit:read'] denormalization_context: @@ -14,6 +15,9 @@ resources: provider: App\State\Provider\OrganizationalUnitProvider ApiPlatform\Metadata\Patch: provider: App\State\Provider\OrganizationalUnitProvider + validationContext: + groups: ['organizational-unit:patch' ] + ApiPlatform\Metadata\Delete: ~ organizational_unit_root: class: ApiPlatform\Metadata\Post diff --git a/config/api_platform/User.yaml b/config/api_platform/User.yaml index efe4597..8f58ad6 100644 --- a/config/api_platform/User.yaml +++ b/config/api_platform/User.yaml @@ -8,7 +8,6 @@ resources: groups: ['default', 'user:read'] denormalization_context: groups: ['user:write'] - operations: ApiPlatform\Metadata\GetCollection: provider: App\State\Provider\UserProvider diff --git a/config/services.yaml b/config/services.yaml index 7e12544..d9649c3 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -36,6 +36,16 @@ services: $itemProvider: '@api_platform.doctrine.orm.state.item_provider' App\State\Provider\OrganizationalUnitProvider: + bind: + $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' + $itemProvider: '@api_platform.doctrine.orm.state.item_provider' + + App\State\Provider\ClientProvider: + bind: + $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' + $itemProvider: '@api_platform.doctrine.orm.state.item_provider' + + App\State\Provider\HardwareProvider: bind: $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' $itemProvider: '@api_platform.doctrine.orm.state.item_provider' \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index b970b39..8b3b902 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -37,6 +37,8 @@ services: - ./:/var/www/html depends_on: - database + environment: + PHP_IDE_CONFIG: serverName=ogcore networks: - ogcore-network diff --git a/docker/Dockerfile-php b/docker/Dockerfile-php index 0ce2698..da6f17e 100644 --- a/docker/Dockerfile-php +++ b/docker/Dockerfile-php @@ -18,3 +18,13 @@ RUN apk add --no-cache bash git jq moreutils openssh rsync yq ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/ RUN chmod +x /usr/local/bin/install-php-extensions RUN install-php-extensions sockets + +# Add xdebug +RUN apk add --no-cache --virtual .build-deps $PHPIZE_DEPS +RUN apk add --update linux-headers +RUN pecl install xdebug +RUN docker-php-ext-enable xdebug +RUN apk del -f .build-deps + +COPY ./docker/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini + diff --git a/docker/xdebug.ini b/docker/xdebug.ini index e69de29..f717c09 100644 --- a/docker/xdebug.ini +++ b/docker/xdebug.ini @@ -0,0 +1,4 @@ +xdebug.mode=debug +xdebug.start_with_request=yes +xdebug.client_host=172.17.0.1/ +xdebug.client_port=9003 \ No newline at end of file diff --git a/src/DataFixtures/AppFixtures.php b/src/DataFixtures/AppFixtures.php index f2b8986..76fb475 100644 --- a/src/DataFixtures/AppFixtures.php +++ b/src/DataFixtures/AppFixtures.php @@ -5,6 +5,7 @@ namespace App\DataFixtures; use App\Entity\OrganizationalUnit; use App\Factory\OrganizationalUnitFactory; use App\Factory\UserFactory; +use App\Model\OrganizationalUnitTypes; use App\Model\UserGroupPermissions; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Persistence\ObjectManager; @@ -19,16 +20,18 @@ class AppFixtures extends Fixture public function load(ObjectManager $manager): void { UserFactory::createOne(['username' => self::ADMIN_USER, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); - $rootUnit = OrganizationalUnitFactory::createOne(['name' => 'Centro de Computación', 'parent' => null]); + $rootUnit = OrganizationalUnitFactory::createOne(['name' => 'Centro de Computación', 'parent' => null, 'type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); $roomUnit = OrganizationalUnitFactory::createOne([ 'name' => 'Aula 1', - 'parent' => $rootUnit + 'parent' => $rootUnit, + 'type' => OrganizationalUnitTypes::CLASSROOMS_GROUP ]); OrganizationalUnitFactory::createOne([ 'name' => 'Aula 2', - 'parent' => $roomUnit + 'parent' => $roomUnit, + 'type' => OrganizationalUnitTypes::CLASSROOM ]); } } diff --git a/src/Dto/Input/ClientInput.php b/src/Dto/Input/ClientInput.php index c3af412..f929311 100644 --- a/src/Dto/Input/ClientInput.php +++ b/src/Dto/Input/ClientInput.php @@ -2,7 +2,78 @@ namespace App\Dto\Input; -class ClientInput -{ +use ApiPlatform\Metadata\ApiProperty; +use App\Dto\Output\OrganizationalUnitOutput; +use App\Entity\Client; +use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Validator\Constraints as Assert; +final class ClientInput +{ + #[Assert\NotBlank] + #[Groups(['client:write'])] + #[ApiProperty(description: 'The name of the client', example: "Client 1")] + public ?string $name = null; + + #[Groups(['client:write'])] + #[ApiProperty(description: 'The serial number of the client', example: "123456")] + public ?string $serialNumber = null; + + #[Groups(['client:write'])] + #[ApiProperty(description: 'The network interface of the client', example: "eth0")] + public ?string $netiface = null; + + #[Groups(['client:write'])] + #[ApiProperty(description: 'The network driver of the client', example: "e1000e")] + public ?string $netDriver = null; + + #[Groups(['client:write'])] + #[ApiProperty(description: 'The MAC address of the client', example: "00:11:22:33:44:55")] + public ?string $mac = null; + + #[Groups(['client:write'])] + #[ApiProperty(description: 'The IP address of the client', example: "127.0.0.1")] + public ?string $ip = null; + + #[Groups(['client:write'])] + public ?string $status = null; + + #[Assert\NotNull] + #[Groups(['client:write', 'client:patch'])] + #[ApiProperty(description: 'The organizational unit of the client')] + public ?OrganizationalUnitOutput $organizationalUnit = null; + + public function __construct(?Client $client = null) + { + if (!$client) { + return; + } + + $this->name = $client->getName(); + $this->serialNumber = $client->getSerialNumber(); + $this->netiface = $client->getNetiface(); + $this->organizationalUnit = new OrganizationalUnitOutput($client->getOrganizationalUnit()); + $this->netDriver = $client->getNetDriver(); + $this->mac = $client->getMac(); + $this->ip = $client->getIp(); + $this->status = $client->getStatus(); + } + + public function createOrUpdateEntity(?Client $client = null): Client + { + if (!$client) { + $client = new Client(); + } + + $client->setName($this->name); + $client->setSerialNumber($this->serialNumber); + $client->setNetiface($this->netiface); + $client->setOrganizationalUnit($this->organizationalUnit->getEntity()); + $client->setNetDriver($this->netDriver); + $client->setMac($this->mac); + $client->setIp($this->ip); + $client->setStatus($this->status); + + return $client; + } } \ No newline at end of file diff --git a/src/Dto/Input/HardwareInput.php b/src/Dto/Input/HardwareInput.php index d3134fd..f46117a 100644 --- a/src/Dto/Input/HardwareInput.php +++ b/src/Dto/Input/HardwareInput.php @@ -2,7 +2,48 @@ namespace App\Dto\Input; -class HardwareInput -{ +use ApiPlatform\Metadata\ApiProperty; +use App\Entity\Hardware; +use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Validator\Constraints as Assert; +final class HardwareInput +{ + #[Assert\NotBlank] + #[Groups(['hardware:write'])] + #[ApiProperty(description: 'The name of the hardware', example: "Hardware 1")] + public ?string $name = null; + + #[Groups(['hardware:write'])] + #[ApiProperty(description: 'The description of the hardware', example: "Hardware 1 description")] + public ?string $description = null; + + #[Groups(['hardware:write'])] + #[ApiProperty(description: 'The type of the hardware', example: "Server")] + public ?string $type = null; + + + public function __construct(?Hardware $hardware = null) + { + if (!$hardware) { + return; + } + + $this->name = $hardware->getName(); + $this->description = $hardware->getDescription(); + $this->type = $hardware->getType(); + } + + public function createOrUpdateEntity(?Hardware $hardware = null): Hardware + { + if (!$hardware) { + $hardware = new Hardware(); + } + + $hardware->setName($this->name); + $hardware->setDescription($this->description); + $hardware->setType($this->type); + + return $hardware; + } } \ No newline at end of file diff --git a/src/Dto/Input/OrganizationalUnitClassroomGroupInput.php b/src/Dto/Input/OrganizationalUnitClassroomGroupInput.php index 3d1aee5..8b8f33f 100644 --- a/src/Dto/Input/OrganizationalUnitClassroomGroupInput.php +++ b/src/Dto/Input/OrganizationalUnitClassroomGroupInput.php @@ -31,7 +31,7 @@ final class OrganizationalUnitClassroomGroupInput } $this->name = $organizationalUnit->getName(); - $this->parent = $organizationalUnit->getParent(); + $this->parent = new OrganizationalUnitOutput($organizationalUnit->getParent()); $this->description = $organizationalUnit->getDescription(); $this->comments = $organizationalUnit->getComments(); } diff --git a/src/Dto/Input/OrganizationalUnitClassroomInput.php b/src/Dto/Input/OrganizationalUnitClassroomInput.php index 1bdf977..7603906 100644 --- a/src/Dto/Input/OrganizationalUnitClassroomInput.php +++ b/src/Dto/Input/OrganizationalUnitClassroomInput.php @@ -3,8 +3,10 @@ namespace App\Dto\Input; use App\Dto\Output\OrganizationalUnitOutput; +use App\Entity\NetworkSettings; use App\Entity\OrganizationalUnit; use App\Model\OrganizationalUnitTypes; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; @@ -15,7 +17,7 @@ final class OrganizationalUnitClassroomInput public ?string $name = null; #[Assert\NotNull] - #[Groups(['organizational-unit:write'])] + #[Groups(['organizational-unit:write', 'organizational-unit:patch'])] public ?OrganizationalUnitOutput $parent = null; #[Groups(['organizational-unit:write'])] @@ -36,6 +38,40 @@ final class OrganizationalUnitClassroomInput #[Groups(['organizational-unit:write'])] public ?int $capacity = null; + #[Groups(['organizational-unit:write'])] + public ?string $proxy = null; + + #[Groups(['organizational-unit:write'])] + public ?string $dns = null; + + #[Groups(['organizational-unit:write'])] + public ?string $netmask = null; + + #[Groups(['organizational-unit:write'])] + public ?string $router = null; + + #[Groups(['organizational-unit:write'])] + public ?string $ntp = null; + + #[Groups(['organizational-unit:write'])] + public ?string $p2pMode = null; + + #[Groups(['organizational-unit:write'])] + public ?int $p2pTime = null; + + #[Assert\Ip] + #[Groups(['organizational-unit:write'])] + public ?string $mcastIp = null; + + #[Groups(['organizational-unit:write'])] + public ?int $mcastSpeed = null; + + #[Groups(['organizational-unit:write'])] + public ?int $mcastPort = null; + + #[Groups(['organizational-unit:write'])] + public ?string $mcastMode = null; + public function __construct(?OrganizationalUnit $organizationalUnit = null) { if (!$organizationalUnit) { @@ -43,16 +79,30 @@ final class OrganizationalUnitClassroomInput } $this->name = $organizationalUnit->getName(); - $this->parent = $organizationalUnit->getParent(); + $this->parent = new OrganizationalUnitOutput($organizationalUnit->getParent()); $this->description = $organizationalUnit->getDescription(); $this->comments = $organizationalUnit->getComments(); $this->location = $organizationalUnit->getLocation(); $this->projector = $organizationalUnit->isProjector(); $this->board = $organizationalUnit->isBoard(); $this->capacity = $organizationalUnit->getCapacity(); + $this->proxy = $organizationalUnit->getNetworkSettings()->getProxy(); + $this->dns = $organizationalUnit->getNetworkSettings()->getDns(); + $this->netmask = $organizationalUnit->getNetworkSettings()->getNetmask(); + $this->router = $organizationalUnit->getNetworkSettings()->getRouter(); + $this->ntp = $organizationalUnit->getNetworkSettings()->getNtp(); + $this->p2pMode = $organizationalUnit->getNetworkSettings()->getP2pMode(); + $this->p2pTime = $organizationalUnit->getNetworkSettings()->getP2pTime(); + $this->mcastIp = $organizationalUnit->getNetworkSettings()->getMcastIp(); + $this->mcastSpeed = $organizationalUnit->getNetworkSettings()->getMcastSpeed(); + $this->mcastPort = $organizationalUnit->getNetworkSettings()->getMcastPort(); + $this->mcastMode = $organizationalUnit->getNetworkSettings()->getMcastMode(); } - public function createOrUpdateEntity(?OrganizationalUnit $organizationalUnit = null): OrganizationalUnit + public function createOrUpdateEntity( + ?OrganizationalUnit $organizationalUnit = null, + ?EntityManagerInterface $entityManager = null + ): OrganizationalUnit { if (!$organizationalUnit) { $organizationalUnit = new OrganizationalUnit(); @@ -68,6 +118,22 @@ final class OrganizationalUnitClassroomInput $organizationalUnit->setBoard($this->board); $organizationalUnit->setCapacity($this->capacity); + $networkSettings = new NetworkSettings(); + $networkSettings->setProxy($this->proxy); + $networkSettings->setDns($this->dns); + $networkSettings->setNetmask($this->netmask); + $networkSettings->setRouter($this->router); + $networkSettings->setNtp($this->ntp); + $networkSettings->setP2pMode($this->p2pMode); + $networkSettings->setP2pTime($this->p2pTime); + $networkSettings->setMcastIp($this->mcastIp); + $networkSettings->setMcastSpeed($this->mcastSpeed); + $networkSettings->setMcastPort($this->mcastPort); + $networkSettings->setMcastMode($this->mcastMode); + $entityManager->persist($networkSettings); + + $organizationalUnit->setNetworkSettings($networkSettings); + return $organizationalUnit; } } \ No newline at end of file diff --git a/src/Dto/Input/OrganizationalUnitClientGroupInput.php b/src/Dto/Input/OrganizationalUnitClientGroupInput.php index 9ef1742..bbc9458 100644 --- a/src/Dto/Input/OrganizationalUnitClientGroupInput.php +++ b/src/Dto/Input/OrganizationalUnitClientGroupInput.php @@ -31,7 +31,7 @@ final class OrganizationalUnitClientGroupInput } $this->name = $organizationalUnit->getName(); - $this->parent = $organizationalUnit->getParent(); + $this->parent = new OrganizationalUnitOutput($organizationalUnit->getParent()); $this->description = $organizationalUnit->getDescription(); $this->comments = $organizationalUnit->getComments(); } diff --git a/src/Dto/Output/ClientOutput.php b/src/Dto/Output/ClientOutput.php index 3bcaf3a..fd48afd 100644 --- a/src/Dto/Output/ClientOutput.php +++ b/src/Dto/Output/ClientOutput.php @@ -2,7 +2,41 @@ namespace App\Dto\Output; -class ClientOutput -{ +use ApiPlatform\Metadata\Get; +use App\Entity\Client; +use App\Entity\OrganizationalUnit; +use Symfony\Component\Serializer\Annotation\Groups; +#[Get(shortName: 'Client')] +final class ClientOutput extends AbstractOutput +{ + #[Groups(['client:read'])] + public string $name; + + #[Groups(['client:read'])] + public ?string $serialNumber = ''; + + #[Groups(['client:read'])] + public ?string $netiface = ''; + + #[Groups(['client:read'])] + public ?OrganizationalUnit $organizationalUnit = null; + + #[Groups(['client:read'])] + public \DateTime $createAt; + + #[Groups(['client:read'])] + public ?string $createBy = null; + + public function __construct(Client $client) + { + parent::__construct($client); + + $this->name = $client->getName(); + $this->serialNumber = $client->getSerialNumber(); + $this->netiface = $client->getNetiface(); + $this->organizationalUnit = $client->getOrganizationalUnit(); + $this->createAt = $client->getCreatedAt(); + $this->createBy = $client->getCreatedBy(); + } } \ No newline at end of file diff --git a/src/Dto/Output/HardwareOutput.php b/src/Dto/Output/HardwareOutput.php index e1603db..a0ebf9d 100644 --- a/src/Dto/Output/HardwareOutput.php +++ b/src/Dto/Output/HardwareOutput.php @@ -2,7 +2,36 @@ namespace App\Dto\Output; -class HardwareOutput -{ +use ApiPlatform\Metadata\Get; +use App\Entity\Hardware; +use Symfony\Component\Serializer\Annotation\Groups; +#[Get(shortName: 'Hardware')] +final class HardwareOutput extends AbstractOutput +{ + #[Groups(['hardware:read'])] + public string $name; + + #[Groups(['hardware:read'])] + public string $description; + + #[Groups(['hardware:read'])] + public string $type; + + #[Groups(['hardware:read'])] + public \DateTime $createAt; + + #[Groups(['hardware:read'])] + public ?string $createBy = null; + + public function __construct(Hardware $hardware) + { + parent::__construct($hardware); + + $this->name = $hardware->getName(); + $this->description = $hardware->getDescription(); + $this->type = $hardware->getType(); + $this->createAt = $hardware->getCreatedAt(); + $this->createBy = $hardware->getCreatedBy(); + } } \ No newline at end of file diff --git a/src/Dto/Output/NetworkSettingsOutput.php b/src/Dto/Output/NetworkSettingsOutput.php index c5ae79a..082d26b 100644 --- a/src/Dto/Output/NetworkSettingsOutput.php +++ b/src/Dto/Output/NetworkSettingsOutput.php @@ -2,7 +2,64 @@ namespace App\Dto\Output; -class NetworkSettingsOutput -{ +use App\Entity\NetworkSettings; +use Symfony\Component\Serializer\Annotation\Groups; +final class NetworkSettingsOutput +{ + #[Groups(['organizational-unit:read'])] + public ?string $proxy = null; + + #[Groups(['organizational-unit:read'])] + public ?string $dns = null; + + #[Groups(['organizational-unit:read'])] + public ?string $netmask = null; + + #[Groups(['organizational-unit:read'])] + public ?string $router = null; + + #[Groups(['organizational-unit:read'])] + public ?string $ntp = null; + + #[Groups(['organizational-unit:read'])] + public ?string $p2pMode = null; + + #[Groups(['organizational-unit:read'])] + public ?int $p2pTime = null; + + #[Groups(['organizational-unit:read'])] + public ?string $mcastIp = null; + + #[Groups(['organizational-unit:read'])] + public ?int $mcastSpeed = null; + + #[Groups(['organizational-unit:read'])] + public ?int $mcastPort = null; + + #[Groups(['organizational-unit:read'])] + public ?string $mcastMode = null; + + #[Groups(['organizational-unit:read'])] + public \DateTime $createAt; + + #[Groups(['organizational-unit:read'])] + public ?string $createBy = null; + + public function __construct(NetworkSettings $networkSettings) + { + $this->proxy = $networkSettings->getProxy(); + $this->dns = $networkSettings->getDns(); + $this->netmask = $networkSettings->getNetmask(); + $this->router = $networkSettings->getRouter(); + $this->ntp = $networkSettings->getNtp(); + $this->p2pMode = $networkSettings->getP2pMode(); + $this->p2pTime = $networkSettings->getP2pTime(); + $this->mcastIp = $networkSettings->getMcastIp(); + $this->mcastSpeed = $networkSettings->getMcastSpeed(); + $this->mcastPort = $networkSettings->getMcastPort(); + $this->mcastMode = $networkSettings->getMcastMode(); + $this->createAt = $networkSettings->getCreatedAt(); + $this->createBy = $networkSettings->getCreatedBy(); + } } \ No newline at end of file diff --git a/src/Dto/Output/OrganizationalUnitOutput.php b/src/Dto/Output/OrganizationalUnitOutput.php index 923b2f0..2ab65e5 100644 --- a/src/Dto/Output/OrganizationalUnitOutput.php +++ b/src/Dto/Output/OrganizationalUnitOutput.php @@ -2,6 +2,7 @@ namespace App\Dto\Output; +use ApiPlatform\Metadata\ApiProperty; use ApiPlatform\Metadata\Get; use App\Entity\OrganizationalUnit; use Symfony\Component\Serializer\Annotation\Groups; @@ -16,16 +17,23 @@ final class OrganizationalUnitOutput extends AbstractOutput public string $type; #[Groups(['organizational-unit:read'])] - public ?OrganizationalUnit $parent = null; + public ?self $parent = null; #[Groups(['organizational-unit:read'])] public string $path; #[Groups(['organizational-unit:read'])] - public \DateTime $createAt; + public ?NetworkSettingsOutput $networkSettings = null; + + #[Groups(['user:read'])] + public array $clients = []; #[Groups(['organizational-unit:read'])] - public ?string $createBy = null; + public \DateTime $createdAt; + + #[Groups(['organizational-unit:read'])] + public ?string $createdBy = null; + public function __construct(OrganizationalUnit $organizationalUnit) { @@ -33,9 +41,15 @@ final class OrganizationalUnitOutput extends AbstractOutput $this->name = $organizationalUnit->getName(); $this->type = $organizationalUnit->getType(); - $this->parent = $organizationalUnit->getParent(); + $this->networkSettings = $organizationalUnit->getNetworkSettings() ? new NetworkSettingsOutput($organizationalUnit->getNetworkSettings()) : null; + $this->clients = $organizationalUnit->getClients()->toArray(); + + if ($organizationalUnit->getParent()) { + $this->parent = new self($organizationalUnit->getParent()); + } + $this->path = $organizationalUnit->getPath(); - $this->createAt = $organizationalUnit->getCreatedAt(); - $this->createBy = $organizationalUnit->getCreatedBy(); + $this->createdAt = $organizationalUnit->getCreatedAt(); + $this->createdBy = $organizationalUnit->getCreatedBy(); } } \ No newline at end of file diff --git a/src/State/Processor/ClientProcessor.php b/src/State/Processor/ClientProcessor.php index 4f6e068..c3deba4 100644 --- a/src/State/Processor/ClientProcessor.php +++ b/src/State/Processor/ClientProcessor.php @@ -2,7 +2,68 @@ namespace App\State\Processor; -class ClientProcessor -{ +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Operation; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\Metadata\Put; +use ApiPlatform\State\ProcessorInterface; +use ApiPlatform\Validator\ValidatorInterface; +use App\Dto\Input\ClientInput; +use App\Dto\Output\ClientOutput; +use App\Dto\Output\UserGroupOutput; +use App\Repository\ClientRepository; -} \ No newline at end of file +class ClientProcessor implements ProcessorInterface +{ + public function __construct( + private readonly ClientRepository $clientRepository, + private readonly ValidatorInterface $validator + ) + { + } + + /** + * @throws \Exception + */ + public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ClientOutput + { + switch ($operation){ + case $operation instanceof Post: + case $operation instanceof Put: + case $operation instanceof Patch: + return $this->processCreateOrUpdate($data, $operation, $uriVariables, $context); + case $operation instanceof Delete: + return $this->processDelete($data, $operation, $uriVariables, $context); + } + } + + /** + * @throws \Exception + */ + private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): ClientOutput + { + if (!($data instanceof ClientInput)) { + throw new \Exception(sprintf('data is not instance of %s', ClientInput::class)); + } + + $entity = null; + if (isset($uriVariables['uuid'])) { + $entity = $this->clientRepository->findOneByUuid($uriVariables['uuid']); + } + + $userGroup = $data->createOrUpdateEntity($entity); + $this->validator->validate($userGroup); + $this->clientRepository->save($userGroup); + + return new ClientOutput($userGroup); + } + + private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null + { + $user = $this->clientRepository->findOneByUuid($uriVariables['uuid']); + $this->clientRepository->delete($user); + + return null; + } +} diff --git a/src/State/Processor/HardwareProcessor.php b/src/State/Processor/HardwareProcessor.php index 6831264..c396d3e 100644 --- a/src/State/Processor/HardwareProcessor.php +++ b/src/State/Processor/HardwareProcessor.php @@ -2,7 +2,69 @@ namespace App\State\Processor; -class HardwareProcessor -{ +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Operation; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\Metadata\Put; +use ApiPlatform\State\ProcessorInterface; +use ApiPlatform\Validator\ValidatorInterface; +use App\Dto\Input\ClientInput; +use App\Dto\Input\HardwareInput; +use App\Dto\Output\ClientOutput; +use App\Dto\Output\HardwareOutput; +use App\Repository\HardwareRepository; -} \ No newline at end of file +class HardwareProcessor implements ProcessorInterface +{ + public function __construct( + private readonly HardwareRepository $hardwareRepository, + private readonly ValidatorInterface $validator + ) + { + } + + /** + * @throws \Exception + */ + public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): HardwareOutput + { + switch ($operation){ + case $operation instanceof Post: + case $operation instanceof Put: + case $operation instanceof Patch: + return $this->processCreateOrUpdate($data, $operation, $uriVariables, $context); + case $operation instanceof Delete: + return $this->processDelete($data, $operation, $uriVariables, $context); + } + } + + /** + * @throws \Exception + */ + private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): HardwareOutput + { + if (!($data instanceof ClientInput)) { + throw new \Exception(sprintf('data is not instance of %s', HardwareInput::class)); + } + + $entity = null; + if (isset($uriVariables['uuid'])) { + $entity = $this->hardwareRepository->findOneByUuid($uriVariables['uuid']); + } + + $userGroup = $data->createOrUpdateEntity($entity); + $this->validator->validate($userGroup); + $this->hardwareRepository->save($userGroup); + + return new HardwareOutput($userGroup); + } + + private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null + { + $user = $this->hardwareRepository->findOneByUuid($uriVariables['uuid']); + $this->hardwareRepository->delete($user); + + return null; + } +} diff --git a/src/State/Processor/OrganizationalUnitProcessor.php b/src/State/Processor/OrganizationalUnitProcessor.php index 5bd3c99..f307079 100644 --- a/src/State/Processor/OrganizationalUnitProcessor.php +++ b/src/State/Processor/OrganizationalUnitProcessor.php @@ -15,12 +15,14 @@ use App\Dto\Input\OrganizationalUnitClientGroupInput; use App\Dto\Input\OrganizationalUnitRootInput; use App\Dto\Output\OrganizationalUnitOutput; use App\Repository\OrganizationalUnitRepository; +use Doctrine\ORM\EntityManagerInterface; class OrganizationalUnitProcessor implements ProcessorInterface { public function __construct( private readonly OrganizationalUnitRepository $organizationalUnitRepository, - private readonly ValidatorInterface $validator + private readonly ValidatorInterface $validator, + private readonly EntityManagerInterface $entityManager ) { } @@ -62,7 +64,7 @@ class OrganizationalUnitProcessor implements ProcessorInterface $entity = $this->organizationalUnitRepository->findOneByUuid($uriVariables['uuid']); } - $organizationalUnit = $data->createOrUpdateEntity($entity); + $organizationalUnit = $data->createOrUpdateEntity($entity, $this->entityManager); $this->validator->validate($organizationalUnit); $this->organizationalUnitRepository->save($organizationalUnit); diff --git a/src/State/Provider/ClientProvider.php b/src/State/Provider/ClientProvider.php index a468d9b..d398a0f 100644 --- a/src/State/Provider/ClientProvider.php +++ b/src/State/Provider/ClientProvider.php @@ -2,7 +2,70 @@ namespace App\State\Provider; -class ClientProvider -{ +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\Input\ClientInput; +use App\Dto\Output\ClientOutput; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -} \ No newline at end of file +class ClientProvider implements ProviderInterface +{ + public function __construct( + private readonly ProviderInterface $collectionProvider, + private readonly 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 Patch: + case $operation instanceof Put: + return $this->provideInput($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 ClientOutput($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('Client not found'); + } + + return new ClientOutput($item); + } + + public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + if (isset($uriVariables['uuid'])) { + $item = $this->itemProvider->provide($operation, $uriVariables, $context); + + return $item !== null ? new ClientInput($item) : null; + } + + return new ClientInput(); + } +} diff --git a/src/State/Provider/HardwareProvider.php b/src/State/Provider/HardwareProvider.php index abc07ba..d62dd29 100644 --- a/src/State/Provider/HardwareProvider.php +++ b/src/State/Provider/HardwareProvider.php @@ -2,7 +2,72 @@ namespace App\State\Provider; -class HardwareProvider -{ +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\Input\ClientInput; +use App\Dto\Input\HardwareInput; +use App\Dto\Output\ClientOutput; +use App\Dto\Output\HardwareOutput; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -} \ No newline at end of file +class HardwareProvider implements ProviderInterface +{ + public function __construct( + private readonly ProviderInterface $collectionProvider, + private readonly 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 Patch: + case $operation instanceof Put: + return $this->provideInput($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 HardwareOutput($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('Hardware not found'); + } + + return new HardwareOutput($item); + } + + public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + if (isset($uriVariables['uuid'])) { + $item = $this->itemProvider->provide($operation, $uriVariables, $context); + + return $item !== null ? new ClientInput($item) : null; + } + + return new HardwareInput(); + } +} diff --git a/src/State/Provider/OrganizationalUnitProvider.php b/src/State/Provider/OrganizationalUnitProvider.php index 83d5735..be6031d 100644 --- a/src/State/Provider/OrganizationalUnitProvider.php +++ b/src/State/Provider/OrganizationalUnitProvider.php @@ -9,8 +9,14 @@ use ApiPlatform\Metadata\Patch; use ApiPlatform\Metadata\Put; use ApiPlatform\State\Pagination\TraversablePaginator; use ApiPlatform\State\ProviderInterface; +use App\Dto\Input\OrganizationalUnitClassroomGroupInput; +use App\Dto\Input\OrganizationalUnitClassroomInput; +use App\Dto\Input\OrganizationalUnitClientGroupInput; +use App\Dto\Input\OrganizationalUnitRootInput; use App\Dto\Input\UserGroupInput; use App\Dto\Output\OrganizationalUnitOutput; +use App\Entity\OrganizationalUnit; +use App\Model\OrganizationalUnitTypes; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class OrganizationalUnitProvider implements ProviderInterface @@ -60,12 +66,28 @@ class OrganizationalUnitProvider implements ProviderInterface public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null { + $input = null; + if (isset($uriVariables['uuid'])) { $item = $this->itemProvider->provide($operation, $uriVariables, $context); - return $item !== null ? new UserGroupInput($item) : null; - } + if ( $item !== null ) { + switch ($item->getType()) { + case OrganizationalUnitTypes::ORGANIZATIONAL_UNIT: + $input = new OrganizationalUnitRootInput($item); + break; + case OrganizationalUnitTypes::CLASSROOMS_GROUP: + $input = new OrganizationalUnitClassroomGroupInput($item); + break; + case OrganizationalUnitTypes::CLIENTS_GROUP: + $input = new OrganizationalUnitClientGroupInput($item); + break; + case OrganizationalUnitTypes::CLASSROOM; + $input = new OrganizationalUnitClassroomInput($item); + } + } - return new UserGroupInput(); + return $input; + } } } From ccc33d761505260d962e97ea4c4bf6b82ced139f Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Mon, 10 Jun 2024 12:42:04 +0200 Subject: [PATCH 05/35] refs #427. Fixed organizationalUnit bug in POST/PUT classroom --- config/api_platform/OrganizationalUnit.yaml | 1 + docker-compose.yaml | 2 + docker/xdebug.ini | 4 +- .../OrganizationalUnitClassroomGroupInput.php | 43 +-------------- .../OrganizationalUnitClassroomInput.php | 27 +-------- .../OrganizationalUnitClientGroupInput.php | 43 +-------------- src/Dto/Input/OrganizationalUnitInput.php | 55 +++++++++++++++++++ src/Dto/Input/OrganizationalUnitRootInput.php | 36 +----------- src/Dto/Output/ClientOutput.php | 4 +- src/Dto/Output/OrganizationalUnitOutput.php | 1 - .../Processor/OrganizationalUnitProcessor.php | 3 +- .../Provider/OrganizationalUnitProvider.php | 1 + 12 files changed, 74 insertions(+), 146 deletions(-) create mode 100644 src/Dto/Input/OrganizationalUnitInput.php diff --git a/config/api_platform/OrganizationalUnit.yaml b/config/api_platform/OrganizationalUnit.yaml index 2b7e137..72fcdbf 100644 --- a/config/api_platform/OrganizationalUnit.yaml +++ b/config/api_platform/OrganizationalUnit.yaml @@ -2,6 +2,7 @@ resources: App\Entity\OrganizationalUnit: processor: App\State\Processor\OrganizationalUnitProcessor output: App\Dto\Output\OrganizationalUnitOutput + input: App\Dto\Input\OrganizationalUnitInput normalization_context: groups: ['default', 'organizational-unit:read'] denormalization_context: diff --git a/docker-compose.yaml b/docker-compose.yaml index 8b3b902..aad1b74 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -38,6 +38,8 @@ services: depends_on: - database environment: + XDEBUG_CLIENT_HOST: 127.17.0.1 + XDEBUG_CLIENT_PORT: 9003 PHP_IDE_CONFIG: serverName=ogcore networks: - ogcore-network diff --git a/docker/xdebug.ini b/docker/xdebug.ini index f717c09..aa01684 100644 --- a/docker/xdebug.ini +++ b/docker/xdebug.ini @@ -1,4 +1,4 @@ xdebug.mode=debug xdebug.start_with_request=yes -xdebug.client_host=172.17.0.1/ -xdebug.client_port=9003 \ No newline at end of file +xdebug.client_host=${XDEBUG_CLIENT_HOST} +xdebug.client_port=${XDEBUG_CLIENT_PORT} \ No newline at end of file diff --git a/src/Dto/Input/OrganizationalUnitClassroomGroupInput.php b/src/Dto/Input/OrganizationalUnitClassroomGroupInput.php index 8b8f33f..403fc8a 100644 --- a/src/Dto/Input/OrganizationalUnitClassroomGroupInput.php +++ b/src/Dto/Input/OrganizationalUnitClassroomGroupInput.php @@ -2,52 +2,13 @@ namespace App\Dto\Input; -use App\Dto\Output\OrganizationalUnitOutput; use App\Entity\OrganizationalUnit; use App\Model\OrganizationalUnitTypes; -use Symfony\Component\Serializer\Annotation\Groups; -use Symfony\Component\Validator\Constraints as Assert; -final class OrganizationalUnitClassroomGroupInput +final class OrganizationalUnitClassroomGroupInput extends OrganizationalUnitInput { - #[Assert\NotBlank] - #[Groups(['organizational-unit:write'])] - public ?string $name = null; - - #[Assert\NotNull] - #[Groups(['organizational-unit:write'])] - public ?OrganizationalUnitOutput $parent = null; - - #[Groups(['organizational-unit:write'])] - public ?string $description = null; - - #[Groups(['organizational-unit:write'])] - public ?string $comments = null; - public function __construct(?OrganizationalUnit $organizationalUnit = null) { - if (!$organizationalUnit) { - return; - } - - $this->name = $organizationalUnit->getName(); - $this->parent = new OrganizationalUnitOutput($organizationalUnit->getParent()); - $this->description = $organizationalUnit->getDescription(); - $this->comments = $organizationalUnit->getComments(); - } - - public function createOrUpdateEntity(?OrganizationalUnit $organizationalUnit = null): OrganizationalUnit - { - if (!$organizationalUnit) { - $organizationalUnit = new OrganizationalUnit(); - } - - $organizationalUnit->setName($this->name); - $organizationalUnit->setParent($this->parent->getEntity()); - $organizationalUnit->setType(OrganizationalUnitTypes::CLASSROOMS_GROUP); - $organizationalUnit->setDescription($this->description); - $organizationalUnit->setComments($this->comments); - - return $organizationalUnit; + parent::__construct($organizationalUnit, OrganizationalUnitTypes::CLASSROOMS_GROUP); } } \ No newline at end of file diff --git a/src/Dto/Input/OrganizationalUnitClassroomInput.php b/src/Dto/Input/OrganizationalUnitClassroomInput.php index 7603906..8231b46 100644 --- a/src/Dto/Input/OrganizationalUnitClassroomInput.php +++ b/src/Dto/Input/OrganizationalUnitClassroomInput.php @@ -2,7 +2,6 @@ namespace App\Dto\Input; -use App\Dto\Output\OrganizationalUnitOutput; use App\Entity\NetworkSettings; use App\Entity\OrganizationalUnit; use App\Model\OrganizationalUnitTypes; @@ -10,22 +9,8 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; -final class OrganizationalUnitClassroomInput +final class OrganizationalUnitClassroomInput extends OrganizationalUnitInput { - #[Assert\NotBlank] - #[Groups(['organizational-unit:write'])] - public ?string $name = null; - - #[Assert\NotNull] - #[Groups(['organizational-unit:write', 'organizational-unit:patch'])] - public ?OrganizationalUnitOutput $parent = null; - - #[Groups(['organizational-unit:write'])] - public ?string $description = null; - - #[Groups(['organizational-unit:write'])] - public ?string $comments = null; - #[Groups(['organizational-unit:write'])] public ?string $location = null; @@ -74,14 +59,12 @@ final class OrganizationalUnitClassroomInput public function __construct(?OrganizationalUnit $organizationalUnit = null) { + parent::__construct($organizationalUnit, OrganizationalUnitTypes::CLASSROOM); + if (!$organizationalUnit) { return; } - $this->name = $organizationalUnit->getName(); - $this->parent = new OrganizationalUnitOutput($organizationalUnit->getParent()); - $this->description = $organizationalUnit->getDescription(); - $this->comments = $organizationalUnit->getComments(); $this->location = $organizationalUnit->getLocation(); $this->projector = $organizationalUnit->isProjector(); $this->board = $organizationalUnit->isBoard(); @@ -108,11 +91,7 @@ final class OrganizationalUnitClassroomInput $organizationalUnit = new OrganizationalUnit(); } - $organizationalUnit->setName($this->name); $organizationalUnit->setType(OrganizationalUnitTypes::CLASSROOM); - $organizationalUnit->setParent($this->parent->getEntity()); - $organizationalUnit->setDescription($this->description); - $organizationalUnit->setComments($this->comments); $organizationalUnit->setLocation($this->location); $organizationalUnit->setProjector($this->projector); $organizationalUnit->setBoard($this->board); diff --git a/src/Dto/Input/OrganizationalUnitClientGroupInput.php b/src/Dto/Input/OrganizationalUnitClientGroupInput.php index bbc9458..2a4cb3b 100644 --- a/src/Dto/Input/OrganizationalUnitClientGroupInput.php +++ b/src/Dto/Input/OrganizationalUnitClientGroupInput.php @@ -2,52 +2,13 @@ namespace App\Dto\Input; -use App\Dto\Output\OrganizationalUnitOutput; use App\Entity\OrganizationalUnit; use App\Model\OrganizationalUnitTypes; -use Symfony\Component\Serializer\Annotation\Groups; -use Symfony\Component\Validator\Constraints as Assert; -final class OrganizationalUnitClientGroupInput +final class OrganizationalUnitClientGroupInput extends OrganizationalUnitInput { - #[Assert\NotBlank] - #[Groups(['organizational-unit:write'])] - public ?string $name = null; - - #[Assert\NotNull] - #[Groups(['organizational-unit:write'])] - public ?OrganizationalUnitOutput $parent = null; - - #[Groups(['organizational-unit:write'])] - public ?string $description = null; - - #[Groups(['organizational-unit:write'])] - public ?string $comments = null; - public function __construct(?OrganizationalUnit $organizationalUnit = null) { - if (!$organizationalUnit) { - return; - } - - $this->name = $organizationalUnit->getName(); - $this->parent = new OrganizationalUnitOutput($organizationalUnit->getParent()); - $this->description = $organizationalUnit->getDescription(); - $this->comments = $organizationalUnit->getComments(); - } - - public function createOrUpdateEntity(?OrganizationalUnit $organizationalUnit = null): OrganizationalUnit - { - if (!$organizationalUnit) { - $organizationalUnit = new OrganizationalUnit(); - } - - $organizationalUnit->setName($this->name); - $organizationalUnit->setParent($this->parent->getEntity()); - $organizationalUnit->setType(OrganizationalUnitTypes::CLIENTS_GROUP); - $organizationalUnit->setDescription($this->description); - $organizationalUnit->setComments($this->comments); - - return $organizationalUnit; + parent::__construct($organizationalUnit, OrganizationalUnitTypes::CLIENTS_GROUP); } } \ No newline at end of file diff --git a/src/Dto/Input/OrganizationalUnitInput.php b/src/Dto/Input/OrganizationalUnitInput.php new file mode 100644 index 0000000..4906ccc --- /dev/null +++ b/src/Dto/Input/OrganizationalUnitInput.php @@ -0,0 +1,55 @@ +name = $organizationalUnit->getName(); + if ($organizationalUnit->getParent()) { + $this->parent = new OrganizationalUnitOutput($organizationalUnit->getParent()); + } + $this->description = $organizationalUnit->getDescription(); + $this->comments = $organizationalUnit->getComments(); + } + + public function createOrUpdateEntity(?OrganizationalUnit $organizationalUnit = null): OrganizationalUnit + { + if (!$organizationalUnit) { + $organizationalUnit = new OrganizationalUnit(); + } + + $organizationalUnit->setName($this->name); + if ($this->parent) { + $organizationalUnit->setParent($this->parent->getEntity()); + } + $organizationalUnit->setDescription($this->description); + $organizationalUnit->setComments($this->comments); + $organizationalUnit->setType($this->type); + + return $organizationalUnit; + } +} \ No newline at end of file diff --git a/src/Dto/Input/OrganizationalUnitRootInput.php b/src/Dto/Input/OrganizationalUnitRootInput.php index 27a36f3..b4aa96b 100644 --- a/src/Dto/Input/OrganizationalUnitRootInput.php +++ b/src/Dto/Input/OrganizationalUnitRootInput.php @@ -4,43 +4,11 @@ namespace App\Dto\Input; use App\Entity\OrganizationalUnit; use App\Model\OrganizationalUnitTypes; -use Symfony\Component\Serializer\Annotation\Groups; -use Symfony\Component\Validator\Constraints as Assert; -final class OrganizationalUnitRootInput +final class OrganizationalUnitRootInput extends OrganizationalUnitInput { - #[Assert\NotBlank] - #[Groups(['organizational-unit:write'])] - public ?string $name = null; - - #[Groups(['organizational-unit:write'])] - public ?string $description = null; - - #[Groups(['organizational-unit:write'])] - public ?string $comments = null; - public function __construct(?OrganizationalUnit $organizationalUnit = null) { - if (!$organizationalUnit) { - return; - } - - $this->name = $organizationalUnit->getName(); - $this->description = $organizationalUnit->getDescription(); - $this->comments = $organizationalUnit->getComments(); - } - - public function createOrUpdateEntity(?OrganizationalUnit $organizationalUnit = null): OrganizationalUnit - { - if (!$organizationalUnit) { - $organizationalUnit = new OrganizationalUnit(); - } - - $organizationalUnit->setName($this->name); - $organizationalUnit->setType(OrganizationalUnitTypes::ORGANIZATIONAL_UNIT); - $organizationalUnit->setDescription($this->description); - $organizationalUnit->setComments($this->comments); - - return $organizationalUnit; + parent::__construct($organizationalUnit, OrganizationalUnitTypes::ORGANIZATIONAL_UNIT); } } \ No newline at end of file diff --git a/src/Dto/Output/ClientOutput.php b/src/Dto/Output/ClientOutput.php index fd48afd..64f064b 100644 --- a/src/Dto/Output/ClientOutput.php +++ b/src/Dto/Output/ClientOutput.php @@ -20,7 +20,7 @@ final class ClientOutput extends AbstractOutput public ?string $netiface = ''; #[Groups(['client:read'])] - public ?OrganizationalUnit $organizationalUnit = null; + public ?OrganizationalUnitOutput $organizationalUnit = null; #[Groups(['client:read'])] public \DateTime $createAt; @@ -35,7 +35,7 @@ final class ClientOutput extends AbstractOutput $this->name = $client->getName(); $this->serialNumber = $client->getSerialNumber(); $this->netiface = $client->getNetiface(); - $this->organizationalUnit = $client->getOrganizationalUnit(); + $this->organizationalUnit = new OrganizationalUnitOutput($client->getOrganizationalUnit()); $this->createAt = $client->getCreatedAt(); $this->createBy = $client->getCreatedBy(); } diff --git a/src/Dto/Output/OrganizationalUnitOutput.php b/src/Dto/Output/OrganizationalUnitOutput.php index 2ab65e5..393c154 100644 --- a/src/Dto/Output/OrganizationalUnitOutput.php +++ b/src/Dto/Output/OrganizationalUnitOutput.php @@ -2,7 +2,6 @@ namespace App\Dto\Output; -use ApiPlatform\Metadata\ApiProperty; use ApiPlatform\Metadata\Get; use App\Entity\OrganizationalUnit; use Symfony\Component\Serializer\Annotation\Groups; diff --git a/src/State/Processor/OrganizationalUnitProcessor.php b/src/State/Processor/OrganizationalUnitProcessor.php index f307079..8238321 100644 --- a/src/State/Processor/OrganizationalUnitProcessor.php +++ b/src/State/Processor/OrganizationalUnitProcessor.php @@ -12,6 +12,7 @@ use ApiPlatform\Validator\ValidatorInterface; use App\Dto\Input\OrganizationalUnitClassroomGroupInput; use App\Dto\Input\OrganizationalUnitClassroomInput; use App\Dto\Input\OrganizationalUnitClientGroupInput; +use App\Dto\Input\OrganizationalUnitInput; use App\Dto\Input\OrganizationalUnitRootInput; use App\Dto\Output\OrganizationalUnitOutput; use App\Repository\OrganizationalUnitRepository; @@ -54,7 +55,7 @@ class OrganizationalUnitProcessor implements ProcessorInterface throw new \Exception(sprintf('data is not an instance of %s, %s, %s, or %s', OrganizationalUnitRootInput::class, OrganizationalUnitClassroomInput::class, - OrganizationalUnitClientGroupInput::class, + OrganizationalUnitInput::class, OrganizationalUnitClassroomGroupInput::class )); } diff --git a/src/State/Provider/OrganizationalUnitProvider.php b/src/State/Provider/OrganizationalUnitProvider.php index be6031d..b55385e 100644 --- a/src/State/Provider/OrganizationalUnitProvider.php +++ b/src/State/Provider/OrganizationalUnitProvider.php @@ -12,6 +12,7 @@ use ApiPlatform\State\ProviderInterface; use App\Dto\Input\OrganizationalUnitClassroomGroupInput; use App\Dto\Input\OrganizationalUnitClassroomInput; use App\Dto\Input\OrganizationalUnitClientGroupInput; +use App\Dto\Input\OrganizationalUnitInput; use App\Dto\Input\OrganizationalUnitRootInput; use App\Dto\Input\UserGroupInput; use App\Dto\Output\OrganizationalUnitOutput; From 2f5fba6e2e3fd693ebec456bbe363e6739da5961 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Mon, 10 Jun 2024 15:53:03 +0200 Subject: [PATCH 06/35] refs #427. Added Hardware profile MVP --- config/api_platform/Client.yaml | 8 ++ config/api_platform/Hardware.yaml | 2 +- config/api_platform/HardwareProfile.yaml | 30 ++++++++ config/services.yaml | 5 ++ config/services/api_platform.yaml | 16 +++- migrations/.gitignore | 0 src/Controller/.gitignore | 0 .../ChangeOrganizationalUnitAction.php | 42 +++++++++++ .../Input/ChangeOrganizationalUnitInput.php | 22 ++++++ src/Dto/Input/HardwareProfileInput.php | 51 +++++++++++++ src/Dto/Output/HardwareOutput.php | 4 +- src/Dto/Output/HardwareProfileOutput.php | 39 ++++++++++ src/Repository/HardwareProfileRepository.php | 27 +------ src/State/Processor/HardwareProcessor.php | 3 +- .../Processor/HardwareProfileProcessor.php | 69 +++++++++++++++++ .../Provider/HardwareProfileProvider.php | 75 +++++++++++++++++++ src/State/Provider/HardwareProvider.php | 2 +- 17 files changed, 362 insertions(+), 33 deletions(-) delete mode 100644 migrations/.gitignore delete mode 100644 src/Controller/.gitignore create mode 100644 src/Controller/ChangeOrganizationalUnitAction.php create mode 100644 src/Dto/Input/ChangeOrganizationalUnitInput.php create mode 100644 src/Dto/Input/HardwareProfileInput.php create mode 100644 src/Dto/Output/HardwareProfileOutput.php create mode 100644 src/State/Processor/HardwareProfileProcessor.php create mode 100644 src/State/Provider/HardwareProfileProvider.php diff --git a/config/api_platform/Client.yaml b/config/api_platform/Client.yaml index 196c658..3dc25d5 100644 --- a/config/api_platform/Client.yaml +++ b/config/api_platform/Client.yaml @@ -25,6 +25,14 @@ resources: ApiPlatform\Metadata\Post: ~ ApiPlatform\Metadata\Delete: ~ + change_organizational_units: + provider: App\State\Provider\ClientProvider + class: ApiPlatform\Metadata\Post + method: POST + input: App\Dto\Input\ChangeOrganizationalUnitInput + uriTemplate: /clients/change-organizational-units + controller: App\Controller\ChangeOrganizationalUnitAction + properties: App\Entity\Client: id: diff --git a/config/api_platform/Hardware.yaml b/config/api_platform/Hardware.yaml index 3e81cc6..dd3ef97 100644 --- a/config/api_platform/Hardware.yaml +++ b/config/api_platform/Hardware.yaml @@ -13,7 +13,7 @@ resources: filters: - 'api_platform.filter.hardware.order' - 'api_platform.filter.hardware.search' - - 'api_platform.filter.hardware.boolean' + ApiPlatform\Metadata\Get: provider: App\State\Provider\HardwareProvider ApiPlatform\Metadata\Put: diff --git a/config/api_platform/HardwareProfile.yaml b/config/api_platform/HardwareProfile.yaml index e69de29..5dd6c67 100644 --- a/config/api_platform/HardwareProfile.yaml +++ b/config/api_platform/HardwareProfile.yaml @@ -0,0 +1,30 @@ +resources: + App\Entity\HardwareProfile: + processor: App\State\Processor\HardwareProfileProcessor + input: App\Dto\Input\HardwareProfileInput + output: App\Dto\Output\HardwareProfileOutput + normalization_context: + groups: ['default', 'hardware-profile:read'] + denormalization_context: + groups: ['hardware-profile:write'] + operations: + ApiPlatform\Metadata\GetCollection: + provider: App\State\Provider\HardwareProfileProvider + filters: + - 'api_platform.filter.hardware.order' + - 'api_platform.filter.hardware.search' + ApiPlatform\Metadata\Get: + provider: App\State\Provider\HardwareProfileProvider + ApiPlatform\Metadata\Put: + provider: App\State\Provider\HardwareProfileProvider + ApiPlatform\Metadata\Patch: + provider: App\State\Provider\HardwareProfileProvider + ApiPlatform\Metadata\Post: ~ + ApiPlatform\Metadata\Delete: ~ + +properties: + App\Entity\HardwareProfile: + id: + identifier: false + uuid: + identifier: true \ No newline at end of file diff --git a/config/services.yaml b/config/services.yaml index d9649c3..124187d 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -46,6 +46,11 @@ services: $itemProvider: '@api_platform.doctrine.orm.state.item_provider' App\State\Provider\HardwareProvider: + bind: + $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' + $itemProvider: '@api_platform.doctrine.orm.state.item_provider' + + App\State\Provider\HardwareProfileProvider: bind: $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' $itemProvider: '@api_platform.doctrine.orm.state.item_provider' \ No newline at end of file diff --git a/config/services/api_platform.yaml b/config/services/api_platform.yaml index 8049096..1541e80 100644 --- a/config/services/api_platform.yaml +++ b/config/services/api_platform.yaml @@ -37,4 +37,18 @@ services: parent: 'api_platform.doctrine.orm.boolean_filter' arguments: [ { 'enabled': ~ } ] tags: - - [ 'api_platform.filter' ] \ No newline at end of file + - [ 'api_platform.filter' ] + + api_platform.filter.hardware.order: + parent: 'api_platform.doctrine.orm.order_filter' + arguments: + $properties: { 'id': ~, 'name': ~ } + $orderParameterName: 'order' + tags: + - [ 'api_platform.filter' ] + + api_platform.filter.hardware.search: + parent: 'api_platform.doctrine.orm.search_filter' + arguments: [ { 'id': 'exact', 'name': 'partial' } ] + tags: + - [ 'api_platform.filter' ] diff --git a/migrations/.gitignore b/migrations/.gitignore deleted file mode 100644 index e69de29..0000000 diff --git a/src/Controller/.gitignore b/src/Controller/.gitignore deleted file mode 100644 index e69de29..0000000 diff --git a/src/Controller/ChangeOrganizationalUnitAction.php b/src/Controller/ChangeOrganizationalUnitAction.php new file mode 100644 index 0000000..4d0609b --- /dev/null +++ b/src/Controller/ChangeOrganizationalUnitAction.php @@ -0,0 +1,42 @@ +clients as $client) { + /** @var Client $client */ + $clientEntity = $this->clientRepository->find($client->getEntity()->getId()); + if (!$clientEntity) { + throw new NotFoundHttpException('Client not found'); + } + + $organizationalUnit = $input->organizationalUnit->getEntity(); + $clientEntity->setOrganizationalUnit($organizationalUnit); + + $this->entityManager->persist($clientEntity); + } + + $this->entityManager->flush(); + + return new JsonResponse( data: 'Clients updated successfully', status: Response::HTTP_OK); + } +} \ No newline at end of file diff --git a/src/Dto/Input/ChangeOrganizationalUnitInput.php b/src/Dto/Input/ChangeOrganizationalUnitInput.php new file mode 100644 index 0000000..71f8cec --- /dev/null +++ b/src/Dto/Input/ChangeOrganizationalUnitInput.php @@ -0,0 +1,22 @@ +description = $hardwareProfile->getDescription(); + $this->comments = $hardwareProfile->getComments(); + if($hardwareProfile->getOrganizationalUnit()) { + $this->organizationalUnit = new OrganizationalUnitOutput($hardwareProfile->getOrganizationalUnit()); + } + } + + public function createOrUpdateEntity(?HardwareProfile $hardwareProfile = null): HardwareProfile + { + if (!$hardwareProfile) { + $hardwareProfile = new HardwareProfile(); + } + + $hardwareProfile->setDescription($this->description); + $hardwareProfile->setComments($this->comments); + if ($this->organizationalUnit) { + $hardwareProfile->setOrganizationalUnit($this->organizationalUnit->getEntity()); + } + + return $hardwareProfile; + } +} \ No newline at end of file diff --git a/src/Dto/Output/HardwareOutput.php b/src/Dto/Output/HardwareOutput.php index a0ebf9d..262cd6d 100644 --- a/src/Dto/Output/HardwareOutput.php +++ b/src/Dto/Output/HardwareOutput.php @@ -13,10 +13,10 @@ final class HardwareOutput extends AbstractOutput public string $name; #[Groups(['hardware:read'])] - public string $description; + public ?string $description = ''; #[Groups(['hardware:read'])] - public string $type; + public ?string $type = ''; #[Groups(['hardware:read'])] public \DateTime $createAt; diff --git a/src/Dto/Output/HardwareProfileOutput.php b/src/Dto/Output/HardwareProfileOutput.php new file mode 100644 index 0000000..ed2315d --- /dev/null +++ b/src/Dto/Output/HardwareProfileOutput.php @@ -0,0 +1,39 @@ +description = $hardwareProfile->getDescription(); + $this->comments = $hardwareProfile->getComments(); + if($hardwareProfile->getOrganizationalUnit()) { + $this->organizationalUnit = new OrganizationalUnitOutput($hardwareProfile->getOrganizationalUnit()); + } + $this->createAt = $hardwareProfile->getCreatedAt(); + $this->createBy = $hardwareProfile->getCreatedBy(); + } +} \ No newline at end of file diff --git a/src/Repository/HardwareProfileRepository.php b/src/Repository/HardwareProfileRepository.php index 0e4ff1a..256a73e 100644 --- a/src/Repository/HardwareProfileRepository.php +++ b/src/Repository/HardwareProfileRepository.php @@ -9,35 +9,10 @@ use Doctrine\Persistence\ManagerRegistry; /** * @extends ServiceEntityRepository */ -class HardwareProfileRepository extends ServiceEntityRepository +class HardwareProfileRepository extends AbstractRepository { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, HardwareProfile::class); } - - // /** - // * @return HardwareProfile[] Returns an array of HardwareProfile objects - // */ - // public function findByExampleField($value): array - // { - // return $this->createQueryBuilder('h') - // ->andWhere('h.exampleField = :val') - // ->setParameter('val', $value) - // ->orderBy('h.id', 'ASC') - // ->setMaxResults(10) - // ->getQuery() - // ->getResult() - // ; - // } - - // public function findOneBySomeField($value): ?HardwareProfile - // { - // return $this->createQueryBuilder('h') - // ->andWhere('h.exampleField = :val') - // ->setParameter('val', $value) - // ->getQuery() - // ->getOneOrNullResult() - // ; - // } } diff --git a/src/State/Processor/HardwareProcessor.php b/src/State/Processor/HardwareProcessor.php index c396d3e..25781a8 100644 --- a/src/State/Processor/HardwareProcessor.php +++ b/src/State/Processor/HardwareProcessor.php @@ -11,7 +11,6 @@ use ApiPlatform\State\ProcessorInterface; use ApiPlatform\Validator\ValidatorInterface; use App\Dto\Input\ClientInput; use App\Dto\Input\HardwareInput; -use App\Dto\Output\ClientOutput; use App\Dto\Output\HardwareOutput; use App\Repository\HardwareRepository; @@ -44,7 +43,7 @@ class HardwareProcessor implements ProcessorInterface */ private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): HardwareOutput { - if (!($data instanceof ClientInput)) { + if (!($data instanceof HardwareInput)) { throw new \Exception(sprintf('data is not instance of %s', HardwareInput::class)); } diff --git a/src/State/Processor/HardwareProfileProcessor.php b/src/State/Processor/HardwareProfileProcessor.php new file mode 100644 index 0000000..aaf2bdd --- /dev/null +++ b/src/State/Processor/HardwareProfileProcessor.php @@ -0,0 +1,69 @@ +processCreateOrUpdate($data, $operation, $uriVariables, $context); + case $operation instanceof Delete: + return $this->processDelete($data, $operation, $uriVariables, $context); + } + } + + /** + * @throws \Exception + */ + private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): HardwareProfileOutput + { + if (!($data instanceof HardwareProfileInput)) { + throw new \Exception(sprintf('data is not instance of %s', HardwareInput::class)); + } + + $entity = null; + if (isset($uriVariables['uuid'])) { + $entity = $this->hardwareProfileRepository->findOneByUuid($uriVariables['uuid']); + } + + $userGroup = $data->createOrUpdateEntity($entity); + $this->validator->validate($userGroup); + $this->hardwareProfileRepository->save($userGroup); + + return new HardwareProfileOutput($userGroup); + } + + private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null + { + $user = $this->hardwareProfileRepository->findOneByUuid($uriVariables['uuid']); + $this->hardwareProfileRepository->delete($user); + + return null; + } +} diff --git a/src/State/Provider/HardwareProfileProvider.php b/src/State/Provider/HardwareProfileProvider.php new file mode 100644 index 0000000..241fda1 --- /dev/null +++ b/src/State/Provider/HardwareProfileProvider.php @@ -0,0 +1,75 @@ +provideCollection($operation, $uriVariables, $context); + case $operation instanceof Patch: + case $operation instanceof Put: + return $this->provideInput($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 HardwareProfileOutput($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('Hardware profile not found'); + } + + return new HardwareProfileOutput($item); + } + + public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + if (isset($uriVariables['uuid'])) { + $item = $this->itemProvider->provide($operation, $uriVariables, $context); + + return $item !== null ? new HardwareProfileInput($item) : null; + } + + return new HardwareProfileInput(); + } +} diff --git a/src/State/Provider/HardwareProvider.php b/src/State/Provider/HardwareProvider.php index d62dd29..0342d64 100644 --- a/src/State/Provider/HardwareProvider.php +++ b/src/State/Provider/HardwareProvider.php @@ -65,7 +65,7 @@ class HardwareProvider implements ProviderInterface if (isset($uriVariables['uuid'])) { $item = $this->itemProvider->provide($operation, $uriVariables, $context); - return $item !== null ? new ClientInput($item) : null; + return $item !== null ? new HardwareInput($item) : null; } return new HardwareInput(); From 8a17d8c527146c6a905d2d407ff48cc5a89a0b66 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Tue, 11 Jun 2024 16:26:55 +0200 Subject: [PATCH 07/35] refs #452. New migration system. Clean database --- .env | 2 + composer.lock | 737 ++++++++--------- config/packages/doctrine.yaml | 46 +- docker/xdebug.ini | 3 +- migrations/.gitignore | 0 migrations/Version20240606102152.php | 47 -- ...06081620.php => Version20240611090540.php} | 26 +- .../Migration/MigrateClientsCommand.php | 86 ++ ...grateHardwareAndHardwareProfileCommand.php | 40 + .../MigrateOrganizationalUnitCommand.php | 204 +++-- src/DataFixtures/AppFixtures.php | 17 +- src/Dto/Output/ClientOutput.php | 1 - src/Entity/Migration/Aulas.php | 753 ------------------ src/Entity/Migration/Centros.php | 133 ---- src/Entity/Migration/Gruposordenadores.php | 133 ---- src/Entity/Migration/Ordenadores.php | 663 --------------- src/Factory/UserFactory.php | 2 +- src/Repository/.gitignore | 0 symfony.lock | 38 +- 19 files changed, 681 insertions(+), 2250 deletions(-) create mode 100644 migrations/.gitignore delete mode 100644 migrations/Version20240606102152.php rename migrations/{Version20240606081620.php => Version20240611090540.php} (65%) create mode 100644 src/Command/Migration/MigrateClientsCommand.php create mode 100644 src/Command/Migration/MigrateHardwareAndHardwareProfileCommand.php delete mode 100644 src/Entity/Migration/Aulas.php delete mode 100644 src/Entity/Migration/Centros.php delete mode 100644 src/Entity/Migration/Gruposordenadores.php delete mode 100644 src/Entity/Migration/Ordenadores.php create mode 100644 src/Repository/.gitignore diff --git a/.env b/.env index 48bdf9b..2d1c753 100644 --- a/.env +++ b/.env @@ -26,6 +26,8 @@ APP_SECRET=e95c7f17da15ce1b03d77ad655379c34 # DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db" # DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4" DATABASE_URL="mysql://root:root@ogcore-database:3306/ogcore?serverVersion=10.11.2-MariaDB&charset=utf8mb4" +OG_1_DATABASE_URL="mysql://root:root@ogcore-database:3306/ogcore_old_og?serverVersion=10.11.2-MariaDB&charset=utf8mb4" + #DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8" ###< doctrine/doctrine-bundle ### diff --git a/composer.lock b/composer.lock index 2b0b43f..98d87a8 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "api-platform/core", - "version": "v3.3.3", + "version": "v3.3.5", "source": { "type": "git", "url": "https://github.com/api-platform/core.git", - "reference": "59dca65e4f9aa2be6fd85fa944482a7d73eb5fc2" + "reference": "b5a93fb0bb855273aabb0807505ba61b68813246" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/core/zipball/59dca65e4f9aa2be6fd85fa944482a7d73eb5fc2", - "reference": "59dca65e4f9aa2be6fd85fa944482a7d73eb5fc2", + "url": "https://api.github.com/repos/api-platform/core/zipball/b5a93fb0bb855273aabb0807505ba61b68813246", + "reference": "b5a93fb0bb855273aabb0807505ba61b68813246", "shasum": "" }, "require": { @@ -190,9 +190,9 @@ ], "support": { "issues": "https://github.com/api-platform/core/issues", - "source": "https://github.com/api-platform/core/tree/v3.3.3" + "source": "https://github.com/api-platform/core/tree/v3.3.5" }, - "time": "2024-05-10T11:16:59+00:00" + "time": "2024-05-29T05:48:47+00:00" }, { "name": "behat/transliterator", @@ -2329,16 +2329,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.29.0", + "version": "1.29.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "536889f2b340489d328f5ffb7b02bb6b183ddedc" + "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/536889f2b340489d328f5ffb7b02bb6b183ddedc", - "reference": "536889f2b340489d328f5ffb7b02bb6b183ddedc", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fcaefacf2d5c417e928405b71b400d4ce10daaf4", + "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4", "shasum": "" }, "require": { @@ -2370,9 +2370,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.1" }, - "time": "2024-05-06T12:04:23+00:00" + "time": "2024-05-31T08:52:43+00:00" }, { "name": "psr/cache", @@ -2863,26 +2863,26 @@ }, { "name": "ramsey/uuid-doctrine", - "version": "2.0.0", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/ramsey/uuid-doctrine.git", - "reference": "b002676be0e5e342d857c47f1b68e24de6841d08" + "reference": "491e1bfa4d9d81e52a60470fa92c871f7eef919e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid-doctrine/zipball/b002676be0e5e342d857c47f1b68e24de6841d08", - "reference": "b002676be0e5e342d857c47f1b68e24de6841d08", + "url": "https://api.github.com/repos/ramsey/uuid-doctrine/zipball/491e1bfa4d9d81e52a60470fa92c871f7eef919e", + "reference": "491e1bfa4d9d81e52a60470fa92c871f7eef919e", "shasum": "" }, "require": { - "doctrine/dbal": "^2.8 || ^3.0", - "php": "^7.4 || ^8.0", + "doctrine/dbal": "^2.8 || ^3.0 || ^4.0", + "php": "^8.1", "ramsey/uuid": "^3.9.7 || ^4.0" }, "require-dev": { "captainhook/plugin-composer": "^5.3", - "doctrine/orm": "^2.5", + "doctrine/orm": "^2.5 || ^3.0", "ergebnis/composer-normalize": "^2.28.3", "mockery/mockery": "^1.5", "php-parallel-lint/php-console-highlighter": "^1.0", @@ -2892,12 +2892,9 @@ "phpstan/phpstan": "^1.9", "phpstan/phpstan-mockery": "^1.1", "phpstan/phpstan-phpunit": "^1.3", - "phpunit/phpunit": "^9.5", - "psalm/plugin-mockery": "^1.1", - "psalm/plugin-phpunit": "^0.18.4", + "phpunit/phpunit": "^10.5", "ramsey/coding-standard": "^2.0.3", - "ramsey/conventional-commits": "^1.3", - "vimeo/psalm": "^5.4" + "ramsey/conventional-commits": "^1.3" }, "type": "library", "extra": { @@ -2934,7 +2931,7 @@ ], "support": { "issues": "https://github.com/ramsey/uuid-doctrine/issues", - "source": "https://github.com/ramsey/uuid-doctrine/tree/2.0.0" + "source": "https://github.com/ramsey/uuid-doctrine/tree/2.1.0" }, "funding": [ { @@ -2946,7 +2943,7 @@ "type": "tidelift" } ], - "time": "2022-12-20T23:38:28+00:00" + "time": "2024-05-27T00:00:21+00:00" }, { "name": "stof/doctrine-extensions-bundle", @@ -3030,16 +3027,16 @@ }, { "name": "symfony/asset", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/asset.git", - "reference": "743757ab1dfa7114a8a3c63aeb376dfcf4b0a191" + "reference": "c668aa320e26b7379540368832b9d1dd43d32603" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/743757ab1dfa7114a8a3c63aeb376dfcf4b0a191", - "reference": "743757ab1dfa7114a8a3c63aeb376dfcf4b0a191", + "url": "https://api.github.com/repos/symfony/asset/zipball/c668aa320e26b7379540368832b9d1dd43d32603", + "reference": "c668aa320e26b7379540368832b9d1dd43d32603", "shasum": "" }, "require": { @@ -3079,7 +3076,7 @@ "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/asset/tree/v6.4.7" + "source": "https://github.com/symfony/asset/tree/v6.4.8" }, "funding": [ { @@ -3095,20 +3092,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/cache", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "b9e9b93c9817ec6c789c7943f5e54b57a041c16a" + "reference": "287142df5579ce223c485b3872df3efae8390984" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/b9e9b93c9817ec6c789c7943f5e54b57a041c16a", - "reference": "b9e9b93c9817ec6c789c7943f5e54b57a041c16a", + "url": "https://api.github.com/repos/symfony/cache/zipball/287142df5579ce223c485b3872df3efae8390984", + "reference": "287142df5579ce223c485b3872df3efae8390984", "shasum": "" }, "require": { @@ -3175,7 +3172,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.4.7" + "source": "https://github.com/symfony/cache/tree/v6.4.8" }, "funding": [ { @@ -3191,7 +3188,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/cache-contracts", @@ -3271,16 +3268,16 @@ }, { "name": "symfony/clock", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "83667074bdae743f8cd884ac50b266d2af287ea8" + "reference": "7a4840efd17135cbd547e41ec49fb910ed4f8b98" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/83667074bdae743f8cd884ac50b266d2af287ea8", - "reference": "83667074bdae743f8cd884ac50b266d2af287ea8", + "url": "https://api.github.com/repos/symfony/clock/zipball/7a4840efd17135cbd547e41ec49fb910ed4f8b98", + "reference": "7a4840efd17135cbd547e41ec49fb910ed4f8b98", "shasum": "" }, "require": { @@ -3325,7 +3322,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v6.4.7" + "source": "https://github.com/symfony/clock/tree/v6.4.8" }, "funding": [ { @@ -3341,20 +3338,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:51:39+00:00" }, { "name": "symfony/config", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "51da0e4494d81bd7b5b5bd80319c55d8e0d7f4ff" + "reference": "12e7e52515ce37191b193cf3365903c4f3951e35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/51da0e4494d81bd7b5b5bd80319c55d8e0d7f4ff", - "reference": "51da0e4494d81bd7b5b5bd80319c55d8e0d7f4ff", + "url": "https://api.github.com/repos/symfony/config/zipball/12e7e52515ce37191b193cf3365903c4f3951e35", + "reference": "12e7e52515ce37191b193cf3365903c4f3951e35", "shasum": "" }, "require": { @@ -3400,7 +3397,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v6.4.7" + "source": "https://github.com/symfony/config/tree/v6.4.8" }, "funding": [ { @@ -3416,20 +3413,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/console", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "a170e64ae10d00ba89e2acbb590dc2e54da8ad8f" + "reference": "be5854cee0e8c7b110f00d695d11debdfa1a2a91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/a170e64ae10d00ba89e2acbb590dc2e54da8ad8f", - "reference": "a170e64ae10d00ba89e2acbb590dc2e54da8ad8f", + "url": "https://api.github.com/repos/symfony/console/zipball/be5854cee0e8c7b110f00d695d11debdfa1a2a91", + "reference": "be5854cee0e8c7b110f00d695d11debdfa1a2a91", "shasum": "" }, "require": { @@ -3494,7 +3491,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.7" + "source": "https://github.com/symfony/console/tree/v6.4.8" }, "funding": [ { @@ -3510,20 +3507,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/dependency-injection", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "d8c5f9781b71c2a868ae9d0e5c9b283684740b6d" + "reference": "d3b618176e8c3a9e5772151c51eba0c52a0c771c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/d8c5f9781b71c2a868ae9d0e5c9b283684740b6d", - "reference": "d8c5f9781b71c2a868ae9d0e5c9b283684740b6d", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/d3b618176e8c3a9e5772151c51eba0c52a0c771c", + "reference": "d3b618176e8c3a9e5772151c51eba0c52a0c771c", "shasum": "" }, "require": { @@ -3575,7 +3572,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v6.4.7" + "source": "https://github.com/symfony/dependency-injection/tree/v6.4.8" }, "funding": [ { @@ -3591,7 +3588,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/deprecation-contracts", @@ -3662,16 +3659,16 @@ }, { "name": "symfony/doctrine-bridge", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "0eb1189828f66c74697737e89a12b3aded8b748c" + "reference": "afbf291ccaf595c8ff6f4ed3943aa0ea479e4d04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/0eb1189828f66c74697737e89a12b3aded8b748c", - "reference": "0eb1189828f66c74697737e89a12b3aded8b748c", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/afbf291ccaf595c8ff6f4ed3943aa0ea479e4d04", + "reference": "afbf291ccaf595c8ff6f4ed3943aa0ea479e4d04", "shasum": "" }, "require": { @@ -3750,7 +3747,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v6.4.7" + "source": "https://github.com/symfony/doctrine-bridge/tree/v6.4.8" }, "funding": [ { @@ -3766,20 +3763,20 @@ "type": "tidelift" } ], - "time": "2024-04-22T16:59:38+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/dotenv", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "982a8d58c73a7d91d229bc20493b8ae13208741c" + "reference": "55aefa0029adff89ecffdb560820e945c7983f06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/982a8d58c73a7d91d229bc20493b8ae13208741c", - "reference": "982a8d58c73a7d91d229bc20493b8ae13208741c", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/55aefa0029adff89ecffdb560820e945c7983f06", + "reference": "55aefa0029adff89ecffdb560820e945c7983f06", "shasum": "" }, "require": { @@ -3824,7 +3821,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v6.4.7" + "source": "https://github.com/symfony/dotenv/tree/v6.4.8" }, "funding": [ { @@ -3840,20 +3837,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/error-handler", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "667a072466c6a53827ed7b119af93806b884cbb3" + "reference": "ef836152bf13472dc5fb5b08b0c0c4cfeddc0fcc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/667a072466c6a53827ed7b119af93806b884cbb3", - "reference": "667a072466c6a53827ed7b119af93806b884cbb3", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/ef836152bf13472dc5fb5b08b0c0c4cfeddc0fcc", + "reference": "ef836152bf13472dc5fb5b08b0c0c4cfeddc0fcc", "shasum": "" }, "require": { @@ -3899,7 +3896,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v6.4.7" + "source": "https://github.com/symfony/error-handler/tree/v6.4.8" }, "funding": [ { @@ -3915,20 +3912,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "d84384f3f67de3cb650db64d685d70395dacfc3f" + "reference": "8d7507f02b06e06815e56bb39aa0128e3806208b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d84384f3f67de3cb650db64d685d70395dacfc3f", - "reference": "d84384f3f67de3cb650db64d685d70395dacfc3f", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8d7507f02b06e06815e56bb39aa0128e3806208b", + "reference": "8d7507f02b06e06815e56bb39aa0128e3806208b", "shasum": "" }, "require": { @@ -3979,7 +3976,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.7" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.8" }, "funding": [ { @@ -3995,7 +3992,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -4075,16 +4072,16 @@ }, { "name": "symfony/expression-language", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/expression-language.git", - "reference": "f64e152029200cf35da13e9e1444e5fc8ff7fdfa" + "reference": "0b63cb437741a42104d3ccc9bf60bbd8e1acbd2a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/f64e152029200cf35da13e9e1444e5fc8ff7fdfa", - "reference": "f64e152029200cf35da13e9e1444e5fc8ff7fdfa", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/0b63cb437741a42104d3ccc9bf60bbd8e1acbd2a", + "reference": "0b63cb437741a42104d3ccc9bf60bbd8e1acbd2a", "shasum": "" }, "require": { @@ -4119,7 +4116,7 @@ "description": "Provides an engine that can compile and evaluate expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/expression-language/tree/v6.4.7" + "source": "https://github.com/symfony/expression-language/tree/v6.4.8" }, "funding": [ { @@ -4135,27 +4132,29 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/filesystem", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "78dde75f8f6dbbca4ec436a4b0087f7af02076d4" + "reference": "4d37529150e7081c51b3c5d5718c55a04a9503f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/78dde75f8f6dbbca4ec436a4b0087f7af02076d4", - "reference": "78dde75f8f6dbbca4ec436a4b0087f7af02076d4", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/4d37529150e7081c51b3c5d5718c55a04a9503f3", + "reference": "4d37529150e7081c51b3c5d5718c55a04a9503f3", "shasum": "" }, "require": { "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8", - "symfony/process": "^5.4|^6.4" + "symfony/polyfill-mbstring": "~1.8" + }, + "require-dev": { + "symfony/process": "^5.4|^6.4|^7.0" }, "type": "library", "autoload": { @@ -4183,7 +4182,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.7" + "source": "https://github.com/symfony/filesystem/tree/v6.4.8" }, "funding": [ { @@ -4199,20 +4198,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/finder", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "511c48990be17358c23bf45c5d71ab85d40fb764" + "reference": "3ef977a43883215d560a2cecb82ec8e62131471c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/511c48990be17358c23bf45c5d71ab85d40fb764", - "reference": "511c48990be17358c23bf45c5d71ab85d40fb764", + "url": "https://api.github.com/repos/symfony/finder/zipball/3ef977a43883215d560a2cecb82ec8e62131471c", + "reference": "3ef977a43883215d560a2cecb82ec8e62131471c", "shasum": "" }, "require": { @@ -4247,7 +4246,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.4.7" + "source": "https://github.com/symfony/finder/tree/v6.4.8" }, "funding": [ { @@ -4263,7 +4262,7 @@ "type": "tidelift" } ], - "time": "2024-04-23T10:36:43+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/flex", @@ -4332,16 +4331,16 @@ }, { "name": "symfony/framework-bundle", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "58196b824903d203b71e580baac73eee29246ace" + "reference": "7c7739f87f1a8be1c2f5e7d28addfe763a917acb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/58196b824903d203b71e580baac73eee29246ace", - "reference": "58196b824903d203b71e580baac73eee29246ace", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/7c7739f87f1a8be1c2f5e7d28addfe763a917acb", + "reference": "7c7739f87f1a8be1c2f5e7d28addfe763a917acb", "shasum": "" }, "require": { @@ -4460,7 +4459,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v6.4.7" + "source": "https://github.com/symfony/framework-bundle/tree/v6.4.8" }, "funding": [ { @@ -4476,20 +4475,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/http-foundation", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "b4db6b833035477cb70e18d0ae33cb7c2b521759" + "reference": "27de8cc95e11db7a50b027e71caaab9024545947" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/b4db6b833035477cb70e18d0ae33cb7c2b521759", - "reference": "b4db6b833035477cb70e18d0ae33cb7c2b521759", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/27de8cc95e11db7a50b027e71caaab9024545947", + "reference": "27de8cc95e11db7a50b027e71caaab9024545947", "shasum": "" }, "require": { @@ -4537,7 +4536,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.4.7" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.8" }, "funding": [ { @@ -4553,20 +4552,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "b7b5e6cdef670a0c82d015a966ffc7e855861a98" + "reference": "6c519aa3f32adcfd1d1f18d923f6b227d9acf3c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/b7b5e6cdef670a0c82d015a966ffc7e855861a98", - "reference": "b7b5e6cdef670a0c82d015a966ffc7e855861a98", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6c519aa3f32adcfd1d1f18d923f6b227d9acf3c1", + "reference": "6c519aa3f32adcfd1d1f18d923f6b227d9acf3c1", "shasum": "" }, "require": { @@ -4651,7 +4650,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.4.7" + "source": "https://github.com/symfony/http-kernel/tree/v6.4.8" }, "funding": [ { @@ -4667,20 +4666,20 @@ "type": "tidelift" } ], - "time": "2024-04-29T11:24:44+00:00" + "time": "2024-06-02T16:06:25+00:00" }, { "name": "symfony/password-hasher", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/password-hasher.git", - "reference": "73afaed1d87f6127dcd71bc88e9a16fd9325cf1c" + "reference": "90ebbe946e5d64a5fad9ac9427e335045cf2bd31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/password-hasher/zipball/73afaed1d87f6127dcd71bc88e9a16fd9325cf1c", - "reference": "73afaed1d87f6127dcd71bc88e9a16fd9325cf1c", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/90ebbe946e5d64a5fad9ac9427e335045cf2bd31", + "reference": "90ebbe946e5d64a5fad9ac9427e335045cf2bd31", "shasum": "" }, "require": { @@ -4723,7 +4722,7 @@ "password" ], "support": { - "source": "https://github.com/symfony/password-hasher/tree/v6.4.7" + "source": "https://github.com/symfony/password-hasher/tree/v6.4.8" }, "funding": [ { @@ -4739,7 +4738,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -5057,79 +5056,18 @@ ], "time": "2024-01-29T20:11:03+00:00" }, - { - "name": "symfony/process", - "version": "v6.4.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "cdb1c81c145fd5aa9b0038bab694035020943381" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/cdb1c81c145fd5aa9b0038bab694035020943381", - "reference": "cdb1c81c145fd5aa9b0038bab694035020943381", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Executes commands in sub-processes", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/process/tree/v6.4.7" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-04-18T09:22:46+00:00" - }, { "name": "symfony/property-access", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "9174e2ec62563dfc15fbe84d1618613092e09d91" + "reference": "e4d9b00983612f9c0013ca37c61affdba2dd975a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/9174e2ec62563dfc15fbe84d1618613092e09d91", - "reference": "9174e2ec62563dfc15fbe84d1618613092e09d91", + "url": "https://api.github.com/repos/symfony/property-access/zipball/e4d9b00983612f9c0013ca37c61affdba2dd975a", + "reference": "e4d9b00983612f9c0013ca37c61affdba2dd975a", "shasum": "" }, "require": { @@ -5177,7 +5115,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v6.4.7" + "source": "https://github.com/symfony/property-access/tree/v6.4.8" }, "funding": [ { @@ -5193,20 +5131,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/property-info", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "42778ca731b8796e02e237008f4ed871361ddfce" + "reference": "7f544bc6ceb1a6a2283c7af8e8621262c43b7ede" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/42778ca731b8796e02e237008f4ed871361ddfce", - "reference": "42778ca731b8796e02e237008f4ed871361ddfce", + "url": "https://api.github.com/repos/symfony/property-info/zipball/7f544bc6ceb1a6a2283c7af8e8621262c43b7ede", + "reference": "7f544bc6ceb1a6a2283c7af8e8621262c43b7ede", "shasum": "" }, "require": { @@ -5260,7 +5198,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v6.4.7" + "source": "https://github.com/symfony/property-info/tree/v6.4.8" }, "funding": [ { @@ -5276,20 +5214,20 @@ "type": "tidelift" } ], - "time": "2024-04-28T10:28:08+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/routing", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "276e06398f71fa2a973264d94f28150f93cfb907" + "reference": "8a40d0f9b01f0fbb80885d3ce0ad6714fb603a58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/276e06398f71fa2a973264d94f28150f93cfb907", - "reference": "276e06398f71fa2a973264d94f28150f93cfb907", + "url": "https://api.github.com/repos/symfony/routing/zipball/8a40d0f9b01f0fbb80885d3ce0ad6714fb603a58", + "reference": "8a40d0f9b01f0fbb80885d3ce0ad6714fb603a58", "shasum": "" }, "require": { @@ -5343,7 +5281,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.4.7" + "source": "https://github.com/symfony/routing/tree/v6.4.8" }, "funding": [ { @@ -5359,20 +5297,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/runtime", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/runtime.git", - "reference": "20c90eb66bbf82fdb3ef74f2ea4ecf08518cbb5e" + "reference": "b4bfa2fd4cad1fee62f80b3dfe4eb674cc3302a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/runtime/zipball/20c90eb66bbf82fdb3ef74f2ea4ecf08518cbb5e", - "reference": "20c90eb66bbf82fdb3ef74f2ea4ecf08518cbb5e", + "url": "https://api.github.com/repos/symfony/runtime/zipball/b4bfa2fd4cad1fee62f80b3dfe4eb674cc3302a0", + "reference": "b4bfa2fd4cad1fee62f80b3dfe4eb674cc3302a0", "shasum": "" }, "require": { @@ -5422,7 +5360,7 @@ "runtime" ], "support": { - "source": "https://github.com/symfony/runtime/tree/v6.4.7" + "source": "https://github.com/symfony/runtime/tree/v6.4.8" }, "funding": [ { @@ -5438,20 +5376,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/security-bundle", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/security-bundle.git", - "reference": "c9112933215b9b3c48851eb6644263d5c9d93245" + "reference": "dfb286069b0332e1f1c21962133d17c0fbc1e5e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-bundle/zipball/c9112933215b9b3c48851eb6644263d5c9d93245", - "reference": "c9112933215b9b3c48851eb6644263d5c9d93245", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/dfb286069b0332e1f1c21962133d17c0fbc1e5e7", + "reference": "dfb286069b0332e1f1c21962133d17c0fbc1e5e7", "shasum": "" }, "require": { @@ -5534,7 +5472,7 @@ "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-bundle/tree/v6.4.7" + "source": "https://github.com/symfony/security-bundle/tree/v6.4.8" }, "funding": [ { @@ -5550,20 +5488,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/security-core", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "54d35e432abd5c86bf7ba97e521168d364ac50b0" + "reference": "5fc7850ada5e8e03d78c1739c82c64d5e2f7d495" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/54d35e432abd5c86bf7ba97e521168d364ac50b0", - "reference": "54d35e432abd5c86bf7ba97e521168d364ac50b0", + "url": "https://api.github.com/repos/symfony/security-core/zipball/5fc7850ada5e8e03d78c1739c82c64d5e2f7d495", + "reference": "5fc7850ada5e8e03d78c1739c82c64d5e2f7d495", "shasum": "" }, "require": { @@ -5620,7 +5558,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v6.4.7" + "source": "https://github.com/symfony/security-core/tree/v6.4.8" }, "funding": [ { @@ -5636,20 +5574,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/security-csrf", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/security-csrf.git", - "reference": "91fe7e829a8fe1e78bd3615c7a410dce6876325b" + "reference": "f46ab02b76311087873257071559edcaf6d7ab99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-csrf/zipball/91fe7e829a8fe1e78bd3615c7a410dce6876325b", - "reference": "91fe7e829a8fe1e78bd3615c7a410dce6876325b", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/f46ab02b76311087873257071559edcaf6d7ab99", + "reference": "f46ab02b76311087873257071559edcaf6d7ab99", "shasum": "" }, "require": { @@ -5688,7 +5626,7 @@ "description": "Symfony Security Component - CSRF Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-csrf/tree/v6.4.7" + "source": "https://github.com/symfony/security-csrf/tree/v6.4.8" }, "funding": [ { @@ -5704,20 +5642,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/security-http", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/security-http.git", - "reference": "01643fd75e415bc463d63e86bb27afccf5477745" + "reference": "fb82ddec887dc67f3bcf4d6df3cb8efd529be104" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-http/zipball/01643fd75e415bc463d63e86bb27afccf5477745", - "reference": "01643fd75e415bc463d63e86bb27afccf5477745", + "url": "https://api.github.com/repos/symfony/security-http/zipball/fb82ddec887dc67f3bcf4d6df3cb8efd529be104", + "reference": "fb82ddec887dc67f3bcf4d6df3cb8efd529be104", "shasum": "" }, "require": { @@ -5776,7 +5714,7 @@ "description": "Symfony Security Component - HTTP Integration", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-http/tree/v6.4.7" + "source": "https://github.com/symfony/security-http/tree/v6.4.8" }, "funding": [ { @@ -5792,20 +5730,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T17:31:08+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/serializer", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "73820ab43d12c2f29445080004054b0066082bf1" + "reference": "d6eda9966a3e5d1823c1cedf41bf98f8ed969d7c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/73820ab43d12c2f29445080004054b0066082bf1", - "reference": "73820ab43d12c2f29445080004054b0066082bf1", + "url": "https://api.github.com/repos/symfony/serializer/zipball/d6eda9966a3e5d1823c1cedf41bf98f8ed969d7c", + "reference": "d6eda9966a3e5d1823c1cedf41bf98f8ed969d7c", "shasum": "" }, "require": { @@ -5874,7 +5812,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v6.4.7" + "source": "https://github.com/symfony/serializer/tree/v6.4.8" }, "funding": [ { @@ -5890,7 +5828,7 @@ "type": "tidelift" } ], - "time": "2024-04-23T09:00:49+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/service-contracts", @@ -5977,16 +5915,16 @@ }, { "name": "symfony/stopwatch", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "ffec95ba269e541eb2232126c0c20f83086b5c68" + "reference": "63e069eb616049632cde9674c46957819454b8aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/ffec95ba269e541eb2232126c0c20f83086b5c68", - "reference": "ffec95ba269e541eb2232126c0c20f83086b5c68", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/63e069eb616049632cde9674c46957819454b8aa", + "reference": "63e069eb616049632cde9674c46957819454b8aa", "shasum": "" }, "require": { @@ -6019,7 +5957,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v6.4.7" + "source": "https://github.com/symfony/stopwatch/tree/v6.4.8" }, "funding": [ { @@ -6035,20 +5973,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/string", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "ffeb9591c61f65a68d47f77d12b83fa530227a69" + "reference": "a147c0f826c4a1f3afb763ab8e009e37c877a44d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/ffeb9591c61f65a68d47f77d12b83fa530227a69", - "reference": "ffeb9591c61f65a68d47f77d12b83fa530227a69", + "url": "https://api.github.com/repos/symfony/string/zipball/a147c0f826c4a1f3afb763ab8e009e37c877a44d", + "reference": "a147c0f826c4a1f3afb763ab8e009e37c877a44d", "shasum": "" }, "require": { @@ -6105,7 +6043,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.7" + "source": "https://github.com/symfony/string/tree/v6.4.8" }, "funding": [ { @@ -6121,7 +6059,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/translation-contracts", @@ -6203,16 +6141,16 @@ }, { "name": "symfony/twig-bridge", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "544e47a4f2d4a786abd65531d2c326fb6e53da72" + "reference": "57de1b7d7499053a2c5beb9344751e8bfd332649" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/544e47a4f2d4a786abd65531d2c326fb6e53da72", - "reference": "544e47a4f2d4a786abd65531d2c326fb6e53da72", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/57de1b7d7499053a2c5beb9344751e8bfd332649", + "reference": "57de1b7d7499053a2c5beb9344751e8bfd332649", "shasum": "" }, "require": { @@ -6292,7 +6230,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v6.4.7" + "source": "https://github.com/symfony/twig-bridge/tree/v6.4.8" }, "funding": [ { @@ -6308,20 +6246,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/twig-bundle", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "33cf43405366beb08b9b95db9cfebe2a8a63cb03" + "reference": "ef17bc8fc2cb2376b235cd1b98f0275a78c5ba65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/33cf43405366beb08b9b95db9cfebe2a8a63cb03", - "reference": "33cf43405366beb08b9b95db9cfebe2a8a63cb03", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/ef17bc8fc2cb2376b235cd1b98f0275a78c5ba65", + "reference": "ef17bc8fc2cb2376b235cd1b98f0275a78c5ba65", "shasum": "" }, "require": { @@ -6376,7 +6314,7 @@ "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v6.4.7" + "source": "https://github.com/symfony/twig-bundle/tree/v6.4.8" }, "funding": [ { @@ -6392,20 +6330,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/validator", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "4761a08d161d823ec281151ade0905547e0502a7" + "reference": "dab2781371d54c86f6b25623ab16abb2dde2870c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/4761a08d161d823ec281151ade0905547e0502a7", - "reference": "4761a08d161d823ec281151ade0905547e0502a7", + "url": "https://api.github.com/repos/symfony/validator/zipball/dab2781371d54c86f6b25623ab16abb2dde2870c", + "reference": "dab2781371d54c86f6b25623ab16abb2dde2870c", "shasum": "" }, "require": { @@ -6452,7 +6390,8 @@ "Symfony\\Component\\Validator\\": "" }, "exclude-from-classmap": [ - "/Tests/" + "/Tests/", + "/Resources/bin/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -6472,7 +6411,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v6.4.7" + "source": "https://github.com/symfony/validator/tree/v6.4.8" }, "funding": [ { @@ -6488,20 +6427,20 @@ "type": "tidelift" } ], - "time": "2024-04-28T10:38:38+00:00" + "time": "2024-06-02T15:48:50+00:00" }, { "name": "symfony/var-dumper", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "7a9cd977cd1c5fed3694bee52990866432af07d7" + "reference": "ad23ca4312395f0a8a8633c831ef4c4ee542ed25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/7a9cd977cd1c5fed3694bee52990866432af07d7", - "reference": "7a9cd977cd1c5fed3694bee52990866432af07d7", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/ad23ca4312395f0a8a8633c831ef4c4ee542ed25", + "reference": "ad23ca4312395f0a8a8633c831ef4c4ee542ed25", "shasum": "" }, "require": { @@ -6557,7 +6496,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.7" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.8" }, "funding": [ { @@ -6573,20 +6512,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/var-exporter", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "825f9b00c37bbe1c1691cc1aff9b5451fc9b4405" + "reference": "792ca836f99b340f2e9ca9497c7953948c49a504" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/825f9b00c37bbe1c1691cc1aff9b5451fc9b4405", - "reference": "825f9b00c37bbe1c1691cc1aff9b5451fc9b4405", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/792ca836f99b340f2e9ca9497c7953948c49a504", + "reference": "792ca836f99b340f2e9ca9497c7953948c49a504", "shasum": "" }, "require": { @@ -6634,7 +6573,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.4.7" + "source": "https://github.com/symfony/var-exporter/tree/v6.4.8" }, "funding": [ { @@ -6650,20 +6589,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/web-link", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/web-link.git", - "reference": "63e03d53df4ddb7e054d7dc5a43f58be9c67bd7a" + "reference": "304c67cefe7128ea3957e9bb1ac6ce08a90a635b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-link/zipball/63e03d53df4ddb7e054d7dc5a43f58be9c67bd7a", - "reference": "63e03d53df4ddb7e054d7dc5a43f58be9c67bd7a", + "url": "https://api.github.com/repos/symfony/web-link/zipball/304c67cefe7128ea3957e9bb1ac6ce08a90a635b", + "reference": "304c67cefe7128ea3957e9bb1ac6ce08a90a635b", "shasum": "" }, "require": { @@ -6717,7 +6656,7 @@ "push" ], "support": { - "source": "https://github.com/symfony/web-link/tree/v6.4.7" + "source": "https://github.com/symfony/web-link/tree/v6.4.8" }, "funding": [ { @@ -6733,20 +6672,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/yaml", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "53e8b1ef30a65f78eac60fddc5ee7ebbbdb1dee0" + "reference": "52903de178d542850f6f341ba92995d3d63e60c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/53e8b1ef30a65f78eac60fddc5ee7ebbbdb1dee0", - "reference": "53e8b1ef30a65f78eac60fddc5ee7ebbbdb1dee0", + "url": "https://api.github.com/repos/symfony/yaml/zipball/52903de178d542850f6f341ba92995d3d63e60c9", + "reference": "52903de178d542850f6f341ba92995d3d63e60c9", "shasum": "" }, "require": { @@ -6789,7 +6728,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.4.7" + "source": "https://github.com/symfony/yaml/tree/v6.4.8" }, "funding": [ { @@ -6805,7 +6744,7 @@ "type": "tidelift" } ], - "time": "2024-04-28T10:28:08+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "twig/twig", @@ -7004,21 +6943,21 @@ "packages-dev": [ { "name": "dama/doctrine-test-bundle", - "version": "v8.1.0", + "version": "v8.2.0", "source": { "type": "git", "url": "https://github.com/dmaicher/doctrine-test-bundle.git", - "reference": "21b4dd73546991c7df34ba92ecbf305a1ae5a0ee" + "reference": "1f81a280ea63f049d24e9c8ce00e557b18e0ff2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dmaicher/doctrine-test-bundle/zipball/21b4dd73546991c7df34ba92ecbf305a1ae5a0ee", - "reference": "21b4dd73546991c7df34ba92ecbf305a1ae5a0ee", + "url": "https://api.github.com/repos/dmaicher/doctrine-test-bundle/zipball/1f81a280ea63f049d24e9c8ce00e557b18e0ff2f", + "reference": "1f81a280ea63f049d24e9c8ce00e557b18e0ff2f", "shasum": "" }, "require": { "doctrine/dbal": "^3.3 || ^4.0", - "doctrine/doctrine-bundle": "^2.2.2", + "doctrine/doctrine-bundle": "^2.11.0", "php": "^7.4 || ^8.0", "psr/cache": "^1.0 || ^2.0 || ^3.0", "symfony/cache": "^5.4 || ^6.3 || ^7.0", @@ -7065,9 +7004,9 @@ ], "support": { "issues": "https://github.com/dmaicher/doctrine-test-bundle/issues", - "source": "https://github.com/dmaicher/doctrine-test-bundle/tree/v8.1.0" + "source": "https://github.com/dmaicher/doctrine-test-bundle/tree/v8.2.0" }, - "time": "2024-05-21T18:06:21+00:00" + "time": "2024-05-28T15:41:06+00:00" }, { "name": "doctrine/data-fixtures", @@ -7155,16 +7094,16 @@ }, { "name": "doctrine/doctrine-fixtures-bundle", - "version": "3.6.0", + "version": "3.6.1", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineFixturesBundle.git", - "reference": "87f5d53708a3855aa018bf0a00d0d4b0ef58a956" + "reference": "d13a08ebf244f74c8adb8ff15aa55d01c404e534" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/87f5d53708a3855aa018bf0a00d0d4b0ef58a956", - "reference": "87f5d53708a3855aa018bf0a00d0d4b0ef58a956", + "url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/d13a08ebf244f74c8adb8ff15aa55d01c404e534", + "reference": "d13a08ebf244f74c8adb8ff15aa55d01c404e534", "shasum": "" }, "require": { @@ -7222,7 +7161,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineFixturesBundle/issues", - "source": "https://github.com/doctrine/DoctrineFixturesBundle/tree/3.6.0" + "source": "https://github.com/doctrine/DoctrineFixturesBundle/tree/3.6.1" }, "funding": [ { @@ -7238,7 +7177,7 @@ "type": "tidelift" } ], - "time": "2024-05-02T18:06:53+00:00" + "time": "2024-05-07T07:16:35+00:00" }, { "name": "fakerphp/faker", @@ -8992,16 +8931,16 @@ }, { "name": "symfony/browser-kit", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "c276856598f70e96f75403fc04841cec1dc56e74" + "reference": "62ab90b92066ef6cce5e79365625b4b1432464c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/c276856598f70e96f75403fc04841cec1dc56e74", - "reference": "c276856598f70e96f75403fc04841cec1dc56e74", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/62ab90b92066ef6cce5e79365625b4b1432464c8", + "reference": "62ab90b92066ef6cce5e79365625b4b1432464c8", "shasum": "" }, "require": { @@ -9040,7 +8979,7 @@ "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/browser-kit/tree/v6.4.7" + "source": "https://github.com/symfony/browser-kit/tree/v6.4.8" }, "funding": [ { @@ -9056,20 +8995,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/css-selector", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "1c5d5c2103c3762aff27a27e1e2409e30a79083b" + "reference": "4b61b02fe15db48e3687ce1c45ea385d1780fe08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/1c5d5c2103c3762aff27a27e1e2409e30a79083b", - "reference": "1c5d5c2103c3762aff27a27e1e2409e30a79083b", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/4b61b02fe15db48e3687ce1c45ea385d1780fe08", + "reference": "4b61b02fe15db48e3687ce1c45ea385d1780fe08", "shasum": "" }, "require": { @@ -9105,7 +9044,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v6.4.7" + "source": "https://github.com/symfony/css-selector/tree/v6.4.8" }, "funding": [ { @@ -9121,20 +9060,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/dom-crawler", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "2088c5da700b1e7a8689fffc10dda6c1f643deea" + "reference": "105b56a0305d219349edeb60a800082eca864e4b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/2088c5da700b1e7a8689fffc10dda6c1f643deea", - "reference": "2088c5da700b1e7a8689fffc10dda6c1f643deea", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/105b56a0305d219349edeb60a800082eca864e4b", + "reference": "105b56a0305d219349edeb60a800082eca864e4b", "shasum": "" }, "require": { @@ -9172,7 +9111,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v6.4.7" + "source": "https://github.com/symfony/dom-crawler/tree/v6.4.8" }, "funding": [ { @@ -9188,20 +9127,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/http-client", - "version": "v6.4.7", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "3683d8107cf1efdd24795cc5f7482be1eded34ac" + "reference": "61faba993e620fc22d4f0ab3b6bcf8fbb0d44b05" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/3683d8107cf1efdd24795cc5f7482be1eded34ac", - "reference": "3683d8107cf1efdd24795cc5f7482be1eded34ac", + "url": "https://api.github.com/repos/symfony/http-client/zipball/61faba993e620fc22d4f0ab3b6bcf8fbb0d44b05", + "reference": "61faba993e620fc22d4f0ab3b6bcf8fbb0d44b05", "shasum": "" }, "require": { @@ -9265,7 +9204,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.4.7" + "source": "https://github.com/symfony/http-client/tree/v6.4.8" }, "funding": [ { @@ -9281,7 +9220,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/http-client-contracts", @@ -9363,16 +9302,16 @@ }, { "name": "symfony/maker-bundle", - "version": "v1.59.1", + "version": "v1.60.0", "source": { "type": "git", "url": "https://github.com/symfony/maker-bundle.git", - "reference": "b87b1b25c607a8a50832395bc751c784946a0350" + "reference": "c305a02a22974670f359d4274c9431e1a191f559" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/b87b1b25c607a8a50832395bc751c784946a0350", - "reference": "b87b1b25c607a8a50832395bc751c784946a0350", + "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/c305a02a22974670f359d4274c9431e1a191f559", + "reference": "c305a02a22974670f359d4274c9431e1a191f559", "shasum": "" }, "require": { @@ -9435,7 +9374,7 @@ ], "support": { "issues": "https://github.com/symfony/maker-bundle/issues", - "source": "https://github.com/symfony/maker-bundle/tree/v1.59.1" + "source": "https://github.com/symfony/maker-bundle/tree/v1.60.0" }, "funding": [ { @@ -9451,20 +9390,20 @@ "type": "tidelift" } ], - "time": "2024-05-06T03:59:59+00:00" + "time": "2024-06-10T06:03:18+00:00" }, { "name": "symfony/phpunit-bridge", - "version": "v7.0.7", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "0a0b90ba08b9a03e09ad49f8d613bdf3eca3a7a9" + "reference": "3e1cb8c4dee341cfe96ae9fe29b1acda52a6bb16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/0a0b90ba08b9a03e09ad49f8d613bdf3eca3a7a9", - "reference": "0a0b90ba08b9a03e09ad49f8d613bdf3eca3a7a9", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/3e1cb8c4dee341cfe96ae9fe29b1acda52a6bb16", + "reference": "3e1cb8c4dee341cfe96ae9fe29b1acda52a6bb16", "shasum": "" }, "require": { @@ -9496,7 +9435,8 @@ "Symfony\\Bridge\\PhpUnit\\": "" }, "exclude-from-classmap": [ - "/Tests/" + "/Tests/", + "/bin/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -9516,7 +9456,7 @@ "description": "Provides utilities for PHPUnit, especially user deprecation notices management", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v7.0.7" + "source": "https://github.com/symfony/phpunit-bridge/tree/v7.1.1" }, "funding": [ { @@ -9532,20 +9472,81 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-06-04T06:50:37+00:00" }, { - "name": "symfony/web-profiler-bundle", - "version": "v6.4.7", + "name": "symfony/process", + "version": "v6.4.8", "source": { "type": "git", - "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "60fd8e550e08308ff8d2e88cfc50bb6c040a2fc3" + "url": "https://github.com/symfony/process.git", + "reference": "8d92dd79149f29e89ee0f480254db595f6a6a2c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/60fd8e550e08308ff8d2e88cfc50bb6c040a2fc3", - "reference": "60fd8e550e08308ff8d2e88cfc50bb6c040a2fc3", + "url": "https://api.github.com/repos/symfony/process/zipball/8d92dd79149f29e89ee0f480254db595f6a6a2c5", + "reference": "8d92dd79149f29e89ee0f480254db595f6a6a2c5", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v6.4.8" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T14:49:08+00:00" + }, + { + "name": "symfony/web-profiler-bundle", + "version": "v6.4.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/web-profiler-bundle.git", + "reference": "bcc806d1360991de3bf78ac5ca0202db85de9bfc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/bcc806d1360991de3bf78ac5ca0202db85de9bfc", + "reference": "bcc806d1360991de3bf78ac5ca0202db85de9bfc", "shasum": "" }, "require": { @@ -9598,7 +9599,7 @@ "dev" ], "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.4.7" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.4.8" }, "funding": [ { @@ -9614,7 +9615,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:22:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "theseer/tokenizer", @@ -9783,16 +9784,16 @@ }, { "name": "zenstruck/foundry", - "version": "v1.37.0", + "version": "v1.38.0", "source": { "type": "git", "url": "https://github.com/zenstruck/foundry.git", - "reference": "e01d77f01d2837e568ed92d226e6e778c37319a4" + "reference": "fd3c763de120445878077e54c608d8d75a3cc22d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zenstruck/foundry/zipball/e01d77f01d2837e568ed92d226e6e778c37319a4", - "reference": "e01d77f01d2837e568ed92d226e6e778c37319a4", + "url": "https://api.github.com/repos/zenstruck/foundry/zipball/fd3c763de120445878077e54c608d8d75a3cc22d", + "reference": "fd3c763de120445878077e54c608d8d75a3cc22d", "shasum": "" }, "require": { @@ -9809,7 +9810,7 @@ "doctrine/mongodb-odm": "2.5.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.4", + "bamarni/composer-bin-plugin": "^1.8", "dama/doctrine-test-bundle": "^7.0|^8.0", "doctrine/doctrine-bundle": "^2.5", "doctrine/doctrine-migrations-bundle": "^2.2|^3.0", @@ -9834,10 +9835,12 @@ }, "autoload": { "files": [ - "src/functions.php" + "src/functions.php", + "src/Persistence/functions.php" ], "psr-4": { - "Zenstruck\\Foundry\\": "src/" + "Zenstruck\\Foundry\\": "src/", + "Zenstruck\\Foundry\\Utils\\Rector\\": "utils/rector/src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -9863,7 +9866,7 @@ ], "support": { "issues": "https://github.com/zenstruck/foundry/issues", - "source": "https://github.com/zenstruck/foundry/tree/v1.37.0" + "source": "https://github.com/zenstruck/foundry/tree/v1.38.0" }, "funding": [ { @@ -9871,7 +9874,7 @@ "type": "github" } ], - "time": "2024-03-20T15:09:26+00:00" + "time": "2024-06-07T23:04:21+00:00" } ], "aliases": [], diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index b247cd0..9979dcc 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -1,24 +1,34 @@ doctrine: dbal: - url: '%env(resolve:DATABASE_URL)%' - profiling_collect_backtrace: '%kernel.debug%' - use_savepoints: true - mapping_types: - enum: string + connections: + default: + url: '%env(resolve:DATABASE_URL)%' + profiling_collect_backtrace: '%kernel.debug%' + mapping_types: + enum: string + og_1: + url: '%env(resolve:OG_1_DATABASE_URL)%' + default_connection: default + orm: - auto_generate_proxy_classes: true - enable_lazy_ghost_objects: true - report_fields_where_declared: true - validate_xml_mapping: true - naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware - auto_mapping: true - mappings: - App: - type: attribute - is_bundle: false - dir: '%kernel.project_dir%/src/Entity' - prefix: 'App\Entity' - alias: App + default_entity_manager: default + entity_managers: + default: + auto_mapping: true + connection: default + naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware + report_fields_where_declared: true + mappings: + App: + is_bundle: false + type: attribute + dir: '%kernel.project_dir%/src/Entity' + prefix: 'App\Entity' + alias: App + + og_1: + connection: og_1 + controller_resolver: auto_mapping: true diff --git a/docker/xdebug.ini b/docker/xdebug.ini index aa01684..af39592 100644 --- a/docker/xdebug.ini +++ b/docker/xdebug.ini @@ -1,4 +1,5 @@ xdebug.mode=debug -xdebug.start_with_request=yes +xdebug.start_with_request=trigger +xdebug.discover_client_host = 1 xdebug.client_host=${XDEBUG_CLIENT_HOST} xdebug.client_port=${XDEBUG_CLIENT_PORT} \ No newline at end of file diff --git a/migrations/.gitignore b/migrations/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/migrations/Version20240606102152.php b/migrations/Version20240606102152.php deleted file mode 100644 index 3415b95..0000000 --- a/migrations/Version20240606102152.php +++ /dev/null @@ -1,47 +0,0 @@ -addSql('CREATE TABLE hardware (id INT AUTO_INCREMENT 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, description VARCHAR(255) DEFAULT NULL, type VARCHAR(255) DEFAULT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_FE99E9E0D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('CREATE TABLE hardware_profile (id INT AUTO_INCREMENT NOT NULL, organizational_unit_id INT DEFAULT 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, description VARCHAR(255) DEFAULT NULL, comments VARCHAR(255) DEFAULT NULL, UNIQUE INDEX UNIQ_2D9A2460D17F50A6 (uuid), INDEX IDX_2D9A2460FB84408A (organizational_unit_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('CREATE TABLE hardware_profile_hardware (hardware_profile_id INT NOT NULL, hardware_id INT NOT NULL, INDEX IDX_18C7E12CFA495C1 (hardware_profile_id), INDEX IDX_18C7E12C9CC762B (hardware_id), PRIMARY KEY(hardware_profile_id, hardware_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('ALTER TABLE hardware_profile ADD CONSTRAINT FK_2D9A2460FB84408A FOREIGN KEY (organizational_unit_id) REFERENCES organizational_unit (id)'); - $this->addSql('ALTER TABLE hardware_profile_hardware ADD CONSTRAINT FK_18C7E12CFA495C1 FOREIGN KEY (hardware_profile_id) REFERENCES hardware_profile (id) ON DELETE CASCADE'); - $this->addSql('ALTER TABLE hardware_profile_hardware ADD CONSTRAINT FK_18C7E12C9CC762B FOREIGN KEY (hardware_id) REFERENCES hardware (id) ON DELETE CASCADE'); - $this->addSql('ALTER TABLE client ADD hardware_profile_id INT DEFAULT NULL'); - $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455CFA495C1 FOREIGN KEY (hardware_profile_id) REFERENCES hardware_profile (id)'); - $this->addSql('CREATE INDEX IDX_C7440455CFA495C1 ON client (hardware_profile_id)'); - } - - 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_C7440455CFA495C1'); - $this->addSql('ALTER TABLE hardware_profile DROP FOREIGN KEY FK_2D9A2460FB84408A'); - $this->addSql('ALTER TABLE hardware_profile_hardware DROP FOREIGN KEY FK_18C7E12CFA495C1'); - $this->addSql('ALTER TABLE hardware_profile_hardware DROP FOREIGN KEY FK_18C7E12C9CC762B'); - $this->addSql('DROP TABLE hardware'); - $this->addSql('DROP TABLE hardware_profile'); - $this->addSql('DROP TABLE hardware_profile_hardware'); - $this->addSql('DROP INDEX IDX_C7440455CFA495C1 ON client'); - $this->addSql('ALTER TABLE client DROP hardware_profile_id'); - } -} diff --git a/migrations/Version20240606081620.php b/migrations/Version20240611090540.php similarity index 65% rename from migrations/Version20240606081620.php rename to migrations/Version20240611090540.php index 498f6b2..5f4e3cb 100644 --- a/migrations/Version20240606081620.php +++ b/migrations/Version20240611090540.php @@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration; /** * Auto-generated Migration: Please modify to your needs! */ -final class Version20240606081620 extends AbstractMigration +final class Version20240611090540 extends AbstractMigration { public function getDescription(): string { @@ -20,12 +20,11 @@ final class Version20240606081620 extends AbstractMigration public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs - $this->addSql('CREATE TABLE aulas (idaula INT AUTO_INCREMENT NOT NULL, nombreaula VARCHAR(255) NOT NULL, idcentro INT NOT NULL, urlfoto VARCHAR(255) NOT NULL, cagnon TINYINT(1) NOT NULL, pizarra TINYINT(1) NOT NULL, grupoid INT NOT NULL, ubicacion VARCHAR(255) NOT NULL, comentarios VARCHAR(255) NOT NULL, puestos INT NOT NULL, horaresevini TINYINT(1) NOT NULL, horaresevfin TINYINT(1) NOT NULL, modomul TINYINT(1) NOT NULL, ipmul VARCHAR(255) NOT NULL, pormul VARCHAR(255) NOT NULL, velmul VARCHAR(255) NOT NULL, router VARCHAR(255) NOT NULL, netmask VARCHAR(255) NOT NULL, dns VARCHAR(255) NOT NULL, proxy VARCHAR(255) NOT NULL, ntp VARCHAR(255) NOT NULL, modp2p VARCHAR(255) NOT NULL, timep2p VARCHAR(255) NOT NULL, validacion TINYINT(1) NOT NULL, paginalogin VARCHAR(255) NOT NULL, paginavalidacion VARCHAR(255) NOT NULL, inremotepc VARCHAR(255) NOT NULL, oglivedir VARCHAR(255) NOT NULL, PRIMARY KEY(idaula)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('CREATE TABLE centros (idcentro INT AUTO_INCREMENT NOT NULL, nombrecentro VARCHAR(255) NOT NULL, identidad INT NOT NULL, comentarios VARCHAR(255) DEFAULT NULL, directorio VARCHAR(255) DEFAULT NULL, PRIMARY KEY(idcentro)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('CREATE TABLE client (id INT AUTO_INCREMENT NOT NULL, organizational_unit_id INT DEFAULT 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, name VARCHAR(255) DEFAULT NULL, serial_number VARCHAR(255) DEFAULT NULL, netiface VARCHAR(255) DEFAULT NULL, net_driver VARCHAR(255) DEFAULT NULL, mac VARCHAR(255) DEFAULT NULL, ip VARCHAR(255) DEFAULT NULL, status VARCHAR(255) DEFAULT NULL, UNIQUE INDEX UNIQ_C7440455D17F50A6 (uuid), INDEX IDX_C7440455FB84408A (organizational_unit_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('CREATE TABLE gruposordenadores (idgrupo INT AUTO_INCREMENT NOT NULL, nombregrupoordenador VARCHAR(255) NOT NULL, idaula VARCHAR(255) NOT NULL, grupoid VARCHAR(255) NOT NULL, comentarios VARCHAR(255) NOT NULL, PRIMARY KEY(idgrupo)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE client (id INT AUTO_INCREMENT NOT NULL, organizational_unit_id INT DEFAULT NULL, hardware_profile_id INT DEFAULT 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, name VARCHAR(255) DEFAULT NULL, serial_number VARCHAR(255) DEFAULT NULL, netiface VARCHAR(255) DEFAULT NULL, net_driver VARCHAR(255) DEFAULT NULL, mac VARCHAR(255) DEFAULT NULL, ip VARCHAR(255) DEFAULT NULL, status VARCHAR(255) DEFAULT NULL, UNIQUE INDEX UNIQ_C7440455D17F50A6 (uuid), INDEX IDX_C7440455FB84408A (organizational_unit_id), INDEX IDX_C7440455CFA495C1 (hardware_profile_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE hardware (id INT AUTO_INCREMENT 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, description VARCHAR(255) DEFAULT NULL, type VARCHAR(255) DEFAULT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_FE99E9E0D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE hardware_profile (id INT AUTO_INCREMENT NOT NULL, organizational_unit_id INT DEFAULT 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, description VARCHAR(255) DEFAULT NULL, comments VARCHAR(255) DEFAULT NULL, UNIQUE INDEX UNIQ_2D9A2460D17F50A6 (uuid), INDEX IDX_2D9A2460FB84408A (organizational_unit_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE hardware_profile_hardware (hardware_profile_id INT NOT NULL, hardware_id INT NOT NULL, INDEX IDX_18C7E12CFA495C1 (hardware_profile_id), INDEX IDX_18C7E12C9CC762B (hardware_id), PRIMARY KEY(hardware_profile_id, hardware_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE network_settings (id INT AUTO_INCREMENT 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, proxy VARCHAR(255) DEFAULT NULL, dns VARCHAR(255) DEFAULT NULL, netmask VARCHAR(255) DEFAULT NULL, router VARCHAR(255) DEFAULT NULL, ntp VARCHAR(255) DEFAULT NULL, p2p_time INT DEFAULT NULL, p2p_mode VARCHAR(255) DEFAULT NULL, mcast_ip VARCHAR(255) DEFAULT NULL, mcast_speed INT NOT NULL, mcast_mode VARCHAR(255) DEFAULT NULL, mcast_port INT DEFAULT NULL, UNIQUE INDEX UNIQ_48869B54D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('CREATE TABLE ordenadores (idordenador INT AUTO_INCREMENT NOT NULL, PRIMARY KEY(idordenador)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE organizational_unit (id INT AUTO_INCREMENT NOT NULL, parent_id INT DEFAULT NULL, network_settings_id INT DEFAULT 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, description VARCHAR(255) DEFAULT NULL, comments VARCHAR(255) DEFAULT NULL, path VARCHAR(255) DEFAULT NULL, level INT DEFAULT NULL, slug VARCHAR(255) DEFAULT NULL, type VARCHAR(255) NOT NULL, location VARCHAR(255) DEFAULT NULL, projector TINYINT(1) DEFAULT NULL, board TINYINT(1) DEFAULT NULL, capacity INT DEFAULT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_749AEB2DD17F50A6 (uuid), INDEX IDX_749AEB2D727ACA70 (parent_id), INDEX IDX_749AEB2D9B9A36D0 (network_settings_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE refresh_tokens (id INT AUTO_INCREMENT NOT NULL, refresh_token VARCHAR(128) NOT NULL, username VARCHAR(255) NOT NULL, valid DATETIME NOT NULL, UNIQUE INDEX UNIQ_9BACE7E1C74F2195 (refresh_token), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE user (id INT AUTO_INCREMENT 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, username VARCHAR(180) NOT NULL, roles JSON NOT NULL COMMENT \'(DC2Type:json)\', password VARCHAR(255) NOT NULL, enabled TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_8D93D649D17F50A6 (uuid), UNIQUE INDEX UNIQ_IDENTIFIER_USERNAME (username), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); @@ -33,6 +32,10 @@ final class Version20240606081620 extends AbstractMigration $this->addSql('CREATE TABLE user_group (id INT AUTO_INCREMENT 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, permissions JSON NOT NULL COMMENT \'(DC2Type:json)\', name VARCHAR(255) NOT NULL, enabled TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_8F02BF9DD17F50A6 (uuid), UNIQUE INDEX UNIQ_IDENTIFIER_NAME (name), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE user_group_user (user_group_id INT NOT NULL, user_id INT NOT NULL, INDEX IDX_3AE4BD51ED93D47 (user_group_id), INDEX IDX_3AE4BD5A76ED395 (user_id), PRIMARY KEY(user_group_id, user_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455FB84408A FOREIGN KEY (organizational_unit_id) REFERENCES organizational_unit (id)'); + $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455CFA495C1 FOREIGN KEY (hardware_profile_id) REFERENCES hardware_profile (id)'); + $this->addSql('ALTER TABLE hardware_profile ADD CONSTRAINT FK_2D9A2460FB84408A FOREIGN KEY (organizational_unit_id) REFERENCES organizational_unit (id)'); + $this->addSql('ALTER TABLE hardware_profile_hardware ADD CONSTRAINT FK_18C7E12CFA495C1 FOREIGN KEY (hardware_profile_id) REFERENCES hardware_profile (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE hardware_profile_hardware ADD CONSTRAINT FK_18C7E12C9CC762B FOREIGN KEY (hardware_id) REFERENCES hardware (id) ON DELETE CASCADE'); $this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D727ACA70 FOREIGN KEY (parent_id) REFERENCES organizational_unit (id) ON DELETE SET NULL'); $this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D9B9A36D0 FOREIGN KEY (network_settings_id) REFERENCES network_settings (id)'); $this->addSql('ALTER TABLE user_organizational_unit ADD CONSTRAINT FK_5E59845FA76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE'); @@ -45,18 +48,21 @@ final class Version20240606081620 extends AbstractMigration { // this down() migration is auto-generated, please modify it to your needs $this->addSql('ALTER TABLE client DROP FOREIGN KEY FK_C7440455FB84408A'); + $this->addSql('ALTER TABLE client DROP FOREIGN KEY FK_C7440455CFA495C1'); + $this->addSql('ALTER TABLE hardware_profile DROP FOREIGN KEY FK_2D9A2460FB84408A'); + $this->addSql('ALTER TABLE hardware_profile_hardware DROP FOREIGN KEY FK_18C7E12CFA495C1'); + $this->addSql('ALTER TABLE hardware_profile_hardware DROP FOREIGN KEY FK_18C7E12C9CC762B'); $this->addSql('ALTER TABLE organizational_unit DROP FOREIGN KEY FK_749AEB2D727ACA70'); $this->addSql('ALTER TABLE organizational_unit DROP FOREIGN KEY FK_749AEB2D9B9A36D0'); $this->addSql('ALTER TABLE user_organizational_unit DROP FOREIGN KEY FK_5E59845FA76ED395'); $this->addSql('ALTER TABLE user_organizational_unit DROP FOREIGN KEY FK_5E59845FFB84408A'); $this->addSql('ALTER TABLE user_group_user DROP FOREIGN KEY FK_3AE4BD51ED93D47'); $this->addSql('ALTER TABLE user_group_user DROP FOREIGN KEY FK_3AE4BD5A76ED395'); - $this->addSql('DROP TABLE aulas'); - $this->addSql('DROP TABLE centros'); $this->addSql('DROP TABLE client'); - $this->addSql('DROP TABLE gruposordenadores'); + $this->addSql('DROP TABLE hardware'); + $this->addSql('DROP TABLE hardware_profile'); + $this->addSql('DROP TABLE hardware_profile_hardware'); $this->addSql('DROP TABLE network_settings'); - $this->addSql('DROP TABLE ordenadores'); $this->addSql('DROP TABLE organizational_unit'); $this->addSql('DROP TABLE refresh_tokens'); $this->addSql('DROP TABLE user'); diff --git a/src/Command/Migration/MigrateClientsCommand.php b/src/Command/Migration/MigrateClientsCommand.php new file mode 100644 index 0000000..9d0560a --- /dev/null +++ b/src/Command/Migration/MigrateClientsCommand.php @@ -0,0 +1,86 @@ +doctrine->getManager('og_1'); + + $clientRepository = $this->entityManager->getRepository(Client::class); + $organizationalUnitRepository = $this->entityManager->getRepository(OrganizationalUnit::class); + + /** Obtener los ordenadores de la base de datos antigua **/ + $rsmClients = new ResultSetMapping(); + $rsmClients->addScalarResult('idordenador', 'idordenador'); + $rsmClients->addScalarResult('nombrgrupoordenador', 'nombrgrupoordenador'); + $rsmClients->addScalarResult('comentarios', 'comentarios'); + $pcsQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idordenador FROM ordenadores', $rsmClients); + $pcs = $pcsQuery->getResult(); + + /** Ordenadores **/ + foreach ($pcs as $pc){ + $newClient = $clientRepository->findOneBy(['migrationId' => $pc->getIdordenador()]); + if(!$newClient){ + $newClient = new Client(); + $newClient->setMigrationId($pc->getIdordenador()); + $this->entityManager->persist($newClient); + } + $newClient->setName($pc->getNombreordenador()); + $newClient->setSerialNumber($pc->getNumserie()); + $newClient->setNetiface($pc->getNetiface()); + $newClient->setNetdriver($pc->getNetdriver()); + $newClient->setMac($pc->getMac()); + $newClient->setIp($pc->getIp()); + //$client->setStatus(); + //$newClient->setCache($pc->getCache()); + //$newClient->setIdproautoexec($pc->getIdproautoexec()); + //$newClient->setOglive($pc->getOglivedir()); + + // Netboot + + //$migrationId = "" + + // HardwareProfile + //$hardwareProfile = $hardwareProfileRepository->findOneBy(['migrationId' => $pc->getIdperfilhard()]); + //$newClient->setHardwareProfile($hardwareProfile); + + // Menu + //$menu = $menuRepository->findOneBy(['migrationId' => $pc->getIdmenu()]); + //$newClient->setMenu($menu); + + // Repository + //$repository = $repositoryRepository->findOneBy(['migrationId' => $pc->getIdrepositorio()]); + //$newClient->setRepository($repository); + + // OrganizationalUnit + $migrationId = $pc->getGrupoid() == 0 ? $pc->getIdaula() : $pc->getGrupoid(); + $organizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $migrationId]); + $newClient->setOrganizationalUnit($organizationalUnit); + + } + $this->entityManager->flush(); + } + +} \ No newline at end of file diff --git a/src/Command/Migration/MigrateHardwareAndHardwareProfileCommand.php b/src/Command/Migration/MigrateHardwareAndHardwareProfileCommand.php new file mode 100644 index 0000000..96d8c24 --- /dev/null +++ b/src/Command/Migration/MigrateHardwareAndHardwareProfileCommand.php @@ -0,0 +1,40 @@ +doctrine->getManager('og_1'); + + /** Obtener los centros de la base de datos antigua **/ + $rsmCenters = new ResultSetMapping(); + $rsmCenters->addScalarResult('idcentro', 'idcentro'); + $rsmCenters->addScalarResult('nombrecentro', 'nombrecentro'); + $rsmCenters->addScalarResult('comentarios', 'comentarios'); + + + + return Command::SUCCESS; + } +} diff --git a/src/Command/Migration/MigrateOrganizationalUnitCommand.php b/src/Command/Migration/MigrateOrganizationalUnitCommand.php index a595626..3e561d4 100644 --- a/src/Command/Migration/MigrateOrganizationalUnitCommand.php +++ b/src/Command/Migration/MigrateOrganizationalUnitCommand.php @@ -3,13 +3,12 @@ namespace App\Command\Migration; use App\Entity\Client; -use App\Entity\Migration\Aulas; -use App\Entity\Migration\Centros; -use App\Entity\Migration\Gruposordenadores; -use App\Entity\Migration\Ordenadores; use App\Entity\NetworkSettings; use App\Entity\OrganizationalUnit; +use App\Model\OrganizationalUnitTypes; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Query\ResultSetMapping; +use Doctrine\Persistence\ManagerRegistry; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -20,7 +19,7 @@ class MigrateOrganizationalUnitCommand extends Command { public function __construct( private readonly EntityManagerInterface $entityManager, - private readonly EntityManagerInterface $entityManagerSlave + private readonly ManagerRegistry $doctrine ) { parent::__construct(); @@ -28,40 +27,121 @@ class MigrateOrganizationalUnitCommand extends Command protected function execute(InputInterface $input, OutputInterface $output): int { - $centers = $this->entityManagerSlave->getRepository(Centros::class)->findAll(); - $rooms = $this->entityManagerSlave->getRepository(Aulas::class)->findAll(); - $pcGroups = $this->entityManagerSlave->getRepository(Gruposordenadores::class)->findAll(); - $pcs = $this->entityManagerSlave->getRepository(Ordenadores::class)->findAll(); + /** @var EntityManagerInterface $oldDatabaseEntityManager */ + $oldDatabaseEntityManager = $this->doctrine->getManager('og_1'); + + /** Obtener los centros de la base de datos antigua **/ + $rsmCenters = new ResultSetMapping(); + $rsmCenters->addScalarResult('idcentro', 'idcentro'); + $rsmCenters->addScalarResult('nombrecentro', 'nombrecentro'); + $rsmCenters->addScalarResult('comentarios', 'comentarios'); + + $centersQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idcentro, nombrecentro, comentarios FROM centros', $rsmCenters); + $centers = $centersQuery->getResult(); + + /** Obtener los grupos de aulas de la base de datos antigua **/ + $rsmGroups = new ResultSetMapping(); + $rsmGroups->addScalarResult('idgrupo', 'idgrupo'); + $rsmGroups->addScalarResult('nombregrupo', 'nombregrupo'); + $rsmGroups->addScalarResult('comentarios', 'grupos.comentarios'); + $rsmGroups->addScalarResult('idcentro', 'grupos.idcentro'); + + $groupsQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idgrupo, nombregrupo, grupos.comentarios, grupos.idcentro FROM grupos INNER JOIN centros ON grupos.idcentro = centros.idcentro', $rsmGroups); + $groups = $groupsQuery->getResult(); + + /** Obtener las aulas de la base de datos antigua **/ + $rsmClassrooms = new ResultSetMapping(); + $rsmClassrooms->addScalarResult('idaula', 'idaula'); + $rsmClassrooms->addScalarResult('nombreaula', 'nombreaula'); + $rsmClassrooms->addScalarResult('comentarios', 'aulas.comentarios'); + $rsmClassrooms->addScalarResult('grupoid', 'aulas.grupoid'); + $rsmClassrooms->addScalarResult('proxy', 'proxy'); + $rsmClassrooms->addScalarResult('dns', 'dns'); + $rsmClassrooms->addScalarResult('netmask', 'netmask'); + $rsmClassrooms->addScalarResult('router', 'router'); + $rsmClassrooms->addScalarResult('ntp', 'ntp'); + $rsmClassrooms->addScalarResult('timep2p', 'timep2p'); + $rsmClassrooms->addScalarResult('modp2p', 'modp2p'); + $rsmClassrooms->addScalarResult('ipmul', 'ipmul'); + $rsmClassrooms->addScalarResult('pormul', 'pormul'); + $rsmClassrooms->addScalarResult('modomul', 'modomul'); + $rsmClassrooms->addScalarResult('velmul', 'velmul'); + $rsmClassrooms->addScalarResult('pizarra', 'pizarra'); + $rsmClassrooms->addScalarResult('cagnon', 'cagnon'); + $rsmClassrooms->addScalarResult('ubicacion', 'ubicacion'); + + $roomsQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idaula, nombreaula, aulas.comentarios, aulas.grupoid, proxy, dns, netmask, router, ntp, timep2p, modp2p, modomul, ipmul, velmul, pormul, pizarra, cagnon, ubicacion FROM aulas INNER JOIN grupos ON aulas.grupoid = grupos.idgrupo', $rsmClassrooms); + $rooms = $roomsQuery->getResult(); + + /** Obtener los grupos de ordenadores de la base de datos antigua **/ + $rsmClientGroups = new ResultSetMapping(); + $rsmClientGroups->addScalarResult('idgrupo', 'idgrupo'); + $rsmClientGroups->addScalarResult('nombregrupoordenador', 'nombregrupoordenador'); + $rsmClientGroups->addScalarResult('comentarios', 'gruposordenadores.comentarios'); + $rsmClientGroups->addScalarResult('idaula', 'gruposordenadores.idaula'); + $clientGroupsQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idgrupo, nombregrupoordenador, gruposordenadores.comentarios, gruposordenadores.idaula FROM gruposordenadores INNER JOIN aulas ON gruposordenadores.idaula = aulas.idaula', $rsmClientGroups); + $clientGroups = $clientGroupsQuery->getResult(); $organizationalUnitRepository = $this->entityManager->getRepository(OrganizationalUnit::class); - $clientRepository = $this->entityManager->getRepository(Client::class); /** Centros **/ $output->writeln("CENTROS TOTAL: ". count($centers)); foreach ($centers as $center){ $centerOrganizationalUnit = null; - $centerOrganizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $center->getIdcentro()]); + $centerOrganizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $center['idcentro']]); if(!$centerOrganizationalUnit){ $centerOrganizationalUnit = new OrganizationalUnit(); - $centerOrganizationalUnit->setMigrationId($center->getIdcentro()); - $centerOrganizationalUnit->setName($center->getNombrecentro()); - $centerOrganizationalUnit->setComments($center->getComentarios()); + $centerOrganizationalUnit->setMigrationId($center['idcentro']); + $centerOrganizationalUnit->setName($center['nombrecentro']); + $centerOrganizationalUnit->setComments($center['comentarios']); + $centerOrganizationalUnit->setType(OrganizationalUnitTypes::ORGANIZATIONAL_UNIT); $this->entityManager->persist($centerOrganizationalUnit); } } $this->entityManager->flush(); + /** Grupos de aulas **/ + $output->writeln("GRUPOS DE AULAS TOTAL: ". count($groups)); + foreach ($groups as $group){ + $groupPcOrganizationalUnit = null; + $groupPcOrganizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $group['idgrupo']]); + if(!$groupPcOrganizationalUnit){ + $groupPcOrganizationalUnit = new OrganizationalUnit(); + $groupPcOrganizationalUnit->setMigrationId($group['idgrupo']); + $groupPcOrganizationalUnit->setName($group['nombregrupo']); + $groupPcOrganizationalUnit->setComments($group['grupos.comentarios']); + $groupPcOrganizationalUnit->setType(OrganizationalUnitTypes::CLASSROOMS_GROUP); + + $center = $organizationalUnitRepository->findOneBy(['migrationId' => $group['grupos.idcentro']]); + if ($center){ + $groupPcOrganizationalUnit->setParent($center); + } + + $this->entityManager->persist($groupPcOrganizationalUnit); + } + } + $this->entityManager->flush(); + /** Aulas **/ $output->writeln("AULAS TOTAL: ". count($rooms)); foreach ($rooms as $room){ $roomOrganizationalUnit = null; - $roomOrganizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $room->getIdaula()]); + $roomOrganizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $room['idaula']]); if(!$roomOrganizationalUnit){ $roomOrganizationalUnit = new OrganizationalUnit(); - $roomOrganizationalUnit->setMigrationId($room->getIdaula()); - $roomOrganizationalUnit->setName($room->getNombreaula()); - $roomOrganizationalUnitParent = $organizationalUnitRepository->findOneBy(['migrationId' => $room->getIdcentro()]); - $roomOrganizationalUnit->setParent($roomOrganizationalUnitParent); + $roomOrganizationalUnit->setMigrationId($room['idaula']); + $roomOrganizationalUnit->setName($room['nombreaula']); + $roomOrganizationalUnit->setComments($room['aulas.comentarios']); + $roomOrganizationalUnit->setBoard($room['pizarra']); + $roomOrganizationalUnit->setProjector($room['cagnon']); + $roomOrganizationalUnit->setLocation($room['ubicacion']); + $roomOrganizationalUnit->setType(OrganizationalUnitTypes::CLASSROOM); + + $group = $organizationalUnitRepository->findOneBy(['migrationId' => $room['aulas.grupoid']]); + if ($group){ + $roomOrganizationalUnit->setParent($group); + } + $this->entityManager->persist($roomOrganizationalUnit); } @@ -71,82 +151,44 @@ class MigrateOrganizationalUnitCommand extends Command $roomOrganizationalUnit->setNetworkSettings($networkSettings); $this->entityManager->persist($networkSettings); } - $networkSettings->setProxy($room->getProxy()); - $networkSettings->setDns($room->getDns()); - $networkSettings->setNetmask($room->getNetmask()); - $networkSettings->setRouter($room->getRouter()); - $networkSettings->setNtp($room->getNtp()); - $networkSettings->setP2pTime($room->getTimep2p()); - $networkSettings->setP2pMode($room->getModp2p()); - $networkSettings->setMcastIp($room->getIpmul()); - $networkSettings->setMcastSpeed($room->getVelmul()); - $networkSettings->setMcastPort($room->getPormul()); - $networkSettings->setMcastMode($room->getModomul()); + $networkSettings->setProxy($room['proxy']); + $networkSettings->setDns($room['dns']); + $networkSettings->setNetmask($room['netmask']); + $networkSettings->setRouter($room['router']); + $networkSettings->setNtp($room['ntp']); + $networkSettings->setP2pTime($room['timep2p']); + $networkSettings->setP2pMode($room['modp2p']); + $networkSettings->setMcastIp($room['ipmul']); + $networkSettings->setMcastSpeed($room['velmul']); + $networkSettings->setMcastPort($room['pormul']); + $networkSettings->setMcastMode($room['modomul']); } $this->entityManager->flush(); /** Grupo Ordenador **/ $output->writeln("GRUPOS ORDENADORES ". count($rooms)); - foreach ($pcGroups as $group){ + foreach ($clientGroups as $clientGroup){ + var_dump($clientGroup ); $groupPcOrganizationalUnit = null; - $migrateParentId = ($group->getGrupoid() == 0) ? $group->getIdaula() : $group->getGrupoid(); - $groupPcOrganizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $group->getIdgrupo()]); + $groupPcOrganizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $clientGroup['idgrupo']]); if(!$groupPcOrganizationalUnit){ $groupPcOrganizationalUnit = new OrganizationalUnit(); - $groupPcOrganizationalUnit->setMigrationId($group->getIdgrupo()); - $groupPcOrganizationalUnit->setName($group->getNombregrupoordenador()); - $groupPcOrganizationalUnit->setComments($group->getComentarios()); - $groupPcOrganizationalUnitParent = $organizationalUnitRepository->findOneBy(['migrationId' => $migrateParentId]); - $groupPcOrganizationalUnit->setParent($groupPcOrganizationalUnitParent); + $groupPcOrganizationalUnit->setMigrationId($clientGroup['idgrupo']); + $groupPcOrganizationalUnit->setName($clientGroup['nombregrupoordenador']); + $groupPcOrganizationalUnit->setComments($clientGroup['gruposordenadores.comentarios']); + $groupPcOrganizationalUnit->setType(OrganizationalUnitTypes::CLIENTS_GROUP); + + $room = $organizationalUnitRepository->findOneBy(['migrationId' => $clientGroup['gruposordenadores.idaula']]); + if ($room){ + $groupPcOrganizationalUnit->setParent($room); + } + $this->entityManager->persist($groupPcOrganizationalUnit); } } $this->entityManager->flush(); - /** Ordenadores **/ - foreach ($pcs as $pc){ - $newClient = $clientRepository->findOneBy(['migrationId' => $pc->getIdordenador()]); - if(!$newClient){ - $newClient = new Client(); - $newClient->setMigrationId($pc->getIdordenador()); - $this->entityManager->persist($newClient); - } - $newClient->setName($pc->getNombreordenador()); - $newClient->setSerialNumber($pc->getNumserie()); - $newClient->setNetiface($pc->getNetiface()); - $newClient->setNetdriver($pc->getNetdriver()); - $newClient->setMac($pc->getMac()); - $newClient->setIp($pc->getIp()); - //$client->setStatus(); - //$newClient->setCache($pc->getCache()); - //$newClient->setIdproautoexec($pc->getIdproautoexec()); - //$newClient->setOglive($pc->getOglivedir()); - - // Netboot - - //$migrationId = "" - - // HardwareProfile - //$hardwareProfile = $hardwareProfileRepository->findOneBy(['migrationId' => $pc->getIdperfilhard()]); - //$newClient->setHardwareProfile($hardwareProfile); - - // Menu - //$menu = $menuRepository->findOneBy(['migrationId' => $pc->getIdmenu()]); - //$newClient->setMenu($menu); - - // Repository - //$repository = $repositoryRepository->findOneBy(['migrationId' => $pc->getIdrepositorio()]); - //$newClient->setRepository($repository); - - // OrganizationalUnit - $migrationId = $pc->getGrupoid() == 0 ? $pc->getIdaula() : $pc->getGrupoid(); - $organizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $migrationId]); - $newClient->setOrganizationalUnit($organizationalUnit); - - } - $this->entityManager->flush(); - return 1; } } \ No newline at end of file diff --git a/src/DataFixtures/AppFixtures.php b/src/DataFixtures/AppFixtures.php index 76fb475..358cac9 100644 --- a/src/DataFixtures/AppFixtures.php +++ b/src/DataFixtures/AppFixtures.php @@ -2,17 +2,14 @@ namespace App\DataFixtures; -use App\Entity\OrganizationalUnit; -use App\Factory\OrganizationalUnitFactory; use App\Factory\UserFactory; -use App\Model\OrganizationalUnitTypes; use App\Model\UserGroupPermissions; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Persistence\ObjectManager; class AppFixtures extends Fixture { - CONST ADMIN_USER = 'ogadmin'; + CONST string ADMIN_USER = 'ogadmin'; /** * @throws \Exception @@ -20,18 +17,6 @@ class AppFixtures extends Fixture public function load(ObjectManager $manager): void { UserFactory::createOne(['username' => self::ADMIN_USER, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); - $rootUnit = OrganizationalUnitFactory::createOne(['name' => 'Centro de Computación', 'parent' => null, 'type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); - $roomUnit = OrganizationalUnitFactory::createOne([ - 'name' => 'Aula 1', - 'parent' => $rootUnit, - 'type' => OrganizationalUnitTypes::CLASSROOMS_GROUP - ]); - - OrganizationalUnitFactory::createOne([ - 'name' => 'Aula 2', - 'parent' => $roomUnit, - 'type' => OrganizationalUnitTypes::CLASSROOM - ]); } } diff --git a/src/Dto/Output/ClientOutput.php b/src/Dto/Output/ClientOutput.php index 64f064b..5366342 100644 --- a/src/Dto/Output/ClientOutput.php +++ b/src/Dto/Output/ClientOutput.php @@ -4,7 +4,6 @@ namespace App\Dto\Output; use ApiPlatform\Metadata\Get; use App\Entity\Client; -use App\Entity\OrganizationalUnit; use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'Client')] diff --git a/src/Entity/Migration/Aulas.php b/src/Entity/Migration/Aulas.php deleted file mode 100644 index d4179e3..0000000 --- a/src/Entity/Migration/Aulas.php +++ /dev/null @@ -1,753 +0,0 @@ -nombreaula = $nombreaula; - - return $this; - } - - /** - * Get nombreaula. - * - * @return string - */ - public function getNombreaula() - { - return $this->nombreaula; - } - - /** - * Set idcentro. - * - * @param int $idcentro - * - * @return Aulas - */ - public function setIdcentro($idcentro) - { - $this->idcentro = $idcentro; - - return $this; - } - - /** - * Get idcentro. - * - * @return int - */ - public function getIdcentro() - { - return $this->idcentro; - } - - /** - * Set urlfoto. - * - * @param string|null $urlfoto - * - * @return Aulas - */ - public function setUrlfoto($urlfoto = null) - { - $this->urlfoto = $urlfoto; - - return $this; - } - - /** - * Get urlfoto. - * - * @return string|null - */ - public function getUrlfoto() - { - return $this->urlfoto; - } - - /** - * Set cagnon. - * - * @param bool|null $cagnon - * - * @return Aulas - */ - public function setCagnon($cagnon = null) - { - $this->cagnon = $cagnon; - - return $this; - } - - /** - * Get cagnon. - * - * @return bool|null - */ - public function getCagnon() - { - return $this->cagnon; - } - - /** - * Set pizarra. - * - * @param bool|null $pizarra - * - * @return Aulas - */ - public function setPizarra($pizarra = null) - { - $this->pizarra = $pizarra; - - return $this; - } - - /** - * Get pizarra. - * - * @return bool|null - */ - public function getPizarra() - { - return $this->pizarra; - } - - /** - * Set grupoid. - * - * @param int|null $grupoid - * - * @return Aulas - */ - public function setGrupoid($grupoid = null) - { - $this->grupoid = $grupoid; - - return $this; - } - - /** - * Get grupoid. - * - * @return int|null - */ - public function getGrupoid() - { - return $this->grupoid; - } - - /** - * Set ubicacion. - * - * @param string|null $ubicacion - * - * @return Aulas - */ - public function setUbicacion($ubicacion = null) - { - $this->ubicacion = $ubicacion; - - return $this; - } - - /** - * Get ubicacion. - * - * @return string|null - */ - public function getUbicacion() - { - return $this->ubicacion; - } - - /** - * Set comentarios. - * - * @param string|null $comentarios - * - * @return Aulas - */ - public function setComentarios($comentarios = null) - { - $this->comentarios = $comentarios; - - return $this; - } - - /** - * Get comentarios. - * - * @return string|null - */ - public function getComentarios() - { - return $this->comentarios; - } - - /** - * Set puestos. - * - * @param int|null $puestos - * - * @return Aulas - */ - public function setPuestos($puestos = null) - { - $this->puestos = $puestos; - - return $this; - } - - /** - * Get puestos. - * - * @return int|null - */ - public function getPuestos() - { - return $this->puestos; - } - - /** - * Set horaresevini. - * - * @param bool|null $horaresevini - * - * @return Aulas - */ - public function setHoraresevini($horaresevini = null) - { - $this->horaresevini = $horaresevini; - - return $this; - } - - /** - * Get horaresevini. - * - * @return bool|null - */ - public function getHoraresevini() - { - return $this->horaresevini; - } - - /** - * Set horaresevfin. - * - * @param bool|null $horaresevfin - * - * @return Aulas - */ - public function setHoraresevfin($horaresevfin = null) - { - $this->horaresevfin = $horaresevfin; - - return $this; - } - - /** - * Get horaresevfin. - * - * @return bool|null - */ - public function getHoraresevfin() - { - return $this->horaresevfin; - } - - /** - * Set modomul. - * - * @param bool $modomul - * - * @return Aulas - */ - public function setModomul($modomul) - { - $this->modomul = $modomul; - - return $this; - } - - /** - * Get modomul. - * - * @return bool - */ - public function getModomul() - { - return $this->modomul; - } - - /** - * Set ipmul. - * - * @param string $ipmul - * - * @return Aulas - */ - public function setIpmul($ipmul) - { - $this->ipmul = $ipmul; - - return $this; - } - - /** - * Get ipmul. - * - * @return string - */ - public function getIpmul() - { - return $this->ipmul; - } - - /** - * Set pormul. - * - * @param int $pormul - * - * @return Aulas - */ - public function setPormul($pormul) - { - $this->pormul = $pormul; - - return $this; - } - - /** - * Get pormul. - * - * @return int - */ - public function getPormul() - { - return $this->pormul; - } - - /** - * Set velmul. - * - * @param int $velmul - * - * @return Aulas - */ - public function setVelmul($velmul) - { - $this->velmul = $velmul; - - return $this; - } - - /** - * Get velmul. - * - * @return int - */ - public function getVelmul() - { - return $this->velmul; - } - - /** - * Set router. - * - * @param string|null $router - * - * @return Aulas - */ - public function setRouter($router = null) - { - $this->router = $router; - - return $this; - } - - /** - * Get router. - * - * @return string|null - */ - public function getRouter() - { - return $this->router; - } - - /** - * Set netmask. - * - * @param string|null $netmask - * - * @return Aulas - */ - public function setNetmask($netmask = null) - { - $this->netmask = $netmask; - - return $this; - } - - /** - * Get netmask. - * - * @return string|null - */ - public function getNetmask() - { - return $this->netmask; - } - - /** - * Set dns. - * - * @param string|null $dns - * - * @return Aulas - */ - public function setDns($dns = null) - { - $this->dns = $dns; - - return $this; - } - - /** - * Get dns. - * - * @return string|null - */ - public function getDns() - { - return $this->dns; - } - - /** - * Set proxy. - * - * @param string|null $proxy - * - * @return Aulas - */ - public function setProxy($proxy = null) - { - $this->proxy = $proxy; - - return $this; - } - - /** - * Get proxy. - * - * @return string|null - */ - public function getProxy() - { - return $this->proxy; - } - - /** - * Set ntp. - * - * @param string|null $ntp - * - * @return Aulas - */ - public function setNtp($ntp = null) - { - $this->ntp = $ntp; - - return $this; - } - - /** - * Get ntp. - * - * @return string|null - */ - public function getNtp() - { - return $this->ntp; - } - - /** - * Set modp2p. - * - * @param string|null $modp2p - * - * @return Aulas - */ - public function setModp2p($modp2p = null) - { - $this->modp2p = $modp2p; - - return $this; - } - - /** - * Get modp2p. - * - * @return string|null - */ - public function getModp2p() - { - return $this->modp2p; - } - - /** - * Set timep2p. - * - * @param int $timep2p - * - * @return Aulas - */ - public function setTimep2p($timep2p) - { - $this->timep2p = $timep2p; - - return $this; - } - - /** - * Get timep2p. - * - * @return int - */ - public function getTimep2p() - { - return $this->timep2p; - } - - /** - * Set validacion. - * - * @param bool|null $validacion - * - * @return Aulas - */ - public function setValidacion($validacion = null) - { - $this->validacion = $validacion; - - return $this; - } - - /** - * Get validacion. - * - * @return bool|null - */ - public function getValidacion() - { - return $this->validacion; - } - - /** - * Set paginalogin. - * - * @param string|null $paginalogin - * - * @return Aulas - */ - public function setPaginalogin($paginalogin = null) - { - $this->paginalogin = $paginalogin; - - return $this; - } - - /** - * Get paginalogin. - * - * @return string|null - */ - public function getPaginalogin() - { - return $this->paginalogin; - } - - /** - * Set paginavalidacion. - * - * @param string|null $paginavalidacion - * - * @return Aulas - */ - public function setPaginavalidacion($paginavalidacion = null) - { - $this->paginavalidacion = $paginavalidacion; - - return $this; - } - - /** - * Get paginavalidacion. - * - * @return string|null - */ - public function getPaginavalidacion() - { - return $this->paginavalidacion; - } - - /** - * Set inremotepc. - * - * @param bool|null $inremotepc - * - * @return Aulas - */ - public function setInremotepc($inremotepc = null) - { - $this->inremotepc = $inremotepc; - - return $this; - } - - /** - * Get inremotepc. - * - * @return bool|null - */ - public function getInremotepc() - { - return $this->inremotepc; - } - - /** - * Set oglivedir. - * - * @param string $oglivedir - * - * @return Aulas - */ - public function setOglivedir($oglivedir) - { - $this->oglivedir = $oglivedir; - - return $this; - } - - /** - * Get oglivedir. - * - * @return string - */ - public function getOglivedir() - { - return $this->oglivedir; - } - - /** - * Get idaula. - * - * @return int - */ - public function getIdaula() - { - return $this->idaula; - } -} diff --git a/src/Entity/Migration/Centros.php b/src/Entity/Migration/Centros.php deleted file mode 100644 index 1978a02..0000000 --- a/src/Entity/Migration/Centros.php +++ /dev/null @@ -1,133 +0,0 @@ -nombrecentro = $nombrecentro; - - return $this; - } - - /** - * Get nombrecentro. - * - * @return string - */ - public function getNombrecentro() - { - return $this->nombrecentro; - } - - /** - * Set identidad. - * - * @param int|null $identidad - * - * @return Centros - */ - public function setIdentidad($identidad = null) - { - $this->identidad = $identidad; - - return $this; - } - - /** - * Get identidad. - * - * @return int|null - */ - public function getIdentidad() - { - return $this->identidad; - } - - /** - * Set comentarios. - * - * @param string|null $comentarios - * - * @return Centros - */ - public function setComentarios($comentarios = null) - { - $this->comentarios = $comentarios; - - return $this; - } - - /** - * Get comentarios. - * - * @return string|null - */ - public function getComentarios() - { - return $this->comentarios; - } - - /** - * Set directorio. - * - * @param string|null $directorio - * - * @return Centros - */ - public function setDirectorio($directorio = null) - { - $this->directorio = $directorio; - - return $this; - } - - /** - * Get directorio. - * - * @return string|null - */ - public function getDirectorio() - { - return $this->directorio; - } - - /** - * Get idcentro. - * - * @return int - */ - public function getIdcentro() - { - return $this->idcentro; - } -} diff --git a/src/Entity/Migration/Gruposordenadores.php b/src/Entity/Migration/Gruposordenadores.php deleted file mode 100644 index d2a27b4..0000000 --- a/src/Entity/Migration/Gruposordenadores.php +++ /dev/null @@ -1,133 +0,0 @@ -nombregrupoordenador = $nombregrupoordenador; - - return $this; - } - - /** - * Get nombregrupoordenador. - * - * @return string - */ - public function getNombregrupoordenador() - { - return $this->nombregrupoordenador; - } - - /** - * Set idaula. - * - * @param int $idaula - * - * @return Gruposordenadores - */ - public function setIdaula($idaula) - { - $this->idaula = $idaula; - - return $this; - } - - /** - * Get idaula. - * - * @return int - */ - public function getIdaula() - { - return $this->idaula; - } - - /** - * Set grupoid. - * - * @param int|null $grupoid - * - * @return Gruposordenadores - */ - public function setGrupoid($grupoid = null) - { - $this->grupoid = $grupoid; - - return $this; - } - - /** - * Get grupoid. - * - * @return int|null - */ - public function getGrupoid() - { - return $this->grupoid; - } - - /** - * Set comentarios. - * - * @param string|null $comentarios - * - * @return Gruposordenadores - */ - public function setComentarios($comentarios = null) - { - $this->comentarios = $comentarios; - - return $this; - } - - /** - * Get comentarios. - * - * @return string|null - */ - public function getComentarios() - { - return $this->comentarios; - } - - /** - * Get idgrupo. - * - * @return int - */ - public function getIdgrupo() - { - return $this->idgrupo; - } -} diff --git a/src/Entity/Migration/Ordenadores.php b/src/Entity/Migration/Ordenadores.php deleted file mode 100644 index 351defe..0000000 --- a/src/Entity/Migration/Ordenadores.php +++ /dev/null @@ -1,663 +0,0 @@ -nombreordenador = $nombreordenador; - - return $this; - } - - /** - * Get nombreordenador. - * - * @return string|null - */ - public function getNombreordenador() - { - return $this->nombreordenador; - } - - /** - * Set numserie. - * - * @param string|null $numserie - * - * @return Ordenadores - */ - public function setNumserie($numserie = null) - { - $this->numserie = $numserie; - - return $this; - } - - /** - * Get numserie. - * - * @return string|null - */ - public function getNumserie() - { - return $this->numserie; - } - - /** - * Set ip. - * - * @param string $ip - * - * @return Ordenadores - */ - public function setIp($ip) - { - $this->ip = $ip; - - return $this; - } - - /** - * Get ip. - * - * @return string - */ - public function getIp() - { - return $this->ip; - } - - /** - * Set mac. - * - * @param string|null $mac - * - * @return Ordenadores - */ - public function setMac($mac = null) - { - $this->mac = $mac; - - return $this; - } - - /** - * Get mac. - * - * @return string|null - */ - public function getMac() - { - return $this->mac; - } - - /** - * Set idaula. - * - * @param int|null $idaula - * - * @return Ordenadores - */ - public function setIdaula($idaula = null) - { - $this->idaula = $idaula; - - return $this; - } - - /** - * Get idaula. - * - * @return int|null - */ - public function getIdaula() - { - return $this->idaula; - } - - /** - * Set idperfilhard. - * - * @param int|null $idperfilhard - * - * @return Ordenadores - */ - public function setIdperfilhard($idperfilhard = null) - { - $this->idperfilhard = $idperfilhard; - - return $this; - } - - /** - * Get idperfilhard. - * - * @return int|null - */ - public function getIdperfilhard() - { - return $this->idperfilhard; - } - - /** - * Set idrepositorio. - * - * @param int|null $idrepositorio - * - * @return Ordenadores - */ - public function setIdrepositorio($idrepositorio = null) - { - $this->idrepositorio = $idrepositorio; - - return $this; - } - - /** - * Get idrepositorio. - * - * @return int|null - */ - public function getIdrepositorio() - { - return $this->idrepositorio; - } - - /** - * Set grupoid. - * - * @param int|null $grupoid - * - * @return Ordenadores - */ - public function setGrupoid($grupoid = null) - { - $this->grupoid = $grupoid; - - return $this; - } - - /** - * Get grupoid. - * - * @return int|null - */ - public function getGrupoid() - { - return $this->grupoid; - } - - /** - * Set idmenu. - * - * @param int|null $idmenu - * - * @return Ordenadores - */ - public function setIdmenu($idmenu = null) - { - $this->idmenu = $idmenu; - - return $this; - } - - /** - * Get idmenu. - * - * @return int|null - */ - public function getIdmenu() - { - return $this->idmenu; - } - - /** - * Set cache. - * - * @param int|null $cache - * - * @return Ordenadores - */ - public function setCache($cache = null) - { - $this->cache = $cache; - - return $this; - } - - /** - * Get cache. - * - * @return int|null - */ - public function getCache() - { - return $this->cache; - } - - /** - * Set router. - * - * @param string $router - * - * @return Ordenadores - */ - public function setRouter($router) - { - $this->router = $router; - - return $this; - } - - /** - * Get router. - * - * @return string - */ - public function getRouter() - { - return $this->router; - } - - /** - * Set mascara. - * - * @param string $mascara - * - * @return Ordenadores - */ - public function setMascara($mascara) - { - $this->mascara = $mascara; - - return $this; - } - - /** - * Get mascara. - * - * @return string - */ - public function getMascara() - { - return $this->mascara; - } - - /** - * Set idproautoexec. - * - * @param int $idproautoexec - * - * @return Ordenadores - */ - public function setIdproautoexec($idproautoexec) - { - $this->idproautoexec = $idproautoexec; - - return $this; - } - - /** - * Get idproautoexec. - * - * @return int - */ - public function getIdproautoexec() - { - return $this->idproautoexec; - } - - /** - * Set arranque. - * - * @param string $arranque - * - * @return Ordenadores - */ - public function setArranque($arranque) - { - $this->arranque = $arranque; - - return $this; - } - - /** - * Get arranque. - * - * @return string - */ - public function getArranque() - { - return $this->arranque; - } - - /** - * Set netiface. - * - * @param string|null $netiface - * - * @return Ordenadores - */ - public function setNetiface($netiface = null) - { - $this->netiface = $netiface; - - return $this; - } - - /** - * Get netiface. - * - * @return string|null - */ - public function getNetiface() - { - return $this->netiface; - } - - /** - * Set netdriver. - * - * @param string $netdriver - * - * @return Ordenadores - */ - public function setNetdriver($netdriver) - { - $this->netdriver = $netdriver; - - return $this; - } - - /** - * Get netdriver. - * - * @return string - */ - public function getNetdriver() - { - return $this->netdriver; - } - - /** - * Set fotoord. - * - * @param string $fotoord - * - * @return Ordenadores - */ - public function setFotoord($fotoord) - { - $this->fotoord = $fotoord; - - return $this; - } - - /** - * Get fotoord. - * - * @return string - */ - public function getFotoord() - { - return $this->fotoord; - } - - /** - * Set validacion. - * - * @param bool|null $validacion - * - * @return Ordenadores - */ - public function setValidacion($validacion = null) - { - $this->validacion = $validacion; - - return $this; - } - - /** - * Get validacion. - * - * @return bool|null - */ - public function getValidacion() - { - return $this->validacion; - } - - /** - * Set paginalogin. - * - * @param string|null $paginalogin - * - * @return Ordenadores - */ - public function setPaginalogin($paginalogin = null) - { - $this->paginalogin = $paginalogin; - - return $this; - } - - /** - * Get paginalogin. - * - * @return string|null - */ - public function getPaginalogin() - { - return $this->paginalogin; - } - - /** - * Set paginavalidacion. - * - * @param string|null $paginavalidacion - * - * @return Ordenadores - */ - public function setPaginavalidacion($paginavalidacion = null) - { - $this->paginavalidacion = $paginavalidacion; - - return $this; - } - - /** - * Get paginavalidacion. - * - * @return string|null - */ - public function getPaginavalidacion() - { - return $this->paginavalidacion; - } - - /** - * Set agentkey. - * - * @param string|null $agentkey - * - * @return Ordenadores - */ - public function setAgentkey($agentkey = null) - { - $this->agentkey = $agentkey; - - return $this; - } - - /** - * Get agentkey. - * - * @return string|null - */ - public function getAgentkey() - { - return $this->agentkey; - } - - /** - * Set oglivedir. - * - * @param string $oglivedir - * - * @return Ordenadores - */ - public function setOglivedir($oglivedir) - { - $this->oglivedir = $oglivedir; - - return $this; - } - - /** - * Get oglivedir. - * - * @return string - */ - public function getOglivedir() - { - return $this->oglivedir; - } - - /** - * Get idordenador. - * - * @return int - */ - public function getIdordenador() - { - return $this->idordenador; - } -} diff --git a/src/Factory/UserFactory.php b/src/Factory/UserFactory.php index d626634..01cca77 100644 --- a/src/Factory/UserFactory.php +++ b/src/Factory/UserFactory.php @@ -14,7 +14,7 @@ use Zenstruck\Foundry\RepositoryProxy; */ final class UserFactory extends ModelFactory { - CONST PLAIN_PASSWORD = '12345678'; + CONST string PLAIN_PASSWORD = '12345678'; public function __construct() { diff --git a/src/Repository/.gitignore b/src/Repository/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/symfony.lock b/symfony.lock index 8640694..d9f1015 100644 --- a/symfony.lock +++ b/symfony.lock @@ -14,24 +14,21 @@ ] }, "dama/doctrine-test-bundle": { - "version": "8.1", + "version": "8.2", "recipe": { "repo": "github.com/symfony/recipes-contrib", "branch": "main", "version": "7.2", "ref": "896306d79d4ee143af9eadf9b09fd34a8c391b70" - }, - "files": [ - "config/packages/dama_doctrine_test_bundle.yaml" - ] + } }, "doctrine/doctrine-bundle": { "version": "2.12", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "2.12", - "ref": "7b1b0b637b337f6beb895589948cd119da705524" + "version": "2.10", + "ref": "c170ded8fc587d6bd670550c43dafcf093762245" }, "files": [ "config/packages/doctrine.yaml", @@ -71,12 +68,7 @@ "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", @@ -117,28 +109,22 @@ ] }, "ramsey/uuid-doctrine": { - "version": "2.0", + "version": "2.1", "recipe": { "repo": "github.com/symfony/recipes-contrib", "branch": "main", "version": "1.3", "ref": "471aed0fbf5620b8d7f92b7a5ebbbf6c0945c27a" - }, - "files": [ - "config/packages/ramsey_uuid_doctrine.yaml" - ] + } }, "stof/doctrine-extensions-bundle": { - "version": "1.10", + "version": "1.11", "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", @@ -184,7 +170,7 @@ ] }, "symfony/maker-bundle": { - "version": "1.59", + "version": "1.60", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", @@ -193,7 +179,7 @@ } }, "symfony/phpunit-bridge": { - "version": "7.0", + "version": "7.1", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", @@ -272,7 +258,7 @@ ] }, "zenstruck/foundry": { - "version": "1.37", + "version": "1.38", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", From 2893c0921edaef0cf178113c80fe6aa98e635d7c Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Wed, 12 Jun 2024 12:40:38 +0200 Subject: [PATCH 08/35] refs #452. Migrate clients and hardware profile ended --- composer.lock | 20 ++--- config/packages/doctrine.yaml | 2 + .../Migration/MigrateClientsCommand.php | 78 +++++++++---------- ...grateHardwareAndHardwareProfileCommand.php | 41 ++++++++-- .../MigrateOrganizationalUnitCommand.php | 26 ++++--- src/Entity/Client.php | 16 +--- tests/Functional/AbstractTest.php | 1 - 7 files changed, 102 insertions(+), 82 deletions(-) diff --git a/composer.lock b/composer.lock index 98d87a8..f49d68c 100644 --- a/composer.lock +++ b/composer.lock @@ -575,16 +575,16 @@ }, { "name": "doctrine/dbal", - "version": "3.8.4", + "version": "3.8.5", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "b05e48a745f722801f55408d0dbd8003b403dbbd" + "reference": "0e3536ba088a749985c8801105b6b3ac6c1280b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/b05e48a745f722801f55408d0dbd8003b403dbbd", - "reference": "b05e48a745f722801f55408d0dbd8003b403dbbd", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/0e3536ba088a749985c8801105b6b3ac6c1280b6", + "reference": "0e3536ba088a749985c8801105b6b3ac6c1280b6", "shasum": "" }, "require": { @@ -600,12 +600,12 @@ "doctrine/coding-standard": "12.0.0", "fig/log-test": "^1", "jetbrains/phpstorm-stubs": "2023.1", - "phpstan/phpstan": "1.10.58", - "phpstan/phpstan-strict-rules": "^1.5", - "phpunit/phpunit": "9.6.16", + "phpstan/phpstan": "1.11.1", + "phpstan/phpstan-strict-rules": "^1.6", + "phpunit/phpunit": "9.6.19", "psalm/plugin-phpunit": "0.18.4", "slevomat/coding-standard": "8.13.1", - "squizlabs/php_codesniffer": "3.9.0", + "squizlabs/php_codesniffer": "3.9.2", "symfony/cache": "^5.4|^6.0|^7.0", "symfony/console": "^4.4|^5.4|^6.0|^7.0", "vimeo/psalm": "4.30.0" @@ -668,7 +668,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.8.4" + "source": "https://github.com/doctrine/dbal/tree/3.8.5" }, "funding": [ { @@ -684,7 +684,7 @@ "type": "tidelift" } ], - "time": "2024-04-25T07:04:44+00:00" + "time": "2024-06-08T17:49:56+00:00" }, { "name": "doctrine/deprecations", diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index 9979dcc..5dedfc1 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -4,10 +4,12 @@ doctrine: default: url: '%env(resolve:DATABASE_URL)%' profiling_collect_backtrace: '%kernel.debug%' + use_savepoints: true mapping_types: enum: string og_1: url: '%env(resolve:OG_1_DATABASE_URL)%' + use_savepoints: true default_connection: default orm: diff --git a/src/Command/Migration/MigrateClientsCommand.php b/src/Command/Migration/MigrateClientsCommand.php index 9d0560a..1dc517c 100644 --- a/src/Command/Migration/MigrateClientsCommand.php +++ b/src/Command/Migration/MigrateClientsCommand.php @@ -3,6 +3,7 @@ namespace App\Command\Migration; use App\Entity\Client; +use App\Entity\HardwareProfile; use App\Entity\OrganizationalUnit; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query\ResultSetMapping; @@ -30,57 +31,56 @@ class MigrateClientsCommand extends Command $clientRepository = $this->entityManager->getRepository(Client::class); $organizationalUnitRepository = $this->entityManager->getRepository(OrganizationalUnit::class); + $hardwareProfileRepository = $this->entityManager->getRepository(HardwareProfile::class); /** Obtener los ordenadores de la base de datos antigua **/ $rsmClients = new ResultSetMapping(); $rsmClients->addScalarResult('idordenador', 'idordenador'); - $rsmClients->addScalarResult('nombrgrupoordenador', 'nombrgrupoordenador'); - $rsmClients->addScalarResult('comentarios', 'comentarios'); - $pcsQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idordenador FROM ordenadores', $rsmClients); - $pcs = $pcsQuery->getResult(); + $rsmClients->addScalarResult('nombreordenador', 'nombreordenador'); + $rsmClients->addScalarResult('numserie', 'numserie'); + $rsmClients->addScalarResult('mac', 'mac'); + $rsmClients->addScalarResult('ip', 'ip'); + $rsmClients->addScalarResult('netiface', 'netiface'); + $rsmClients->addScalarResult('netdriver', 'netdriver'); + $rsmClients->addScalarResult('idperfilhard', 'ordenadores.idperfilhard'); + $rsmClients->addScalarResult('grupoid', 'ordenadores.grupoid'); + $rsmClients->addScalarResult('idaula', 'ordenadores.idaula'); + + $clientsQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idordenador, nombreordenador, numserie, ip, mac, netiface, netdriver, ordenadores.idaula, ordenadores.grupoid, ordenadores.idperfilhard FROM ordenadores LEFT JOIN aulas ON ordenadores.idaula = aulas.idaula LEFT JOIN perfileshard ON ordenadores.idperfilhard = perfileshard.idperfilhard', $rsmClients); + $clients = $clientsQuery->getResult(); /** Ordenadores **/ - foreach ($pcs as $pc){ - $newClient = $clientRepository->findOneBy(['migrationId' => $pc->getIdordenador()]); - if(!$newClient){ - $newClient = new Client(); - $newClient->setMigrationId($pc->getIdordenador()); - $this->entityManager->persist($newClient); + $output->writeln("CLIENTES TOTAL: ". count($clients)); + foreach ($clients as $client){ + $clientEntity = $clientRepository->findOneBy(['migrationId' => $client['idordenador']]); + if(!$clientEntity){ + $clientEntity = new Client(); + $clientEntity->setMigrationId($client['idordenador']); + $clientEntity->setName($client['nombreordenador']); + $clientEntity->setSerialNumber($client['numserie']); + $clientEntity->setNetiface($client['netiface']); + $clientEntity->setNetdriver($client['netdriver']); + $clientEntity->setMac($client['mac']); + $clientEntity->setIp($client['ip']); } - $newClient->setName($pc->getNombreordenador()); - $newClient->setSerialNumber($pc->getNumserie()); - $newClient->setNetiface($pc->getNetiface()); - $newClient->setNetdriver($pc->getNetdriver()); - $newClient->setMac($pc->getMac()); - $newClient->setIp($pc->getIp()); - //$client->setStatus(); - //$newClient->setCache($pc->getCache()); - //$newClient->setIdproautoexec($pc->getIdproautoexec()); - //$newClient->setOglive($pc->getOglivedir()); - // Netboot - - //$migrationId = "" - - // HardwareProfile - //$hardwareProfile = $hardwareProfileRepository->findOneBy(['migrationId' => $pc->getIdperfilhard()]); - //$newClient->setHardwareProfile($hardwareProfile); - - // Menu - //$menu = $menuRepository->findOneBy(['migrationId' => $pc->getIdmenu()]); - //$newClient->setMenu($menu); - - // Repository - //$repository = $repositoryRepository->findOneBy(['migrationId' => $pc->getIdrepositorio()]); - //$newClient->setRepository($repository); - - // OrganizationalUnit - $migrationId = $pc->getGrupoid() == 0 ? $pc->getIdaula() : $pc->getGrupoid(); + $migrationId = $client['ordenadores.grupoid'] === 0 ? $client['ordenadores.idaula'] : $client['ordenadores.grupoid']; $organizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $migrationId]); - $newClient->setOrganizationalUnit($organizationalUnit); + if ($organizationalUnit){ + $clientEntity->setOrganizationalUnit($organizationalUnit); + } + + $hardwareProfile = $hardwareProfileRepository->findOneBy(['migrationId' => $client['ordenadores.idperfilhard']]); + if ($hardwareProfile){ + $clientEntity->setHardwareProfile($hardwareProfile); + } + + $this->entityManager->persist($clientEntity); } $this->entityManager->flush(); + + return Command::SUCCESS; } } \ No newline at end of file diff --git a/src/Command/Migration/MigrateHardwareAndHardwareProfileCommand.php b/src/Command/Migration/MigrateHardwareAndHardwareProfileCommand.php index 96d8c24..890f0fd 100644 --- a/src/Command/Migration/MigrateHardwareAndHardwareProfileCommand.php +++ b/src/Command/Migration/MigrateHardwareAndHardwareProfileCommand.php @@ -2,6 +2,8 @@ namespace App\Command\Migration; +use App\Entity\HardwareProfile; +use App\Entity\OrganizationalUnit; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query\ResultSetMapping; use Doctrine\Persistence\ManagerRegistry; @@ -10,7 +12,7 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -#[AsCommand(name: 'opengnsys:migrate_hardware_and_hardware_profile', description: 'Migrate hardware and hardware profile data')] +#[AsCommand(name: 'opengnsys:migrate-hardware-profile', description: 'Migrate hardware and hardware profile data')] class MigrateHardwareAndHardwareProfileCommand extends Command { public function __construct( @@ -27,13 +29,42 @@ class MigrateHardwareAndHardwareProfileCommand extends Command /** @var EntityManagerInterface $oldDatabaseEntityManager */ $oldDatabaseEntityManager = $this->doctrine->getManager('og_1'); + $organizationalUnitRepository = $this->entityManager->getRepository(OrganizationalUnit::class); + $hardwareProfileRepository = $this->entityManager->getRepository(HardwareProfile::class); + /** Obtener los centros de la base de datos antigua **/ - $rsmCenters = new ResultSetMapping(); - $rsmCenters->addScalarResult('idcentro', 'idcentro'); - $rsmCenters->addScalarResult('nombrecentro', 'nombrecentro'); - $rsmCenters->addScalarResult('comentarios', 'comentarios'); + $rsmHardwareProfiles = new ResultSetMapping(); + $rsmHardwareProfiles->addScalarResult('idperfilhard', 'idperfilhard'); + $rsmHardwareProfiles->addScalarResult('descripcion', 'descripcion'); + $rsmHardwareProfiles->addScalarResult('comentarios', 'perfilhard.comentarios'); + $rsmHardwareProfiles->addScalarResult('grupoid', 'perfilhard.grupoid'); + $rsmHardwareProfiles->addScalarResult('idcentro', 'perfilhard.idcentro'); + $hardwareProfilesQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idperfilhard, descripcion, grupos.comentarios, perfileshard.grupoid, perfileshard.idcentro FROM perfileshard LEFT JOIN grupos ON perfileshard.grupoid = grupos.idgrupo', $rsmHardwareProfiles); + $hardwareProfiles = $hardwareProfilesQuery->getResult(); + /** Perfiles hardware **/ + $output->writeln("PERFILES HARDWARE TOTAL: ". count($hardwareProfiles)); + foreach ($hardwareProfiles as $hardwareProfile){ + $hardwareProfileEntity = null; + $hardwareProfileEntity = $hardwareProfileRepository->findOneBy(['migrationId' => $hardwareProfile['idperfilhard']]); + if(!$hardwareProfileEntity){ + $hardwareProfileEntity = new HardwareProfile(); + $hardwareProfileEntity->setMigrationId($hardwareProfile['idperfilhard']); + $hardwareProfileEntity->setDescription($hardwareProfile['descripcion']); + $hardwareProfileEntity->setComments($hardwareProfile['perfilhard.comentarios']); + } + + $migrationId = $hardwareProfile['perfilhard.grupoid'] === 0 ? $hardwareProfile['perfilhard.idcentro'] : $hardwareProfile['perfilhard.grupoid']; + $organizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $migrationId]); + + if ($organizationalUnit){ + $hardwareProfileEntity->setOrganizationalUnit($organizationalUnit); + } + + $this->entityManager->persist($hardwareProfileEntity); + } + $this->entityManager->flush(); return Command::SUCCESS; } diff --git a/src/Command/Migration/MigrateOrganizationalUnitCommand.php b/src/Command/Migration/MigrateOrganizationalUnitCommand.php index 3e561d4..7234b26 100644 --- a/src/Command/Migration/MigrateOrganizationalUnitCommand.php +++ b/src/Command/Migration/MigrateOrganizationalUnitCommand.php @@ -46,7 +46,7 @@ class MigrateOrganizationalUnitCommand extends Command $rsmGroups->addScalarResult('comentarios', 'grupos.comentarios'); $rsmGroups->addScalarResult('idcentro', 'grupos.idcentro'); - $groupsQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idgrupo, nombregrupo, grupos.comentarios, grupos.idcentro FROM grupos INNER JOIN centros ON grupos.idcentro = centros.idcentro', $rsmGroups); + $groupsQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idgrupo, nombregrupo, grupos.comentarios, grupos.idcentro FROM grupos LEFT JOIN centros ON grupos.idcentro = centros.idcentro', $rsmGroups); $groups = $groupsQuery->getResult(); /** Obtener las aulas de la base de datos antigua **/ @@ -55,6 +55,7 @@ class MigrateOrganizationalUnitCommand extends Command $rsmClassrooms->addScalarResult('nombreaula', 'nombreaula'); $rsmClassrooms->addScalarResult('comentarios', 'aulas.comentarios'); $rsmClassrooms->addScalarResult('grupoid', 'aulas.grupoid'); + $rsmClassrooms->addScalarResult('idcentro', 'aulas.idcentro'); $rsmClassrooms->addScalarResult('proxy', 'proxy'); $rsmClassrooms->addScalarResult('dns', 'dns'); $rsmClassrooms->addScalarResult('netmask', 'netmask'); @@ -70,7 +71,7 @@ class MigrateOrganizationalUnitCommand extends Command $rsmClassrooms->addScalarResult('cagnon', 'cagnon'); $rsmClassrooms->addScalarResult('ubicacion', 'ubicacion'); - $roomsQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idaula, nombreaula, aulas.comentarios, aulas.grupoid, proxy, dns, netmask, router, ntp, timep2p, modp2p, modomul, ipmul, velmul, pormul, pizarra, cagnon, ubicacion FROM aulas INNER JOIN grupos ON aulas.grupoid = grupos.idgrupo', $rsmClassrooms); + $roomsQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idaula, nombreaula, aulas.comentarios, aulas.grupoid, aulas.idcentro, proxy, dns, netmask, router, ntp, timep2p, modp2p, modomul, ipmul, velmul, pormul, pizarra, cagnon, ubicacion FROM aulas LEFT JOIN grupos ON aulas.grupoid = grupos.idgrupo', $rsmClassrooms); $rooms = $roomsQuery->getResult(); /** Obtener los grupos de ordenadores de la base de datos antigua **/ @@ -79,7 +80,7 @@ class MigrateOrganizationalUnitCommand extends Command $rsmClientGroups->addScalarResult('nombregrupoordenador', 'nombregrupoordenador'); $rsmClientGroups->addScalarResult('comentarios', 'gruposordenadores.comentarios'); $rsmClientGroups->addScalarResult('idaula', 'gruposordenadores.idaula'); - $clientGroupsQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idgrupo, nombregrupoordenador, gruposordenadores.comentarios, gruposordenadores.idaula FROM gruposordenadores INNER JOIN aulas ON gruposordenadores.idaula = aulas.idaula', $rsmClientGroups); + $clientGroupsQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idgrupo, nombregrupoordenador, gruposordenadores.comentarios, gruposordenadores.idaula FROM gruposordenadores LEFT JOIN aulas ON gruposordenadores.idaula = aulas.idaula', $rsmClientGroups); $clientGroups = $clientGroupsQuery->getResult(); $organizationalUnitRepository = $this->entityManager->getRepository(OrganizationalUnit::class); @@ -88,7 +89,7 @@ class MigrateOrganizationalUnitCommand extends Command $output->writeln("CENTROS TOTAL: ". count($centers)); foreach ($centers as $center){ $centerOrganizationalUnit = null; - $centerOrganizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $center['idcentro']]); + $centerOrganizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $center['idcentro'], 'type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); if(!$centerOrganizationalUnit){ $centerOrganizationalUnit = new OrganizationalUnit(); $centerOrganizationalUnit->setMigrationId($center['idcentro']); @@ -104,7 +105,7 @@ class MigrateOrganizationalUnitCommand extends Command $output->writeln("GRUPOS DE AULAS TOTAL: ". count($groups)); foreach ($groups as $group){ $groupPcOrganizationalUnit = null; - $groupPcOrganizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $group['idgrupo']]); + $groupPcOrganizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $group['idgrupo'], 'type' => OrganizationalUnitTypes::CLASSROOMS_GROUP]); if(!$groupPcOrganizationalUnit){ $groupPcOrganizationalUnit = new OrganizationalUnit(); $groupPcOrganizationalUnit->setMigrationId($group['idgrupo']); @@ -126,7 +127,7 @@ class MigrateOrganizationalUnitCommand extends Command $output->writeln("AULAS TOTAL: ". count($rooms)); foreach ($rooms as $room){ $roomOrganizationalUnit = null; - $roomOrganizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $room['idaula']]); + $roomOrganizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $room['idaula'], 'type' => OrganizationalUnitTypes::CLASSROOM]); if(!$roomOrganizationalUnit){ $roomOrganizationalUnit = new OrganizationalUnit(); $roomOrganizationalUnit->setMigrationId($room['idaula']); @@ -137,9 +138,11 @@ class MigrateOrganizationalUnitCommand extends Command $roomOrganizationalUnit->setLocation($room['ubicacion']); $roomOrganizationalUnit->setType(OrganizationalUnitTypes::CLASSROOM); - $group = $organizationalUnitRepository->findOneBy(['migrationId' => $room['aulas.grupoid']]); - if ($group){ - $roomOrganizationalUnit->setParent($group); + $migrationId = $room['aulas.grupoid'] === 0 ? $room['aulas.idcentro'] : $room['aulas.grupoid']; + $organizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $migrationId]); + + if ($organizationalUnit){ + $roomOrganizationalUnit->setParent($organizationalUnit); } $this->entityManager->persist($roomOrganizationalUnit); @@ -167,11 +170,10 @@ class MigrateOrganizationalUnitCommand extends Command $this->entityManager->flush(); /** Grupo Ordenador **/ - $output->writeln("GRUPOS ORDENADORES ". count($rooms)); + $output->writeln("GRUPOS ORDENADORES ". count($clientGroups)); foreach ($clientGroups as $clientGroup){ - var_dump($clientGroup ); $groupPcOrganizationalUnit = null; - $groupPcOrganizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $clientGroup['idgrupo']]); + $groupPcOrganizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $clientGroup['idgrupo'], 'type' => OrganizationalUnitTypes::CLIENTS_GROUP]); if(!$groupPcOrganizationalUnit){ $groupPcOrganizationalUnit = new OrganizationalUnit(); $groupPcOrganizationalUnit->setMigrationId($clientGroup['idgrupo']); diff --git a/src/Entity/Client.php b/src/Entity/Client.php index fab44f4..6aba709 100644 --- a/src/Entity/Client.php +++ b/src/Entity/Client.php @@ -8,8 +8,7 @@ use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: ClientRepository::class)] class Client extends AbstractEntity { - #[ORM\Column(length: 255, nullable: true)] - private ?string $name = null; + use NameableTrait; #[ORM\Column(length: 255, nullable: true)] private ?string $serialNumber = null; @@ -35,19 +34,6 @@ class Client extends AbstractEntity #[ORM\ManyToOne(inversedBy: 'clients')] private ?HardwareProfile $hardwareProfile = null; - - public function getName(): ?string - { - return $this->name; - } - - public function setName(?string $name): static - { - $this->name = $name; - - return $this; - } - public function getSerialNumber(): ?string { return $this->serialNumber; diff --git a/tests/Functional/AbstractTest.php b/tests/Functional/AbstractTest.php index 956517f..089d7cc 100644 --- a/tests/Functional/AbstractTest.php +++ b/tests/Functional/AbstractTest.php @@ -4,7 +4,6 @@ namespace Functional; use ApiPlatform\Symfony\Bundle\Test\ApiTestCase; use ApiPlatform\Symfony\Bundle\Test\Client; -use App\Factory\UserFactory; use Faker\Factory; use Faker\Generator; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; From a5d37d5092b2aa5717a307eea00cbd3d942968dc Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Wed, 12 Jun 2024 14:53:22 +0200 Subject: [PATCH 09/35] refs #452. Migrate clients and hardware profile ended --- migrations/Version20240612105731.php | 33 ++++ migrations/Version20240612111552.php | 37 +++++ .../OrganizationalUnitClassroomInput.php | 5 +- src/Entity/NetworkSettings.php | 4 +- tests/Functional/OrganizationalUnitTest.php | 148 ++++++++++++++++++ 5 files changed, 222 insertions(+), 5 deletions(-) create mode 100644 migrations/Version20240612105731.php create mode 100644 migrations/Version20240612111552.php create mode 100644 tests/Functional/OrganizationalUnitTest.php diff --git a/migrations/Version20240612105731.php b/migrations/Version20240612105731.php new file mode 100644 index 0000000..f61d5c1 --- /dev/null +++ b/migrations/Version20240612105731.php @@ -0,0 +1,33 @@ +addSql('ALTER TABLE client CHANGE name name VARCHAR(255) NOT NULL'); + $this->addSql('ALTER TABLE network_settings CHANGE mcast_speed mcast_speed INT DEFAULT 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 CHANGE mcast_speed mcast_speed INT NOT NULL'); + $this->addSql('ALTER TABLE client CHANGE name name VARCHAR(255) DEFAULT NULL'); + } +} diff --git a/migrations/Version20240612111552.php b/migrations/Version20240612111552.php new file mode 100644 index 0000000..a5cca1d --- /dev/null +++ b/migrations/Version20240612111552.php @@ -0,0 +1,37 @@ +addSql('ALTER TABLE client CHANGE name name VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE hardware CHANGE name name VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE organizational_unit CHANGE name name VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE user_group CHANGE name name VARCHAR(255) DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE hardware CHANGE name name VARCHAR(255) NOT NULL'); + $this->addSql('ALTER TABLE user_group CHANGE name name VARCHAR(255) NOT NULL'); + $this->addSql('ALTER TABLE organizational_unit CHANGE name name VARCHAR(255) NOT NULL'); + $this->addSql('ALTER TABLE client CHANGE name name VARCHAR(255) NOT NULL'); + } +} diff --git a/src/Dto/Input/OrganizationalUnitClassroomInput.php b/src/Dto/Input/OrganizationalUnitClassroomInput.php index 8231b46..dad97b7 100644 --- a/src/Dto/Input/OrganizationalUnitClassroomInput.php +++ b/src/Dto/Input/OrganizationalUnitClassroomInput.php @@ -2,6 +2,7 @@ namespace App\Dto\Input; +use App\Dto\Output\OrganizationalUnitOutput; use App\Entity\NetworkSettings; use App\Entity\OrganizationalUnit; use App\Model\OrganizationalUnitTypes; @@ -87,9 +88,7 @@ final class OrganizationalUnitClassroomInput extends OrganizationalUnitInput ?EntityManagerInterface $entityManager = null ): OrganizationalUnit { - if (!$organizationalUnit) { - $organizationalUnit = new OrganizationalUnit(); - } + $organizationalUnit = parent::createOrUpdateEntity($organizationalUnit); $organizationalUnit->setType(OrganizationalUnitTypes::CLASSROOM); $organizationalUnit->setLocation($this->location); diff --git a/src/Entity/NetworkSettings.php b/src/Entity/NetworkSettings.php index e229208..c9a0a4c 100644 --- a/src/Entity/NetworkSettings.php +++ b/src/Entity/NetworkSettings.php @@ -34,7 +34,7 @@ class NetworkSettings extends AbstractEntity #[ORM\Column(length: 255, nullable: true)] private ?string $mcastIp = null; - #[ORM\Column] + #[ORM\Column(length: 255, nullable: true)] private ?int $mcastSpeed = null; #[ORM\Column(length: 255, nullable: true)] @@ -161,7 +161,7 @@ class NetworkSettings extends AbstractEntity return $this->mcastSpeed; } - public function setMcastSpeed(int $mcastSpeed): static + public function setMcastSpeed(?int $mcastSpeed): static { $this->mcastSpeed = $mcastSpeed; diff --git a/tests/Functional/OrganizationalUnitTest.php b/tests/Functional/OrganizationalUnitTest.php new file mode 100644 index 0000000..7bd6ca7 --- /dev/null +++ b/tests/Functional/OrganizationalUnitTest.php @@ -0,0 +1,148 @@ + self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + OrganizationalUnitFactory::createMany(2, ['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); + OrganizationalUnitFactory::createMany(2, ['type' => OrganizationalUnitTypes::CLASSROOMS_GROUP]); + OrganizationalUnitFactory::createMany(2, ['type' => OrganizationalUnitTypes::CLASSROOM]); + OrganizationalUnitFactory::createMany(2, ['type' => OrganizationalUnitTypes::CLIENTS_GROUP]); + + $this->createClientWithCredentials()->request('GET', '/organizational-units'); + $this->assertResponseStatusCodeSame(Response::HTTP_OK); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/OrganizationalUnit', + '@id' => '/organizational-units', + '@type' => 'hydra:Collection', + 'hydra:totalItems' => 8, + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testCreateOrganizationalUnitRoot(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + $this->createClientWithCredentials()->request('POST', '/organizational-units/root',['json' => [ + 'name' => self::ORGANIZATIONAL_UNIT_CREATE, + ]]); + + $this->assertResponseStatusCodeSame(201); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/OrganizationalUnitOutput', + '@type' => 'OrganizationalUnit', + 'name' => self::ORGANIZATIONAL_UNIT_CREATE, + 'type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT, + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testCreateOrganizationalUnitClassroomGroup(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + $this->createClientWithCredentials()->request('POST', '/organizational-units/classroom-group',['json' => [ + 'name' => self::ORGANIZATIONAL_UNIT_CREATE, + ]]); + + $this->assertResponseStatusCodeSame(201); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/OrganizationalUnitOutput', + '@type' => 'OrganizationalUnit', + 'name' => self::ORGANIZATIONAL_UNIT_CREATE, + 'type' => OrganizationalUnitTypes::CLASSROOMS_GROUP, + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testCreateOrganizationalUnitClassroom(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + $this->createClientWithCredentials()->request('POST', '/organizational-units/classroom',['json' => [ + 'name' => self::ORGANIZATIONAL_UNIT_CREATE, + ]]); + + $this->assertResponseStatusCodeSame(201); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/OrganizationalUnitOutput', + '@type' => 'OrganizationalUnit', + 'name' => self::ORGANIZATIONAL_UNIT_CREATE, + 'type' => OrganizationalUnitTypes::CLASSROOM, + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testCreateOrganizationalUnitClientGroup(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + $this->createClientWithCredentials()->request('POST', '/organizational-units/client-group',['json' => [ + 'name' => self::ORGANIZATIONAL_UNIT_CREATE, + ]]); + + $this->assertResponseStatusCodeSame(201); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/OrganizationalUnitOutput', + '@type' => 'OrganizationalUnit', + 'name' => self::ORGANIZATIONAL_UNIT_CREATE, + 'type' => OrganizationalUnitTypes::CLIENTS_GROUP, + ]); + } +} \ No newline at end of file From f3e19eb8eecd82bce2e13a78495d501893cb1ccb Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Wed, 12 Jun 2024 16:46:35 +0200 Subject: [PATCH 10/35] refs #451. Testing OrganizationalUnit, and partial Client --- src/Dto/Input/ClientInput.php | 8 ++ src/Dto/Output/ClientOutput.php | 10 +- src/Dto/Output/OrganizationalUnitOutput.php | 4 + src/Factory/ClientFactory.php | 57 ++++++++++ src/Factory/HardwareProfileFactory.php | 57 ++++++++++ tests/Functional/ClientTest.php | 115 ++++++++++++++++++++ tests/Functional/OrganizationalUnitTest.php | 53 ++++++++- tests/Functional/UserGroupTest.php | 12 +- 8 files changed, 307 insertions(+), 9 deletions(-) create mode 100644 src/Factory/ClientFactory.php create mode 100644 src/Factory/HardwareProfileFactory.php create mode 100644 tests/Functional/ClientTest.php diff --git a/src/Dto/Input/ClientInput.php b/src/Dto/Input/ClientInput.php index f929311..8c39d2d 100644 --- a/src/Dto/Input/ClientInput.php +++ b/src/Dto/Input/ClientInput.php @@ -3,6 +3,7 @@ namespace App\Dto\Input; use ApiPlatform\Metadata\ApiProperty; +use App\Dto\Output\HardwareProfileOutput; use App\Dto\Output\OrganizationalUnitOutput; use App\Entity\Client; use Symfony\Component\Serializer\Annotation\Groups; @@ -43,6 +44,11 @@ final class ClientInput #[ApiProperty(description: 'The organizational unit of the client')] public ?OrganizationalUnitOutput $organizationalUnit = null; + #[Assert\NotNull] + #[Groups(['client:write', 'client:patch'])] + #[ApiProperty(description: 'The hardware profile of the client')] + public ?HardwareProfileOutput $hardwareProfile = null; + public function __construct(?Client $client = null) { if (!$client) { @@ -53,6 +59,7 @@ final class ClientInput $this->serialNumber = $client->getSerialNumber(); $this->netiface = $client->getNetiface(); $this->organizationalUnit = new OrganizationalUnitOutput($client->getOrganizationalUnit()); + $this->hardwareProfile = new HardwareProfileOutput($client->getHardwareProfile()); $this->netDriver = $client->getNetDriver(); $this->mac = $client->getMac(); $this->ip = $client->getIp(); @@ -69,6 +76,7 @@ final class ClientInput $client->setSerialNumber($this->serialNumber); $client->setNetiface($this->netiface); $client->setOrganizationalUnit($this->organizationalUnit->getEntity()); + $client->setHardwareProfile($this->hardwareProfile->getEntity()); $client->setNetDriver($this->netDriver); $client->setMac($this->mac); $client->setIp($this->ip); diff --git a/src/Dto/Output/ClientOutput.php b/src/Dto/Output/ClientOutput.php index 5366342..6961c0b 100644 --- a/src/Dto/Output/ClientOutput.php +++ b/src/Dto/Output/ClientOutput.php @@ -21,6 +21,9 @@ final class ClientOutput extends AbstractOutput #[Groups(['client:read'])] public ?OrganizationalUnitOutput $organizationalUnit = null; + #[Groups(['client:read'])] + public ?HardwareProfileOutput $hardwareProfile = null; + #[Groups(['client:read'])] public \DateTime $createAt; @@ -34,7 +37,12 @@ final class ClientOutput extends AbstractOutput $this->name = $client->getName(); $this->serialNumber = $client->getSerialNumber(); $this->netiface = $client->getNetiface(); - $this->organizationalUnit = new OrganizationalUnitOutput($client->getOrganizationalUnit()); + if ($client->getOrganizationalUnit()) { + $this->organizationalUnit = new OrganizationalUnitOutput($client->getOrganizationalUnit()); + } + if($client->getHardwareProfile()) { + $this->hardwareProfile = new HardwareProfileOutput($client->getHardwareProfile()); + } $this->createAt = $client->getCreatedAt(); $this->createBy = $client->getCreatedBy(); } diff --git a/src/Dto/Output/OrganizationalUnitOutput.php b/src/Dto/Output/OrganizationalUnitOutput.php index 393c154..bb0ee2c 100644 --- a/src/Dto/Output/OrganizationalUnitOutput.php +++ b/src/Dto/Output/OrganizationalUnitOutput.php @@ -12,6 +12,9 @@ final class OrganizationalUnitOutput extends AbstractOutput #[Groups(['organizational-unit:read'])] public string $name; + #[Groups(['organizational-unit:read'])] + public ?string $comments = null; + #[Groups(['organizational-unit:read'])] public string $type; @@ -39,6 +42,7 @@ final class OrganizationalUnitOutput extends AbstractOutput parent::__construct($organizationalUnit); $this->name = $organizationalUnit->getName(); + $this->comments = $organizationalUnit->getComments(); $this->type = $organizationalUnit->getType(); $this->networkSettings = $organizationalUnit->getNetworkSettings() ? new NetworkSettingsOutput($organizationalUnit->getNetworkSettings()) : null; $this->clients = $organizationalUnit->getClients()->toArray(); diff --git a/src/Factory/ClientFactory.php b/src/Factory/ClientFactory.php new file mode 100644 index 0000000..a967161 --- /dev/null +++ b/src/Factory/ClientFactory.php @@ -0,0 +1,57 @@ + + */ +final class ClientFactory extends ModelFactory +{ + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services + * + * @todo inject services if required + */ + public function __construct() + { + parent::__construct(); + } + + public static function class(): string + { + return Client::class; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories + * + * @todo add your default values here + */ + protected function getDefaults(): array + { + return [ + 'createdAt' => self::faker()->dateTime(), + 'name' => self::faker()->text(255), + 'updatedAt' => self::faker()->dateTime(), + ]; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization + */ + protected function initialize(): self + { + return $this + // ->afterInstantiate(function(Client $client): void {}) + ; + } + + protected static function getClass(): string + { + return Client::class; + } +} diff --git a/src/Factory/HardwareProfileFactory.php b/src/Factory/HardwareProfileFactory.php new file mode 100644 index 0000000..eacb105 --- /dev/null +++ b/src/Factory/HardwareProfileFactory.php @@ -0,0 +1,57 @@ + + */ +final class HardwareProfileFactory extends ModelFactory +{ + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services + * + * @todo inject services if required + */ + public function __construct() + { + parent::__construct(); + } + + public static function class(): string + { + return HardwareProfile::class; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories + * + * @todo add your default values here + */ + protected function getDefaults(): array + { + return [ + 'createdAt' => self::faker()->dateTime(), + 'updatedAt' => self::faker()->dateTime(), + 'description' => self::faker()->text(255), + ]; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization + */ + protected function initialize(): self + { + return $this + // ->afterInstantiate(function(HardwareProfile $hardwareProfile): void {}) + ; + } + + protected static function getClass(): string + { + return HardwareProfile::class; + } +} diff --git a/tests/Functional/ClientTest.php b/tests/Functional/ClientTest.php new file mode 100644 index 0000000..eca7cbc --- /dev/null +++ b/tests/Functional/ClientTest.php @@ -0,0 +1,115 @@ + self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + ClientFactory::createMany(10); + + $this->createClientWithCredentials()->request('GET', '/clients'); + $this->assertResponseStatusCodeSame(Response::HTTP_OK); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/Client', + '@id' => '/clients', + '@type' => 'hydra:Collection', + 'hydra:totalItems' => 10, + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testCreateClient(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); + $ouIri = $this->findIriBy(OrganizationalUnit::class, ['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); + + HardwareProfileFactory::createOne(['description' => self::HW_PROFILE]); + $hpIri = $this->findIriBy(HardwareProfile::class, ['description' => self::HW_PROFILE]); + + $this->createClientWithCredentials()->request('POST', '/clients',['json' => [ + 'name' => self::CLIENT_CREATE, + 'organizationalUnit' => $ouIri, + 'hardwareProfile' => $hpIri, + 'serialNumber' => '123abc', + ]]); + + $this->assertResponseStatusCodeSame(201); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/ClientOutput', + '@type' => 'Client', + 'name' => self::CLIENT_CREATE, + 'serialNumber' => '123abc', + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testUpdateUserGroup(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + ClientFactory::createOne(['name' => self::CLIENT_UPDATE, 'serialNumber' => '123abc']); + $iri = $this->findIriBy(Client::class, ['name' => self::CLIENT_UPDATE]); + + $this->createClientWithCredentials()->request('PUT', $iri, ['json' => [ + 'name' => self::CLIENT_UPDATE, + 'serialNumber' => '987zyx' + ]]); + + $this->assertResponseIsSuccessful(); + $this->assertJsonContains([ + '@id' => $iri, + 'name' => self::CLIENT_UPDATE, + 'serialNumber' => '987zyx' + ]); + } +} \ No newline at end of file diff --git a/tests/Functional/OrganizationalUnitTest.php b/tests/Functional/OrganizationalUnitTest.php index 7bd6ca7..eaecd08 100644 --- a/tests/Functional/OrganizationalUnitTest.php +++ b/tests/Functional/OrganizationalUnitTest.php @@ -2,6 +2,8 @@ namespace Functional; +use App\Entity\OrganizationalUnit; +use App\Entity\UserGroup; use App\Factory\OrganizationalUnitFactory; use App\Factory\UserFactory; use App\Model\OrganizationalUnitTypes; @@ -16,8 +18,9 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; class OrganizationalUnitTest extends AbstractTest { CONST string USER_ADMIN = 'ogadmin'; - CONST string ORGANIZATIONAL_UNIT_CREATE = 'test-organizational-unit-create'; + CONST string ORGANIZATIONAL_UNIT_UPDATE = 'test-organizational-unit-update'; + CONST string ORGANIZATIONAL_UNIT_DELETE = 'test-organizational-unit-delete'; /** * @throws RedirectionExceptionInterface @@ -145,4 +148,52 @@ class OrganizationalUnitTest extends AbstractTest 'type' => OrganizationalUnitTypes::CLIENTS_GROUP, ]); } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testUpdateOrganizationalUnit(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + OrganizationalUnitFactory::createOne(['name' => self::ORGANIZATIONAL_UNIT_CREATE, 'type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); + $iri = $this->findIriBy(OrganizationalUnit::class, ['name' => self::ORGANIZATIONAL_UNIT_CREATE]); + + $this->createClientWithCredentials()->request('PUT', $iri, ['json' => [ + 'name' => self::ORGANIZATIONAL_UNIT_UPDATE, + 'comments' => 'comments', + ]]); + + $this->assertResponseIsSuccessful(); + $this->assertJsonContains([ + '@id' => $iri, + 'name' => self::ORGANIZATIONAL_UNIT_UPDATE, + 'comments' => 'comments' + ]); + } + + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + */ + public function testDeleteOrganizationalUnit(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + OrganizationalUnitFactory::createOne(['name' => self::ORGANIZATIONAL_UNIT_DELETE, 'type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); + $iri = $this->findIriBy(OrganizationalUnit::class, ['name' => self::ORGANIZATIONAL_UNIT_DELETE]); + + $this->createClientWithCredentials()->request('DELETE', $iri); + $this->assertResponseStatusCodeSame(204); + $this->assertNull( + static::getContainer()->get('doctrine')->getRepository(UserGroup::class)->findOneBy(['name' => self::ORGANIZATIONAL_UNIT_DELETE]) + ); + } } \ No newline at end of file diff --git a/tests/Functional/UserGroupTest.php b/tests/Functional/UserGroupTest.php index 257360e..bc38bfe 100644 --- a/tests/Functional/UserGroupTest.php +++ b/tests/Functional/UserGroupTest.php @@ -2,7 +2,6 @@ namespace Functional; -use App\Entity\User; use App\Entity\UserGroup; use App\Factory\UserFactory; use App\Factory\UserGroupFactory; @@ -16,12 +15,11 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; class UserGroupTest extends AbstractTest { - CONST USER_ADMIN = 'ogadmin'; - - CONST USER_GROUP_CREATE = 'test-user-group-create'; - CONST USER_GROUP_UPDATE = 'test-user-group-update'; - CONST USER_GROUP_DELETE = 'test-user-group-delete'; - CONST ROLE_ORGANIZATIONAL_UNIT_ADMIN = 'ROLE_ORGANIZATIONAL_UNIT_ADMIN'; + CONST string USER_ADMIN = 'ogadmin'; + CONST string USER_GROUP_CREATE = 'test-user-group-create'; + CONST string USER_GROUP_UPDATE = 'test-user-group-update'; + CONST string USER_GROUP_DELETE = 'test-user-group-delete'; + CONST string ROLE_ORGANIZATIONAL_UNIT_ADMIN = 'ROLE_ORGANIZATIONAL_UNIT_ADMIN'; /** * @throws RedirectionExceptionInterface From 33210baf5ac3fc7e75a2287e673dbd0035bbbbfb Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Thu, 13 Jun 2024 08:43:17 +0200 Subject: [PATCH 11/35] refs #452. New docu --- README.md | 29 +++++++++++++++++- .../MigrateOrganizationalUnitCommand.php | 1 - swagger-assets/img_bbdd.png | Bin 0 -> 16853 bytes 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 swagger-assets/img_bbdd.png diff --git a/README.md b/README.md index 4aeaad1..2d8d104 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ docker exec ogcore-php php bin/console doctrine:migrations:migrate --no-interact ```sh docker exec ogcore-php php bin/console doctrine:fixtures:load --no-interaction -docker exec ogcore-php php bin/console app:load-default-user-groups +docker exec ogcore-php php bin/console app:load-default-user-groups #cargamos los grupos por defecto ``` ## UX Api Platform @@ -105,3 +105,30 @@ Es posible que en momentos de desarrollo, sea necesario volver a cargar la base docker exec ogcore-php php bin/console doctrine:database:drop --force docker exec ogcore-php php bin/console doctrine:database:create ``` + +## Migraciones de datos + +Para poder cargar los datos de las migraciones, previamente necesitamos poder tener un esquema de base de datos con un dump de OpenGnsys. Es decir: + - Creamos una base de datos temporal simulando una insancia de OpenGnsys 1.1. La solicitaremos al equipo de desarrollo de las universidades + - Necesitaremos un dump de la base de datos de OpenGnsys 1.1 + +Mediante doctrine, creamos la base de datos temporal: + +```sh +docker exec ogcore-php php bin/console doctrine:database:create --connection=og_1 + +``` + +![img.png](swagger-assets/img_bbdd.png) +Aqui podemos ver como tenemos las 2 bases de datos. OgCore es la actual, donde estamos desarrollando, y ogcore_old_og es la base de datos temporal que acabamos de crear. + +Aqui vendria el paso de cargar el dump en dicha base de datos, ya que contiene informacion sensible, no se aloja en el repositorio, por eso tendremos que solicitarla al equipo correspondiente. +Una vez tengamos la base de datos cargada, podremos ejecutar las migraciones de datos: + +```sh +--- Migraciones de OpenGnsys. --- +docker exec ogcore-php php bin/console opengnsys:migration:organizational-unit #cargamos las unidades organizativas +docker exec ogcore-php php bin/console opengnsys:migrate-hardware-profiles #cargamos los perfiles de hardware +docker exec ogcore-php php bin/console pengnsys:migration:clients #cargamos los clientes +``` + diff --git a/src/Command/Migration/MigrateOrganizationalUnitCommand.php b/src/Command/Migration/MigrateOrganizationalUnitCommand.php index 7234b26..8d2826c 100644 --- a/src/Command/Migration/MigrateOrganizationalUnitCommand.php +++ b/src/Command/Migration/MigrateOrganizationalUnitCommand.php @@ -2,7 +2,6 @@ namespace App\Command\Migration; -use App\Entity\Client; use App\Entity\NetworkSettings; use App\Entity\OrganizationalUnit; use App\Model\OrganizationalUnitTypes; diff --git a/swagger-assets/img_bbdd.png b/swagger-assets/img_bbdd.png new file mode 100644 index 0000000000000000000000000000000000000000..ce55b519ceb02019dbdda434810dafc223fbf683 GIT binary patch literal 16853 zcmd74byQs2w(gsR0EHJCoI(O5xCFN0>RxixI+y+3GGt(eR?7-P=fzyAIDs8DrPc|2@N?0fg_;XPN7d2#RF zeF*Bu7Jz~JT?~JEg~{R4PM2g%2Kt zvHL#=%VdALv`eT(GUu=u)h^8XG^{Q=b30Q?T6#=HkinC7#EEe?GRf_%OJ*=-?-dz8 z|F|f&z>mEy7Uj%I_HU?H^V^z<^v|MF0~0}MC=-RoRGBkwwF z9Y?BF7?9U;*IzyP{r7~u^V1Q(p4!$rsY~9V+u_Z zsLFso1++TCXBX8&of54_tu9lnztSa+`K0ac>1l_@w%!J{ATfMJ)x%!aW@I_qu`{(K z)g2#*wnUv}|61|gep)KOH`xj=oDa>pz5qhVl066@eFaArSC@O|-(AVddADww{Liv) zakLf;KD;i{Z+L)7b=z0H>~00EUNiyvQrUf5FojB@C(zk-CHmb)?uNZ`7oC1vpHC^h zcpJ!dV`p#V#@z1BBIg~JYK80c!P2t{6Rb$OBEjZR7mL$fZa$@&4S|q-L0wk%ROXwv zuZQ8ghmXVCgDNoHr{P`S_F0d+OV1A{TaB-mA2W$yL(H#|P#*xylb;&#Q z`84X@)EzE^pyTB^*6-f}scT0PkplW`A#(c*ljqR%Ts_LW_i+kWU=_fDK5EJ(u!PPJ z`MU2eaqxocEpuh?TZ^NO3my1#$G)c>`TDopXdO^r!5sWX|!g zI+*2Pqd7aojO{qqgzM0|zN7sY9P*yeIT~7Tah8**v|CqckLP@YzV^g4Fr$Z>g&xcS zM!S!s00-{B?^9fh^JRgO`TVY}76)7B6G7Za^VnXsXRG^MzEPvCbvC8LjDlr#_Jwhk>Qh@h;IJ_JxR`-{IqQ@d8xL& zyut>5#;enJYonA^(N5XzQAZ(XBb}zMk@iJ&)sLdyP3|tLzwjmg^i>etwFsk!vGbz_ zb$tf7>z>LZ%+P)F^Vh*p$Z=B1T8?VlhpRM%?`_mbkc3!s8D=nDaPjoP9-5Jw_Kl{)6S0!vFWs<&Jv}oZ^hm?M}Ip$v5SaK z+CQ*)c3Q0SfU88ZqL+iUaWW$M((e55gp2%Abbr5Bmo;$YKD`O}b0aEj#Gw2C`*Gyo z3pw@FsF+ltje2Rf`Ta)yzl~PwGTJg#<27B1%4<&rj%P&V!0WKj3sUbyw94U=6Fk@u zmd;}gqOtlgyylvyn>dj7QOUH`>T>s1oK!@yp{#8@RL;aYMHC-Gj2=*8qHX%XkF{8SX*?R}+~j~`)GRs4x%4Ny8G(eV2?Z7VA# zw{MM-*z|pD0?84kX=PEX0-A|Cj761*8w&t$NlT3xGIq4ir4c)Ao^q~5 zFVZ+?RqXV$jj?G_lznTU)#yWd>v(h^4&__PEe+socfU4`Th!h#RY>Hi_SKc2DD?Fy zU-@XdeTw+*50?}Dd5>FP6FQ@PEWes+mGeraFG%f|b(kI(vb{rW?Z2A5zm(|Sf15cQFZr`tZSB(5kh1OTJZjo3!|TK=*^&SJ)QWQs9zJdv|iAb zrVi9x{$4hmp)72O0N%5^!Q4FP`fyoKdqexpj>8FFr&x(sn_6(-Y#>qmgyUHF{XbTA z4olE&v%#}uSIkecBAWXLOmcRH`Fi?sjlVKkRHr|r^Kzu(n&oPg+j+IxbWdKu0sz2H zpXtu+_~a+{Q&Jk&Yp^D1K*ykF1iCno{!TR@W}b#D3Y+>Owz2Qm%`{%i_od<}rh`);j^3v9u}uvpvL%#&-(C0}kbpxquVzt0>P@pZ zrtfQy3uG=_W98p*V40iC-|DaDO(>=Fy4LH{xE*%yL%!%Gsrh0^x5j|sLoVIT1Gr%S`vb6l;?$uB3yc?_7wY2P)I<%kYUto2`P z@%G~L&N^H2%O~2m3;Xo@3DIl033x3EDQWsJsNa0Q-8S#KcV0jq%&JvT#><&r+5w># z7VavD5-&+FS?6Cq*ndq4Day?g(w*W=(|ZH^DSNt-ED`jbotHH$y3QYknfeZYUI$AMf7~L*EkC%n zD`ru93(whM+`ZM{vlCPj>+)8P?7RNF*Vrxjt|miA4e0>3@P+uD#)~Ar%{X8>a;Su{ zi#c7)43C?;N_e~i>Po=V55EkrQuU67Z0L8HmAuhYyB-`4l1GQLBo_+Cu>6&S{!az? zKPS$GISlwKyuP^V7#Q?}+mrwVaG>Dy2&ND4Wy*9iVfMY~j{V>{Q#` z5b_HfdE4r@JP>wB|M%57W4ZE+ffW7skt|==6pW{eBGrtpCmPb7M2xMuFIy&$z~90 z;e-_p_+kv4u3c)|?!$nGFbUu!#|)@R=Z5T-?F?kKV?;t%kLEJSStx>|+4+X)`jq^& z9VX(|60jpK;_Py^bX(l0pkqoX<3yu+Lnp+=iqmzy2UGM22=0!Eo!|aM7!aNA+t1?EZ+gl-eE+FOIutb z-WNX~+tbr&x1_E+BOIa&M&wg;Z}nS;R9IyA+Z!cKf^c=c2+`-3J8#nX+G9}hRhy!a zar=v?_PzA_HzSe>vLr@+(;1pB&{!6O&U|xS3*2S$399{u2BJbO)w5Ca8;-ei?gwcb zIF}-N4u=TirfrX?k9~rYt$sK6__Oai^DIgB?9zfuD_wQmkDZs*+f?+eX#)?AIOG@78il**S5b8v|<~6hqV>W4e-LtE6VE%7$&rk zZ-HEu3F7Csow&Fy%b zNRmR3!DTxRlIioFfr-tPfcAZ&>j|L}ttISuRLl z``0r-($r3=84PX;sNgliG=PW9e25g~gddK2Q462ltJn`En7k}ri>+9#dhNp&+vCu* zij!=cD$RXn6x&7J6{WiyaJT+6;gIf}n01f3r?Jqy491q|l>MRN?Cn90A1|Q(MoF({ z)ccG#>s?r81Y29!7lRlPn?&?JA&kakjkq%^L7zn|(-jSBPst!=PS})0|3|&LuQYAN zS@ZjE90+SYlgl~afVRiQ>mCMyq#8wO*mJa2T@&QHXq0X^(Gub*+li*?!du~KPCwJ> zGF;4K%WVk+FIRH&r=v&tXM&|I{WU;dMHf^--N6cBYrgo4fv@!~qMaugd=G^koxNp8 z^*Dtx=pzZb86M_-Vh9tD67pvpS~L@8V27xG_dV~Nmn)tJu|s~ethrAJhmZ{iPmYv5 z4m`=Adj7^jZnjtOxW=b*EZiJaJ2P2CE=(Y=aWrd7>ArU;TG@&{vG*&m!G zUIVzDywF!-`TU$Jcc8CW=hPGuUWX^dnvrzsLY4f!`TP`BPyH5&sG!Xr7pl~6E~W4s zk^%M$h{>gtqw8rkOzz6KUk6?;W9G`KR20cu2spsW%xUvUjc(|&$@5z7(d`P+Eojp7 zHvx3c8EpFn1wZsZ~MG}#h~qt&Z`FkP6s~FTy@;*ucU4b zHhC_nadaSlIBjk9m7uc{RZ*A>8VSt;Bb3EqTYmiC{8o=Kqj{n+lBoOyw0F$I-_2Sd zJ7qUkC(wN)=hT;bCY1cfq*6cqj!3+j7@RkCi-FdDV_@ONprBl*DRcuiwy|uzMW5d{ zw_w3@$c}>tYh@1mMeUjkB1e1-m$~pV3pd5C>(p^25U`e5f$g7iVFQZEqn?YNR@+5f zr^9Wc-h!Gm9zkAv{1#T@KMe+e7~OLA!i#c1>|xo210Y?5N^hhivi_%B%6%O{`^|EU zn@gh~^9`ZeWFbz}uuZff#KfBq(H^s5Yzp%k zl4E`sheIeV_yp zh7ljO0RUpDOcB*Gnz{Ltp7o(=y999LR4D*qz{aO^u(oUlopK=TVWT~Gxft1%=q?*< zyF9|eac!`ad?_FSwBDS(*a~iUEs~*@eLiN+KQ9&yB;)0g*LYE{SSronG^NZTi=>GIqjgAY0DN3E`;!bT4~B^I-ZR=K$~Ub1QJQ(fg3Ctu{1vv z9uksX_a;~Mi8OU1F|`AA&Rod0B62rBze+k`M|3BA#|iM$za4Qz(l?-!GPmy3!{!_@ zOGP+C05R`Le4HlbSRf1~FdPUVbY2v}^Ej6vX}u1b*jl|FVtL{>*2`lA5XOe+92)#M zQC5o#ICFZrT+68(X{@@m&&K&ssYn{3Nf%eS@u{B^vch^?HPSaW2?> zel|cUSe2gL?46{}pl_#bV`RHNSPFZ_ZR(NN+P6qgd@))nw~>3v$zJMCtIUdTH|+c7 zLC%ie)45l9dl$F?2RKy?giU^zz%8wEUfcfEJAhh!1^o@+_T1)@vr4=j=tu%%zizJ^ zbv8&z$N+m=xJNZr$FCU*0%{pIow>SOd{Z2-vTIK<9WoTwg_7I(b`!8o%|Xdp7b|S6XlP1EL!e;M8O`-wj|G3 zQO8T|c|+mj_vYtU>xq-T(v`o7k8F^0ALp01yK+|uA>7FXp)}_NNp4u=umPxw}PKv z;_Lf-4RENs@6|yP12b9fl&*=!3h?2m^8!({EKK+?%M6l1fxK+QaeoN|A9|zSdSX}C zJ|g?7K3Mlr5+H5>bYKv=Gk$}()(Md!ld5 znPBCEqAQh<5RP?_33~@34QK)zTgc$K`P7*v8xAM)unMnOBH`a`P+|7O53mB{hp3?M&q5f(D- zPXOtr4%&r*mKA~6@{z-G;ol<`;Tw%8MQF*XW)OjyOGd2&FVopgb4AOLP(`JHBmB$2 zt473bXNWyeYs@G23_0`N_Xc}DhIZz;bPx~j>s4vn>^)e>coqPa8Zt%cd+Uf`?INf% z$JOy!kVULBjhb5UN_4miFenQ}Yu-phPt!OP&9#hs#TfKmXl?!o{mB9QVY0x(Y$bzd z6|X05m|)6!{9qxf_LxdsQKfcXBT+sDV~737`zntF4DEywG8hK2I5(k zUj<{8s(z8;SZ!BKd+(!$J2nYeea>o4Bm1(8`61it{tK94SD0yxkoBY-@K%~EIu1j8 z;Y}|%FO2G$B8ht7V|ufs?+vKwAxDR&fvU86EP;+pZ8}1lV?hf@jrHKGgUexXQAM3~ zQN(PxUSt4b<7C~&FKFy5t+Gm_PCa|Uy|v8-Zo}&!jWKS@k)pM)75KB&q_Fra>SEir zuSgzpl?=G0S5(LIr-c&43}#vQ5afv@-@w*;)HIb44hOLp5~1y^5pvaWDgct`vhdsA zN=NptxP;*DBlmU{AH=D@u#;LGg5EazPn=-UJ4O22FQ6ORTu@b6s&JF{7?Mvc&1dw) zblSRWk3WVDV*bB^J%2sg|ICH_;=aMqw0)ND42L%EL?643fWB-33L9X+5eS&|=Wy13 z0#Vc*W>ZJa(jp1l*N3_D-}>Vmdao1p#xsarZ}nRTR$(C|=D5DJoO^Gr};s(OA?1S!qP!_NY#GW16WY*JWjSk`h_v3xTweG=ta;w zkA5=~yM>_CYnxt$sGt!O3i@<^e?-uikGQoRh4cOv@`M9Y$JnNG$u?@Dr zI#FCCF@Y$YLcpl36y1%0sUy+OT-cGT8PYfbNNanj(xddT1g~s&IpP)r#NG_tBATS< zvl9W_!S#a>`yhpBV@pt$;I52fURoye$|E?as%=1T*OmPC7-aH=N9c!;*)xWZ^5!6M zPb{XnAJgV1!u-h+KMg;=V_5fWH9qfh=*+Lr$N?*eO#=+f(TPYalEAEyvd=pJs3-_h zU=Cn!A|I#Zur))MN`8%Q)ARbvd3klrr~PoP4jg`L>KA2F=&V$CREeD?I|HN@78 zzpP{wd$-krGe0-LLTHa{*XlKXcD-7aL7bFbl4T2?2+UD!$a%DzT$lhAmsGQ-wSyn{ zIeohT-2~y^)CxdoogUyda9+1a5+hsKac!t4X)(d;Ibm%xLsYR*{u?bR-1jGP|KCC3EIox?Ccl^g*&6NWNS|=fNAug^z%jnRk(lTUq3j7;6q+RFALv4Wyj(f_!t9YX5eY3t{RBZ%a?VNrEChk zsgxy$Rpf-2(UZ&4D~LTphfDqZu3l(UQg#w(CI8#DFH1{WQU96-F%T5Ap_#}kuz%9z z9baDBfM;N^V*!PB-i&n#-Bw{f8UjygL^B4isn7D@ra6!_N9|H#nj={SZ*KU-FtRuJ z_-#fUgr1{6fA?gw5sy2998Nc(VmXb$kI`ol{bM-nT!uBD?YRn3cnf(;P$?V;)$o-DfN~2tqZsI z9i$?K2qrAsN^=FtwJr}Nj;vezh8@jnNk6OJkBbK#S~!0@J|ha(+3TTWybYu{yY#pX|ACQphXq z$r~3E?PNc?W=5L2dMBE8v>VWwLD2fP;}0ukcOU2R&Lu@}pp}ELO_YDXC_vBZIOlG!+M@p{QVQvkj=b@!KRh5IX&nU>FeN%VpJ{uIr&`mZ-I3hFv$y`Ic2%uldODh z|BL|HqS$+#4WyvF$7P9&|14^VoKUf{AakcKj6`xm@bPt)CjFdU%}YCozBJf^ar?)u z()lUu#9(!`mJ;2Z7Vhw#3f!D8)7N0{>)`x+&XS*MOZ}&v?JVYop!0fbHQ@`gr{c?b zi+th_j7!4g=!Tmev4HN1D<``yNuF{FsjE_SW%{ofX6&6h|I0_y(_+YL>1u=*x(0QLRcjh zxcd#T;#8C7POY#yWJo)yj3dQFiLiAUKUx0L{>ePS_d!v_Kj}URiloV9uyhC4t5EgZr zz0`ksRl+FCER+xlGMVHWcaUW*wf!JB8O}l~3f!?~EW^48CG!Rj3p}Lo0{8Z7|J1p) z?wb&}x{f_F#N{x>im8Z=Euox#YDAMXej>n^p)!uBN|n2wVOzg;$9oblXuwoyVcj4` z@wKsgN1w6C->iaX&Wmz;B=xnHjKaeH;nE+R_$Z5wwO8(s!u5QWPn#kV)5MdJ9k$57OP?-i2bn zPh_WkjOW?Z921~UN)`De6I%%~Sdj$h%~mmGE;+42j>h{|rR#L4m0#>sT3TZ_TI&a( z%p83-RoRdk%!Phn(Uf}k;xk_tA*0I@hdnp)H;KkB@8eqKKEJxXe;I{cl%ST761|)! zdC2s!Iw~vw9kKr>NB1Xn#>Ltgp>Et^o81UcPIN`AtDJ6eKX|A@1mH73Vw!hF(`wWp zR={Tgwbd?jGPeVnwll~^9SM@WX%BL83V%Ip?_7IXO1 zZ}knFxa6%yKlmfM`L^iS{eMQO{==NVy&GhGX;zMGNFiV-Rze4i@5V09Ar)mBz!@+j1hXm8 za3Dj3Tv@JaZvI1A-<~j0h5G*)j9D@=DFB`amv+RhQ?rLoi%HfQmm60Y<6JRfpbA`f zAeqbu4V}5xw*ABOR!M=jsIDks2k1c{J*vi~HF@`{=7-glw^5Io5774QHmcd`00a#a z$zTN2|AA9ZyHH#NNYGv~iB&r!sJ7nWjcU#63~+}4JRo$xQds@fk=a4|8`jlnK(*yR ztb)&W;R1l^xYRW+{mu`IiZRVk9&Pbf6m5nC#Y@g}sk86`9qIeuTG6EJT6 zBrK6YB}NYugA*LtjA9^9sA}uDab?_B97%Sju;||U6^djbR{|tT!K`?Yxe2E{@6n)| z;b@D!O|bcu*IeOLG}A!!^VH*u;2|YoKU|Sr&NgDpuWgnX(o1~Fz4%KUFkRqOL#Adv ztDR(j1>K%*qziri*l(=vT#9CAM<-?VdGQBP8qw>A zajsff`Pmp3@OY#3FC&sr34g>NDa_v`g(igpV#RJyjqZWI0pRD#Tjdr0NVpYSZAv9z zW)4z*c9Zn7bg=7J`#UJlY{MhH$|X<+`&UravN<|3?kBhJhDr^7xhc7BiOS$6;LNFK z^I4ye&oAmbZHCu|d$)^4n^Q|P$pIDeX$aitciLau*mgT8_XOwVJqA_v?GO-iet78# zmMTeFNBHi>{?9YNDf~!O-x;NgMZwfJE{%;cgVX!lz5#K^G9biGDqm;Gz}JU|M)?F}`We`1RN+b$-r?Hxyrfpr!{*W&HmISlPkaM6u!aqP6aPxX zrIB3ofQqx$&~V%Cvva`u##UFP{#s>RKJXANV4V%k;Rk zy1-60;eECWGk^MsOiU_{`r@alH}eET8G*!hQqz>FP@1k;zOA1lK6%ZFUzTM$$Xkw8 zeS7O~q8+aM>XL))-##|E)d;~g-69vYPV^y{=b6$B56CA}zbK%O@5=gO1iJ%aI@k=f zhiep%E}12CF>FCNY0M9$OBLFZhI#l^)5Dp#NptMjhh?W~272rdsV|`IL%X^p7*ESg zyl5oG6G3qtnp}%8y%`aby!y8xx1tASN7xhlBl#%2B3hHSma$bUCW5vxs#G`nm0F^3 z1U`CvA2XX|0zAc6?(6g}GmZd${{4)*DjmGNvbD8-{=Miar%)+FS9J5<$3JQ-vbgW$ z)K=6fCn4%3FQl_VWRvGXufDM`;B7h9Fo?Rb37F-+OX9*Yf9Ag=z~D7Y3mu;Jcfo?c zq&Jr>e_&l}LJuo`X_HOxj%N?ts~v=lh8cc~Gkm4r)ERwm(j5A}7W%82yk?#{EJ|T% zIIBxNT&%jQhLmO0!aFKUN|@@o!rcn>heq;?Z2%*}z^Q>}sR1@5`|nQos<0PwU4KBjP)e%H0uOVy{oO^`HECvp`fe4 zu~sOPgE^uoV?A+fxhGXBpaiFNZ)C-PYU$=Q0Nm>YguQ7w(9TEfv`UY;(L6~2f0M}kM?Z`CYdlKDtUub_gEamkSbiOD{j!K-XR;K5w*gP% zHzDs(e|`Jo88y9Dbce)o&8BX8c$tk>v{B()g~49+%UG;hMHqMenXeH;y8VXFYE3kTfCZOKf?*)Bd@+W=%Gma(8R@^>wWo z0qCUxOf}Sd@>XTfk=Jw6y~;FNu)|F<3+HC{7v*T9P!oY3RQWy?(p0rNM$c>z^|6?W zuseEJA4RByH0`D%RC} zs<7mwOR7YdJ1jWOv#I_xl^-xq zN=y}9AbBfeHX%nX{-$5er&7Rn$!4|%&F@-gXz_82+ueP-kTYxA{Yiqr9qrierJq!2 z$(+z{FN9MZJKs??V!Uc5y}ymes@9#4Py8lL;e&3!58wyZ)LAFD&y7+#tYSg~RhdA_ zUf^@d0yK-XyM2JERo2UB=L9-pij>FhUi6sog3!^RKT30IZ}g6|W!4uCCDtUR122$0 z!(D!Oikp$crGz4)L6vI?{UysT%ZCl2)^3_RI69}(8^7cCCd9UX(FH41aUz!pOl6zB z96qu0dmf%!Fc2{g8a3k9f6{f<`qDQ0cPC*{=%|9w45CTD0s=I9FPGVd8(KBdw^iqt zy8+(`+DQ9HraaN~0e(Oyg|YuoRQqUjmhPiXSoyu+x+`3(?&ivXU8iBNV36XuJz3Ov z72M68e@o$aolSkx^AgaWBkW8OmX9Ql=c~YCsN!;o)?@~&3g{G0Z+c;p( z(FXVYoOQXTelq!SdAvtXpItXRrq9}vXwfuecq;Jv%eSQaPu43djc2`Yeg2gmf z=}BZt$ZDCr*AYTE({`UJVF8QJT=F*o>5IW|2exYtjX8OkxS zO7hNlSQ9#^D4jP$4UIw>GA1;R0wu|Hxb%kOn1tHu;PvMwI-kfbB%|F~ko0CX>5LvS z0=|u>4@>pD5EmK&Y8egtmq-lQ z+npyE9L{pYm%150Wk!XY%Cu#p7VnHi`MX=Wt$x7s-=Vec26wpXNV)uXSVurh#;N?S zo%BF+w|l5|rjPVsQ(aRx(v~H>OH@3l^TJ7{ccjWNAjT-XLoW!`4bo6y-^9H#hb7u* zf+aL#0$ILLe%Lqd_=&ANt@y*0IkGb@;vbODmAV(#^PbS4@{JQeQ|QfGVhQ~r>AF%P z-aA&AAdGJVmW}M0a{ooL5PS!f*yy zrCjKd(JUujN1qcDG&+W^Dl;Ia99P;65<{r!<=1_zMdU`t5v044&rwq>6e_puM1tN= zA1WC<5u3CsaS@%lmvkPZ_EA#qLx$JR;r(&Gs7rD9OY612+q6dt1Aq4yz^(Hl!zc@v zX!vL?&TdreHJAf8{%`T!D+;zlc$keUzEP>xndKpcmcP1?m9v2EN3&~ul|`2?+P;S4 zUG9cfs9hS^DXR;Xg1KanM6(5OtG(Z&nP-?kP}$Y(pR=n(>v>bz-Y#`8I=r|c;m<2g zJ$1`5fS6fpJVYh4-`q&@*TBi$b4P)S@2?s4Oy||S=7jMVwK}pX*0Oq=1zkAXYYfDH$Kokk zdP!7MG7<`q9_HO<#~Og`41yxN+5|E94W{1bI8rou8<$5K+!ZW@-E&2yf{2$i%uOP( z52`=n+;e$wD$b+)_AZVEUgSceLYe|B`q-gF=ugU)0A4CGpaTD6dU#rM8~C80jH#3T zrS946`0YrY+~+VSgKT$$1Z+uH&Rc5~&vEwU7@6it6_;;61zdnpqS_zvhUP1{H};`9 zQd@<}Ggux@x7)KNido*j6qUzo%VqlvAM$lFyY_}cHN%tJc!uSlE9r~;q7GLZbmWSJ ze4*aHr8}(#!}}nc9Sb|x1_^(e@DbO3UHAm zLj!By@-s`AydUV2YQUI^r=$58V`hXgU1G&`)Jf)7TwcKbq&g$72Mq(7_jzMu+`nNP$B*$awI|BD$ zo37R;nyOgJjUPTeUXHoosx6RY*}ks#O&s`xJmJv8V{N&xth)cOgUMnXNec(=th*Ir zLnRMsHdik+cLte)pO%x?^Wc-|RjjbDr+y-4ctHYtVEtlpH!Vc;dcGiy zqA8#(M=sh6-D-uvC$uT+YXKEs<7!Y*j!^WPZx9HATsjW?mc^mz2;VCj!`g$$( zD=^wn3|5CU-9etS`1O#IjqkR+sSdi;ECzf$1#xuB8K!xuQuPD?dH!E~-j=l0-sWTM z9bHCe3}Sv%N!TFptsz=K;lZS#PdBs4O3nyC%xf0w;2{Z2z};hD9={`l78b#e5lq=r zBnLZO$NeJD^#PV5a#bV|EH{Qp9q~f>p~0RTZmUp~(6h5jen2P-6@05mDhndO2gv!2 zy1_5IFdp`q!~{Od*3Ir3D!Qlemr+_nRzc*eQ3$jx|B-8OsLlkPdJkx|`0`69;(FVL zrBnL<9)$|SR(dJG_+&0|>&)@XuN1VA1y_g|COZ5Z6cUqE``fAaJ|KP73I)G>$+sZj zl6`k{kF)q0<~*>ZxUvp|b)@stt&#r7ei9+@lf5E8$nb1tU+R+19Q5snDqLI5n)cAeHTS}uB7ntj!Ps?;UQ#>No|ACvU_>umJ z&57a=GE8!x16(N_*{at|6as3?{7$E+E~aNyd%5JmtiU?{A66-BP#^dV;qT2OP;=%# z#oLgIUT}5ZQ+;f%MU(A9TWKvVQA#Q*hdXDUD9N2RStp?Dk7Wg<@DEp9X>)4X((J}= z6p-&%@sq@hZnL<=Rhf07R(%1E(+<0|MZ;y3v%the9A{E*fJ@%6eViuvefM5;u>$;v zemjPLUO55jxQy38OYYbOvPsTP1SlmG{vxcn$8iq2jzv$L0w8!F z4nzSm3OW;_(_0f(%2JI>jx zcOll@ye|$Ze1_B)M0e^m6%xAYi~GFJbXq#@7FT@3n; zQ^FeK=W+J5#koDK>UxO>tMt=C2W7;`Mt^tArU4Ows%KOmzwCV*cM~C(*W1st!F6eb zAWawEQigY^7`wM{`M&VGHceG<%egg*qH?r^n;@H6_6C;hTZ6WTK8|Dn9q=sRB4*V0FV zjyLrJiHv98*{ZA~5fsV@=O&pA-Efy=tR%E>W`KF6(3So}q~ymwp=q(O63m=lT|yx~ zi#iY+s-XvBh~{s?+xs_DO7ojZUc|eyVlvE^jG2cg@;}<#5UuQO6@9B*kIPrxOZ~!Z zz>b2mFQm=VcPm^OqO*`re2Q66<;hPe4sP1fDM`?s7YDm;c_IKOH9?hL2{i!LtsePkf8)6whUgA$5z; zuM4ocAb*71RQ^rk{tnhwWB-8NGwfk8$nrfwf6tepaW2T~rS-VFF$;kS__xKm8iMb3 z>j*z<#xLxzJi9eo%{?EklQunyK2eGPkRvm4!+bVuT1S;R1Iw zKoSp`ylP^n!7(ja;{%2xQ90_}eXM7vU}3vN4lLDS%rFN1j(} zAubLmUohJ>D42~-ID7D_x<$^`%W0zz*>fBYP6Fx)ja1-WA&64IGdU_0r?`nN5{a%M zEKxzaytL$3tOKpcXS7Q=ercm%^)iNBO`Cuvu`cR=1F^12bM0xUJS=WCsaJ<8Iz~#; zec+lf)f2aR#%OMuzWti$kOw5iif4FgsaG<~AiE{8|7T3>J4w;vlUFYIwQarSK9d+Zm21IvE+o@gx(dVy~RJW8X0UZ zn^235qG?Ira^NULZ?uIo{tE?nHj-b6S<-awPq{_-(FE5V;g#&D{3_ilcl>QzIF7Zb zbr^FeOGuBMQU}Ms!fzkI41ILDZ`wpEpKY#cI&U`+hYg=z&4VHg*ZC$Vxr~Vy8QF=v zqsy{s<*`TLHOAy3%dDO>^UrD~=}MHzUcYy8F(Bvm?Z~qvk2If<9*&e6|7|J^sbv3| zm-aee{BWZ(B`4te{RhBpY84c*NN=^oAmhqqq8>O5!CT~kN>uFqmBByhI`LtRb@&bhW`H#namke literal 0 HcmV?d00001 From 1da36b96ac5bd86c73fef34e78e34438ebd5e204 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Thu, 13 Jun 2024 08:44:41 +0200 Subject: [PATCH 12/35] refs #452. New docu --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2d8d104..f82faca 100644 --- a/README.md +++ b/README.md @@ -108,18 +108,18 @@ docker exec ogcore-php php bin/console doctrine:database:create ## Migraciones de datos -Para poder cargar los datos de las migraciones, previamente necesitamos poder tener un esquema de base de datos con un dump de OpenGnsys. Es decir: +Para poder migrar los datos desde la base de datos "antigua", previamente necesitamos poder tener un esquema de base de datos con un dump de OpenGnsys. Es decir: - Creamos una base de datos temporal simulando una insancia de OpenGnsys 1.1. La solicitaremos al equipo de desarrollo de las universidades - - Necesitaremos un dump de la base de datos de OpenGnsys 1.1 + - Necesitaremos un dump de la base de datos de OpenGnsys 1.1. Mediante doctrine, creamos la base de datos temporal: ```sh docker exec ogcore-php php bin/console doctrine:database:create --connection=og_1 - ``` ![img.png](swagger-assets/img_bbdd.png) + Aqui podemos ver como tenemos las 2 bases de datos. OgCore es la actual, donde estamos desarrollando, y ogcore_old_og es la base de datos temporal que acabamos de crear. Aqui vendria el paso de cargar el dump en dicha base de datos, ya que contiene informacion sensible, no se aloja en el repositorio, por eso tendremos que solicitarla al equipo correspondiente. From 6be6e67797b1175d1581436169a0476f9e41eb31 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Thu, 13 Jun 2024 10:59:19 +0200 Subject: [PATCH 13/35] refs #425. Client and ORganizationalUnit classroom validation --- README.md | 1 + src/Dto/Input/ClientInput.php | 1 + .../OrganizationalUnitClassroomInput.php | 6 ++++ ...anizationalUnitClassroomMulticastModes.php | 29 +++++++++++++++++ .../OrganizationalUnitClassroomP2pModes.php | 31 +++++++++++++++++++ ...ganizationalUnitClassroomMulticastMode.php | 27 ++++++++++++++++ ...nalUnitClassroomMulticastModeValidator.php | 23 ++++++++++++++ ...ganizationalUnitClassroomMulticastPort.php | 21 +++++++++++++ ...nalUnitClassroomMulticastPortValidator.php | 26 ++++++++++++++++ .../OrganizationalUnitClassroomP2pMode.php | 27 ++++++++++++++++ ...izationalUnitClassroomP2pModeValidator.php | 22 +++++++++++++ 11 files changed, 214 insertions(+) create mode 100644 src/Model/OrganizationalUnitClassroomMulticastModes.php create mode 100644 src/Model/OrganizationalUnitClassroomP2pModes.php create mode 100644 src/Validator/Constraints/OrganizationalUnitClassroomMulticastMode.php create mode 100644 src/Validator/Constraints/OrganizationalUnitClassroomMulticastModeValidator.php create mode 100644 src/Validator/Constraints/OrganizationalUnitClassroomMulticastPort.php create mode 100644 src/Validator/Constraints/OrganizationalUnitClassroomMulticastPortValidator.php create mode 100644 src/Validator/Constraints/OrganizationalUnitClassroomP2pMode.php create mode 100644 src/Validator/Constraints/OrganizationalUnitClassroomP2pModeValidator.php diff --git a/README.md b/README.md index f82faca..c74951d 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,7 @@ docker exec ogcore-php php bin/console doctrine:database:create ## Migraciones de datos Para poder migrar los datos desde la base de datos "antigua", previamente necesitamos poder tener un esquema de base de datos con un dump de OpenGnsys. Es decir: + - Creamos una base de datos temporal simulando una insancia de OpenGnsys 1.1. La solicitaremos al equipo de desarrollo de las universidades - Necesitaremos un dump de la base de datos de OpenGnsys 1.1. diff --git a/src/Dto/Input/ClientInput.php b/src/Dto/Input/ClientInput.php index 8c39d2d..06938d6 100644 --- a/src/Dto/Input/ClientInput.php +++ b/src/Dto/Input/ClientInput.php @@ -33,6 +33,7 @@ final class ClientInput public ?string $mac = null; #[Groups(['client:write'])] + #[Assert\Ip] #[ApiProperty(description: 'The IP address of the client', example: "127.0.0.1")] public ?string $ip = null; diff --git a/src/Dto/Input/OrganizationalUnitClassroomInput.php b/src/Dto/Input/OrganizationalUnitClassroomInput.php index dad97b7..4260bee 100644 --- a/src/Dto/Input/OrganizationalUnitClassroomInput.php +++ b/src/Dto/Input/OrganizationalUnitClassroomInput.php @@ -6,6 +6,9 @@ use App\Dto\Output\OrganizationalUnitOutput; use App\Entity\NetworkSettings; use App\Entity\OrganizationalUnit; use App\Model\OrganizationalUnitTypes; +use App\Validator\Constraints\OrganizationalUnitClassroomMulticastMode; +use App\Validator\Constraints\OrganizationalUnitClassroomMulticastPort; +use App\Validator\Constraints\OrganizationalUnitClassroomP2pMode; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; @@ -40,6 +43,7 @@ final class OrganizationalUnitClassroomInput extends OrganizationalUnitInput public ?string $ntp = null; #[Groups(['organizational-unit:write'])] + #[OrganizationalUnitClassroomP2pMode] public ?string $p2pMode = null; #[Groups(['organizational-unit:write'])] @@ -53,9 +57,11 @@ final class OrganizationalUnitClassroomInput extends OrganizationalUnitInput public ?int $mcastSpeed = null; #[Groups(['organizational-unit:write'])] + #[OrganizationalUnitClassroomMulticastPort] public ?int $mcastPort = null; #[Groups(['organizational-unit:write'])] + #[OrganizationalUnitClassroomMulticastMode] public ?string $mcastMode = null; public function __construct(?OrganizationalUnit $organizationalUnit = null) diff --git a/src/Model/OrganizationalUnitClassroomMulticastModes.php b/src/Model/OrganizationalUnitClassroomMulticastModes.php new file mode 100644 index 0000000..299a4c6 --- /dev/null +++ b/src/Model/OrganizationalUnitClassroomMulticastModes.php @@ -0,0 +1,29 @@ + 'Half Duplex', + self::FULL_DUPLEX => 'Full Duplex', + ]; + + public static function getMcastModeNames(): array + { + return self::MCAST_MODES; + } + + public static function getMcastType(string $mcastMode): ?string + { + return self::MCAST_MODES[$mcastMode] ?? null; + } + + public static function getMcastModes(): array + { + return array_keys(self::MCAST_MODES); + } +} \ No newline at end of file diff --git a/src/Model/OrganizationalUnitClassroomP2pModes.php b/src/Model/OrganizationalUnitClassroomP2pModes.php new file mode 100644 index 0000000..5ee1581 --- /dev/null +++ b/src/Model/OrganizationalUnitClassroomP2pModes.php @@ -0,0 +1,31 @@ + 'El cliente no comparte mientras descarga la imagen', + self::P2P_MODE_PEER => 'El cliente, mientras descarga la imagen, comparte los datos que ya tenga descargados', + self::P2P_MODE_SEEDER => 'Modo de trabajo en modo distribuido', + ]; + + public static function getP2pModeNames(): array + { + return self::P2P_MODE_NAMES; + } + + public static function getP2pModeName(string $p2pMode): ?string + { + return self::P2P_MODE_NAMES[$p2pMode] ?? null; + } + + public static function getP2pModes(): array + { + return array_keys(self::P2P_MODE_NAMES); + } +} \ No newline at end of file diff --git a/src/Validator/Constraints/OrganizationalUnitClassroomMulticastMode.php b/src/Validator/Constraints/OrganizationalUnitClassroomMulticastMode.php new file mode 100644 index 0000000..9ce375a --- /dev/null +++ b/src/Validator/Constraints/OrganizationalUnitClassroomMulticastMode.php @@ -0,0 +1,27 @@ +modes = OrganizationalUnitClassroomMulticastModes::getMcastModes(); + $this->message = sprintf( + 'The multicast mode is not valid. Please use one of the following: %s', + implode(', ', $this->modes) + ); + } + + +} \ No newline at end of file diff --git a/src/Validator/Constraints/OrganizationalUnitClassroomMulticastModeValidator.php b/src/Validator/Constraints/OrganizationalUnitClassroomMulticastModeValidator.php new file mode 100644 index 0000000..ad1b68e --- /dev/null +++ b/src/Validator/Constraints/OrganizationalUnitClassroomMulticastModeValidator.php @@ -0,0 +1,23 @@ +context->buildViolation($constraint->message)->addViolation(); + } + } +} \ No newline at end of file diff --git a/src/Validator/Constraints/OrganizationalUnitClassroomMulticastPort.php b/src/Validator/Constraints/OrganizationalUnitClassroomMulticastPort.php new file mode 100644 index 0000000..9d18892 --- /dev/null +++ b/src/Validator/Constraints/OrganizationalUnitClassroomMulticastPort.php @@ -0,0 +1,21 @@ +message = 'The multicast port is not valid. Please use a number between 9000 and 9050'; + } + + +} \ No newline at end of file diff --git a/src/Validator/Constraints/OrganizationalUnitClassroomMulticastPortValidator.php b/src/Validator/Constraints/OrganizationalUnitClassroomMulticastPortValidator.php new file mode 100644 index 0000000..ef181c5 --- /dev/null +++ b/src/Validator/Constraints/OrganizationalUnitClassroomMulticastPortValidator.php @@ -0,0 +1,26 @@ +context->buildViolation($constraint->message)->addViolation(); + return; + } + } +} \ No newline at end of file diff --git a/src/Validator/Constraints/OrganizationalUnitClassroomP2pMode.php b/src/Validator/Constraints/OrganizationalUnitClassroomP2pMode.php new file mode 100644 index 0000000..c53c275 --- /dev/null +++ b/src/Validator/Constraints/OrganizationalUnitClassroomP2pMode.php @@ -0,0 +1,27 @@ +modes = OrganizationalUnitClassroomP2pModes::getP2pModes(); + $this->message = sprintf( + 'The p2p mode is not valid. Please use one of the following: %s', + implode(', ', $this->modes) + ); + } + + +} \ No newline at end of file diff --git a/src/Validator/Constraints/OrganizationalUnitClassroomP2pModeValidator.php b/src/Validator/Constraints/OrganizationalUnitClassroomP2pModeValidator.php new file mode 100644 index 0000000..2f627b6 --- /dev/null +++ b/src/Validator/Constraints/OrganizationalUnitClassroomP2pModeValidator.php @@ -0,0 +1,22 @@ +context->buildViolation($constraint->message)->addViolation(); + } + } +} \ No newline at end of file From 58d075ee46b9639b042e27dac210e1a1a8d7aa8d Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Thu, 13 Jun 2024 15:15:01 +0200 Subject: [PATCH 14/35] refs #423. New table and Endpoint Menu --- config/api_platform/Menu.yaml | 30 +++++ config/api_platform/User.yaml | 1 - config/services.yaml | 5 + migrations/Version20240613090444.php | 43 +++++++ src/Dto/Input/ClientInput.php | 8 ++ src/Dto/Input/MenuInput.php | 69 +++++++++++ src/Dto/Output/ClientOutput.php | 14 ++- src/Dto/Output/HardwareProfileOutput.php | 8 +- src/Dto/Output/MenuOutput.php | 50 ++++++++ src/Dto/Output/NetworkSettingsOutput.php | 8 +- src/Dto/Output/OrganizationalUnitOutput.php | 1 - src/Entity/Client.php | 15 +++ src/Entity/Menu.php | 131 ++++++++++++++++++++ src/Repository/MenuRepository.php | 18 +++ src/State/Processor/MenuProcessor.php | 71 +++++++++++ src/State/Provider/MenuProvider.php | 75 +++++++++++ 16 files changed, 533 insertions(+), 14 deletions(-) create mode 100644 config/api_platform/Menu.yaml create mode 100644 migrations/Version20240613090444.php create mode 100644 src/Dto/Input/MenuInput.php create mode 100644 src/Dto/Output/MenuOutput.php create mode 100644 src/Entity/Menu.php create mode 100644 src/Repository/MenuRepository.php create mode 100644 src/State/Processor/MenuProcessor.php create mode 100644 src/State/Provider/MenuProvider.php diff --git a/config/api_platform/Menu.yaml b/config/api_platform/Menu.yaml new file mode 100644 index 0000000..1fac788 --- /dev/null +++ b/config/api_platform/Menu.yaml @@ -0,0 +1,30 @@ +resources: + App\Entity\Menu: + processor: App\State\Processor\MenuProcessor + input: App\Dto\Input\MenuInput + output: App\Dto\Output\MenuOutput + normalization_context: + groups: ['default', 'menu:read'] + denormalization_context: + groups: ['menu:write'] + operations: + ApiPlatform\Metadata\GetCollection: + provider: App\State\Provider\MenuProvider + filters: + - 'api_platform.filter.menu.order' + - 'api_platform.filter.menu.search' + ApiPlatform\Metadata\Get: + provider: App\State\Provider\MenuProvider + ApiPlatform\Metadata\Put: + provider: App\State\Provider\MenuProvider + ApiPlatform\Metadata\Patch: + provider: App\State\Provider\MenuProvider + ApiPlatform\Metadata\Post: ~ + ApiPlatform\Metadata\Delete: ~ + +properties: + App\Entity\Menu: + id: + identifier: false + uuid: + identifier: true \ No newline at end of file diff --git a/config/api_platform/User.yaml b/config/api_platform/User.yaml index 8f58ad6..427c416 100644 --- a/config/api_platform/User.yaml +++ b/config/api_platform/User.yaml @@ -1,6 +1,5 @@ resources: App\Entity\User: - security: 'is_granted("ROLE_SUPER_ADMIN")' input: App\Dto\Input\UserInput output: App\Dto\Output\UserOutput processor: App\State\Processor\UserProcessor diff --git a/config/services.yaml b/config/services.yaml index 124187d..3e2e835 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -51,6 +51,11 @@ services: $itemProvider: '@api_platform.doctrine.orm.state.item_provider' App\State\Provider\HardwareProfileProvider: + bind: + $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' + $itemProvider: '@api_platform.doctrine.orm.state.item_provider' + + App\State\Provider\MenuProvider: bind: $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' $itemProvider: '@api_platform.doctrine.orm.state.item_provider' \ No newline at end of file diff --git a/migrations/Version20240613090444.php b/migrations/Version20240613090444.php new file mode 100644 index 0000000..45413e4 --- /dev/null +++ b/migrations/Version20240613090444.php @@ -0,0 +1,43 @@ +addSql('CREATE TABLE menu (id INT AUTO_INCREMENT 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, title VARCHAR(255) NOT NULL, resolution VARCHAR(255) NOT NULL, comments VARCHAR(255) DEFAULT NULL, public_url VARCHAR(255) DEFAULT NULL, private_url VARCHAR(255) DEFAULT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_7D053A93D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE client ADD menu_id INT DEFAULT NULL, CHANGE name name VARCHAR(255) NOT NULL'); + $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455CCD7E912 FOREIGN KEY (menu_id) REFERENCES menu (id)'); + $this->addSql('CREATE INDEX IDX_C7440455CCD7E912 ON client (menu_id)'); + $this->addSql('ALTER TABLE hardware CHANGE name name VARCHAR(255) NOT NULL'); + $this->addSql('ALTER TABLE organizational_unit CHANGE name name VARCHAR(255) NOT NULL'); + $this->addSql('ALTER TABLE user_group CHANGE name name VARCHAR(255) NOT 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('DROP TABLE menu'); + $this->addSql('ALTER TABLE hardware CHANGE name name VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE user_group CHANGE name name VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE organizational_unit CHANGE name name VARCHAR(255) DEFAULT NULL'); + $this->addSql('DROP INDEX IDX_C7440455CCD7E912 ON client'); + $this->addSql('ALTER TABLE client DROP menu_id, CHANGE name name VARCHAR(255) DEFAULT NULL'); + } +} diff --git a/src/Dto/Input/ClientInput.php b/src/Dto/Input/ClientInput.php index 06938d6..366aa43 100644 --- a/src/Dto/Input/ClientInput.php +++ b/src/Dto/Input/ClientInput.php @@ -4,6 +4,7 @@ namespace App\Dto\Input; use ApiPlatform\Metadata\ApiProperty; use App\Dto\Output\HardwareProfileOutput; +use App\Dto\Output\MenuOutput; use App\Dto\Output\OrganizationalUnitOutput; use App\Entity\Client; use Symfony\Component\Serializer\Annotation\Groups; @@ -50,6 +51,11 @@ final class ClientInput #[ApiProperty(description: 'The hardware profile of the client')] public ?HardwareProfileOutput $hardwareProfile = null; + #[Assert\NotNull] + #[Groups(['client:write'])] + #[ApiProperty(description: 'The menu of the client')] + public ?MenuOutput $menu = null; + public function __construct(?Client $client = null) { if (!$client) { @@ -61,6 +67,7 @@ final class ClientInput $this->netiface = $client->getNetiface(); $this->organizationalUnit = new OrganizationalUnitOutput($client->getOrganizationalUnit()); $this->hardwareProfile = new HardwareProfileOutput($client->getHardwareProfile()); + $this->menu = new MenuOutput($client->getMenu()); $this->netDriver = $client->getNetDriver(); $this->mac = $client->getMac(); $this->ip = $client->getIp(); @@ -78,6 +85,7 @@ final class ClientInput $client->setNetiface($this->netiface); $client->setOrganizationalUnit($this->organizationalUnit->getEntity()); $client->setHardwareProfile($this->hardwareProfile->getEntity()); + $client->setMenu($this->menu->getEntity()); $client->setNetDriver($this->netDriver); $client->setMac($this->mac); $client->setIp($this->ip); diff --git a/src/Dto/Input/MenuInput.php b/src/Dto/Input/MenuInput.php new file mode 100644 index 0000000..03631ee --- /dev/null +++ b/src/Dto/Input/MenuInput.php @@ -0,0 +1,69 @@ +name = $menu->getName(); + $this->title = $menu->getTitle(); + $this->comments = $menu->getComments(); + $this->resolution = $menu->getResolution(); + $this->publicUrl = $menu->getPublicUrl(); + $this->privateUrl = $menu->getPrivateUrl(); + } + + public function createOrUpdateEntity(?Menu $menu = null): Menu + { + if (!$menu) { + $menu = new Menu(); + } + + $menu->setName($this->name); + $menu->setTitle($this->title); + $menu->setComments($this->comments); + $menu->setResolution($this->resolution); + $menu->setPublicUrl($this->publicUrl); + $menu->setPrivateUrl($this->privateUrl); + + return $menu; + } +} \ No newline at end of file diff --git a/src/Dto/Output/ClientOutput.php b/src/Dto/Output/ClientOutput.php index 6961c0b..34c5b3c 100644 --- a/src/Dto/Output/ClientOutput.php +++ b/src/Dto/Output/ClientOutput.php @@ -25,10 +25,13 @@ final class ClientOutput extends AbstractOutput public ?HardwareProfileOutput $hardwareProfile = null; #[Groups(['client:read'])] - public \DateTime $createAt; + public ?MenuOutput $menu = null; #[Groups(['client:read'])] - public ?string $createBy = null; + public \DateTime $createdAt; + + #[Groups(['client:read'])] + public ?string $createdBy = null; public function __construct(Client $client) { @@ -43,7 +46,10 @@ final class ClientOutput extends AbstractOutput if($client->getHardwareProfile()) { $this->hardwareProfile = new HardwareProfileOutput($client->getHardwareProfile()); } - $this->createAt = $client->getCreatedAt(); - $this->createBy = $client->getCreatedBy(); + if($client->getMenu()) { + $this->menu = new MenuOutput($client->getMenu()); + } + $this->createdAt = $client->getCreatedAt(); + $this->createdBy = $client->getCreatedBy(); } } \ No newline at end of file diff --git a/src/Dto/Output/HardwareProfileOutput.php b/src/Dto/Output/HardwareProfileOutput.php index ed2315d..66a91ce 100644 --- a/src/Dto/Output/HardwareProfileOutput.php +++ b/src/Dto/Output/HardwareProfileOutput.php @@ -19,10 +19,10 @@ final class HardwareProfileOutput extends AbstractOutput public ?OrganizationalUnitOutput $organizationalUnit = null; #[Groups(['hardware-profile:read'])] - public \DateTime $createAt; + public \DateTime $createdAt; #[Groups(['hardware-profile:read'])] - public ?string $createBy = null; + public ?string $createdBy = null; public function __construct(HardwareProfile $hardwareProfile) { @@ -33,7 +33,7 @@ final class HardwareProfileOutput extends AbstractOutput if($hardwareProfile->getOrganizationalUnit()) { $this->organizationalUnit = new OrganizationalUnitOutput($hardwareProfile->getOrganizationalUnit()); } - $this->createAt = $hardwareProfile->getCreatedAt(); - $this->createBy = $hardwareProfile->getCreatedBy(); + $this->createdAt = $hardwareProfile->getCreatedAt(); + $this->createdBy = $hardwareProfile->getCreatedBy(); } } \ No newline at end of file diff --git a/src/Dto/Output/MenuOutput.php b/src/Dto/Output/MenuOutput.php new file mode 100644 index 0000000..0c55133 --- /dev/null +++ b/src/Dto/Output/MenuOutput.php @@ -0,0 +1,50 @@ +name = $menu->getName(); + $this->title = $menu->getTitle(); + $this->resolution = $menu->getResolution(); + $this->comments = $menu->getComments(); + $this->publicUrl = $menu->getPublicUrl(); + $this->privateUrl = $menu->getPrivateUrl(); + $this->createdAt = $menu->getCreatedAt(); + $this->createdBy = $menu->getCreatedBy(); + } +} \ No newline at end of file diff --git a/src/Dto/Output/NetworkSettingsOutput.php b/src/Dto/Output/NetworkSettingsOutput.php index 082d26b..b1148b9 100644 --- a/src/Dto/Output/NetworkSettingsOutput.php +++ b/src/Dto/Output/NetworkSettingsOutput.php @@ -41,10 +41,10 @@ final class NetworkSettingsOutput public ?string $mcastMode = null; #[Groups(['organizational-unit:read'])] - public \DateTime $createAt; + public \DateTime $createdAt; #[Groups(['organizational-unit:read'])] - public ?string $createBy = null; + public ?string $createdBy = null; public function __construct(NetworkSettings $networkSettings) { @@ -59,7 +59,7 @@ final class NetworkSettingsOutput $this->mcastSpeed = $networkSettings->getMcastSpeed(); $this->mcastPort = $networkSettings->getMcastPort(); $this->mcastMode = $networkSettings->getMcastMode(); - $this->createAt = $networkSettings->getCreatedAt(); - $this->createBy = $networkSettings->getCreatedBy(); + $this->createdAt = $networkSettings->getCreatedAt(); + $this->createdBy = $networkSettings->getCreatedBy(); } } \ No newline at end of file diff --git a/src/Dto/Output/OrganizationalUnitOutput.php b/src/Dto/Output/OrganizationalUnitOutput.php index bb0ee2c..3499bdf 100644 --- a/src/Dto/Output/OrganizationalUnitOutput.php +++ b/src/Dto/Output/OrganizationalUnitOutput.php @@ -36,7 +36,6 @@ final class OrganizationalUnitOutput extends AbstractOutput #[Groups(['organizational-unit:read'])] public ?string $createdBy = null; - public function __construct(OrganizationalUnit $organizationalUnit) { parent::__construct($organizationalUnit); diff --git a/src/Entity/Client.php b/src/Entity/Client.php index 6aba709..f632a8f 100644 --- a/src/Entity/Client.php +++ b/src/Entity/Client.php @@ -34,6 +34,9 @@ class Client extends AbstractEntity #[ORM\ManyToOne(inversedBy: 'clients')] private ?HardwareProfile $hardwareProfile = null; + #[ORM\ManyToOne(inversedBy: 'clients')] + private ?Menu $menu = null; + public function getSerialNumber(): ?string { return $this->serialNumber; @@ -129,4 +132,16 @@ class Client extends AbstractEntity return $this; } + + public function getMenu(): ?Menu + { + return $this->menu; + } + + public function setMenu(?Menu $menu): static + { + $this->menu = $menu; + + return $this; + } } diff --git a/src/Entity/Menu.php b/src/Entity/Menu.php new file mode 100644 index 0000000..a0107cb --- /dev/null +++ b/src/Entity/Menu.php @@ -0,0 +1,131 @@ + + */ + #[ORM\OneToMany(mappedBy: 'menu', targetEntity: Client::class)] + private Collection $clients; + + 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 + { + return $this->resolution; + } + + public function setResolution(string $resolution): static + { + $this->resolution = $resolution; + + return $this; + } + + public function getComments(): ?string + { + return $this->comments; + } + + public function setComments(?string $comments): static + { + $this->comments = $comments; + + return $this; + } + + public function getPublicUrl(): ?string + { + return $this->publicUrl; + } + + public function setPublicUrl(?string $publicUrl): static + { + $this->publicUrl = $publicUrl; + + return $this; + } + + public function getPrivateUrl(): ?string + { + return $this->privateUrl; + } + + public function setPrivateUrl(?string $privateUrl): static + { + $this->privateUrl = $privateUrl; + + return $this; + } + + /** + * @return Collection + */ + public function getClients(): Collection + { + return $this->clients; + } + + public function addClient(Client $client): static + { + if (!$this->clients->contains($client)) { + $this->clients->add($client); + $client->setMenu($this); + } + + 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); + } + } + + return $this; + } +} diff --git a/src/Repository/MenuRepository.php b/src/Repository/MenuRepository.php new file mode 100644 index 0000000..b23f67d --- /dev/null +++ b/src/Repository/MenuRepository.php @@ -0,0 +1,18 @@ + + */ +class MenuRepository extends AbstractRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Menu::class); + } +} diff --git a/src/State/Processor/MenuProcessor.php b/src/State/Processor/MenuProcessor.php new file mode 100644 index 0000000..bc4a911 --- /dev/null +++ b/src/State/Processor/MenuProcessor.php @@ -0,0 +1,71 @@ +processCreateOrUpdate($data, $operation, $uriVariables, $context); + case $operation instanceof Delete: + return $this->processDelete($data, $operation, $uriVariables, $context); + } + } + + /** + * @throws \Exception + */ + private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): MenuOutput + { + if (!($data instanceof MenuInput)) { + throw new \Exception(sprintf('data is not instance of %s', UserGroupInput::class)); + } + + $entity = null; + if (isset($uriVariables['uuid'])) { + $entity = $this->menuRepository->findOneByUuid($uriVariables['uuid']); + } + + $userGroup = $data->createOrUpdateEntity($entity); + $this->validator->validate($userGroup); + $this->menuRepository->save($userGroup); + + return new MenuOutput($userGroup); + } + + private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null + { + $user = $this->menuRepository->findOneByUuid($uriVariables['uuid']); + $this->menuRepository->delete($user); + + return null; + } +} diff --git a/src/State/Provider/MenuProvider.php b/src/State/Provider/MenuProvider.php new file mode 100644 index 0000000..71359bc --- /dev/null +++ b/src/State/Provider/MenuProvider.php @@ -0,0 +1,75 @@ +provideCollection($operation, $uriVariables, $context); + case $operation instanceof Patch: + case $operation instanceof Put: + return $this->provideInput($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 MenuOutput($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('Menu not found'); + } + + return new MenuOutput($item); + } + + public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + if (isset($uriVariables['uuid'])) { + $item = $this->itemProvider->provide($operation, $uriVariables, $context); + + return $item !== null ? new MenuInput($item) : null; + } + + return new MenuInput(); + } +} From 0e707f1d69d2c4d59083fd01a4bdcd8bca0c100b Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Fri, 14 Jun 2024 10:32:43 +0200 Subject: [PATCH 15/35] refs #423. New table and Endpoint Partition --- config/api_platform/Partition.yaml | 30 ++++ config/services.yaml | 5 + config/services/api_platform.yaml | 77 +++++++-- migrations/Version20240614082024.php | 33 ++++ migrations/Version20240614082735.php | 35 +++++ src/Dto/Input/ClientInput.php | 7 +- src/Dto/Input/MenuInput.php | 1 + src/Dto/Input/PartitionInput.php | 91 +++++++++++ src/Dto/Output/ClientOutput.php | 12 ++ src/Dto/Output/PartitionOutput.php | 52 +++++++ src/Entity/Client.php | 45 ++++++ src/Entity/Partition.php | 146 ++++++++++++++++++ src/Repository/PartitionRepository.php | 18 +++ src/State/Processor/HardwareProcessor.php | 8 +- .../Processor/HardwareProfileProcessor.php | 14 +- src/State/Processor/MenuProcessor.php | 16 +- src/State/Processor/PartitionProcessor.php | 74 +++++++++ src/State/Provider/PartitionProvider.php | 77 +++++++++ 18 files changed, 704 insertions(+), 37 deletions(-) create mode 100644 config/api_platform/Partition.yaml create mode 100644 migrations/Version20240614082024.php create mode 100644 migrations/Version20240614082735.php create mode 100644 src/Dto/Input/PartitionInput.php create mode 100644 src/Dto/Output/PartitionOutput.php create mode 100644 src/Entity/Partition.php create mode 100644 src/Repository/PartitionRepository.php create mode 100644 src/State/Processor/PartitionProcessor.php create mode 100644 src/State/Provider/PartitionProvider.php diff --git a/config/api_platform/Partition.yaml b/config/api_platform/Partition.yaml new file mode 100644 index 0000000..1d270e7 --- /dev/null +++ b/config/api_platform/Partition.yaml @@ -0,0 +1,30 @@ +resources: + App\Entity\Partition: + processor: App\State\Processor\PartitionProcessor + input: App\Dto\Input\PartitionInput + output: App\Dto\Output\PartitionOutput + normalization_context: + groups: ['default', 'partition:read'] + denormalization_context: + groups: ['partition:write'] + operations: + ApiPlatform\Metadata\GetCollection: + provider: App\State\Provider\PartitionProvider + filters: + - 'api_platform.filter.partition.order' + - 'api_platform.filter.partition.search' + ApiPlatform\Metadata\Get: + provider: App\State\Provider\PartitionProvider + ApiPlatform\Metadata\Put: + provider: App\State\Provider\PartitionProvider + ApiPlatform\Metadata\Patch: + provider: App\State\Provider\PartitionProvider + ApiPlatform\Metadata\Post: ~ + ApiPlatform\Metadata\Delete: ~ + +properties: + App\Entity\Partition: + id: + identifier: false + uuid: + identifier: true \ No newline at end of file diff --git a/config/services.yaml b/config/services.yaml index 3e2e835..8b4eaac 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -56,6 +56,11 @@ services: $itemProvider: '@api_platform.doctrine.orm.state.item_provider' App\State\Provider\MenuProvider: + bind: + $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' + $itemProvider: '@api_platform.doctrine.orm.state.item_provider' + + App\State\Provider\PartitionProvider: bind: $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' $itemProvider: '@api_platform.doctrine.orm.state.item_provider' \ No newline at end of file diff --git a/config/services/api_platform.yaml b/config/services/api_platform.yaml index 1541e80..fd54ddb 100644 --- a/config/services/api_platform.yaml +++ b/config/services/api_platform.yaml @@ -1,17 +1,74 @@ services: + api_platform.filter.client.order: + parent: 'api_platform.doctrine.orm.order_filter' + arguments: + $properties: { 'id': ~, 'name': ~, 'serialNumber': ~ } + $orderParameterName: 'order' + tags: + - [ 'api_platform.filter' ] + + api_platform.filter.client.search: + parent: 'api_platform.doctrine.orm.search_filter' + arguments: [ { 'id': 'exact', 'name': 'partial', 'serialNumber': 'exact' } ] + tags: + - [ 'api_platform.filter' ] + + api_platform.filter.hardware.order: + parent: 'api_platform.doctrine.orm.order_filter' + arguments: + $properties: { 'id': ~, 'name': ~ } + $orderParameterName: 'order' + tags: + - [ 'api_platform.filter' ] + + api_platform.filter.hardware.search: + parent: 'api_platform.doctrine.orm.search_filter' + arguments: [ { 'id': 'exact', 'name': 'partial' } ] + tags: + - [ 'api_platform.filter' ] + + api_platform.filter.menu.order: + parent: 'api_platform.doctrine.orm.order_filter' + arguments: + $properties: { 'id': ~, 'name': ~, 'title': ~ } + $orderParameterName: 'order' + tags: + - [ 'api_platform.filter' ] + + api_platform.filter.menu.search: + parent: 'api_platform.doctrine.orm.search_filter' + arguments: [ { 'id': 'exact', 'name': 'exact', 'title': 'exact' } ] + tags: + - [ 'api_platform.filter' ] + + + api_platform.filter.partition.order: + parent: 'api_platform.doctrine.orm.order_filter' + arguments: + $properties: { 'id': ~, 'usage': ~ } + $orderParameterName: 'order' + tags: + - [ 'api_platform.filter' ] + + api_platform.filter.partition.search: + parent: 'api_platform.doctrine.orm.search_filter' + arguments: [ { 'id': 'exact', 'usage': 'exact', 'diskNumber': 'exact' } ] + tags: + - [ 'api_platform.filter' ] + api_platform.filter.user.order: parent: 'api_platform.doctrine.orm.order_filter' arguments: - $properties: { 'id' : ~, 'username': ~ } + $properties: { 'id': ~, 'username': ~ } $orderParameterName: 'order' tags: - - ['api_platform.filter' ] + - [ 'api_platform.filter' ] api_platform.filter.user.search: parent: 'api_platform.doctrine.orm.search_filter' - arguments: [ { 'id': 'exact', 'username': 'partial' }] + arguments: [ { 'id': 'exact', 'username': 'partial' } ] tags: - - ['api_platform.filter' ] + - [ 'api_platform.filter' ] api_platform.filter.user.boolean: parent: 'api_platform.doctrine.orm.boolean_filter' @@ -39,16 +96,4 @@ services: tags: - [ 'api_platform.filter' ] - api_platform.filter.hardware.order: - parent: 'api_platform.doctrine.orm.order_filter' - arguments: - $properties: { 'id': ~, 'name': ~ } - $orderParameterName: 'order' - tags: - - [ 'api_platform.filter' ] - api_platform.filter.hardware.search: - parent: 'api_platform.doctrine.orm.search_filter' - arguments: [ { 'id': 'exact', 'name': 'partial' } ] - tags: - - [ 'api_platform.filter' ] diff --git a/migrations/Version20240614082024.php b/migrations/Version20240614082024.php new file mode 100644 index 0000000..9794d3b --- /dev/null +++ b/migrations/Version20240614082024.php @@ -0,0 +1,33 @@ +addSql('CREATE TABLE `partition` (id INT AUTO_INCREMENT NOT NULL, client_id INT DEFAULT 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, disk_number INT DEFAULT NULL, partition_number INT DEFAULT NULL, partition_code VARCHAR(255) DEFAULT NULL, size INT NOT NULL, cache_content VARCHAR(255) DEFAULT NULL, filesystem VARCHAR(255) DEFAULT NULL, os_name VARCHAR(255) NOT NULL, memory_usage INT NOT NULL, UNIQUE INDEX UNIQ_9EB910E4D17F50A6 (uuid), INDEX IDX_9EB910E419EB6921 (client_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE `partition` ADD CONSTRAINT FK_9EB910E419EB6921 FOREIGN KEY (client_id) REFERENCES client (id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE `partition` DROP FOREIGN KEY FK_9EB910E419EB6921'); + $this->addSql('DROP TABLE `partition`'); + } +} diff --git a/migrations/Version20240614082735.php b/migrations/Version20240614082735.php new file mode 100644 index 0000000..5243e2c --- /dev/null +++ b/migrations/Version20240614082735.php @@ -0,0 +1,35 @@ +addSql('ALTER TABLE client DROP FOREIGN KEY FK_C7440455CCD7E912'); + $this->addSql('DROP INDEX IDX_C7440455CCD7E912 ON client'); + $this->addSql('ALTER TABLE client ADD menu VARCHAR(255) DEFAULT NULL, DROP menu_id'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE client ADD menu_id INT DEFAULT NULL, DROP menu'); + $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455CCD7E912 FOREIGN KEY (menu_id) REFERENCES menu (id)'); + $this->addSql('CREATE INDEX IDX_C7440455CCD7E912 ON client (menu_id)'); + } +} diff --git a/src/Dto/Input/ClientInput.php b/src/Dto/Input/ClientInput.php index 366aa43..6a90ee0 100644 --- a/src/Dto/Input/ClientInput.php +++ b/src/Dto/Input/ClientInput.php @@ -51,7 +51,6 @@ final class ClientInput #[ApiProperty(description: 'The hardware profile of the client')] public ?HardwareProfileOutput $hardwareProfile = null; - #[Assert\NotNull] #[Groups(['client:write'])] #[ApiProperty(description: 'The menu of the client')] public ?MenuOutput $menu = null; @@ -85,7 +84,11 @@ final class ClientInput $client->setNetiface($this->netiface); $client->setOrganizationalUnit($this->organizationalUnit->getEntity()); $client->setHardwareProfile($this->hardwareProfile->getEntity()); - $client->setMenu($this->menu->getEntity()); + + if ($this->menu) { + $client->setMenu($this->menu->getEntity()); + } + $client->setNetDriver($this->netDriver); $client->setMac($this->mac); $client->setIp($this->ip); diff --git a/src/Dto/Input/MenuInput.php b/src/Dto/Input/MenuInput.php index 03631ee..d09d78e 100644 --- a/src/Dto/Input/MenuInput.php +++ b/src/Dto/Input/MenuInput.php @@ -16,6 +16,7 @@ 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; diff --git a/src/Dto/Input/PartitionInput.php b/src/Dto/Input/PartitionInput.php new file mode 100644 index 0000000..b4da4ed --- /dev/null +++ b/src/Dto/Input/PartitionInput.php @@ -0,0 +1,91 @@ +diskNumber = $partition->getDiskNumber(); + $this->partitionNumber = $partition->getPartitionNumber(); + $this->partitionCode = $partition->getPartitionCode(); + $this->size = $partition->getSize(); + $this->cacheContent = $partition->getCacheContent(); + $this->filesystem = $partition->getFilesystem(); + $this->osName = $partition->getOsName(); + $this->client = new ClientOutput($partition->getClient()); + $this->memoryUsage = $partition->getMemoryUsage(); + } + + public function createOrUpdateEntity(?Partition $partition = null): Partition + { + if (!$partition) { + $partition = new Partition(); + } + + $partition->setDiskNumber($this->diskNumber); + $partition->setPartitionNumber($this->partitionNumber); + $partition->setPartitionCode($this->partitionCode); + $partition->setSize($this->size * 100); + $partition->setCacheContent($this->cacheContent); + $partition->setFilesystem($this->filesystem); + $partition->setOsName($this->osName); + $partition->setClient($this->client->getEntity()); + $partition->setMemoryUsage($this->memoryUsage * 100); + + return $partition; + } +} \ No newline at end of file diff --git a/src/Dto/Output/ClientOutput.php b/src/Dto/Output/ClientOutput.php index 34c5b3c..d95e0ca 100644 --- a/src/Dto/Output/ClientOutput.php +++ b/src/Dto/Output/ClientOutput.php @@ -4,6 +4,7 @@ namespace App\Dto\Output; use ApiPlatform\Metadata\Get; use App\Entity\Client; +use App\Entity\Partition; use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'Client')] @@ -27,6 +28,12 @@ final class ClientOutput extends AbstractOutput #[Groups(['client:read'])] public ?MenuOutput $menu = null; + /** + * @var Partition[] + */ + #[Groups(['client:read'])] + public array $partitions = []; + #[Groups(['client:read'])] public \DateTime $createdAt; @@ -49,6 +56,11 @@ final class ClientOutput extends AbstractOutput if($client->getMenu()) { $this->menu = new MenuOutput($client->getMenu()); } + + foreach ($client->getPartitions() as $partition) { + $this->partitions[] = new PartitionOutput($partition); + } + $this->createdAt = $client->getCreatedAt(); $this->createdBy = $client->getCreatedBy(); } diff --git a/src/Dto/Output/PartitionOutput.php b/src/Dto/Output/PartitionOutput.php new file mode 100644 index 0000000..273c4b8 --- /dev/null +++ b/src/Dto/Output/PartitionOutput.php @@ -0,0 +1,52 @@ +diskNumber = $partition->getDiskNumber(); + $this->partitionNumber = $partition->getPartitionNumber(); + $this->partitionCode = $partition->getPartitionCode(); + $this->size = $partition->getSize() / 100; + $this->cacheContent = $partition->getCacheContent(); + $this->filesystem = $partition->getFilesystem(); + $this->osName = $partition->getOsName(); + $this->client = new ClientOutput($partition->getClient()); + $this->memoryUsage = $partition->getMemoryUsage() / 100; + } + +} \ No newline at end of file diff --git a/src/Entity/Client.php b/src/Entity/Client.php index f632a8f..0fc4f47 100644 --- a/src/Entity/Client.php +++ b/src/Entity/Client.php @@ -3,6 +3,8 @@ namespace App\Entity; use App\Repository\ClientRepository; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: ClientRepository::class)] @@ -35,8 +37,21 @@ class Client extends AbstractEntity private ?HardwareProfile $hardwareProfile = null; #[ORM\ManyToOne(inversedBy: 'clients')] + #[ORM\Column(nullable: true)] private ?Menu $menu = null; + /** + * @var Collection + */ + #[ORM\OneToMany(mappedBy: 'client', targetEntity: Partition::class)] + private Collection $partitions; + + public function __construct() + { + parent::__construct(); + $this->partitions = new ArrayCollection(); + } + public function getSerialNumber(): ?string { return $this->serialNumber; @@ -144,4 +159,34 @@ class Client extends AbstractEntity return $this; } + + /** + * @return Collection + */ + public function getPartitions(): Collection + { + return $this->partitions; + } + + public function addPartition(Partition $partition): static + { + if (!$this->partitions->contains($partition)) { + $this->partitions->add($partition); + $partition->setClient($this); + } + + return $this; + } + + public function removePartition(Partition $partition): static + { + if ($this->partitions->removeElement($partition)) { + // set the owning side to null (unless already changed) + if ($partition->getClient() === $this) { + $partition->setClient(null); + } + } + + return $this; + } } diff --git a/src/Entity/Partition.php b/src/Entity/Partition.php new file mode 100644 index 0000000..316eb28 --- /dev/null +++ b/src/Entity/Partition.php @@ -0,0 +1,146 @@ +diskNumber; + } + + public function setDiskNumber(?int $diskNumber): static + { + $this->diskNumber = $diskNumber; + + return $this; + } + + public function getPartitionNumber(): ?int + { + return $this->partitionNumber; + } + + public function setPartitionNumber(?int $partitionNumber): static + { + $this->partitionNumber = $partitionNumber; + + return $this; + } + + public function getPartitionCode(): ?string + { + return $this->partitionCode; + } + + public function setPartitionCode(?string $partitionCode): static + { + $this->partitionCode = $partitionCode; + + return $this; + } + + public function getSize(): ?int + { + return $this->size; + } + + public function setSize(int $size): static + { + $this->size = $size; + + return $this; + } + + public function getCacheContent(): ?string + { + return $this->cacheContent; + } + + public function setCacheContent(?string $cacheContent): static + { + $this->cacheContent = $cacheContent; + + return $this; + } + + public function getFilesystem(): ?string + { + return $this->filesystem; + } + + public function setFilesystem(?string $filesystem): static + { + $this->filesystem = $filesystem; + + return $this; + } + + public function getOsName(): ?string + { + return $this->osName; + } + + public function setOsName(string $osName): static + { + $this->osName = $osName; + + return $this; + } + + public function getClient(): ?Client + { + return $this->client; + } + + public function setClient(?Client $client): static + { + $this->client = $client; + + return $this; + } + + public function getMemoryUsage(): ?int + { + return $this->memoryUsage; + } + + public function setMemoryUsage(int $memoryUsage): static + { + $this->memoryUsage = $memoryUsage; + + return $this; + } +} diff --git a/src/Repository/PartitionRepository.php b/src/Repository/PartitionRepository.php new file mode 100644 index 0000000..e4964b3 --- /dev/null +++ b/src/Repository/PartitionRepository.php @@ -0,0 +1,18 @@ + + */ +class PartitionRepository extends AbstractRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Partition::class); + } +} diff --git a/src/State/Processor/HardwareProcessor.php b/src/State/Processor/HardwareProcessor.php index 25781a8..971fb3d 100644 --- a/src/State/Processor/HardwareProcessor.php +++ b/src/State/Processor/HardwareProcessor.php @@ -52,11 +52,11 @@ class HardwareProcessor implements ProcessorInterface $entity = $this->hardwareRepository->findOneByUuid($uriVariables['uuid']); } - $userGroup = $data->createOrUpdateEntity($entity); - $this->validator->validate($userGroup); - $this->hardwareRepository->save($userGroup); + $hardware = $data->createOrUpdateEntity($entity); + $this->validator->validate($hardware); + $this->hardwareRepository->save($hardware); - return new HardwareOutput($userGroup); + return new HardwareOutput($hardware); } private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null diff --git a/src/State/Processor/HardwareProfileProcessor.php b/src/State/Processor/HardwareProfileProcessor.php index aaf2bdd..ed6ccf8 100644 --- a/src/State/Processor/HardwareProfileProcessor.php +++ b/src/State/Processor/HardwareProfileProcessor.php @@ -17,8 +17,8 @@ use App\Repository\HardwareProfileRepository; readonly class HardwareProfileProcessor implements ProcessorInterface { public function __construct( - private HardwareProfileRepository $hardwareProfileRepository, - private ValidatorInterface $validator + private HardwareProfileRepository $hardwareProfileRepository, + private ValidatorInterface $validator ) { } @@ -44,7 +44,7 @@ readonly class HardwareProfileProcessor implements ProcessorInterface private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): HardwareProfileOutput { if (!($data instanceof HardwareProfileInput)) { - throw new \Exception(sprintf('data is not instance of %s', HardwareInput::class)); + throw new \Exception(sprintf('data is not instance of %s', HardwareProfileInput::class)); } $entity = null; @@ -52,11 +52,11 @@ readonly class HardwareProfileProcessor implements ProcessorInterface $entity = $this->hardwareProfileRepository->findOneByUuid($uriVariables['uuid']); } - $userGroup = $data->createOrUpdateEntity($entity); - $this->validator->validate($userGroup); - $this->hardwareProfileRepository->save($userGroup); + $hardwareProfile = $data->createOrUpdateEntity($entity); + $this->validator->validate($hardwareProfile); + $this->hardwareProfileRepository->save($hardwareProfile); - return new HardwareProfileOutput($userGroup); + return new HardwareProfileOutput($hardwareProfile); } private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null diff --git a/src/State/Processor/MenuProcessor.php b/src/State/Processor/MenuProcessor.php index bc4a911..16bda49 100644 --- a/src/State/Processor/MenuProcessor.php +++ b/src/State/Processor/MenuProcessor.php @@ -16,11 +16,11 @@ use App\Dto\Output\UserGroupOutput; use App\Repository\MenuRepository; use App\Repository\UserGroupRepository; -class MenuProcessor implements ProcessorInterface +readonly class MenuProcessor implements ProcessorInterface { public function __construct( - private readonly MenuRepository $menuRepository, - private readonly ValidatorInterface $validator + private MenuRepository $menuRepository, + private ValidatorInterface $validator ) { } @@ -46,7 +46,7 @@ class MenuProcessor implements ProcessorInterface private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): MenuOutput { if (!($data instanceof MenuInput)) { - throw new \Exception(sprintf('data is not instance of %s', UserGroupInput::class)); + throw new \Exception(sprintf('data is not instance of %s', MenuInput::class)); } $entity = null; @@ -54,11 +54,11 @@ class MenuProcessor implements ProcessorInterface $entity = $this->menuRepository->findOneByUuid($uriVariables['uuid']); } - $userGroup = $data->createOrUpdateEntity($entity); - $this->validator->validate($userGroup); - $this->menuRepository->save($userGroup); + $menu = $data->createOrUpdateEntity($entity); + $this->validator->validate($menu); + $this->menuRepository->save($menu); - return new MenuOutput($userGroup); + return new MenuOutput($menu); } private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null diff --git a/src/State/Processor/PartitionProcessor.php b/src/State/Processor/PartitionProcessor.php new file mode 100644 index 0000000..f17affc --- /dev/null +++ b/src/State/Processor/PartitionProcessor.php @@ -0,0 +1,74 @@ +processCreateOrUpdate($data, $operation, $uriVariables, $context); + case $operation instanceof Delete: + return $this->processDelete($data, $operation, $uriVariables, $context); + } + } + + /** + * @throws \Exception + */ + private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): PartitionOutput + { + if (!($data instanceof PartitionInput)) { + throw new \Exception(sprintf('data is not instance of %s', PartitionInput::class)); + } + + $entity = null; + if (isset($uriVariables['uuid'])) { + $entity = $this->partitionRepository->findOneByUuid($uriVariables['uuid']); + } + + $partition = $data->createOrUpdateEntity($entity); + $this->validator->validate($partition); + $this->partitionRepository->save($partition); + + return new PartitionOutput($partition); + } + + private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null + { + $user = $this->partitionRepository->findOneByUuid($uriVariables['uuid']); + $this->partitionRepository->delete($user); + + return null; + } +} diff --git a/src/State/Provider/PartitionProvider.php b/src/State/Provider/PartitionProvider.php new file mode 100644 index 0000000..ae6abe8 --- /dev/null +++ b/src/State/Provider/PartitionProvider.php @@ -0,0 +1,77 @@ +provideCollection($operation, $uriVariables, $context); + case $operation instanceof Patch: + case $operation instanceof Put: + return $this->provideInput($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 PartitionOutput($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('Partition not found'); + } + + return new PartitionOutput($item); + } + + public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + if (isset($uriVariables['uuid'])) { + $item = $this->itemProvider->provide($operation, $uriVariables, $context); + + return $item !== null ? new PartitionInput($item) : null; + } + + return new PartitionInput(); + } +} From f64fbecd2e53e2c14a2095958ebe3f8f67028a1f Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Tue, 18 Jun 2024 08:46:08 +0200 Subject: [PATCH 16/35] refs #433. Hierarchy property --- config/api_platform/NetworkSettings.yaml | 18 +++ config/api_platform/OrganizationalUnit.yaml | 30 +--- config/api_platform/User.yaml | 1 - config/services.yaml | 5 + migrations/Version20240612105731.php | 33 ----- migrations/Version20240612111552.php | 37 ----- migrations/Version20240613090444.php | 43 ------ migrations/Version20240614082024.php | 33 ----- ...11090540.php => Version20240617113606.php} | 18 ++- ...14082735.php => Version20240618062825.php} | 18 ++- src/Dto/Input/ClientInput.php | 27 ++-- src/Dto/Input/NetworkSettingsInput.php | 99 ++++++++++++++ .../OrganizationalUnitClassroomGroupInput.php | 14 -- .../OrganizationalUnitClassroomInput.php | 123 ----------------- .../OrganizationalUnitClientGroupInput.php | 14 -- src/Dto/Input/OrganizationalUnitInput.php | 16 ++- src/Dto/Input/OrganizationalUnitRootInput.php | 14 -- src/Dto/Output/ClientOutput.php | 24 ++-- src/Dto/Output/NetworkSettingsOutput.php | 6 +- src/Dto/Output/OrganizationalUnitOutput.php | 5 +- src/Dto/Output/PartitionOutput.php | 12 +- src/Entity/Client.php | 61 ++++----- src/Entity/HardwareProfile.php | 2 +- src/Entity/Menu.php | 1 - src/Entity/NetworkSettings.php | 46 ++++++- src/Entity/OrganizationalUnit.php | 39 +----- src/Factory/MenuFactory.php | 60 ++++++++ src/Factory/PartitionFactory.php | 61 +++++++++ src/Repository/ClientPropertiesRepository.php | 43 ++++++ src/State/Processor/ClientProcessor.php | 2 +- .../Processor/OrganizationalUnitProcessor.php | 13 +- .../Provider/NetworkSettingsProvider.php | 61 +++++++++ .../Provider/OrganizationalUnitProvider.php | 23 +--- tests/Functional/ClientTest.php | 34 ++++- tests/Functional/MenuTest.php | 129 ++++++++++++++++++ tests/Functional/OrganizationalUnitTest.php | 80 +---------- tests/Functional/PartitionTest.php | 46 +++++++ 37 files changed, 719 insertions(+), 572 deletions(-) create mode 100644 config/api_platform/NetworkSettings.yaml delete mode 100644 migrations/Version20240612105731.php delete mode 100644 migrations/Version20240612111552.php delete mode 100644 migrations/Version20240613090444.php delete mode 100644 migrations/Version20240614082024.php rename migrations/{Version20240611090540.php => Version20240617113606.php} (72%) rename migrations/{Version20240614082735.php => Version20240618062825.php} (62%) create mode 100644 src/Dto/Input/NetworkSettingsInput.php delete mode 100644 src/Dto/Input/OrganizationalUnitClassroomGroupInput.php delete mode 100644 src/Dto/Input/OrganizationalUnitClassroomInput.php delete mode 100644 src/Dto/Input/OrganizationalUnitClientGroupInput.php delete mode 100644 src/Dto/Input/OrganizationalUnitRootInput.php create mode 100644 src/Factory/MenuFactory.php create mode 100644 src/Factory/PartitionFactory.php create mode 100644 src/Repository/ClientPropertiesRepository.php create mode 100644 src/State/Provider/NetworkSettingsProvider.php create mode 100644 tests/Functional/MenuTest.php create mode 100644 tests/Functional/PartitionTest.php diff --git a/config/api_platform/NetworkSettings.yaml b/config/api_platform/NetworkSettings.yaml new file mode 100644 index 0000000..e9750bd --- /dev/null +++ b/config/api_platform/NetworkSettings.yaml @@ -0,0 +1,18 @@ +resources: + App\Entity\NetworkSettings: + output: App\Dto\Output\NetworkSettingsOutput + operations: + ApiPlatform\Metadata\GetCollection: + provider: App\State\Provider\MenuProvider + filters: + - 'api_platform.filter.menu.order' + - 'api_platform.filter.menu.search' + ApiPlatform\Metadata\Get: + provider: App\State\Provider\MenuProvider + +properties: + App\Entity\NetworkSettings: + id: + identifier: false + uuid: + identifier: true \ No newline at end of file diff --git a/config/api_platform/OrganizationalUnit.yaml b/config/api_platform/OrganizationalUnit.yaml index 72fcdbf..df86419 100644 --- a/config/api_platform/OrganizationalUnit.yaml +++ b/config/api_platform/OrganizationalUnit.yaml @@ -7,6 +7,7 @@ resources: groups: ['default', 'organizational-unit:read'] denormalization_context: groups: ['organizational-unit:write'] + operations: ApiPlatform\Metadata\GetCollection: provider: App\State\Provider\OrganizationalUnitProvider @@ -18,35 +19,8 @@ resources: provider: App\State\Provider\OrganizationalUnitProvider validationContext: groups: ['organizational-unit:patch' ] - + ApiPlatform\Metadata\Post: ~ ApiPlatform\Metadata\Delete: ~ - organizational_unit_root: - class: ApiPlatform\Metadata\Post - method: POST - uriTemplate: /organizational-units/root - input: App\Dto\Input\OrganizationalUnitRootInput - output: App\Dto\Output\OrganizationalUnitOutput - - organizational_unit_classroom_group: - class: ApiPlatform\Metadata\Post - method: POST - uriTemplate: /organizational-units/classroom-group - input: App\Dto\Input\OrganizationalUnitClassroomGroupInput - output: App\Dto\Output\OrganizationalUnitOutput - - organizational_unit_classroom: - class: ApiPlatform\Metadata\Post - method: POST - uriTemplate: /organizational-units/classroom - input: App\Dto\Input\OrganizationalUnitClassroomInput - output: App\Dto\Output\OrganizationalUnitOutput - - organizational_unit_client_group: - class: ApiPlatform\Metadata\Post - method: POST - uriTemplate: /organizational-units/client-group - input: App\Dto\Input\OrganizationalUnitClientGroupInput - output: App\Dto\Output\OrganizationalUnitOutput properties: App\Entity\OrganizationalUnit: diff --git a/config/api_platform/User.yaml b/config/api_platform/User.yaml index 5e005fb..f108627 100644 --- a/config/api_platform/User.yaml +++ b/config/api_platform/User.yaml @@ -9,7 +9,6 @@ resources: groups: ['user:write'] operations: ApiPlatform\Metadata\GetCollection: - security: 'is_granted("ROLE_SUPER_ADMIN")' provider: App\State\Provider\UserProvider filters: - 'api_platform.filter.user.order' diff --git a/config/services.yaml b/config/services.yaml index 8b4eaac..d495931 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -61,6 +61,11 @@ services: $itemProvider: '@api_platform.doctrine.orm.state.item_provider' App\State\Provider\PartitionProvider: + bind: + $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' + $itemProvider: '@api_platform.doctrine.orm.state.item_provider' + + App\State\Provider\NetworkSettingsProvider: bind: $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' $itemProvider: '@api_platform.doctrine.orm.state.item_provider' \ No newline at end of file diff --git a/migrations/Version20240612105731.php b/migrations/Version20240612105731.php deleted file mode 100644 index f61d5c1..0000000 --- a/migrations/Version20240612105731.php +++ /dev/null @@ -1,33 +0,0 @@ -addSql('ALTER TABLE client CHANGE name name VARCHAR(255) NOT NULL'); - $this->addSql('ALTER TABLE network_settings CHANGE mcast_speed mcast_speed INT DEFAULT 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 CHANGE mcast_speed mcast_speed INT NOT NULL'); - $this->addSql('ALTER TABLE client CHANGE name name VARCHAR(255) DEFAULT NULL'); - } -} diff --git a/migrations/Version20240612111552.php b/migrations/Version20240612111552.php deleted file mode 100644 index a5cca1d..0000000 --- a/migrations/Version20240612111552.php +++ /dev/null @@ -1,37 +0,0 @@ -addSql('ALTER TABLE client CHANGE name name VARCHAR(255) DEFAULT NULL'); - $this->addSql('ALTER TABLE hardware CHANGE name name VARCHAR(255) DEFAULT NULL'); - $this->addSql('ALTER TABLE organizational_unit CHANGE name name VARCHAR(255) DEFAULT NULL'); - $this->addSql('ALTER TABLE user_group CHANGE name name VARCHAR(255) DEFAULT NULL'); - } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql('ALTER TABLE hardware CHANGE name name VARCHAR(255) NOT NULL'); - $this->addSql('ALTER TABLE user_group CHANGE name name VARCHAR(255) NOT NULL'); - $this->addSql('ALTER TABLE organizational_unit CHANGE name name VARCHAR(255) NOT NULL'); - $this->addSql('ALTER TABLE client CHANGE name name VARCHAR(255) NOT NULL'); - } -} diff --git a/migrations/Version20240613090444.php b/migrations/Version20240613090444.php deleted file mode 100644 index 45413e4..0000000 --- a/migrations/Version20240613090444.php +++ /dev/null @@ -1,43 +0,0 @@ -addSql('CREATE TABLE menu (id INT AUTO_INCREMENT 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, title VARCHAR(255) NOT NULL, resolution VARCHAR(255) NOT NULL, comments VARCHAR(255) DEFAULT NULL, public_url VARCHAR(255) DEFAULT NULL, private_url VARCHAR(255) DEFAULT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_7D053A93D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('ALTER TABLE client ADD menu_id INT DEFAULT NULL, CHANGE name name VARCHAR(255) NOT NULL'); - $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455CCD7E912 FOREIGN KEY (menu_id) REFERENCES menu (id)'); - $this->addSql('CREATE INDEX IDX_C7440455CCD7E912 ON client (menu_id)'); - $this->addSql('ALTER TABLE hardware CHANGE name name VARCHAR(255) NOT NULL'); - $this->addSql('ALTER TABLE organizational_unit CHANGE name name VARCHAR(255) NOT NULL'); - $this->addSql('ALTER TABLE user_group CHANGE name name VARCHAR(255) NOT 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('DROP TABLE menu'); - $this->addSql('ALTER TABLE hardware CHANGE name name VARCHAR(255) DEFAULT NULL'); - $this->addSql('ALTER TABLE user_group CHANGE name name VARCHAR(255) DEFAULT NULL'); - $this->addSql('ALTER TABLE organizational_unit CHANGE name name VARCHAR(255) DEFAULT NULL'); - $this->addSql('DROP INDEX IDX_C7440455CCD7E912 ON client'); - $this->addSql('ALTER TABLE client DROP menu_id, CHANGE name name VARCHAR(255) DEFAULT NULL'); - } -} diff --git a/migrations/Version20240614082024.php b/migrations/Version20240614082024.php deleted file mode 100644 index 9794d3b..0000000 --- a/migrations/Version20240614082024.php +++ /dev/null @@ -1,33 +0,0 @@ -addSql('CREATE TABLE `partition` (id INT AUTO_INCREMENT NOT NULL, client_id INT DEFAULT 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, disk_number INT DEFAULT NULL, partition_number INT DEFAULT NULL, partition_code VARCHAR(255) DEFAULT NULL, size INT NOT NULL, cache_content VARCHAR(255) DEFAULT NULL, filesystem VARCHAR(255) DEFAULT NULL, os_name VARCHAR(255) NOT NULL, memory_usage INT NOT NULL, UNIQUE INDEX UNIQ_9EB910E4D17F50A6 (uuid), INDEX IDX_9EB910E419EB6921 (client_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('ALTER TABLE `partition` ADD CONSTRAINT FK_9EB910E419EB6921 FOREIGN KEY (client_id) REFERENCES client (id)'); - } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql('ALTER TABLE `partition` DROP FOREIGN KEY FK_9EB910E419EB6921'); - $this->addSql('DROP TABLE `partition`'); - } -} diff --git a/migrations/Version20240611090540.php b/migrations/Version20240617113606.php similarity index 72% rename from migrations/Version20240611090540.php rename to migrations/Version20240617113606.php index 5f4e3cb..3c98a3c 100644 --- a/migrations/Version20240611090540.php +++ b/migrations/Version20240617113606.php @@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration; /** * Auto-generated Migration: Please modify to your needs! */ -final class Version20240611090540 extends AbstractMigration +final class Version20240617113606 extends AbstractMigration { public function getDescription(): string { @@ -20,24 +20,28 @@ final class Version20240611090540 extends AbstractMigration public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs - $this->addSql('CREATE TABLE client (id INT AUTO_INCREMENT NOT NULL, organizational_unit_id INT DEFAULT NULL, hardware_profile_id INT DEFAULT 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, name VARCHAR(255) DEFAULT NULL, serial_number VARCHAR(255) DEFAULT NULL, netiface VARCHAR(255) DEFAULT NULL, net_driver VARCHAR(255) DEFAULT NULL, mac VARCHAR(255) DEFAULT NULL, ip VARCHAR(255) DEFAULT NULL, status VARCHAR(255) DEFAULT NULL, UNIQUE INDEX UNIQ_C7440455D17F50A6 (uuid), INDEX IDX_C7440455FB84408A (organizational_unit_id), INDEX IDX_C7440455CFA495C1 (hardware_profile_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE client (id INT AUTO_INCREMENT NOT NULL, organizational_unit_id INT DEFAULT 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, serial_number VARCHAR(255) DEFAULT NULL, netiface VARCHAR(255) DEFAULT NULL, net_driver VARCHAR(255) DEFAULT NULL, mac VARCHAR(255) DEFAULT NULL, ip VARCHAR(255) DEFAULT NULL, status VARCHAR(255) DEFAULT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_C7440455D17F50A6 (uuid), INDEX IDX_C7440455FB84408A (organizational_unit_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE hardware (id INT AUTO_INCREMENT 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, description VARCHAR(255) DEFAULT NULL, type VARCHAR(255) DEFAULT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_FE99E9E0D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE hardware_profile (id INT AUTO_INCREMENT NOT NULL, organizational_unit_id INT DEFAULT 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, description VARCHAR(255) DEFAULT NULL, comments VARCHAR(255) DEFAULT NULL, UNIQUE INDEX UNIQ_2D9A2460D17F50A6 (uuid), INDEX IDX_2D9A2460FB84408A (organizational_unit_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE hardware_profile_hardware (hardware_profile_id INT NOT NULL, hardware_id INT NOT NULL, INDEX IDX_18C7E12CFA495C1 (hardware_profile_id), INDEX IDX_18C7E12C9CC762B (hardware_id), PRIMARY KEY(hardware_profile_id, hardware_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('CREATE TABLE network_settings (id INT AUTO_INCREMENT 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, proxy VARCHAR(255) DEFAULT NULL, dns VARCHAR(255) DEFAULT NULL, netmask VARCHAR(255) DEFAULT NULL, router VARCHAR(255) DEFAULT NULL, ntp VARCHAR(255) DEFAULT NULL, p2p_time INT DEFAULT NULL, p2p_mode VARCHAR(255) DEFAULT NULL, mcast_ip VARCHAR(255) DEFAULT NULL, mcast_speed INT NOT NULL, mcast_mode VARCHAR(255) DEFAULT NULL, mcast_port INT DEFAULT NULL, UNIQUE INDEX UNIQ_48869B54D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE menu (id INT AUTO_INCREMENT 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, title VARCHAR(255) NOT NULL, resolution VARCHAR(255) NOT NULL, comments VARCHAR(255) DEFAULT NULL, public_url VARCHAR(255) DEFAULT NULL, private_url VARCHAR(255) DEFAULT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_7D053A93D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE network_settings (id INT AUTO_INCREMENT NOT NULL, menu_id INT DEFAULT NULL, hardware_profile_id INT DEFAULT 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, proxy VARCHAR(255) DEFAULT NULL, dns VARCHAR(255) DEFAULT NULL, netmask VARCHAR(255) DEFAULT NULL, router VARCHAR(255) DEFAULT NULL, ntp VARCHAR(255) DEFAULT NULL, p2p_time INT DEFAULT NULL, p2p_mode VARCHAR(255) DEFAULT NULL, mcast_ip VARCHAR(255) DEFAULT NULL, mcast_speed INT DEFAULT NULL, mcast_mode VARCHAR(255) DEFAULT NULL, mcast_port INT DEFAULT NULL, validation TINYINT(1) DEFAULT NULL, UNIQUE INDEX UNIQ_48869B54D17F50A6 (uuid), INDEX IDX_48869B54CCD7E912 (menu_id), INDEX IDX_48869B54CFA495C1 (hardware_profile_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE organizational_unit (id INT AUTO_INCREMENT NOT NULL, parent_id INT DEFAULT NULL, network_settings_id INT DEFAULT 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, description VARCHAR(255) DEFAULT NULL, comments VARCHAR(255) DEFAULT NULL, path VARCHAR(255) DEFAULT NULL, level INT DEFAULT NULL, slug VARCHAR(255) DEFAULT NULL, type VARCHAR(255) NOT NULL, location VARCHAR(255) DEFAULT NULL, projector TINYINT(1) DEFAULT NULL, board TINYINT(1) DEFAULT NULL, capacity INT DEFAULT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_749AEB2DD17F50A6 (uuid), INDEX IDX_749AEB2D727ACA70 (parent_id), INDEX IDX_749AEB2D9B9A36D0 (network_settings_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE `partition` (id INT AUTO_INCREMENT NOT NULL, client_id INT DEFAULT 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, disk_number INT DEFAULT NULL, partition_number INT DEFAULT NULL, partition_code VARCHAR(255) DEFAULT NULL, size INT NOT NULL, cache_content VARCHAR(255) DEFAULT NULL, filesystem VARCHAR(255) DEFAULT NULL, os_name VARCHAR(255) NOT NULL, memory_usage INT NOT NULL, UNIQUE INDEX UNIQ_9EB910E4D17F50A6 (uuid), INDEX IDX_9EB910E419EB6921 (client_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE refresh_tokens (id INT AUTO_INCREMENT NOT NULL, refresh_token VARCHAR(128) NOT NULL, username VARCHAR(255) NOT NULL, valid DATETIME NOT NULL, UNIQUE INDEX UNIQ_9BACE7E1C74F2195 (refresh_token), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE user (id INT AUTO_INCREMENT 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, username VARCHAR(180) NOT NULL, roles JSON NOT NULL COMMENT \'(DC2Type:json)\', password VARCHAR(255) NOT NULL, enabled TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_8D93D649D17F50A6 (uuid), UNIQUE INDEX UNIQ_IDENTIFIER_USERNAME (username), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE user_organizational_unit (user_id INT NOT NULL, organizational_unit_id INT NOT NULL, INDEX IDX_5E59845FA76ED395 (user_id), INDEX IDX_5E59845FFB84408A (organizational_unit_id), PRIMARY KEY(user_id, organizational_unit_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE user_group (id INT AUTO_INCREMENT 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, permissions JSON NOT NULL COMMENT \'(DC2Type:json)\', name VARCHAR(255) NOT NULL, enabled TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_8F02BF9DD17F50A6 (uuid), UNIQUE INDEX UNIQ_IDENTIFIER_NAME (name), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('CREATE TABLE user_group_user (user_group_id INT NOT NULL, user_id INT NOT NULL, INDEX IDX_3AE4BD51ED93D47 (user_group_id), INDEX IDX_3AE4BD5A76ED395 (user_id), PRIMARY KEY(user_group_id, user_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455FB84408A FOREIGN KEY (organizational_unit_id) REFERENCES organizational_unit (id)'); - $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455CFA495C1 FOREIGN KEY (hardware_profile_id) REFERENCES hardware_profile (id)'); $this->addSql('ALTER TABLE hardware_profile ADD CONSTRAINT FK_2D9A2460FB84408A FOREIGN KEY (organizational_unit_id) REFERENCES organizational_unit (id)'); $this->addSql('ALTER TABLE hardware_profile_hardware ADD CONSTRAINT FK_18C7E12CFA495C1 FOREIGN KEY (hardware_profile_id) REFERENCES hardware_profile (id) ON DELETE CASCADE'); $this->addSql('ALTER TABLE hardware_profile_hardware ADD CONSTRAINT FK_18C7E12C9CC762B FOREIGN KEY (hardware_id) REFERENCES hardware (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE network_settings ADD CONSTRAINT FK_48869B54CCD7E912 FOREIGN KEY (menu_id) REFERENCES menu (id)'); + $this->addSql('ALTER TABLE network_settings ADD CONSTRAINT FK_48869B54CFA495C1 FOREIGN KEY (hardware_profile_id) REFERENCES hardware_profile (id)'); $this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D727ACA70 FOREIGN KEY (parent_id) REFERENCES organizational_unit (id) ON DELETE SET NULL'); $this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D9B9A36D0 FOREIGN KEY (network_settings_id) REFERENCES network_settings (id)'); + $this->addSql('ALTER TABLE `partition` ADD CONSTRAINT FK_9EB910E419EB6921 FOREIGN KEY (client_id) REFERENCES client (id)'); $this->addSql('ALTER TABLE user_organizational_unit ADD CONSTRAINT FK_5E59845FA76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE'); $this->addSql('ALTER TABLE user_organizational_unit ADD CONSTRAINT FK_5E59845FFB84408A FOREIGN KEY (organizational_unit_id) REFERENCES organizational_unit (id) ON DELETE CASCADE'); $this->addSql('ALTER TABLE user_group_user ADD CONSTRAINT FK_3AE4BD51ED93D47 FOREIGN KEY (user_group_id) REFERENCES user_group (id) ON DELETE CASCADE'); @@ -48,12 +52,14 @@ final class Version20240611090540 extends AbstractMigration { // this down() migration is auto-generated, please modify it to your needs $this->addSql('ALTER TABLE client DROP FOREIGN KEY FK_C7440455FB84408A'); - $this->addSql('ALTER TABLE client DROP FOREIGN KEY FK_C7440455CFA495C1'); $this->addSql('ALTER TABLE hardware_profile DROP FOREIGN KEY FK_2D9A2460FB84408A'); $this->addSql('ALTER TABLE hardware_profile_hardware DROP FOREIGN KEY FK_18C7E12CFA495C1'); $this->addSql('ALTER TABLE hardware_profile_hardware DROP FOREIGN KEY FK_18C7E12C9CC762B'); + $this->addSql('ALTER TABLE network_settings DROP FOREIGN KEY FK_48869B54CCD7E912'); + $this->addSql('ALTER TABLE network_settings DROP FOREIGN KEY FK_48869B54CFA495C1'); $this->addSql('ALTER TABLE organizational_unit DROP FOREIGN KEY FK_749AEB2D727ACA70'); $this->addSql('ALTER TABLE organizational_unit DROP FOREIGN KEY FK_749AEB2D9B9A36D0'); + $this->addSql('ALTER TABLE `partition` DROP FOREIGN KEY FK_9EB910E419EB6921'); $this->addSql('ALTER TABLE user_organizational_unit DROP FOREIGN KEY FK_5E59845FA76ED395'); $this->addSql('ALTER TABLE user_organizational_unit DROP FOREIGN KEY FK_5E59845FFB84408A'); $this->addSql('ALTER TABLE user_group_user DROP FOREIGN KEY FK_3AE4BD51ED93D47'); @@ -62,8 +68,10 @@ final class Version20240611090540 extends AbstractMigration $this->addSql('DROP TABLE hardware'); $this->addSql('DROP TABLE hardware_profile'); $this->addSql('DROP TABLE hardware_profile_hardware'); + $this->addSql('DROP TABLE menu'); $this->addSql('DROP TABLE network_settings'); $this->addSql('DROP TABLE organizational_unit'); + $this->addSql('DROP TABLE `partition`'); $this->addSql('DROP TABLE refresh_tokens'); $this->addSql('DROP TABLE user'); $this->addSql('DROP TABLE user_organizational_unit'); diff --git a/migrations/Version20240614082735.php b/migrations/Version20240618062825.php similarity index 62% rename from migrations/Version20240614082735.php rename to migrations/Version20240618062825.php index 5243e2c..7cb73fe 100644 --- a/migrations/Version20240614082735.php +++ b/migrations/Version20240618062825.php @@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration; /** * Auto-generated Migration: Please modify to your needs! */ -final class Version20240614082735 extends AbstractMigration +final class Version20240618062825 extends AbstractMigration { public function getDescription(): string { @@ -20,16 +20,20 @@ final class Version20240614082735 extends AbstractMigration 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('DROP INDEX IDX_C7440455CCD7E912 ON client'); - $this->addSql('ALTER TABLE client ADD menu VARCHAR(255) DEFAULT NULL, DROP menu_id'); + $this->addSql('ALTER TABLE client ADD menu_id INT DEFAULT NULL, ADD hardware_profile_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455CCD7E912 FOREIGN KEY (menu_id) REFERENCES menu (id)'); + $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455CFA495C1 FOREIGN KEY (hardware_profile_id) REFERENCES hardware_profile (id)'); + $this->addSql('CREATE INDEX IDX_C7440455CCD7E912 ON client (menu_id)'); + $this->addSql('CREATE INDEX IDX_C7440455CFA495C1 ON client (hardware_profile_id)'); } public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your needs - $this->addSql('ALTER TABLE client ADD menu_id INT DEFAULT NULL, DROP menu'); - $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455CCD7E912 FOREIGN KEY (menu_id) REFERENCES menu (id)'); - $this->addSql('CREATE INDEX IDX_C7440455CCD7E912 ON client (menu_id)'); + $this->addSql('ALTER TABLE client DROP FOREIGN KEY FK_C7440455CCD7E912'); + $this->addSql('ALTER TABLE client DROP FOREIGN KEY FK_C7440455CFA495C1'); + $this->addSql('DROP INDEX IDX_C7440455CCD7E912 ON client'); + $this->addSql('DROP INDEX IDX_C7440455CFA495C1 ON client'); + $this->addSql('ALTER TABLE client DROP menu_id, DROP hardware_profile_id'); } } diff --git a/src/Dto/Input/ClientInput.php b/src/Dto/Input/ClientInput.php index 6a90ee0..2b124dd 100644 --- a/src/Dto/Input/ClientInput.php +++ b/src/Dto/Input/ClientInput.php @@ -46,14 +46,11 @@ final class ClientInput #[ApiProperty(description: 'The organizational unit of the client')] public ?OrganizationalUnitOutput $organizationalUnit = null; - #[Assert\NotNull] - #[Groups(['client:write', 'client:patch'])] - #[ApiProperty(description: 'The hardware profile of the client')] - public ?HardwareProfileOutput $hardwareProfile = null; + #[Groups(['client:write'])] + public ?MenuOutput $menu = null; #[Groups(['client:write'])] - #[ApiProperty(description: 'The menu of the client')] - public ?MenuOutput $menu = null; + public ?HardwareProfileOutput $hardwareProfile = null; public function __construct(?Client $client = null) { @@ -65,12 +62,18 @@ final class ClientInput $this->serialNumber = $client->getSerialNumber(); $this->netiface = $client->getNetiface(); $this->organizationalUnit = new OrganizationalUnitOutput($client->getOrganizationalUnit()); - $this->hardwareProfile = new HardwareProfileOutput($client->getHardwareProfile()); - $this->menu = new MenuOutput($client->getMenu()); $this->netDriver = $client->getNetDriver(); $this->mac = $client->getMac(); $this->ip = $client->getIp(); $this->status = $client->getStatus(); + + if ($client->getMenu()) { + $this->menu = new MenuOutput($client->getMenu()); + } + + if ($client->getHardwareProfile()) { + $this->hardwareProfile = new HardwareProfileOutput($client->getHardwareProfile()); + } } public function createOrUpdateEntity(?Client $client = null): Client @@ -83,16 +86,12 @@ final class ClientInput $client->setSerialNumber($this->serialNumber); $client->setNetiface($this->netiface); $client->setOrganizationalUnit($this->organizationalUnit->getEntity()); - $client->setHardwareProfile($this->hardwareProfile->getEntity()); - - if ($this->menu) { - $client->setMenu($this->menu->getEntity()); - } - $client->setNetDriver($this->netDriver); $client->setMac($this->mac); $client->setIp($this->ip); $client->setStatus($this->status); + $client->setMenu($this->menu?->getEntity()); + $client->setHardwareProfile($this->hardwareProfile?->getEntity()); return $client; } diff --git a/src/Dto/Input/NetworkSettingsInput.php b/src/Dto/Input/NetworkSettingsInput.php new file mode 100644 index 0000000..ddddc7b --- /dev/null +++ b/src/Dto/Input/NetworkSettingsInput.php @@ -0,0 +1,99 @@ +proxy = $networkSettings->getProxy(); + $this->dns = $networkSettings->getDns(); + $this->netmask = $networkSettings->getNetmask(); + $this->router = $networkSettings->getRouter(); + $this->ntp = $networkSettings->getNtp(); + $this->p2pMode = $networkSettings->getP2pMode(); + $this->p2pTime = $networkSettings->getP2pTime(); + $this->mcastIp = $networkSettings->getMcastIp(); + $this->mcastSpeed = $networkSettings->getMcastSpeed(); + $this->mcastPort = $networkSettings->getMcastPort(); + $this->mcastMode = $networkSettings->getMcastMode(); + $this->menu = $networkSettings->getMenu(); + $this->hardwareProfile = $networkSettings->getHardwareProfile(); + $this->validation = $networkSettings->getValidation(); + } + + public function createOrUpdateEntity(?NetworkSettings $networkSettings = null): NetworkSettings + { + if (!$networkSettings) { + $networkSettings = new NetworkSettings(); + } + + $networkSettings->setProxy($this->proxy); + $networkSettings->setDns($this->dns); + $networkSettings->setNetmask($this->netmask); + $networkSettings->setRouter($this->router); + $networkSettings->setNtp($this->ntp); + $networkSettings->setP2pMode($this->p2pMode); + $networkSettings->setP2pTime($this->p2pTime); + $networkSettings->setMcastIp($this->mcastIp); + $networkSettings->setMcastSpeed($this->mcastSpeed); + $networkSettings->setMcastPort($this->mcastPort); + $networkSettings->setMcastMode($this->mcastMode); + $networkSettings->setMenu($this->menu); + $networkSettings->setHardwareProfile($this->hardwareProfile); + $networkSettings->setValidation($this->validation); + + return $networkSettings; + } +} \ No newline at end of file diff --git a/src/Dto/Input/OrganizationalUnitClassroomGroupInput.php b/src/Dto/Input/OrganizationalUnitClassroomGroupInput.php deleted file mode 100644 index 403fc8a..0000000 --- a/src/Dto/Input/OrganizationalUnitClassroomGroupInput.php +++ /dev/null @@ -1,14 +0,0 @@ -location = $organizationalUnit->getLocation(); - $this->projector = $organizationalUnit->isProjector(); - $this->board = $organizationalUnit->isBoard(); - $this->capacity = $organizationalUnit->getCapacity(); - $this->proxy = $organizationalUnit->getNetworkSettings()->getProxy(); - $this->dns = $organizationalUnit->getNetworkSettings()->getDns(); - $this->netmask = $organizationalUnit->getNetworkSettings()->getNetmask(); - $this->router = $organizationalUnit->getNetworkSettings()->getRouter(); - $this->ntp = $organizationalUnit->getNetworkSettings()->getNtp(); - $this->p2pMode = $organizationalUnit->getNetworkSettings()->getP2pMode(); - $this->p2pTime = $organizationalUnit->getNetworkSettings()->getP2pTime(); - $this->mcastIp = $organizationalUnit->getNetworkSettings()->getMcastIp(); - $this->mcastSpeed = $organizationalUnit->getNetworkSettings()->getMcastSpeed(); - $this->mcastPort = $organizationalUnit->getNetworkSettings()->getMcastPort(); - $this->mcastMode = $organizationalUnit->getNetworkSettings()->getMcastMode(); - } - - public function createOrUpdateEntity( - ?OrganizationalUnit $organizationalUnit = null, - ?EntityManagerInterface $entityManager = null - ): OrganizationalUnit - { - $organizationalUnit = parent::createOrUpdateEntity($organizationalUnit); - - $organizationalUnit->setType(OrganizationalUnitTypes::CLASSROOM); - $organizationalUnit->setLocation($this->location); - $organizationalUnit->setProjector($this->projector); - $organizationalUnit->setBoard($this->board); - $organizationalUnit->setCapacity($this->capacity); - - $networkSettings = new NetworkSettings(); - $networkSettings->setProxy($this->proxy); - $networkSettings->setDns($this->dns); - $networkSettings->setNetmask($this->netmask); - $networkSettings->setRouter($this->router); - $networkSettings->setNtp($this->ntp); - $networkSettings->setP2pMode($this->p2pMode); - $networkSettings->setP2pTime($this->p2pTime); - $networkSettings->setMcastIp($this->mcastIp); - $networkSettings->setMcastSpeed($this->mcastSpeed); - $networkSettings->setMcastPort($this->mcastPort); - $networkSettings->setMcastMode($this->mcastMode); - $entityManager->persist($networkSettings); - - $organizationalUnit->setNetworkSettings($networkSettings); - - return $organizationalUnit; - } -} \ No newline at end of file diff --git a/src/Dto/Input/OrganizationalUnitClientGroupInput.php b/src/Dto/Input/OrganizationalUnitClientGroupInput.php deleted file mode 100644 index 2a4cb3b..0000000 --- a/src/Dto/Input/OrganizationalUnitClientGroupInput.php +++ /dev/null @@ -1,14 +0,0 @@ -description = $organizationalUnit->getDescription(); $this->comments = $organizationalUnit->getComments(); + $this->type = $organizationalUnit->getType(); + if ($organizationalUnit->getNetworkSettings()){ + $this->networkSettings = new NetworkSettingsInput($organizationalUnit->getNetworkSettings()); + } } public function createOrUpdateEntity(?OrganizationalUnit $organizationalUnit = null): OrganizationalUnit @@ -50,6 +60,10 @@ class OrganizationalUnitInput $organizationalUnit->setComments($this->comments); $organizationalUnit->setType($this->type); + if ($this->networkSettings){ + $organizationalUnit->setNetworkSettings($this->networkSettings->createOrUpdateEntity($organizationalUnit->getNetworkSettings())); + } + return $organizationalUnit; } } \ No newline at end of file diff --git a/src/Dto/Input/OrganizationalUnitRootInput.php b/src/Dto/Input/OrganizationalUnitRootInput.php deleted file mode 100644 index b4aa96b..0000000 --- a/src/Dto/Input/OrganizationalUnitRootInput.php +++ /dev/null @@ -1,14 +0,0 @@ -name = $client->getName(); $this->serialNumber = $client->getSerialNumber(); $this->netiface = $client->getNetiface(); + if ($client->getOrganizationalUnit()) { $this->organizationalUnit = new OrganizationalUnitOutput($client->getOrganizationalUnit()); } - if($client->getHardwareProfile()) { - $this->hardwareProfile = new HardwareProfileOutput($client->getHardwareProfile()); - } - if($client->getMenu()) { - $this->menu = new MenuOutput($client->getMenu()); - } - foreach ($client->getPartitions() as $partition) { - $this->partitions[] = new PartitionOutput($partition); - } + $this->partitions = $client->getPartitions()->map( + fn(Partition $partition) => new PartitionOutput($partition) + )->toArray(); + + $this->menu = $client->getMenu() ? new MenuOutput($client->getMenu()) : null; + $this->hardwareProfile = $client->getHardwareProfile() ? new HardwareProfileOutput($client->getHardwareProfile()) : null; $this->createdAt = $client->getCreatedAt(); $this->createdBy = $client->getCreatedBy(); diff --git a/src/Dto/Output/NetworkSettingsOutput.php b/src/Dto/Output/NetworkSettingsOutput.php index b1148b9..6508c6e 100644 --- a/src/Dto/Output/NetworkSettingsOutput.php +++ b/src/Dto/Output/NetworkSettingsOutput.php @@ -2,10 +2,12 @@ namespace App\Dto\Output; +use ApiPlatform\Metadata\Get; use App\Entity\NetworkSettings; use Symfony\Component\Serializer\Annotation\Groups; -final class NetworkSettingsOutput +#[Get(shortName: 'NetworkSettings')] +final class NetworkSettingsOutput extends AbstractOutput { #[Groups(['organizational-unit:read'])] public ?string $proxy = null; @@ -48,6 +50,8 @@ final class NetworkSettingsOutput public function __construct(NetworkSettings $networkSettings) { + parent::__construct($networkSettings); + $this->proxy = $networkSettings->getProxy(); $this->dns = $networkSettings->getDns(); $this->netmask = $networkSettings->getNetmask(); diff --git a/src/Dto/Output/OrganizationalUnitOutput.php b/src/Dto/Output/OrganizationalUnitOutput.php index 3499bdf..5c4b658 100644 --- a/src/Dto/Output/OrganizationalUnitOutput.php +++ b/src/Dto/Output/OrganizationalUnitOutput.php @@ -2,7 +2,9 @@ namespace App\Dto\Output; +use ApiPlatform\Metadata\ApiProperty; use ApiPlatform\Metadata\Get; +use App\Entity\ClientProperties; use App\Entity\OrganizationalUnit; use Symfony\Component\Serializer\Annotation\Groups; @@ -25,9 +27,10 @@ final class OrganizationalUnitOutput extends AbstractOutput public string $path; #[Groups(['organizational-unit:read'])] + #[ApiProperty(readableLink: true)] public ?NetworkSettingsOutput $networkSettings = null; - #[Groups(['user:read'])] + #[Groups(['organizational-unit:read'])] public array $clients = []; #[Groups(['organizational-unit:read'])] diff --git a/src/Dto/Output/PartitionOutput.php b/src/Dto/Output/PartitionOutput.php index 273c4b8..cd5a0d6 100644 --- a/src/Dto/Output/PartitionOutput.php +++ b/src/Dto/Output/PartitionOutput.php @@ -2,12 +2,14 @@ namespace App\Dto\Output; +use ApiPlatform\Metadata\Get; use App\Entity\Partition; use Symfony\Component\Serializer\Annotation\Groups; +#[Get(shortName: 'Partition')] class PartitionOutput extends AbstractOutput { - #[Groups(['partition:read'])] + #[Groups(['partition:read', 'client:read'])] public ?int $diskNumber = null; #[Groups(['partition:read'])] @@ -16,7 +18,7 @@ class PartitionOutput extends AbstractOutput #[Groups(['partition:read'])] public ?string $partitionCode = null; - #[Groups(['partition:read'])] + #[Groups(['partition:read', 'client:read'])] public ?int $size = null; #[Groups(['partition:read'])] @@ -25,12 +27,9 @@ class PartitionOutput extends AbstractOutput #[Groups(['partition:read'])] public ?string $filesystem = null; - #[Groups(['partition:read'])] + #[Groups(['partition:read', 'client:read'])] public ?string $osName = null; - #[Groups(['partition:read'])] - public ?ClientOutput $client = null; - #[Groups(['partition:read'])] public ?int $memoryUsage = null; @@ -45,7 +44,6 @@ class PartitionOutput extends AbstractOutput $this->cacheContent = $partition->getCacheContent(); $this->filesystem = $partition->getFilesystem(); $this->osName = $partition->getOsName(); - $this->client = new ClientOutput($partition->getClient()); $this->memoryUsage = $partition->getMemoryUsage() / 100; } diff --git a/src/Entity/Client.php b/src/Entity/Client.php index 0fc4f47..bd5d162 100644 --- a/src/Entity/Client.php +++ b/src/Entity/Client.php @@ -33,19 +33,18 @@ class Client extends AbstractEntity #[ORM\ManyToOne(inversedBy: 'clients')] private ?OrganizationalUnit $organizationalUnit = null; - #[ORM\ManyToOne(inversedBy: 'clients')] - private ?HardwareProfile $hardwareProfile = null; - - #[ORM\ManyToOne(inversedBy: 'clients')] - #[ORM\Column(nullable: true)] - private ?Menu $menu = null; - /** * @var Collection */ #[ORM\OneToMany(mappedBy: 'client', targetEntity: Partition::class)] private Collection $partitions; + #[ORM\ManyToOne] + private ?Menu $menu = null; + + #[ORM\ManyToOne] + private ?HardwareProfile $hardwareProfile = null; + public function __construct() { parent::__construct(); @@ -136,30 +135,6 @@ class Client extends AbstractEntity return $this; } - public function getHardwareProfile(): ?HardwareProfile - { - return $this->hardwareProfile; - } - - public function setHardwareProfile(?HardwareProfile $hardwareProfile): static - { - $this->hardwareProfile = $hardwareProfile; - - return $this; - } - - public function getMenu(): ?Menu - { - return $this->menu; - } - - public function setMenu(?Menu $menu): static - { - $this->menu = $menu; - - return $this; - } - /** * @return Collection */ @@ -189,4 +164,28 @@ class Client extends AbstractEntity return $this; } + + public function getMenu(): ?Menu + { + return $this->menu; + } + + public function setMenu(?Menu $menu): static + { + $this->menu = $menu; + + return $this; + } + + public function getHardwareProfile(): ?HardwareProfile + { + return $this->hardwareProfile; + } + + public function setHardwareProfile(?HardwareProfile $hardwareProfile): static + { + $this->hardwareProfile = $hardwareProfile; + + return $this; + } } diff --git a/src/Entity/HardwareProfile.php b/src/Entity/HardwareProfile.php index 432eedf..253a7fd 100644 --- a/src/Entity/HardwareProfile.php +++ b/src/Entity/HardwareProfile.php @@ -16,7 +16,7 @@ class HardwareProfile extends AbstractEntity #[ORM\Column(length: 255, nullable: true)] private ?string $comments = null; - #[ORM\ManyToOne(inversedBy: 'hardwareProfiles')] + #[ORM\ManyToOne(targetEntity: OrganizationalUnit::class)] private ?OrganizationalUnit $organizationalUnit = null; /** diff --git a/src/Entity/Menu.php b/src/Entity/Menu.php index a0107cb..53c123a 100644 --- a/src/Entity/Menu.php +++ b/src/Entity/Menu.php @@ -111,7 +111,6 @@ class Menu extends AbstractEntity { if (!$this->clients->contains($client)) { $this->clients->add($client); - $client->setMenu($this); } return $this; diff --git a/src/Entity/NetworkSettings.php b/src/Entity/NetworkSettings.php index c9a0a4c..faf7002 100644 --- a/src/Entity/NetworkSettings.php +++ b/src/Entity/NetworkSettings.php @@ -49,6 +49,17 @@ class NetworkSettings extends AbstractEntity #[ORM\OneToMany(mappedBy: 'networkSettings', targetEntity: OrganizationalUnit::class)] private Collection $organizationalUnits; + #[ORM\ManyToOne(targetEntity: Menu::class)] + #[ORM\JoinColumn(nullable: true)] + private ?Menu $menu = null; + + #[ORM\ManyToOne(targetEntity: HardwareProfile::class)] + #[ORM\JoinColumn(nullable: true)] + private ?HardwareProfile $hardwareProfile = null; + + #[ORM\Column(nullable: true)] + private ?bool $validation = null; + public function __construct() { parent::__construct(); @@ -222,8 +233,39 @@ class NetworkSettings extends AbstractEntity return $this; } - public function __toString(): string + public function getMenu(): ?Menu { - return $this->getId() ? (string) $this->getId() : ''; + return $this->menu; + } + + public function setMenu(?Menu $menu): static + { + $this->menu = $menu; + + return $this; + } + + public function getHardwareProfile(): ?HardwareProfile + { + return $this->hardwareProfile; + } + + public function setHardwareProfile(?HardwareProfile $hardwareProfile): static + { + $this->hardwareProfile = $hardwareProfile; + + return $this; + } + + public function getValidation(): ?bool + { + return $this->validation; + } + + public function setValidation(?bool $validation): static + { + $this->validation = $validation; + + return $this; } } diff --git a/src/Entity/OrganizationalUnit.php b/src/Entity/OrganizationalUnit.php index 6a66d38..4061f28 100644 --- a/src/Entity/OrganizationalUnit.php +++ b/src/Entity/OrganizationalUnit.php @@ -44,7 +44,7 @@ class OrganizationalUnit extends AbstractEntity #[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)] private Collection $organizationalUnits; - #[ORM\ManyToOne(targetEntity: NetworkSettings::class, inversedBy: 'organizationalUnits')] + #[ORM\ManyToOne(targetEntity: NetworkSettings::class, inversedBy: 'organizationalUnits', cascade: ['persist'])] #[ORM\JoinColumn(nullable: true)] private ?NetworkSettings $networkSettings = null; @@ -75,19 +75,12 @@ class OrganizationalUnit extends AbstractEntity #[ORM\Column(nullable: true)] private ?int $capacity = null; - /** - * @var Collection - */ - #[ORM\OneToMany(mappedBy: 'organizationalUnit', targetEntity: HardwareProfile::class)] - private Collection $hardwareProfiles; - public function __construct() { parent::__construct(); $this->organizationalUnits = new ArrayCollection(); $this->users = new ArrayCollection(); $this->clients = new ArrayCollection(); - $this->hardwareProfiles = new ArrayCollection(); } public function getDescription(): ?string @@ -319,34 +312,4 @@ class OrganizationalUnit extends AbstractEntity return $this; } - - /** - * @return Collection - */ - public function getHardwareProfiles(): Collection - { - return $this->hardwareProfiles; - } - - public function addHardwareProfile(HardwareProfile $hardwareProfile): static - { - if (!$this->hardwareProfiles->contains($hardwareProfile)) { - $this->hardwareProfiles->add($hardwareProfile); - $hardwareProfile->setOrganizationalUnit($this); - } - - return $this; - } - - public function removeHardwareProfile(HardwareProfile $hardwareProfile): static - { - if ($this->hardwareProfiles->removeElement($hardwareProfile)) { - // set the owning side to null (unless already changed) - if ($hardwareProfile->getOrganizationalUnit() === $this) { - $hardwareProfile->setOrganizationalUnit(null); - } - } - - return $this; - } } diff --git a/src/Factory/MenuFactory.php b/src/Factory/MenuFactory.php new file mode 100644 index 0000000..e5762ca --- /dev/null +++ b/src/Factory/MenuFactory.php @@ -0,0 +1,60 @@ + + */ +final class MenuFactory extends ModelFactory +{ + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services + * + * @todo inject services if required + */ + public function __construct() + { + parent::__construct(); + } + + public static function class(): string + { + return Menu::class; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories + */ + protected function getDefaults(): array + { + return [ + 'createdAt' => self::faker()->dateTime(), + 'name' => self::faker()->text(255), + 'resolution' => self::faker()->text(255), + 'title' => self::faker()->text(255), + 'updatedAt' => self::faker()->dateTime(), + ]; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization + */ + protected function initialize(): self + { + return $this + // ->afterInstantiate(function(Menu $menu): void {}) + ; + } + + protected static function getClass(): string + { + return Menu::class; + } +} diff --git a/src/Factory/PartitionFactory.php b/src/Factory/PartitionFactory.php new file mode 100644 index 0000000..ba15bc4 --- /dev/null +++ b/src/Factory/PartitionFactory.php @@ -0,0 +1,61 @@ + + */ +final class PartitionFactory extends ModelFactory +{ + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services + * + * @todo inject services if required + */ + public function __construct() + { + parent::__construct(); + } + + public static function class(): string + { + return Partition::class; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories + * + * @todo add your default values here + */ + protected function getDefaults(): array + { + return [ + 'createdAt' => self::faker()->dateTime(), + 'memoryUsage' => self::faker()->randomNumber(), + 'osName' => self::faker()->text(255), + 'size' => self::faker()->randomNumber(), + 'updatedAt' => self::faker()->dateTime() + ]; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization + */ + protected function initialize(): self + { + return $this// ->afterInstantiate(function(Partition $partition): void {}) + ; + } + + protected static function getClass(): string + { + return Partition::class; + } +} diff --git a/src/Repository/ClientPropertiesRepository.php b/src/Repository/ClientPropertiesRepository.php new file mode 100644 index 0000000..294ecef --- /dev/null +++ b/src/Repository/ClientPropertiesRepository.php @@ -0,0 +1,43 @@ + + */ +class ClientPropertiesRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, ClientProperties::class); + } + + // /** + // * @return ClientProperties[] Returns an array of ClientProperties objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('c') + // ->andWhere('c.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('c.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?ClientProperties + // { + // return $this->createQueryBuilder('c') + // ->andWhere('c.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/src/State/Processor/ClientProcessor.php b/src/State/Processor/ClientProcessor.php index c3deba4..06eab7a 100644 --- a/src/State/Processor/ClientProcessor.php +++ b/src/State/Processor/ClientProcessor.php @@ -26,7 +26,7 @@ class ClientProcessor implements ProcessorInterface /** * @throws \Exception */ - public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ClientOutput + public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ClientOutput|null { switch ($operation){ case $operation instanceof Post: diff --git a/src/State/Processor/OrganizationalUnitProcessor.php b/src/State/Processor/OrganizationalUnitProcessor.php index 8238321..889ff72 100644 --- a/src/State/Processor/OrganizationalUnitProcessor.php +++ b/src/State/Processor/OrganizationalUnitProcessor.php @@ -9,6 +9,7 @@ use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Put; use ApiPlatform\State\ProcessorInterface; use ApiPlatform\Validator\ValidatorInterface; +use App\Dto\Input\MenuInput; use App\Dto\Input\OrganizationalUnitClassroomGroupInput; use App\Dto\Input\OrganizationalUnitClassroomInput; use App\Dto\Input\OrganizationalUnitClientGroupInput; @@ -48,16 +49,8 @@ class OrganizationalUnitProcessor implements ProcessorInterface */ private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): OrganizationalUnitOutput { - if (!($data instanceof OrganizationalUnitRootInput) && - !($data instanceof OrganizationalUnitClassroomInput) && - !($data instanceof OrganizationalUnitClientGroupInput) && - !($data instanceof OrganizationalUnitClassroomGroupInput)) { - throw new \Exception(sprintf('data is not an instance of %s, %s, %s, or %s', - OrganizationalUnitRootInput::class, - OrganizationalUnitClassroomInput::class, - OrganizationalUnitInput::class, - OrganizationalUnitClassroomGroupInput::class - )); + if (!($data instanceof OrganizationalUnitInput)) { + throw new \Exception(sprintf('data is not instance of %s', OrganizationalUnitInput::class)); } $entity = null; diff --git a/src/State/Provider/NetworkSettingsProvider.php b/src/State/Provider/NetworkSettingsProvider.php new file mode 100644 index 0000000..5357017 --- /dev/null +++ b/src/State/Provider/NetworkSettingsProvider.php @@ -0,0 +1,61 @@ +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 NetworkSettingsOutput($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('Hardware not found'); + } + + return new NetworkSettingsOutput($item); + } + +} diff --git a/src/State/Provider/OrganizationalUnitProvider.php b/src/State/Provider/OrganizationalUnitProvider.php index b55385e..23703f9 100644 --- a/src/State/Provider/OrganizationalUnitProvider.php +++ b/src/State/Provider/OrganizationalUnitProvider.php @@ -14,6 +14,7 @@ use App\Dto\Input\OrganizationalUnitClassroomInput; use App\Dto\Input\OrganizationalUnitClientGroupInput; use App\Dto\Input\OrganizationalUnitInput; use App\Dto\Input\OrganizationalUnitRootInput; +use App\Dto\Input\PartitionInput; use App\Dto\Input\UserGroupInput; use App\Dto\Output\OrganizationalUnitOutput; use App\Entity\OrganizationalUnit; @@ -67,28 +68,12 @@ class OrganizationalUnitProvider implements ProviderInterface public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null { - $input = null; - if (isset($uriVariables['uuid'])) { $item = $this->itemProvider->provide($operation, $uriVariables, $context); - if ( $item !== null ) { - switch ($item->getType()) { - case OrganizationalUnitTypes::ORGANIZATIONAL_UNIT: - $input = new OrganizationalUnitRootInput($item); - break; - case OrganizationalUnitTypes::CLASSROOMS_GROUP: - $input = new OrganizationalUnitClassroomGroupInput($item); - break; - case OrganizationalUnitTypes::CLIENTS_GROUP: - $input = new OrganizationalUnitClientGroupInput($item); - break; - case OrganizationalUnitTypes::CLASSROOM; - $input = new OrganizationalUnitClassroomInput($item); - } - } - - return $input; + return $item !== null ? new OrganizationalUnitInput($item) : null; } + + return new OrganizationalUnitInput(); } } diff --git a/tests/Functional/ClientTest.php b/tests/Functional/ClientTest.php index eca7cbc..e85ffb6 100644 --- a/tests/Functional/ClientTest.php +++ b/tests/Functional/ClientTest.php @@ -5,6 +5,7 @@ namespace Functional; use App\Entity\Client; use App\Entity\HardwareProfile; use App\Entity\OrganizationalUnit; +use App\Entity\User; use App\Entity\UserGroup; use App\Factory\ClientFactory; use App\Factory\HardwareProfileFactory; @@ -93,11 +94,14 @@ class ClientTest extends AbstractTest * @throws TransportExceptionInterface * @throws ServerExceptionInterface */ - public function testUpdateUserGroup(): void + public function testUpdateClient(): void { UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); - ClientFactory::createOne(['name' => self::CLIENT_UPDATE, 'serialNumber' => '123abc']); + $ou = OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); + $hp = HardwareProfileFactory::createOne(['description' => self::HW_PROFILE]); + + ClientFactory::createOne(['name' => self::CLIENT_UPDATE, 'serialNumber' => '123abc', 'organizationalUnit' => $ou, 'hardwareProfile' => $hp]); $iri = $this->findIriBy(Client::class, ['name' => self::CLIENT_UPDATE]); $this->createClientWithCredentials()->request('PUT', $iri, ['json' => [ @@ -112,4 +116,30 @@ class ClientTest extends AbstractTest 'serialNumber' => '987zyx' ]); } + + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + */ + public function testDeleteClient(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + $ou = OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); + $hp = HardwareProfileFactory::createOne(['description' => self::HW_PROFILE]); + + ClientFactory::createOne(['name' => self::CLIENT_DELETE, 'serialNumber' => '123abc', 'organizationalUnit' => $ou, 'hardwareProfile' => $hp]); + $iri = $this->findIriBy(Client::class, ['name' => self::CLIENT_DELETE]); + + $this->createClientWithCredentials()->request('DELETE', $iri); + $this->assertResponseStatusCodeSame(204); + $this->assertNull( + static::getContainer()->get('doctrine')->getRepository(Client::class)->findOneBy(['name' => self::CLIENT_DELETE]) + ); + } + + } \ No newline at end of file diff --git a/tests/Functional/MenuTest.php b/tests/Functional/MenuTest.php new file mode 100644 index 0000000..4276047 --- /dev/null +++ b/tests/Functional/MenuTest.php @@ -0,0 +1,129 @@ + self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + MenuFactory::createMany(10); + + $this->createClientWithCredentials()->request('GET', '/menus'); + $this->assertResponseStatusCodeSame(Response::HTTP_OK); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/Menu', + '@id' => '/menus', + '@type' => 'hydra:Collection', + 'hydra:totalItems' => 10, + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testCreateMenu(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + $this->createClientWithCredentials()->request('POST', '/menus',['json' => [ + 'name' => self::MENU_CREATE, + 'title' => self::MENU_CREATE, + 'resolution' => "1920x1080", + ]]); + + $this->assertResponseStatusCodeSame(201); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/MenuOutput', + '@type' => 'Menu', + 'name' => self::MENU_CREATE, + 'title' => self::MENU_CREATE, + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testUpdateMenu(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + MenuFactory::createOne(['name' => self::MENU_UPDATE, 'title' => self::MENU_UPDATE, 'resolution' => "1920x1080"]); + $iri = $this->findIriBy(Menu::class, ['name' => self::MENU_UPDATE]); + + $this->createClientWithCredentials()->request('PUT', $iri, ['json' => [ + 'name' => self::MENU_UPDATE, + 'resolution' => '1080x768' + ]]); + + $this->assertResponseIsSuccessful(); + $this->assertJsonContains([ + '@id' => $iri, + 'name' => self::MENU_UPDATE, + 'resolution' => '1080x768' + ]); + } + + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + */ + public function testDeleteMenu(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + MenuFactory::createOne(['name' => self::MENU_DELETE, 'title' => self::MENU_DELETE, 'resolution' => "1920x1080"]); + $iri = $this->findIriBy(Menu::class, ['name' => self::MENU_DELETE]); + + $this->createClientWithCredentials()->request('DELETE', $iri); + $this->assertResponseStatusCodeSame(204); + $this->assertNull( + static::getContainer()->get('doctrine')->getRepository(Menu::class)->findOneBy(['name' => self::MENU_DELETE]) + ); + } +} \ No newline at end of file diff --git a/tests/Functional/OrganizationalUnitTest.php b/tests/Functional/OrganizationalUnitTest.php index eaecd08..899093b 100644 --- a/tests/Functional/OrganizationalUnitTest.php +++ b/tests/Functional/OrganizationalUnitTest.php @@ -56,12 +56,13 @@ class OrganizationalUnitTest extends AbstractTest * @throws TransportExceptionInterface * @throws ServerExceptionInterface */ - public function testCreateOrganizationalUnitRoot(): void + public function testCreateOrganizationalUnit(): void { UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); - $this->createClientWithCredentials()->request('POST', '/organizational-units/root',['json' => [ + $this->createClientWithCredentials()->request('POST', '/organizational-units',['json' => [ 'name' => self::ORGANIZATIONAL_UNIT_CREATE, + 'type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT, ]]); $this->assertResponseStatusCodeSame(201); @@ -74,81 +75,6 @@ class OrganizationalUnitTest extends AbstractTest ]); } - /** - * @throws RedirectionExceptionInterface - * @throws DecodingExceptionInterface - * @throws ClientExceptionInterface - * @throws TransportExceptionInterface - * @throws ServerExceptionInterface - */ - public function testCreateOrganizationalUnitClassroomGroup(): void - { - UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); - - $this->createClientWithCredentials()->request('POST', '/organizational-units/classroom-group',['json' => [ - 'name' => self::ORGANIZATIONAL_UNIT_CREATE, - ]]); - - $this->assertResponseStatusCodeSame(201); - $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); - $this->assertJsonContains([ - '@context' => '/contexts/OrganizationalUnitOutput', - '@type' => 'OrganizationalUnit', - 'name' => self::ORGANIZATIONAL_UNIT_CREATE, - 'type' => OrganizationalUnitTypes::CLASSROOMS_GROUP, - ]); - } - - /** - * @throws RedirectionExceptionInterface - * @throws DecodingExceptionInterface - * @throws ClientExceptionInterface - * @throws TransportExceptionInterface - * @throws ServerExceptionInterface - */ - public function testCreateOrganizationalUnitClassroom(): void - { - UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); - - $this->createClientWithCredentials()->request('POST', '/organizational-units/classroom',['json' => [ - 'name' => self::ORGANIZATIONAL_UNIT_CREATE, - ]]); - - $this->assertResponseStatusCodeSame(201); - $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); - $this->assertJsonContains([ - '@context' => '/contexts/OrganizationalUnitOutput', - '@type' => 'OrganizationalUnit', - 'name' => self::ORGANIZATIONAL_UNIT_CREATE, - 'type' => OrganizationalUnitTypes::CLASSROOM, - ]); - } - - /** - * @throws RedirectionExceptionInterface - * @throws DecodingExceptionInterface - * @throws ClientExceptionInterface - * @throws TransportExceptionInterface - * @throws ServerExceptionInterface - */ - public function testCreateOrganizationalUnitClientGroup(): void - { - UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); - - $this->createClientWithCredentials()->request('POST', '/organizational-units/client-group',['json' => [ - 'name' => self::ORGANIZATIONAL_UNIT_CREATE, - ]]); - - $this->assertResponseStatusCodeSame(201); - $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); - $this->assertJsonContains([ - '@context' => '/contexts/OrganizationalUnitOutput', - '@type' => 'OrganizationalUnit', - 'name' => self::ORGANIZATIONAL_UNIT_CREATE, - 'type' => OrganizationalUnitTypes::CLIENTS_GROUP, - ]); - } - /** * @throws RedirectionExceptionInterface * @throws DecodingExceptionInterface diff --git a/tests/Functional/PartitionTest.php b/tests/Functional/PartitionTest.php new file mode 100644 index 0000000..b4a8a53 --- /dev/null +++ b/tests/Functional/PartitionTest.php @@ -0,0 +1,46 @@ + self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + PartitionFactory::createMany(10); + + $this->createClientWithCredentials()->request('GET', '/partitions'); + $this->assertResponseStatusCodeSame(Response::HTTP_OK); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/Partition', + '@id' => '/partitions', + '@type' => 'hydra:Collection', + 'hydra:totalItems' => 10, + ]); + } +} \ No newline at end of file From 00b37723f6d44211d0b7478a7f07bbd3c082d67e Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Tue, 18 Jun 2024 10:40:35 +0200 Subject: [PATCH 17/35] refs #423. Added ddbb and endpoint OperativeSystem --- config/api_platform/OperativeSystem.yaml | 31 +++++ config/services.yaml | 5 + migrations/Version20240618083013.php | 41 ++++++ src/Dto/Input/OperativeSystemInput.php | 35 ++++++ src/Dto/Output/OperativeSystemOutput.php | 21 ++++ src/Dto/Output/PartitionOutput.php | 1 - src/Entity/Hardware.php | 30 ++--- src/Entity/HardwareType.php | 12 ++ src/Entity/OperativeSystem.php | 12 ++ src/Entity/OperativeSystemType.php | 12 ++ src/Factory/OperativeSystemFactory.php | 58 +++++++++ src/Repository/HardwareTypeRepository.php | 18 +++ src/Repository/OperativeSystemRepository.php | 18 +++ .../OperativeSystemTypeRepository.php | 18 +++ .../Processor/OperativeSystemProcessor.php | 74 +++++++++++ .../Provider/OperativeSystemProvider.php | 76 ++++++++++++ tests/Functional/ClientTest.php | 2 - tests/Functional/OperativeSystemTest.php | 117 ++++++++++++++++++ tests/Functional/PartitionTest.php | 56 ++++++++- 19 files changed, 615 insertions(+), 22 deletions(-) create mode 100644 config/api_platform/OperativeSystem.yaml create mode 100644 migrations/Version20240618083013.php create mode 100644 src/Dto/Input/OperativeSystemInput.php create mode 100644 src/Dto/Output/OperativeSystemOutput.php create mode 100644 src/Entity/HardwareType.php create mode 100644 src/Entity/OperativeSystem.php create mode 100644 src/Entity/OperativeSystemType.php create mode 100644 src/Factory/OperativeSystemFactory.php create mode 100644 src/Repository/HardwareTypeRepository.php create mode 100644 src/Repository/OperativeSystemRepository.php create mode 100644 src/Repository/OperativeSystemTypeRepository.php create mode 100644 src/State/Processor/OperativeSystemProcessor.php create mode 100644 src/State/Provider/OperativeSystemProvider.php create mode 100644 tests/Functional/OperativeSystemTest.php diff --git a/config/api_platform/OperativeSystem.yaml b/config/api_platform/OperativeSystem.yaml new file mode 100644 index 0000000..737c8d0 --- /dev/null +++ b/config/api_platform/OperativeSystem.yaml @@ -0,0 +1,31 @@ +resources: + App\Entity\OperativeSystem: + processor: App\State\Processor\OperativeSystemProcessor + input: App\Dto\Input\OperativeSystemInput + output: App\Dto\Output\OperativeSystemOutput + normalization_context: + groups: ['default', 'operative-system:read'] + denormalization_context: + groups: ['operative-system:write'] + operations: + ApiPlatform\Metadata\GetCollection: + provider: App\State\Provider\OperativeSystemProvider + filters: + - 'api_platform.filter.operative-system.order' + - 'api_platform.filter.operative-system.search' + + ApiPlatform\Metadata\Get: + provider: App\State\Provider\OperativeSystemProvider + ApiPlatform\Metadata\Put: + provider: App\State\Provider\OperativeSystemProvider + ApiPlatform\Metadata\Patch: + provider: App\State\Provider\OperativeSystemProvider + ApiPlatform\Metadata\Post: ~ + ApiPlatform\Metadata\Delete: ~ + +properties: + App\Entity\OperativeSystem: + id: + identifier: false + uuid: + identifier: true \ No newline at end of file diff --git a/config/services.yaml b/config/services.yaml index d495931..dd0d241 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -66,6 +66,11 @@ services: $itemProvider: '@api_platform.doctrine.orm.state.item_provider' App\State\Provider\NetworkSettingsProvider: + bind: + $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' + $itemProvider: '@api_platform.doctrine.orm.state.item_provider' + + App\State\Provider\OperativeSystemProvider: bind: $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' $itemProvider: '@api_platform.doctrine.orm.state.item_provider' \ No newline at end of file diff --git a/migrations/Version20240618083013.php b/migrations/Version20240618083013.php new file mode 100644 index 0000000..df541b8 --- /dev/null +++ b/migrations/Version20240618083013.php @@ -0,0 +1,41 @@ +addSql('CREATE TABLE hardware_type (id INT AUTO_INCREMENT 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, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_2AA5A113D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE operative_system (id INT AUTO_INCREMENT 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, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_E9C44095D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE operative_system_type (id INT AUTO_INCREMENT 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, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_4A13A156D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE hardware ADD type_id INT DEFAULT NULL, DROP type'); + $this->addSql('ALTER TABLE hardware ADD CONSTRAINT FK_FE99E9E0C54C8C93 FOREIGN KEY (type_id) REFERENCES hardware_type (id)'); + $this->addSql('CREATE INDEX IDX_FE99E9E0C54C8C93 ON hardware (type_id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE hardware DROP FOREIGN KEY FK_FE99E9E0C54C8C93'); + $this->addSql('DROP TABLE hardware_type'); + $this->addSql('DROP TABLE operative_system'); + $this->addSql('DROP TABLE operative_system_type'); + $this->addSql('DROP INDEX IDX_FE99E9E0C54C8C93 ON hardware'); + $this->addSql('ALTER TABLE hardware ADD type VARCHAR(255) DEFAULT NULL, DROP type_id'); + } +} diff --git a/src/Dto/Input/OperativeSystemInput.php b/src/Dto/Input/OperativeSystemInput.php new file mode 100644 index 0000000..e08416d --- /dev/null +++ b/src/Dto/Input/OperativeSystemInput.php @@ -0,0 +1,35 @@ +name = $operativeSystem->getName(); + } + + public function createOrUpdateEntity(?OperativeSystem $operativeSystem = null): OperativeSystem + { + if (!$operativeSystem) { + $operativeSystem = new OperativeSystem(); + } + + $operativeSystem->setName($this->name); + + return $operativeSystem; + } + +} \ No newline at end of file diff --git a/src/Dto/Output/OperativeSystemOutput.php b/src/Dto/Output/OperativeSystemOutput.php new file mode 100644 index 0000000..8e9002a --- /dev/null +++ b/src/Dto/Output/OperativeSystemOutput.php @@ -0,0 +1,21 @@ +name = $operativeSystem->getName(); + } +} \ No newline at end of file diff --git a/src/Dto/Output/PartitionOutput.php b/src/Dto/Output/PartitionOutput.php index cd5a0d6..483aab7 100644 --- a/src/Dto/Output/PartitionOutput.php +++ b/src/Dto/Output/PartitionOutput.php @@ -46,5 +46,4 @@ class PartitionOutput extends AbstractOutput $this->osName = $partition->getOsName(); $this->memoryUsage = $partition->getMemoryUsage() / 100; } - } \ No newline at end of file diff --git a/src/Entity/Hardware.php b/src/Entity/Hardware.php index 5a1ba19..50545a2 100644 --- a/src/Entity/Hardware.php +++ b/src/Entity/Hardware.php @@ -15,15 +15,15 @@ class Hardware extends AbstractEntity #[ORM\Column(length: 255, nullable: true)] private ?string $description = null; - #[ORM\Column(length: 255, nullable: true)] - private ?string $type = null; - /** * @var Collection */ #[ORM\ManyToMany(targetEntity: HardwareProfile::class, mappedBy: 'hardwareCollection')] private Collection $hardwareProfiles; + #[ORM\ManyToOne] + private ?HardwareType $type = null; + public function __construct() { parent::__Construct(); @@ -48,18 +48,6 @@ class Hardware extends AbstractEntity return $this; } - public function getType(): ?string - { - return $this->type; - } - - public function setType(?string $type): static - { - $this->type = $type; - - return $this; - } - /** * @return Collection */ @@ -86,4 +74,16 @@ class Hardware extends AbstractEntity return $this; } + + public function getType(): ?HardwareType + { + return $this->type; + } + + public function setType(?HardwareType $type): static + { + $this->type = $type; + + return $this; + } } diff --git a/src/Entity/HardwareType.php b/src/Entity/HardwareType.php new file mode 100644 index 0000000..e0c2260 --- /dev/null +++ b/src/Entity/HardwareType.php @@ -0,0 +1,12 @@ + + */ +final class OperativeSystemFactory extends ModelFactory +{ + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services + */ + public function __construct() + { + parent::__construct(); + } + + public static function class(): string + { + return OperativeSystem::class; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories + * + * @todo add your default values here + */ + protected function getDefaults(): array + { + return [ + 'createdAt' => self::faker()->dateTime(), + 'name' => self::faker()->text(255), + 'updatedAt' => self::faker()->dateTime(), + ]; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization + */ + protected function initialize(): self + { + return $this + // ->afterInstantiate(function(OperativeSystem $operativeSystem): void {}) + ; + } + + protected static function getClass(): string + { + return OperativeSystem::class; + } +} diff --git a/src/Repository/HardwareTypeRepository.php b/src/Repository/HardwareTypeRepository.php new file mode 100644 index 0000000..004e63d --- /dev/null +++ b/src/Repository/HardwareTypeRepository.php @@ -0,0 +1,18 @@ + + */ +class HardwareTypeRepository extends AbstractRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, HardwareType::class); + } +} diff --git a/src/Repository/OperativeSystemRepository.php b/src/Repository/OperativeSystemRepository.php new file mode 100644 index 0000000..793093c --- /dev/null +++ b/src/Repository/OperativeSystemRepository.php @@ -0,0 +1,18 @@ + + */ +class OperativeSystemRepository extends AbstractRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, OperativeSystem::class); + } +} diff --git a/src/Repository/OperativeSystemTypeRepository.php b/src/Repository/OperativeSystemTypeRepository.php new file mode 100644 index 0000000..e776e55 --- /dev/null +++ b/src/Repository/OperativeSystemTypeRepository.php @@ -0,0 +1,18 @@ + + */ +class OperativeSystemTypeRepository extends AbstractRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, OperativeSystemType::class); + } +} diff --git a/src/State/Processor/OperativeSystemProcessor.php b/src/State/Processor/OperativeSystemProcessor.php new file mode 100644 index 0000000..dadd449 --- /dev/null +++ b/src/State/Processor/OperativeSystemProcessor.php @@ -0,0 +1,74 @@ +processCreateOrUpdate($data, $operation, $uriVariables, $context); + case $operation instanceof Delete: + return $this->processDelete($data, $operation, $uriVariables, $context); + } + } + + /** + * @throws \Exception + */ + private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): OperativeSystemOutput + { + if (!($data instanceof OperativeSystemInput)) { + throw new \Exception(sprintf('data is not instance of %s', MenuInput::class)); + } + + $entity = null; + if (isset($uriVariables['uuid'])) { + $entity = $this->operativeSystemRepository->findOneByUuid($uriVariables['uuid']); + } + + $operativeSystem = $data->createOrUpdateEntity($entity); + $this->validator->validate($operativeSystem); + $this->operativeSystemRepository->save($operativeSystem); + + return new OperativeSystemOutput($operativeSystem); + } + + private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null + { + $user = $this->operativeSystemRepository->findOneByUuid($uriVariables['uuid']); + $this->operativeSystemRepository->delete($user); + + return null; + } +} diff --git a/src/State/Provider/OperativeSystemProvider.php b/src/State/Provider/OperativeSystemProvider.php new file mode 100644 index 0000000..6b0535c --- /dev/null +++ b/src/State/Provider/OperativeSystemProvider.php @@ -0,0 +1,76 @@ +provideCollection($operation, $uriVariables, $context); + case $operation instanceof Patch: + case $operation instanceof Put: + return $this->provideInput($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 OperativeSystemOutput($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('Operative system not found'); + } + + return new OperativeSystemOutput($item); + } + + public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + if (isset($uriVariables['uuid'])) { + $item = $this->itemProvider->provide($operation, $uriVariables, $context); + + return $item !== null ? new OperativeSystemInput($item) : null; + } + + return new OperativeSystemInput(); + } +} diff --git a/tests/Functional/ClientTest.php b/tests/Functional/ClientTest.php index e85ffb6..f28429a 100644 --- a/tests/Functional/ClientTest.php +++ b/tests/Functional/ClientTest.php @@ -140,6 +140,4 @@ class ClientTest extends AbstractTest static::getContainer()->get('doctrine')->getRepository(Client::class)->findOneBy(['name' => self::CLIENT_DELETE]) ); } - - } \ No newline at end of file diff --git a/tests/Functional/OperativeSystemTest.php b/tests/Functional/OperativeSystemTest.php new file mode 100644 index 0000000..0a0a3f8 --- /dev/null +++ b/tests/Functional/OperativeSystemTest.php @@ -0,0 +1,117 @@ + self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + OperativeSystemFactory::createMany(10); + + $this->createClientWithCredentials()->request('GET', '/operative-systems'); + $this->assertResponseStatusCodeSame(Response::HTTP_OK); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/OperativeSystem', + '@id' => '/operative-systems', + '@type' => 'hydra:Collection', + 'hydra:totalItems' => 10, + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testCreateOperativeSystem(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + $this->createClientWithCredentials()->request('POST', '/operative-systems',['json' => [ + 'name' => self::OS_CREATE, + ]]); + + $this->assertResponseStatusCodeSame(201); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/OperativeSystemOutput', + '@type' => 'OperativeSystem', + 'name' => self::OS_CREATE + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testUpdateOperativeSystem(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + OperativeSystemFactory::createOne(['name' => self::OS_CREATE]); + $iri = $this->findIriBy(OperativeSystem::class, ['name' => self::OS_CREATE]); + + $this->createClientWithCredentials()->request('PUT', $iri, ['json' => [ + 'name' => self::OS_UPDATE, + ]]); + + $this->assertResponseIsSuccessful(); + $this->assertJsonContains([ + '@id' => $iri, + 'name' => self::OS_UPDATE, + ]); + } + + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + */ + public function testDeleteOperativeSystem(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + OperativeSystemFactory::createOne(['name' => self::OS_DELETE]); + $iri = $this->findIriBy(OperativeSystem::class, ['name' => self::OS_DELETE]); + + $this->createClientWithCredentials()->request('DELETE', $iri); + $this->assertResponseStatusCodeSame(204); + $this->assertNull( + static::getContainer()->get('doctrine')->getRepository(OperativeSystem::class)->findOneBy(['name' => self::OS_DELETE]) + ); + } +} \ No newline at end of file diff --git a/tests/Functional/PartitionTest.php b/tests/Functional/PartitionTest.php index b4a8a53..0265dc6 100644 --- a/tests/Functional/PartitionTest.php +++ b/tests/Functional/PartitionTest.php @@ -2,9 +2,16 @@ namespace Functional; +use App\Entity\Client; +use App\Entity\Menu; +use App\Entity\Partition; +use App\Factory\ClientFactory; +use App\Factory\HardwareProfileFactory; use App\Factory\MenuFactory; +use App\Factory\OrganizationalUnitFactory; use App\Factory\PartitionFactory; use App\Factory\UserFactory; +use App\Model\OrganizationalUnitTypes; use App\Model\UserGroupPermissions; use Symfony\Component\HttpFoundation\Response; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; @@ -16,9 +23,9 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; class PartitionTest extends AbstractTest { CONST string USER_ADMIN = 'ogadmin'; - CONST string PARTITION_CREATE = 'test-partition-create'; - CONST string PARTITION_UPDATE = 'test-partition-update'; - CONST string PARTITION_DELETE = 'test-partition-delete'; + CONST string CLIENT_CREATE = 'test-client-create'; + + const string HW_PROFILE = 'HW Test'; /** * @throws RedirectionExceptionInterface @@ -31,7 +38,12 @@ class PartitionTest extends AbstractTest { UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); - PartitionFactory::createMany(10); + $ou = OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); + $hp = HardwareProfileFactory::createOne(['description' => self::HW_PROFILE]); + + $client = ClientFactory::createOne(['name' => self::CLIENT_CREATE, 'serialNumber' => '123abc', 'organizationalUnit' => $ou, 'hardwareProfile' => $hp]); + + PartitionFactory::createMany(10, ['client' => $client]); $this->createClientWithCredentials()->request('GET', '/partitions'); $this->assertResponseStatusCodeSame(Response::HTTP_OK); @@ -43,4 +55,40 @@ class PartitionTest extends AbstractTest 'hydra:totalItems' => 10, ]); } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testCreatePartition(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + $ou = OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); + $hp = HardwareProfileFactory::createOne(['description' => self::HW_PROFILE]); + + ClientFactory::createOne(['name' => self::CLIENT_CREATE, 'serialNumber' => '123abc', 'organizationalUnit' => $ou, 'hardwareProfile' => $hp]); + $iri = $this->findIriBy(Client::class, ['name' => self::CLIENT_CREATE]); + + $this->createClientWithCredentials()->request('POST', '/partitions',['json' => [ + 'size' => 100, + 'osName' => 'Ubuntu', + 'client' => $iri, + 'memoryUsage' => 100 + ]]); + + $this->assertResponseStatusCodeSame(201); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/PartitionOutput', + '@type' => 'Partition', + 'size' => 100, + 'osName' => 'Ubuntu', + 'memoryUsage' => 100 + ]); + } + } \ No newline at end of file From f746f435e4ded0b4feaaa5bfaeb4f464f6f0553c Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Tue, 18 Jun 2024 16:16:42 +0200 Subject: [PATCH 18/35] refs #425. NetworkSettings validation --- config/api_platform/NetworkSettings.yaml | 18 ------ config/api_platform/OrganizationalUnit.yaml | 3 +- config/services.yaml | 5 -- migrations/Version20240618113629.php | 31 ++++++++++ src/Dto/Input/NetworkSettingsInput.php | 36 ++++++----- src/Dto/Input/OrganizationalUnitInput.php | 7 +++ src/Entity/OrganizationalUnit.php | 3 + ...p => OrganizationalUnitMulticastModes.php} | 6 +- ...des.php => OrganizationalUnitP2PModes.php} | 8 +-- src/Model/OrganizationalUnitTypes.php | 10 +-- src/Model/UserGroupPermissions.php | 13 ++-- src/Repository/NetworkSettingsRepository.php | 27 +------- .../Processor/OrganizationalUnitProcessor.php | 4 +- .../Provider/NetworkSettingsProvider.php | 61 ------------------- ...hp => OrganizationalUnitMulticastMode.php} | 6 +- ...anizationalUnitMulticastModeValidator.php} | 8 +-- ...hp => OrganizationalUnitMulticastPort.php} | 4 +- ...anizationalUnitMulticastPortValidator.php} | 4 +- ...Mode.php => OrganizationalUnitP2PMode.php} | 6 +- ...=> OrganizationalUnitP2PModeValidator.php} | 6 +- .../Constraints/OrganizationalUnitType.php | 28 +++++++++ .../OrganizationalUnitTypeValidator.php | 23 +++++++ 22 files changed, 153 insertions(+), 164 deletions(-) delete mode 100644 config/api_platform/NetworkSettings.yaml create mode 100644 migrations/Version20240618113629.php rename src/Model/{OrganizationalUnitClassroomMulticastModes.php => OrganizationalUnitMulticastModes.php} (76%) rename src/Model/{OrganizationalUnitClassroomP2pModes.php => OrganizationalUnitP2PModes.php} (75%) delete mode 100644 src/State/Provider/NetworkSettingsProvider.php rename src/Validator/Constraints/{OrganizationalUnitClassroomMulticastMode.php => OrganizationalUnitMulticastMode.php} (72%) rename src/Validator/Constraints/{OrganizationalUnitClassroomMulticastModeValidator.php => OrganizationalUnitMulticastModeValidator.php} (59%) rename src/Validator/Constraints/{OrganizationalUnitClassroomMulticastPort.php => OrganizationalUnitMulticastPort.php} (86%) rename src/Validator/Constraints/{OrganizationalUnitClassroomMulticastPortValidator.php => OrganizationalUnitMulticastPortValidator.php} (80%) rename src/Validator/Constraints/{OrganizationalUnitClassroomP2pMode.php => OrganizationalUnitP2PMode.php} (74%) rename src/Validator/Constraints/{OrganizationalUnitClassroomP2pModeValidator.php => OrganizationalUnitP2PModeValidator.php} (65%) create mode 100644 src/Validator/Constraints/OrganizationalUnitType.php create mode 100644 src/Validator/Constraints/OrganizationalUnitTypeValidator.php diff --git a/config/api_platform/NetworkSettings.yaml b/config/api_platform/NetworkSettings.yaml deleted file mode 100644 index e9750bd..0000000 --- a/config/api_platform/NetworkSettings.yaml +++ /dev/null @@ -1,18 +0,0 @@ -resources: - App\Entity\NetworkSettings: - output: App\Dto\Output\NetworkSettingsOutput - operations: - ApiPlatform\Metadata\GetCollection: - provider: App\State\Provider\MenuProvider - filters: - - 'api_platform.filter.menu.order' - - 'api_platform.filter.menu.search' - ApiPlatform\Metadata\Get: - provider: App\State\Provider\MenuProvider - -properties: - App\Entity\NetworkSettings: - id: - identifier: false - uuid: - identifier: true \ No newline at end of file diff --git a/config/api_platform/OrganizationalUnit.yaml b/config/api_platform/OrganizationalUnit.yaml index df86419..f161760 100644 --- a/config/api_platform/OrganizationalUnit.yaml +++ b/config/api_platform/OrganizationalUnit.yaml @@ -7,7 +7,8 @@ resources: groups: ['default', 'organizational-unit:read'] denormalization_context: groups: ['organizational-unit:write'] - + validation_context: + groups: ['organizational-unit:write'] operations: ApiPlatform\Metadata\GetCollection: provider: App\State\Provider\OrganizationalUnitProvider diff --git a/config/services.yaml b/config/services.yaml index dd0d241..e842f55 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -65,11 +65,6 @@ services: $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' $itemProvider: '@api_platform.doctrine.orm.state.item_provider' - App\State\Provider\NetworkSettingsProvider: - bind: - $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' - $itemProvider: '@api_platform.doctrine.orm.state.item_provider' - App\State\Provider\OperativeSystemProvider: bind: $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' diff --git a/migrations/Version20240618113629.php b/migrations/Version20240618113629.php new file mode 100644 index 0000000..c9e1d5a --- /dev/null +++ b/migrations/Version20240618113629.php @@ -0,0 +1,31 @@ +addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_NAME ON organizational_unit (name)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP INDEX UNIQ_IDENTIFIER_NAME ON organizational_unit'); + } +} diff --git a/src/Dto/Input/NetworkSettingsInput.php b/src/Dto/Input/NetworkSettingsInput.php index ddddc7b..7b4c935 100644 --- a/src/Dto/Input/NetworkSettingsInput.php +++ b/src/Dto/Input/NetworkSettingsInput.php @@ -5,50 +5,58 @@ namespace App\Dto\Input; use App\Entity\HardwareProfile; use App\Entity\Menu; use App\Entity\NetworkSettings; +use App\Validator\Constraints\OrganizationalUnitMulticastMode; +use App\Validator\Constraints\OrganizationalUnitMulticastPort; +use App\Validator\Constraints\OrganizationalUnitP2PMode; use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Validator\Constraints as Assert; class NetworkSettingsInput { - #[Groups(['organizational-write:read'])] + #[Groups(['organizational-unit:write'])] public ?string $proxy = null; - #[Groups(['organizational-write:read'])] + #[Groups(['organizational-unit:write'])] public ?string $dns = null; - #[Groups(['organizational-write:read'])] + #[Groups(['organizational-unit:write'])] public ?string $netmask = null; - #[Groups(['organizational-write:read'])] + #[Groups(['organizational-unit:write'])] public ?string $router = null; - #[Groups(['organizational-write:read'])] + #[Groups(['organizational-unit:write'])] public ?string $ntp = null; - #[Groups(['organizational-write:read'])] + #[OrganizationalUnitP2PMode] + #[Groups(['organizational-unit:write'])] public ?string $p2pMode = null; - #[Groups(['organizational-write:read'])] + #[Groups(['organizational-unit:write'])] public ?int $p2pTime = null; - #[Groups(['organizational-write:read'])] + #[Assert\Ip()] + #[Groups(['organizational-unit:write'])] public ?string $mcastIp = null; - #[Groups(['organizational-write:read'])] + #[Groups(['organizational-write:write'])] public ?int $mcastSpeed = null; - #[Groups(['organizational-write:read'])] + #[OrganizationalUnitMulticastPort] + #[Groups(['organizational-unit:write'])] public ?int $mcastPort = null; - #[Groups(['organizational-write:read'])] + #[OrganizationalUnitMulticastMode] + #[Groups(['organizational-unit:write'])] public ?string $mcastMode = null; - #[Groups(['organizational-write:read'])] + #[Groups(['organizational-unit:write'])] public ?Menu $menu = null; - #[Groups(['organizational-write:read'])] + #[Groups(['organizational-unit:write'])] public ?HardwareProfile $hardwareProfile = null; - #[Groups(['organizational-write:read'])] + #[Groups(['organizational-unit:write'])] public ?bool $validation = null; public function __construct(?NetworkSettings $networkSettings = null) diff --git a/src/Dto/Input/OrganizationalUnitInput.php b/src/Dto/Input/OrganizationalUnitInput.php index fead8a3..62d7673 100644 --- a/src/Dto/Input/OrganizationalUnitInput.php +++ b/src/Dto/Input/OrganizationalUnitInput.php @@ -2,8 +2,13 @@ namespace App\Dto\Input; +use ApiPlatform\Metadata\ApiProperty; use App\Dto\Output\OrganizationalUnitOutput; use App\Entity\OrganizationalUnit; +use App\Validator\Constraints\OrganizationalUnitMulticastMode; +use App\Validator\Constraints\OrganizationalUnitMulticastPort; +use App\Validator\Constraints\OrganizationalUnitP2PMode; +use App\Validator\Constraints\OrganizationalUnitType; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; @@ -23,9 +28,11 @@ class OrganizationalUnitInput public ?string $comments = null; #[Groups(['organizational-unit:write'])] + #[OrganizationalUnitType] public ?string $type = null; #[Groups(['organizational-unit:write'])] + #[Assert\Valid()] public ?NetworkSettingsInput $networkSettings = null; public function __construct(?OrganizationalUnit $organizationalUnit = null) diff --git a/src/Entity/OrganizationalUnit.php b/src/Entity/OrganizationalUnit.php index 4061f28..cc20f40 100644 --- a/src/Entity/OrganizationalUnit.php +++ b/src/Entity/OrganizationalUnit.php @@ -7,9 +7,12 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use Gedmo\Tree\Entity\Repository\MaterializedPathRepository; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; #[Gedmo\Tree(type: 'materializedPath')] #[ORM\Entity(repositoryClass: MaterializedPathRepository::class)] +#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_NAME', fields: ['name', 'parent_id'])] +#[UniqueEntity(fields: ['name', 'parent'], message: 'This organizational unit already exists.')] class OrganizationalUnit extends AbstractEntity { use NameableTrait; diff --git a/src/Model/OrganizationalUnitClassroomMulticastModes.php b/src/Model/OrganizationalUnitMulticastModes.php similarity index 76% rename from src/Model/OrganizationalUnitClassroomMulticastModes.php rename to src/Model/OrganizationalUnitMulticastModes.php index 299a4c6..2317771 100644 --- a/src/Model/OrganizationalUnitClassroomMulticastModes.php +++ b/src/Model/OrganizationalUnitMulticastModes.php @@ -2,10 +2,10 @@ namespace App\Model; -final class OrganizationalUnitClassroomMulticastModes +final class OrganizationalUnitMulticastModes { - public const string HALF_DUPLEX = 'half_duplex'; - public const string FULL_DUPLEX = 'full_duplex'; + public const string HALF_DUPLEX = 'half-duplex'; + public const string FULL_DUPLEX = 'full-duplex'; private const array MCAST_MODES = [ self::HALF_DUPLEX => 'Half Duplex', diff --git a/src/Model/OrganizationalUnitClassroomP2pModes.php b/src/Model/OrganizationalUnitP2PModes.php similarity index 75% rename from src/Model/OrganizationalUnitClassroomP2pModes.php rename to src/Model/OrganizationalUnitP2PModes.php index 5ee1581..49d7c0d 100644 --- a/src/Model/OrganizationalUnitClassroomP2pModes.php +++ b/src/Model/OrganizationalUnitP2PModes.php @@ -2,11 +2,11 @@ namespace App\Model; -final class OrganizationalUnitClassroomP2pModes +final class OrganizationalUnitP2PModes { - public const string P2P_MODE_LEECHER = 'p2p_mode_leecher'; - public const string P2P_MODE_PEER = 'p2p_mode_peer'; - public const string P2P_MODE_SEEDER = 'p2p_mode_seeder'; + public const string P2P_MODE_LEECHER = 'p2p-mode-leecher'; + public const string P2P_MODE_PEER = 'p2p-mode-peer'; + public const string P2P_MODE_SEEDER = 'p2p-mode-seeder'; private const array P2P_MODE_NAMES = [ self::P2P_MODE_LEECHER => 'El cliente no comparte mientras descarga la imagen', diff --git a/src/Model/OrganizationalUnitTypes.php b/src/Model/OrganizationalUnitTypes.php index 2472da0..e9ee7c0 100644 --- a/src/Model/OrganizationalUnitTypes.php +++ b/src/Model/OrganizationalUnitTypes.php @@ -4,12 +4,12 @@ namespace App\Model; final class OrganizationalUnitTypes { - public const ORGANIZATIONAL_UNIT = 'ORGANIZATIONAL_UNIT'; - public const CLASSROOMS_GROUP = 'CLASSROOMS_GROUP'; - public const CLASSROOM = 'CLASSROOM'; - public const CLIENTS_GROUP = 'CLIENTS_GROUP'; + public const string ORGANIZATIONAL_UNIT = 'organizational-unit'; + public const string CLASSROOMS_GROUP = 'classrooms-group'; + public const string CLASSROOM = 'classroom'; + public const string CLIENTS_GROUP = 'clients-group'; - private const ORGANIZATIONAL_UNIT_TYPES = [ + private const array ORGANIZATIONAL_UNIT_TYPES = [ self::ORGANIZATIONAL_UNIT => 'Unidad Organizativa', self::CLASSROOMS_GROUP => 'Grupo de aulas', self::CLASSROOM => 'Aula', diff --git a/src/Model/UserGroupPermissions.php b/src/Model/UserGroupPermissions.php index 90a3c9b..26fbb9c 100644 --- a/src/Model/UserGroupPermissions.php +++ b/src/Model/UserGroupPermissions.php @@ -4,14 +4,13 @@ namespace App\Model; final class UserGroupPermissions { - public const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN'; - public const ROLE_ORGANIZATIONAL_UNIT_ADMIN = 'ROLE_ORGANIZATIONAL_UNIT_ADMIN'; - public const ROLE_ORGANIZATIONAL_UNIT_OPERATOR = 'ROLE_ORGANIZATIONAL_UNIT_OPERATOR'; - public const ROLE_ORGANIZATIONAL_UNIT_MINIMAL = 'ROLE_ORGANIZATIONAL_UNIT_MINIMAL'; + public const string ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN'; + public const string ROLE_ORGANIZATIONAL_UNIT_ADMIN = 'ROLE_ORGANIZATIONAL_UNIT_ADMIN'; + public const string ROLE_ORGANIZATIONAL_UNIT_OPERATOR = 'ROLE_ORGANIZATIONAL_UNIT_OPERATOR'; + public const string ROLE_ORGANIZATIONAL_UNIT_MINIMAL = 'ROLE_ORGANIZATIONAL_UNIT_MINIMAL'; + public const string ROLE_USER = 'ROLE_USER'; - public const ROLE_USER = 'ROLE_USER'; - - private const ROLE_NAMES = [ + private const array ROLE_NAMES = [ self::ROLE_SUPER_ADMIN => 'Super Admin', self::ROLE_ORGANIZATIONAL_UNIT_ADMIN => 'Admin de aulas', self::ROLE_ORGANIZATIONAL_UNIT_OPERATOR => 'Operador de aulas', diff --git a/src/Repository/NetworkSettingsRepository.php b/src/Repository/NetworkSettingsRepository.php index 66a3251..0de2908 100644 --- a/src/Repository/NetworkSettingsRepository.php +++ b/src/Repository/NetworkSettingsRepository.php @@ -9,35 +9,10 @@ use Doctrine\Persistence\ManagerRegistry; /** * @extends ServiceEntityRepository */ -class NetworkSettingsRepository extends ServiceEntityRepository +class NetworkSettingsRepository extends AbstractRepository { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, NetworkSettings::class); } - -// /** -// * @return NetworkSettings[] Returns an array of NetworkSettings objects -// */ -// public function findByExampleField($value): array -// { -// return $this->createQueryBuilder('n') -// ->andWhere('n.exampleField = :val') -// ->setParameter('val', $value) -// ->orderBy('n.id', 'ASC') -// ->setMaxResults(10) -// ->getQuery() -// ->getResult() -// ; -// } - -// public function findOneBySomeField($value): ?NetworkSettings -// { -// return $this->createQueryBuilder('n') -// ->andWhere('n.exampleField = :val') -// ->setParameter('val', $value) -// ->getQuery() -// ->getOneOrNullResult() -// ; -// } } diff --git a/src/State/Processor/OrganizationalUnitProcessor.php b/src/State/Processor/OrganizationalUnitProcessor.php index 889ff72..cc93a5a 100644 --- a/src/State/Processor/OrganizationalUnitProcessor.php +++ b/src/State/Processor/OrganizationalUnitProcessor.php @@ -58,8 +58,8 @@ class OrganizationalUnitProcessor implements ProcessorInterface $entity = $this->organizationalUnitRepository->findOneByUuid($uriVariables['uuid']); } - $organizationalUnit = $data->createOrUpdateEntity($entity, $this->entityManager); - $this->validator->validate($organizationalUnit); + $organizationalUnit = $data->createOrUpdateEntity($entity); + $this->validator->validate($organizationalUnit, ['groups' => ['organizational-unit:write']]); $this->organizationalUnitRepository->save($organizationalUnit); return new OrganizationalUnitOutput($organizationalUnit); diff --git a/src/State/Provider/NetworkSettingsProvider.php b/src/State/Provider/NetworkSettingsProvider.php deleted file mode 100644 index 5357017..0000000 --- a/src/State/Provider/NetworkSettingsProvider.php +++ /dev/null @@ -1,61 +0,0 @@ -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 NetworkSettingsOutput($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('Hardware not found'); - } - - return new NetworkSettingsOutput($item); - } - -} diff --git a/src/Validator/Constraints/OrganizationalUnitClassroomMulticastMode.php b/src/Validator/Constraints/OrganizationalUnitMulticastMode.php similarity index 72% rename from src/Validator/Constraints/OrganizationalUnitClassroomMulticastMode.php rename to src/Validator/Constraints/OrganizationalUnitMulticastMode.php index 9ce375a..6121b39 100644 --- a/src/Validator/Constraints/OrganizationalUnitClassroomMulticastMode.php +++ b/src/Validator/Constraints/OrganizationalUnitMulticastMode.php @@ -2,12 +2,12 @@ namespace App\Validator\Constraints; -use App\Model\OrganizationalUnitClassroomMulticastModes; +use App\Model\OrganizationalUnitMulticastModes; use App\Model\UserGroupPermissions; use Symfony\Component\Validator\Constraint; #[\Attribute] -class OrganizationalUnitClassroomMulticastMode extends Constraint +class OrganizationalUnitMulticastMode extends Constraint { private array $modes; public string $message; @@ -16,7 +16,7 @@ class OrganizationalUnitClassroomMulticastMode extends Constraint { parent::__construct($options, $groups, $payload); - $this->modes = OrganizationalUnitClassroomMulticastModes::getMcastModes(); + $this->modes = OrganizationalUnitMulticastModes::getMcastModes(); $this->message = sprintf( 'The multicast mode is not valid. Please use one of the following: %s', implode(', ', $this->modes) diff --git a/src/Validator/Constraints/OrganizationalUnitClassroomMulticastModeValidator.php b/src/Validator/Constraints/OrganizationalUnitMulticastModeValidator.php similarity index 59% rename from src/Validator/Constraints/OrganizationalUnitClassroomMulticastModeValidator.php rename to src/Validator/Constraints/OrganizationalUnitMulticastModeValidator.php index ad1b68e..2d6f2ac 100644 --- a/src/Validator/Constraints/OrganizationalUnitClassroomMulticastModeValidator.php +++ b/src/Validator/Constraints/OrganizationalUnitMulticastModeValidator.php @@ -2,13 +2,13 @@ namespace App\Validator\Constraints; -use App\Model\OrganizationalUnitClassroomMulticastModes; -use App\Model\OrganizationalUnitClassroomP2pModes; +use App\Model\OrganizationalUnitMulticastModes; +use App\Model\OrganizationalUnitP2PModes; use App\Model\UserGroupPermissions; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; -class OrganizationalUnitClassroomMulticastModeValidator extends ConstraintValidator +class OrganizationalUnitMulticastModeValidator extends ConstraintValidator { public function validate($value, Constraint $constraint): void { @@ -16,7 +16,7 @@ class OrganizationalUnitClassroomMulticastModeValidator extends ConstraintValida return; } - if (!in_array($value, OrganizationalUnitClassroomMulticastModes::getMcastModes())) { + if (!in_array($value, OrganizationalUnitMulticastModes::getMcastModes())) { $this->context->buildViolation($constraint->message)->addViolation(); } } diff --git a/src/Validator/Constraints/OrganizationalUnitClassroomMulticastPort.php b/src/Validator/Constraints/OrganizationalUnitMulticastPort.php similarity index 86% rename from src/Validator/Constraints/OrganizationalUnitClassroomMulticastPort.php rename to src/Validator/Constraints/OrganizationalUnitMulticastPort.php index 9d18892..2d0a0ef 100644 --- a/src/Validator/Constraints/OrganizationalUnitClassroomMulticastPort.php +++ b/src/Validator/Constraints/OrganizationalUnitMulticastPort.php @@ -6,7 +6,7 @@ use App\Model\UserGroupPermissions; use Symfony\Component\Validator\Constraint; #[\Attribute] -class OrganizationalUnitClassroomMulticastPort extends Constraint +class OrganizationalUnitMulticastPort extends Constraint { public string $message; @@ -16,6 +16,4 @@ class OrganizationalUnitClassroomMulticastPort extends Constraint $this->message = 'The multicast port is not valid. Please use a number between 9000 and 9050'; } - - } \ No newline at end of file diff --git a/src/Validator/Constraints/OrganizationalUnitClassroomMulticastPortValidator.php b/src/Validator/Constraints/OrganizationalUnitMulticastPortValidator.php similarity index 80% rename from src/Validator/Constraints/OrganizationalUnitClassroomMulticastPortValidator.php rename to src/Validator/Constraints/OrganizationalUnitMulticastPortValidator.php index ef181c5..6baabda 100644 --- a/src/Validator/Constraints/OrganizationalUnitClassroomMulticastPortValidator.php +++ b/src/Validator/Constraints/OrganizationalUnitMulticastPortValidator.php @@ -2,12 +2,12 @@ namespace App\Validator\Constraints; -use App\Model\OrganizationalUnitClassroomP2pModes; +use App\Model\OrganizationalUnitP2PModes; use App\Model\UserGroupPermissions; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; -class OrganizationalUnitClassroomMulticastPortValidator extends ConstraintValidator +class OrganizationalUnitMulticastPortValidator extends ConstraintValidator { CONST int minPort = 9000; CONST int maxPort = 9050; diff --git a/src/Validator/Constraints/OrganizationalUnitClassroomP2pMode.php b/src/Validator/Constraints/OrganizationalUnitP2PMode.php similarity index 74% rename from src/Validator/Constraints/OrganizationalUnitClassroomP2pMode.php rename to src/Validator/Constraints/OrganizationalUnitP2PMode.php index c53c275..45a8663 100644 --- a/src/Validator/Constraints/OrganizationalUnitClassroomP2pMode.php +++ b/src/Validator/Constraints/OrganizationalUnitP2PMode.php @@ -2,12 +2,12 @@ namespace App\Validator\Constraints; -use App\Model\OrganizationalUnitClassroomP2pModes; +use App\Model\OrganizationalUnitP2PModes; use App\Model\UserGroupPermissions; use Symfony\Component\Validator\Constraint; #[\Attribute] -class OrganizationalUnitClassroomP2pMode extends Constraint +class OrganizationalUnitP2PMode extends Constraint { private array $modes; public string $message; @@ -16,7 +16,7 @@ class OrganizationalUnitClassroomP2pMode extends Constraint { parent::__construct($options, $groups, $payload); - $this->modes = OrganizationalUnitClassroomP2pModes::getP2pModes(); + $this->modes = OrganizationalUnitP2PModes::getP2pModes(); $this->message = sprintf( 'The p2p mode is not valid. Please use one of the following: %s', implode(', ', $this->modes) diff --git a/src/Validator/Constraints/OrganizationalUnitClassroomP2pModeValidator.php b/src/Validator/Constraints/OrganizationalUnitP2PModeValidator.php similarity index 65% rename from src/Validator/Constraints/OrganizationalUnitClassroomP2pModeValidator.php rename to src/Validator/Constraints/OrganizationalUnitP2PModeValidator.php index 2f627b6..6138146 100644 --- a/src/Validator/Constraints/OrganizationalUnitClassroomP2pModeValidator.php +++ b/src/Validator/Constraints/OrganizationalUnitP2PModeValidator.php @@ -2,12 +2,12 @@ namespace App\Validator\Constraints; -use App\Model\OrganizationalUnitClassroomP2pModes; +use App\Model\OrganizationalUnitP2PModes; use App\Model\UserGroupPermissions; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; -class OrganizationalUnitClassroomP2pModeValidator extends ConstraintValidator +class OrganizationalUnitP2PModeValidator extends ConstraintValidator { public function validate($value, Constraint $constraint): void { @@ -15,7 +15,7 @@ class OrganizationalUnitClassroomP2pModeValidator extends ConstraintValidator return; } - if (!in_array($value, OrganizationalUnitClassroomP2pModes::getP2pModes())) { + if (!in_array($value, OrganizationalUnitP2PModes::getP2pModes())) { $this->context->buildViolation($constraint->message)->addViolation(); } } diff --git a/src/Validator/Constraints/OrganizationalUnitType.php b/src/Validator/Constraints/OrganizationalUnitType.php new file mode 100644 index 0000000..f412677 --- /dev/null +++ b/src/Validator/Constraints/OrganizationalUnitType.php @@ -0,0 +1,28 @@ +types = OrganizationalUnitTypes::getOrganizationalUnitTypeKeys(); + $this->message = sprintf( + 'The organizational unit type is not valid. Please use one of the following: %s', + implode(', ', $this->types) + ); + } + + +} \ No newline at end of file diff --git a/src/Validator/Constraints/OrganizationalUnitTypeValidator.php b/src/Validator/Constraints/OrganizationalUnitTypeValidator.php new file mode 100644 index 0000000..ded0059 --- /dev/null +++ b/src/Validator/Constraints/OrganizationalUnitTypeValidator.php @@ -0,0 +1,23 @@ +context->buildViolation($constraint->message)->addViolation(); + } + } +} \ No newline at end of file From 579d5284b612a615eb641b9537d5992d0d93d9d8 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Tue, 18 Jun 2024 16:38:14 +0200 Subject: [PATCH 19/35] refs #451. Testing hardwareType --- config/api_platform/HardwareType.yaml | 31 +++++ config/services.yaml | 5 + src/Dto/Input/HardwareInput.php | 8 +- src/Dto/Input/HardwareTypeInput.php | 35 ++++++ src/Dto/Output/HardwareOutput.php | 4 +- src/Dto/Output/HardwareTypeOutput.php | 21 ++++ src/Factory/HardwareTypeFactory.php | 76 ++++++++++++ src/State/Processor/HardwareTypeProcessor.php | 77 ++++++++++++ src/State/Provider/HardwareTypeProvider.php | 78 ++++++++++++ tests/Functional/HardwareTypeTest.php | 117 ++++++++++++++++++ 10 files changed, 446 insertions(+), 6 deletions(-) create mode 100644 config/api_platform/HardwareType.yaml create mode 100644 src/Dto/Input/HardwareTypeInput.php create mode 100644 src/Dto/Output/HardwareTypeOutput.php create mode 100644 src/Factory/HardwareTypeFactory.php create mode 100644 src/State/Processor/HardwareTypeProcessor.php create mode 100644 src/State/Provider/HardwareTypeProvider.php create mode 100644 tests/Functional/HardwareTypeTest.php diff --git a/config/api_platform/HardwareType.yaml b/config/api_platform/HardwareType.yaml new file mode 100644 index 0000000..3223e15 --- /dev/null +++ b/config/api_platform/HardwareType.yaml @@ -0,0 +1,31 @@ +resources: + App\Entity\HardwareType: + processor: App\State\Processor\HardwareTypeProcessor + input: App\Dto\Input\HardwareTypeInput + output: App\Dto\Output\HardwareTypeOutput + normalization_context: + groups: ['default', 'hardware-type:read'] + denormalization_context: + groups: ['hardware-type:write'] + operations: + ApiPlatform\Metadata\GetCollection: + provider: App\State\Provider\HardwareTypeProvider + filters: + - 'api_platform.filter.hardware_type.order' + - 'api_platform.filter.hardware_type.search' + + ApiPlatform\Metadata\Get: + provider: App\State\Provider\HardwareTypeProvider + ApiPlatform\Metadata\Put: + provider: App\State\Provider\HardwareTypeProvider + ApiPlatform\Metadata\Patch: + provider: App\State\Provider\HardwareTypeProvider + ApiPlatform\Metadata\Post: ~ + ApiPlatform\Metadata\Delete: ~ + +properties: + App\Entity\HardwareType: + id: + identifier: false + uuid: + identifier: true \ No newline at end of file diff --git a/config/services.yaml b/config/services.yaml index e842f55..f454029 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -66,6 +66,11 @@ services: $itemProvider: '@api_platform.doctrine.orm.state.item_provider' App\State\Provider\OperativeSystemProvider: + bind: + $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' + $itemProvider: '@api_platform.doctrine.orm.state.item_provider' + + App\State\Provider\HardwareTypeProvider: bind: $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' $itemProvider: '@api_platform.doctrine.orm.state.item_provider' \ No newline at end of file diff --git a/src/Dto/Input/HardwareInput.php b/src/Dto/Input/HardwareInput.php index f46117a..0e41d38 100644 --- a/src/Dto/Input/HardwareInput.php +++ b/src/Dto/Input/HardwareInput.php @@ -3,6 +3,7 @@ namespace App\Dto\Input; use ApiPlatform\Metadata\ApiProperty; +use App\Dto\Output\HardwareTypeOutput; use App\Entity\Hardware; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; @@ -20,8 +21,7 @@ final class HardwareInput #[Groups(['hardware:write'])] #[ApiProperty(description: 'The type of the hardware', example: "Server")] - public ?string $type = null; - + public ?HardwareTypeOutput $type = null; public function __construct(?Hardware $hardware = null) { @@ -31,7 +31,7 @@ final class HardwareInput $this->name = $hardware->getName(); $this->description = $hardware->getDescription(); - $this->type = $hardware->getType(); + $this->type = new HardwareTypeOutput($hardware->getType()); } public function createOrUpdateEntity(?Hardware $hardware = null): Hardware @@ -42,7 +42,7 @@ final class HardwareInput $hardware->setName($this->name); $hardware->setDescription($this->description); - $hardware->setType($this->type); + $hardware->setType($this->type->getEntity()); return $hardware; } diff --git a/src/Dto/Input/HardwareTypeInput.php b/src/Dto/Input/HardwareTypeInput.php new file mode 100644 index 0000000..8279a6f --- /dev/null +++ b/src/Dto/Input/HardwareTypeInput.php @@ -0,0 +1,35 @@ +name = $hardwareType->getName(); + } + + public function createOrUpdateEntity(?HardwareType $hardwareType = null): HardwareType + { + if (!$hardwareType) { + $hardwareType = new HardwareType(); + } + + $hardwareType->setName($this->name); + + return $hardwareType; + } + +} \ No newline at end of file diff --git a/src/Dto/Output/HardwareOutput.php b/src/Dto/Output/HardwareOutput.php index 262cd6d..ae879d1 100644 --- a/src/Dto/Output/HardwareOutput.php +++ b/src/Dto/Output/HardwareOutput.php @@ -16,7 +16,7 @@ final class HardwareOutput extends AbstractOutput public ?string $description = ''; #[Groups(['hardware:read'])] - public ?string $type = ''; + public ?HardwareTypeOutput $type = null; #[Groups(['hardware:read'])] public \DateTime $createAt; @@ -30,7 +30,7 @@ final class HardwareOutput extends AbstractOutput $this->name = $hardware->getName(); $this->description = $hardware->getDescription(); - $this->type = $hardware->getType(); + $this->type = new HardwareTypeOutput($hardware->getType()); $this->createAt = $hardware->getCreatedAt(); $this->createBy = $hardware->getCreatedBy(); } diff --git a/src/Dto/Output/HardwareTypeOutput.php b/src/Dto/Output/HardwareTypeOutput.php new file mode 100644 index 0000000..29516b0 --- /dev/null +++ b/src/Dto/Output/HardwareTypeOutput.php @@ -0,0 +1,21 @@ +name = $hardwareType->getName(); + } +} \ No newline at end of file diff --git a/src/Factory/HardwareTypeFactory.php b/src/Factory/HardwareTypeFactory.php new file mode 100644 index 0000000..b307824 --- /dev/null +++ b/src/Factory/HardwareTypeFactory.php @@ -0,0 +1,76 @@ + + * + * @method HardwareType|Proxy create(array|callable $attributes = []) + * @method static HardwareType|Proxy createOne(array $attributes = []) + * @method static HardwareType|Proxy find(object|array|mixed $criteria) + * @method static HardwareType|Proxy findOrCreate(array $attributes) + * @method static HardwareType|Proxy first(string $sortedField = 'id') + * @method static HardwareType|Proxy last(string $sortedField = 'id') + * @method static HardwareType|Proxy random(array $attributes = []) + * @method static HardwareType|Proxy randomOrCreate(array $attributes = []) + * @method static HardwareTypeRepository|ProxyRepositoryDecorator repository() + * @method static HardwareType[]|Proxy[] all() + * @method static HardwareType[]|Proxy[] createMany(int $number, array|callable $attributes = []) + * @method static HardwareType[]|Proxy[] createSequence(iterable|callable $sequence) + * @method static HardwareType[]|Proxy[] findBy(array $attributes) + * @method static HardwareType[]|Proxy[] randomRange(int $min, int $max, array $attributes = []) + * @method static HardwareType[]|Proxy[] randomSet(int $number, array $attributes = []) + */ +final class HardwareTypeFactory extends ModelFactory +{ + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services + * + * @todo inject services if required + */ + public function __construct() + { + parent::__construct(); + } + + public static function class(): string + { + return HardwareType::class; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories + * + * @todo add your default values here + */ + protected function getDefaults(): array + { + return [ + 'createdAt' => self::faker()->dateTime(), + 'name' => self::faker()->text(255), + 'updatedAt' => self::faker()->dateTime(), + ]; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization + */ + protected function initialize(): self + { + return $this + // ->afterInstantiate(function(HardwareType $hardwareType): void {}) + ; + } + + protected static function getClass(): string + { + return HardwareType::class; + } +} diff --git a/src/State/Processor/HardwareTypeProcessor.php b/src/State/Processor/HardwareTypeProcessor.php new file mode 100644 index 0000000..1da80bb --- /dev/null +++ b/src/State/Processor/HardwareTypeProcessor.php @@ -0,0 +1,77 @@ +processCreateOrUpdate($data, $operation, $uriVariables, $context); + case $operation instanceof Delete: + return $this->processDelete($data, $operation, $uriVariables, $context); + } + } + + /** + * @throws \Exception + */ + private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): HardwareTypeOutput + { + if (!($data instanceof HardwareTypeInput)) { + throw new \Exception(sprintf('data is not instance of %s', MenuInput::class)); + } + + $entity = null; + if (isset($uriVariables['uuid'])) { + $entity = $this->hardwareTypeRepository->findOneByUuid($uriVariables['uuid']); + } + + $hardwareType = $data->createOrUpdateEntity($entity); + $this->validator->validate($hardwareType); + $this->hardwareTypeRepository->save($hardwareType); + + return new HardwareTypeOutput($hardwareType); + } + + private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null + { + $user = $this->hardwareTypeRepository->findOneByUuid($uriVariables['uuid']); + $this->hardwareTypeRepository->delete($user); + + return null; + } +} diff --git a/src/State/Provider/HardwareTypeProvider.php b/src/State/Provider/HardwareTypeProvider.php new file mode 100644 index 0000000..891097d --- /dev/null +++ b/src/State/Provider/HardwareTypeProvider.php @@ -0,0 +1,78 @@ +provideCollection($operation, $uriVariables, $context); + case $operation instanceof Patch: + case $operation instanceof Put: + return $this->provideInput($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 HardwareTypeOutput($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('Operative system not found'); + } + + return new HardwareTypeOutput($item); + } + + public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + if (isset($uriVariables['uuid'])) { + $item = $this->itemProvider->provide($operation, $uriVariables, $context); + + return $item !== null ? new HardwareTypeInput($item) : null; + } + + return new HardwareTypeInput(); + } +} diff --git a/tests/Functional/HardwareTypeTest.php b/tests/Functional/HardwareTypeTest.php new file mode 100644 index 0000000..21526bc --- /dev/null +++ b/tests/Functional/HardwareTypeTest.php @@ -0,0 +1,117 @@ + self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + HardwareTypeFactory::createMany(10); + + $this->createClientWithCredentials()->request('GET', '/hardware-types'); + $this->assertResponseStatusCodeSame(Response::HTTP_OK); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/HardwareType', + '@id' => '/hardware-types', + '@type' => 'hydra:Collection', + 'hydra:totalItems' => 10, + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testCreateHardwareType(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + $this->createClientWithCredentials()->request('POST', '/hardware-types',['json' => [ + 'name' => self::HW_TYPE_CREATE, + ]]); + + $this->assertResponseStatusCodeSame(201); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/HardwareTypeOutput', + '@type' => 'HardwareType', + 'name' => self::HW_TYPE_CREATE + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testUpdateHardwareType(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + HardwareTypeFactory::createOne(['name' => self::HW_TYPE_CREATE]); + $iri = $this->findIriBy(HardwareType::class, ['name' => self::HW_TYPE_CREATE]); + + $this->createClientWithCredentials()->request('PUT', $iri, ['json' => [ + 'name' => self::HW_TYPE_UPDATE, + ]]); + + $this->assertResponseIsSuccessful(); + $this->assertJsonContains([ + '@id' => $iri, + 'name' => self::HW_TYPE_UPDATE, + ]); + } + + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + */ + public function testDeleteHardwareType(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + HardwareTypeFactory::createOne(['name' => self::HW_TYPE_DELETE]); + $iri = $this->findIriBy(HardwareType::class, ['name' => self::HW_TYPE_DELETE]); + + $this->createClientWithCredentials()->request('DELETE', $iri); + $this->assertResponseStatusCodeSame(204); + $this->assertNull( + static::getContainer()->get('doctrine')->getRepository(HardwareType::class)->findOneBy(['name' => self::HW_TYPE_DELETE]) + ); + } +} \ No newline at end of file From f186e9d481168b137959542630a188c1abadf69d Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Wed, 19 Jun 2024 10:49:38 +0200 Subject: [PATCH 20/35] refs #433. FUncionality hierarchy --- migrations/Version20240619083230.php | 33 +++++++++++++++++++ migrations/Version20240619084701.php | 31 +++++++++++++++++ src/Dto/Input/NetworkSettingsInput.php | 32 ++++++++++++++---- src/Dto/Input/OrganizationalUnitInput.php | 21 ++++++++++++ src/Dto/Output/NetworkSettingsOutput.php | 21 +++++++++++- src/Dto/Output/OrganizationalUnitOutput.php | 16 +++++++++ src/Entity/Client.php | 20 +++++++++++ src/Entity/OrganizationalUnit.php | 16 +++++++++ .../ChangeClientNetworkSettingsService.php | 18 ++++++++++ .../Processor/OrganizationalUnitProcessor.php | 10 ++++-- 10 files changed, 208 insertions(+), 10 deletions(-) create mode 100644 migrations/Version20240619083230.php create mode 100644 migrations/Version20240619084701.php create mode 100644 src/Service/ChangeClientNetworkSettingsService.php diff --git a/migrations/Version20240619083230.php b/migrations/Version20240619083230.php new file mode 100644 index 0000000..ea1e30b --- /dev/null +++ b/migrations/Version20240619083230.php @@ -0,0 +1,33 @@ +addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_IP ON client (ip)'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_MAC ON client (mac)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP INDEX UNIQ_IDENTIFIER_IP ON client'); + $this->addSql('DROP INDEX UNIQ_IDENTIFIER_MAC ON client'); + } +} diff --git a/migrations/Version20240619084701.php b/migrations/Version20240619084701.php new file mode 100644 index 0000000..22e781b --- /dev/null +++ b/migrations/Version20240619084701.php @@ -0,0 +1,31 @@ +addSql('ALTER TABLE client ADD validation TINYINT(1) DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE client DROP validation'); + } +} diff --git a/src/Dto/Input/NetworkSettingsInput.php b/src/Dto/Input/NetworkSettingsInput.php index 7b4c935..750f0de 100644 --- a/src/Dto/Input/NetworkSettingsInput.php +++ b/src/Dto/Input/NetworkSettingsInput.php @@ -2,6 +2,8 @@ namespace App\Dto\Input; +use App\Dto\Output\HardwareProfileOutput; +use App\Dto\Output\MenuOutput; use App\Entity\HardwareProfile; use App\Entity\Menu; use App\Entity\NetworkSettings; @@ -16,9 +18,11 @@ class NetworkSettingsInput #[Groups(['organizational-unit:write'])] public ?string $proxy = null; + #[Assert\Ip()] #[Groups(['organizational-unit:write'])] public ?string $dns = null; + #[Assert\Ip()] #[Groups(['organizational-unit:write'])] public ?string $netmask = null; @@ -32,6 +36,7 @@ class NetworkSettingsInput #[Groups(['organizational-unit:write'])] public ?string $p2pMode = null; + #[Assert\GreaterThan(0)] #[Groups(['organizational-unit:write'])] public ?int $p2pTime = null; @@ -39,6 +44,7 @@ class NetworkSettingsInput #[Groups(['organizational-unit:write'])] public ?string $mcastIp = null; + #[Assert\GreaterThan(0)] #[Groups(['organizational-write:write'])] public ?int $mcastSpeed = null; @@ -51,10 +57,10 @@ class NetworkSettingsInput public ?string $mcastMode = null; #[Groups(['organizational-unit:write'])] - public ?Menu $menu = null; + public ?MenuOutput $menu = null; #[Groups(['organizational-unit:write'])] - public ?HardwareProfile $hardwareProfile = null; + public ?HardwareProfileOutput $hardwareProfile = null; #[Groups(['organizational-unit:write'])] public ?bool $validation = null; @@ -76,8 +82,15 @@ class NetworkSettingsInput $this->mcastSpeed = $networkSettings->getMcastSpeed(); $this->mcastPort = $networkSettings->getMcastPort(); $this->mcastMode = $networkSettings->getMcastMode(); - $this->menu = $networkSettings->getMenu(); - $this->hardwareProfile = $networkSettings->getHardwareProfile(); + + if ($networkSettings->getMenu()) { + $this->menu = new MenuOutput($networkSettings->getMenu()); + } + + if ($networkSettings->getHardwareProfile()) { + $this->hardwareProfile = new HardwareProfileOutput($networkSettings->getHardwareProfile()); + } + $this->validation = $networkSettings->getValidation(); } @@ -98,8 +111,15 @@ class NetworkSettingsInput $networkSettings->setMcastSpeed($this->mcastSpeed); $networkSettings->setMcastPort($this->mcastPort); $networkSettings->setMcastMode($this->mcastMode); - $networkSettings->setMenu($this->menu); - $networkSettings->setHardwareProfile($this->hardwareProfile); + + if ($this->menu) { + $networkSettings->setMenu($this->menu->getEntity()); + } + + if ($this->hardwareProfile) { + $networkSettings->setHardwareProfile($this->hardwareProfile->getEntity()); + } + $networkSettings->setValidation($this->validation); return $networkSettings; diff --git a/src/Dto/Input/OrganizationalUnitInput.php b/src/Dto/Input/OrganizationalUnitInput.php index 62d7673..26bf8aa 100644 --- a/src/Dto/Input/OrganizationalUnitInput.php +++ b/src/Dto/Input/OrganizationalUnitInput.php @@ -24,6 +24,19 @@ class OrganizationalUnitInput #[Groups(['organizational-unit:write'])] public ?string $description = null; + #[Groups(['organizational-unit:write'])] + public ?string $location = null; + + #[Groups(['organizational-unit:write'])] + public ?bool $projector = null; + + #[Groups(['organizational-unit:write'])] + public ?bool $board = null; + + #[Assert\GreaterThan(0)] + #[Groups(['organizational-unit:write'])] + public ?int $capacity = null; + #[Groups(['organizational-unit:write'])] public ?string $comments = null; @@ -46,6 +59,10 @@ class OrganizationalUnitInput $this->parent = new OrganizationalUnitOutput($organizationalUnit->getParent()); } $this->description = $organizationalUnit->getDescription(); + $this->location = $organizationalUnit->getLocation(); + $this->projector = $organizationalUnit->isProjector(); + $this->board = $organizationalUnit->isBoard(); + $this->capacity = $organizationalUnit->getCapacity(); $this->comments = $organizationalUnit->getComments(); $this->type = $organizationalUnit->getType(); if ($organizationalUnit->getNetworkSettings()){ @@ -64,6 +81,10 @@ class OrganizationalUnitInput $organizationalUnit->setParent($this->parent->getEntity()); } $organizationalUnit->setDescription($this->description); + $organizationalUnit->setLocation($this->location); + $organizationalUnit->setProjector($this->projector); + $organizationalUnit->setBoard($this->board); + $organizationalUnit->setCapacity($this->capacity); $organizationalUnit->setComments($this->comments); $organizationalUnit->setType($this->type); diff --git a/src/Dto/Output/NetworkSettingsOutput.php b/src/Dto/Output/NetworkSettingsOutput.php index 6508c6e..fa90ca2 100644 --- a/src/Dto/Output/NetworkSettingsOutput.php +++ b/src/Dto/Output/NetworkSettingsOutput.php @@ -9,7 +9,7 @@ use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'NetworkSettings')] final class NetworkSettingsOutput extends AbstractOutput { - #[Groups(['organizational-unit:read'])] + #[Groups(['network-settings:read'])] public ?string $proxy = null; #[Groups(['organizational-unit:read'])] @@ -42,6 +42,15 @@ final class NetworkSettingsOutput extends AbstractOutput #[Groups(['organizational-unit:read'])] public ?string $mcastMode = null; + #[Groups(['organizational-unit:read'])] + public ?MenuOutput $menu = null; + + #[Groups(['organizational-unit:read'])] + public ?HardwareProfileOutput $hardwareProfile = null; + + #[Groups(['organizational-unit:read'])] + public ?bool $validation = null; + #[Groups(['organizational-unit:read'])] public \DateTime $createdAt; @@ -63,6 +72,16 @@ final class NetworkSettingsOutput extends AbstractOutput $this->mcastSpeed = $networkSettings->getMcastSpeed(); $this->mcastPort = $networkSettings->getMcastPort(); $this->mcastMode = $networkSettings->getMcastMode(); + + if ($networkSettings->getMenu()) { + $this->menu = new MenuOutput($networkSettings->getMenu()); + } + + if ($networkSettings->getHardwareProfile()) { + $this->hardwareProfile = new HardwareProfileOutput($networkSettings->getHardwareProfile()); + } + + $this->validation = $networkSettings->getValidation(); $this->createdAt = $networkSettings->getCreatedAt(); $this->createdBy = $networkSettings->getCreatedBy(); } diff --git a/src/Dto/Output/OrganizationalUnitOutput.php b/src/Dto/Output/OrganizationalUnitOutput.php index 5c4b658..3dbc75f 100644 --- a/src/Dto/Output/OrganizationalUnitOutput.php +++ b/src/Dto/Output/OrganizationalUnitOutput.php @@ -17,6 +17,18 @@ final class OrganizationalUnitOutput extends AbstractOutput #[Groups(['organizational-unit:read'])] public ?string $comments = null; + #[Groups(['organizational-unit:read'])] + public ?string $location = null; + + #[Groups(['organizational-unit:read'])] + public ?bool $projector = null; + + #[Groups(['organizational-unit:read'])] + public ?bool $board = null; + + #[Groups(['organizational-unit:read'])] + public ?int $capacity = null; + #[Groups(['organizational-unit:read'])] public string $type; @@ -45,6 +57,10 @@ final class OrganizationalUnitOutput extends AbstractOutput $this->name = $organizationalUnit->getName(); $this->comments = $organizationalUnit->getComments(); + $this->location = $organizationalUnit->getLocation(); + $this->projector = $organizationalUnit->isProjector(); + $this->board = $organizationalUnit->isBoard(); + $this->capacity = $organizationalUnit->getCapacity(); $this->type = $organizationalUnit->getType(); $this->networkSettings = $organizationalUnit->getNetworkSettings() ? new NetworkSettingsOutput($organizationalUnit->getNetworkSettings()) : null; $this->clients = $organizationalUnit->getClients()->toArray(); diff --git a/src/Entity/Client.php b/src/Entity/Client.php index bd5d162..16dfc1a 100644 --- a/src/Entity/Client.php +++ b/src/Entity/Client.php @@ -6,8 +6,13 @@ use App\Repository\ClientRepository; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; #[ORM\Entity(repositoryClass: ClientRepository::class)] +#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_IP', fields: ['ip'])] +#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_MAC', fields: ['mac'])] +#[UniqueEntity(fields: ['ip'], message: 'This IP address is already in use.')] +#[UniqueEntity(fields: ['mac'], message: 'This MAC address is already in use.')] class Client extends AbstractEntity { use NameableTrait; @@ -45,6 +50,9 @@ class Client extends AbstractEntity #[ORM\ManyToOne] private ?HardwareProfile $hardwareProfile = null; + #[ORM\Column(nullable: true)] + private ?bool $validation = null; + public function __construct() { parent::__construct(); @@ -188,4 +196,16 @@ class Client extends AbstractEntity return $this; } + + public function getValidation(): ?bool + { + return $this->validation; + } + + public function setValidation(?bool $validation): static + { + $this->validation = $validation; + + return $this; + } } diff --git a/src/Entity/OrganizationalUnit.php b/src/Entity/OrganizationalUnit.php index cc20f40..583687a 100644 --- a/src/Entity/OrganizationalUnit.php +++ b/src/Entity/OrganizationalUnit.php @@ -315,4 +315,20 @@ class OrganizationalUnit extends AbstractEntity return $this; } + + public function updateNetworkSettingsRecursively(?NetworkSettings $networkSettings): void + { + $this->setNetworkSettings($networkSettings); + + /** @var Client $client */ + foreach ($this->getClients() as $client) { + $client->setMenu($networkSettings->getMenu()); + $client->setHardwareProfile($networkSettings->getHardwareProfile()); + $client->setValidation($networkSettings->getValidation()); + } + + foreach ($this->getOrganizationalUnits() as $childUnit) { + $childUnit->updateNetworkSettingsRecursively($networkSettings); + } + } } diff --git a/src/Service/ChangeClientNetworkSettingsService.php b/src/Service/ChangeClientNetworkSettingsService.php new file mode 100644 index 0000000..8dac16e --- /dev/null +++ b/src/Service/ChangeClientNetworkSettingsService.php @@ -0,0 +1,18 @@ +updateNetworkSettingsRecursively($organizationalUnit->GetNetworkSettings()); + } +} \ No newline at end of file diff --git a/src/State/Processor/OrganizationalUnitProcessor.php b/src/State/Processor/OrganizationalUnitProcessor.php index cc93a5a..41d3974 100644 --- a/src/State/Processor/OrganizationalUnitProcessor.php +++ b/src/State/Processor/OrganizationalUnitProcessor.php @@ -9,6 +9,7 @@ use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Put; use ApiPlatform\State\ProcessorInterface; use ApiPlatform\Validator\ValidatorInterface; +use App\Dto\Input\ChangeOrganizationalUnitInput; use App\Dto\Input\MenuInput; use App\Dto\Input\OrganizationalUnitClassroomGroupInput; use App\Dto\Input\OrganizationalUnitClassroomInput; @@ -17,14 +18,15 @@ use App\Dto\Input\OrganizationalUnitInput; use App\Dto\Input\OrganizationalUnitRootInput; use App\Dto\Output\OrganizationalUnitOutput; use App\Repository\OrganizationalUnitRepository; +use App\Service\ChangeClientNetworkSettingsService; use Doctrine\ORM\EntityManagerInterface; class OrganizationalUnitProcessor implements ProcessorInterface { public function __construct( - private readonly OrganizationalUnitRepository $organizationalUnitRepository, - private readonly ValidatorInterface $validator, - private readonly EntityManagerInterface $entityManager + private readonly OrganizationalUnitRepository $organizationalUnitRepository, + private readonly ValidatorInterface $validator, + private readonly ChangeClientNetworkSettingsService $changeClientNetworkSettingsService, ) { } @@ -62,6 +64,8 @@ class OrganizationalUnitProcessor implements ProcessorInterface $this->validator->validate($organizationalUnit, ['groups' => ['organizational-unit:write']]); $this->organizationalUnitRepository->save($organizationalUnit); + $this->changeClientNetworkSettingsService->__invoke($organizationalUnit); + return new OrganizationalUnitOutput($organizationalUnit); } From 1bd85c848ed6895ce99239fb68577033bceff6ef Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Wed, 19 Jun 2024 15:30:50 +0200 Subject: [PATCH 21/35] refs #451. Testing Operative System --- README.md | 2 +- migrations/Version20240619104206.php | 35 ++++++++ ...grateHardwareAndHardwareProfileCommand.php | 85 ++++++++++++++++++- .../MigrateOperativeSystemCommand.php | 59 +++++++++++++ src/Dto/Input/PartitionInput.php | 7 +- src/Dto/Output/HardwareOutput.php | 10 ++- src/Dto/Output/HardwareProfileOutput.php | 10 +++ src/Dto/Output/PartitionOutput.php | 6 +- src/Entity/OperativeSystem.php | 44 ++++++++++ src/Entity/Partition.php | 30 +++---- src/Factory/OperativeSystemTypeFactory.php | 60 +++++++++++++ src/Factory/PartitionFactory.php | 1 - tests/Functional/PartitionTest.php | 9 +- 13 files changed, 329 insertions(+), 29 deletions(-) create mode 100644 migrations/Version20240619104206.php create mode 100644 src/Command/Migration/MigrateOperativeSystemCommand.php create mode 100644 src/Factory/OperativeSystemTypeFactory.php diff --git a/README.md b/README.md index c74951d..df885a9 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,6 @@ Una vez tengamos la base de datos cargada, podremos ejecutar las migraciones de --- Migraciones de OpenGnsys. --- docker exec ogcore-php php bin/console opengnsys:migration:organizational-unit #cargamos las unidades organizativas docker exec ogcore-php php bin/console opengnsys:migrate-hardware-profiles #cargamos los perfiles de hardware -docker exec ogcore-php php bin/console pengnsys:migration:clients #cargamos los clientes +docker exec ogcore-php php bin/console opengnsys:migration:clients #cargamos los clientes ``` diff --git a/migrations/Version20240619104206.php b/migrations/Version20240619104206.php new file mode 100644 index 0000000..d4654c9 --- /dev/null +++ b/migrations/Version20240619104206.php @@ -0,0 +1,35 @@ +addSql('ALTER TABLE `partition` ADD operative_system_id INT DEFAULT NULL, DROP os_name'); + $this->addSql('ALTER TABLE `partition` ADD CONSTRAINT FK_9EB910E4F1E9F66E FOREIGN KEY (operative_system_id) REFERENCES operative_system (id)'); + $this->addSql('CREATE INDEX IDX_9EB910E4F1E9F66E ON `partition` (operative_system_id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE `partition` DROP FOREIGN KEY FK_9EB910E4F1E9F66E'); + $this->addSql('DROP INDEX IDX_9EB910E4F1E9F66E ON `partition`'); + $this->addSql('ALTER TABLE `partition` ADD os_name VARCHAR(255) NOT NULL, DROP operative_system_id'); + } +} diff --git a/src/Command/Migration/MigrateHardwareAndHardwareProfileCommand.php b/src/Command/Migration/MigrateHardwareAndHardwareProfileCommand.php index 890f0fd..9ae4946 100644 --- a/src/Command/Migration/MigrateHardwareAndHardwareProfileCommand.php +++ b/src/Command/Migration/MigrateHardwareAndHardwareProfileCommand.php @@ -2,7 +2,9 @@ namespace App\Command\Migration; +use App\Entity\Hardware; use App\Entity\HardwareProfile; +use App\Entity\HardwareType; use App\Entity\OrganizationalUnit; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query\ResultSetMapping; @@ -31,8 +33,68 @@ class MigrateHardwareAndHardwareProfileCommand extends Command $organizationalUnitRepository = $this->entityManager->getRepository(OrganizationalUnit::class); $hardwareProfileRepository = $this->entityManager->getRepository(HardwareProfile::class); + $hardwareTypeRepository = $this->entityManager->getRepository(HardwareType::class); + $hardwareRepository = $this->entityManager->getRepository(Hardware::class); - /** Obtener los centros de la base de datos antigua **/ + /** Obtener los perfiles hardware de la base de datos antigua **/ + $rsmHardwareTypes = new ResultSetMapping(); + $rsmHardwareTypes->addScalarResult('idtipohardware', 'idtipohardware'); + $rsmHardwareTypes->addScalarResult('descripcion', 'descripcion'); + + $hardwareTypesQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idtipohardware, descripcion FROM tipohardwares', $rsmHardwareTypes); + $hardwareTypes = $hardwareTypesQuery->getResult(); + + $output->writeln("TIPOS HARDWARE TOTAL: ". count($hardwareTypes)); + foreach ($hardwareTypes as $hardwareType){ + $hardwareProfileEntity = null; + $hardwareProfileEntity = $hardwareTypeRepository->findOneBy(['migrationId' => $hardwareType['idtipohardware']]); + if(!$hardwareProfileEntity){ + $hardwareProfileEntity = new HardwareType(); + $hardwareProfileEntity->setMigrationId($hardwareType['idtipohardware']); + $hardwareProfileEntity->setName($hardwareType['descripcion']); + } + + $this->entityManager->persist($hardwareProfileEntity); + } + + /** Obtener los hardware de la base de datos antigua **/ + $rsmHardware = new ResultSetMapping(); + $rsmHardware->addScalarResult('idhardware', 'idhardware'); + $rsmHardware->addScalarResult('idtipohardware', 'hardwares.idtipohardware'); + $rsmHardware->addScalarResult('descripcion', 'descripcion'); + $rsmHardware->addScalarResult('grupoid', 'hardwares.grupoid'); + $rsmHardware->addScalarResult('idcentro', 'hardwares.idcentro'); + + $hardwareQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idhardware, hardwares.idtipohardware, hardwares.descripcion, hardwares.grupoid, hardwares.idcentro FROM hardwares LEFT JOIN tipohardwares ON hardwares.idtipohardware = tipohardwares.idtipohardware', $rsmHardware); + $hardwareCollection = $hardwareQuery->getResult(); + + $output->writeln("HARDWARE TOTAL: ". count($hardwareCollection)); + foreach ($hardwareCollection as $hardware){ + $hardwareEntity = null; + $hardwareEntity = $hardwareRepository->findOneBy(['migrationId' => $hardware['idhardware']]); + if(!$hardwareEntity){ + $hardwareEntity = new Hardware(); + $hardwareEntity->setMigrationId($hardware['idhardware']); + $hardwareEntity->setDescription($hardware['descripcion']); + $hardwareEntity->setName($hardware['descripcion']); + } + + $hardwareType = $hardwareTypeRepository->findOneBy(['migrationId' => $hardware['hardwares.idtipohardware']]); + if ($hardwareType){ + $hardwareEntity->setType($hardwareType); + } + + $migrationId = $hardware['hardwares.grupoid'] === 0 ? $hardware['hardwares.idcentro'] : $hardware['hardwares.grupoid']; + $organizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $migrationId]); + + if ($organizationalUnit){ + $hardwareEntity->setOrganizationalUnit($organizationalUnit); + } + + $this->entityManager->persist($hardwareEntity); + } + + /** Obtener los perfiles hardware de la base de datos antigua **/ $rsmHardwareProfiles = new ResultSetMapping(); $rsmHardwareProfiles->addScalarResult('idperfilhard', 'idperfilhard'); $rsmHardwareProfiles->addScalarResult('descripcion', 'descripcion'); @@ -64,6 +126,27 @@ class MigrateHardwareAndHardwareProfileCommand extends Command $this->entityManager->persist($hardwareProfileEntity); } + + /** Obtener los hardware, y asignarselos a los perfiles hardware **/ + $rsmHardwareProfilesRelation = new ResultSetMapping(); + $rsmHardwareProfilesRelation->addScalarResult('idperfilhard', 'idperfilhard'); + $rsmHardwareProfilesRelation->addScalarResult('idhardware', 'idhardware'); + + $hardwareProfilesQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idperfilhard, idhardware FROM perfileshard_hardwares', $rsmHardwareProfilesRelation); + $hardwareProfileRelations = $hardwareProfilesQuery->getResult(); + + $output->writeln("PERFILES HARDWARE RELACIONES TOTAL: ". count($hardwareProfileRelations)); + foreach ($hardwareProfileRelations as $hardwareProfileRelation){ + $hardwareProfileEntity = $hardwareProfileRepository->findOneBy(['migrationId' => $hardwareProfileRelation['idperfilhard']]); + $hardwareEntity = $hardwareRepository->findOneBy(['migrationId' => $hardwareProfileRelation['idhardware']]); + + if ($hardwareProfileEntity && $hardwareEntity){ + $hardwareProfileEntity->addHardwareCollection($hardwareEntity); + } + $this->entityManager->persist($hardwareProfileEntity); + } + + $this->entityManager->flush(); return Command::SUCCESS; diff --git a/src/Command/Migration/MigrateOperativeSystemCommand.php b/src/Command/Migration/MigrateOperativeSystemCommand.php new file mode 100644 index 0000000..4fec7a6 --- /dev/null +++ b/src/Command/Migration/MigrateOperativeSystemCommand.php @@ -0,0 +1,59 @@ +doctrine->getManager('og_1'); + + $osRepository = $this->entityManager->getRepository(OperativeSystem::class); + + /** Obtener los sistemas operativos de la base de datos antigua **/ + $rsmOperativeSystems = new ResultSetMapping(); + $rsmOperativeSystems->addScalarResult('idnombreso', 'idnombreso'); + $rsmOperativeSystems->addScalarResult('nombreso', 'nombreso'); + + $operativeSystemQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idnombreso, nombreso FROM nombresos', $rsmOperativeSystems); + $opeativeSystems = $operativeSystemQuery->getResult(); + + /** Sistemas operativos **/ + $output->writeln("SISTEMAS OPERATIVOS TOTAL: ". count($opeativeSystems)); + foreach ($opeativeSystems as $client){ + $osEntity = $osRepository->findOneBy(['migrationId' => $client['idnombreso']]); + if(!$osEntity) { + $osEntity = new OperativeSystem(); + $osEntity->setMigrationId($client['idnombreso']); + $osEntity->setName($client['nombreso']); + } + + $this->entityManager->persist($osEntity); + } + $this->entityManager->flush(); + + return Command::SUCCESS; + } +} \ No newline at end of file diff --git a/src/Dto/Input/PartitionInput.php b/src/Dto/Input/PartitionInput.php index b4da4ed..03d633a 100644 --- a/src/Dto/Input/PartitionInput.php +++ b/src/Dto/Input/PartitionInput.php @@ -4,6 +4,7 @@ namespace App\Dto\Input; use ApiPlatform\Metadata\ApiProperty; use App\Dto\Output\ClientOutput; +use App\Dto\Output\OperativeSystemOutput; use App\Dto\Output\OrganizationalUnitOutput; use App\Entity\HardwareProfile; use App\Entity\Menu; @@ -41,7 +42,7 @@ final class PartitionInput #[Assert\NotNull()] #[Groups(['partition:write'])] #[ApiProperty(description: 'The operative system name of the partition', example: "Ubuntu")] - public ?string $osName = null; + public ?OperativeSystemOutput $operativeSystem = null; #[Assert\NotNull()] #[Groups(['partition:write'])] @@ -65,7 +66,7 @@ final class PartitionInput $this->size = $partition->getSize(); $this->cacheContent = $partition->getCacheContent(); $this->filesystem = $partition->getFilesystem(); - $this->osName = $partition->getOsName(); + $this->operativeSystem = new OperativeSystemOutput($partition->getOperativeSystem()); $this->client = new ClientOutput($partition->getClient()); $this->memoryUsage = $partition->getMemoryUsage(); } @@ -82,7 +83,7 @@ final class PartitionInput $partition->setSize($this->size * 100); $partition->setCacheContent($this->cacheContent); $partition->setFilesystem($this->filesystem); - $partition->setOsName($this->osName); + $partition->setOperativeSystem($this->operativeSystem->getEntity()); $partition->setClient($this->client->getEntity()); $partition->setMemoryUsage($this->memoryUsage * 100); diff --git a/src/Dto/Output/HardwareOutput.php b/src/Dto/Output/HardwareOutput.php index ae879d1..1c0e0b8 100644 --- a/src/Dto/Output/HardwareOutput.php +++ b/src/Dto/Output/HardwareOutput.php @@ -2,6 +2,7 @@ namespace App\Dto\Output; +use ApiPlatform\Metadata\ApiProperty; use ApiPlatform\Metadata\Get; use App\Entity\Hardware; use Symfony\Component\Serializer\Annotation\Groups; @@ -16,13 +17,14 @@ final class HardwareOutput extends AbstractOutput public ?string $description = ''; #[Groups(['hardware:read'])] + #[ApiProperty(readableLink: true)] public ?HardwareTypeOutput $type = null; #[Groups(['hardware:read'])] - public \DateTime $createAt; + public \DateTime $createdAt; #[Groups(['hardware:read'])] - public ?string $createBy = null; + public ?string $createdBy = null; public function __construct(Hardware $hardware) { @@ -31,7 +33,7 @@ final class HardwareOutput extends AbstractOutput $this->name = $hardware->getName(); $this->description = $hardware->getDescription(); $this->type = new HardwareTypeOutput($hardware->getType()); - $this->createAt = $hardware->getCreatedAt(); - $this->createBy = $hardware->getCreatedBy(); + $this->createdAt = $hardware->getCreatedAt(); + $this->createdBy = $hardware->getCreatedBy(); } } \ No newline at end of file diff --git a/src/Dto/Output/HardwareProfileOutput.php b/src/Dto/Output/HardwareProfileOutput.php index 66a91ce..a0a8cac 100644 --- a/src/Dto/Output/HardwareProfileOutput.php +++ b/src/Dto/Output/HardwareProfileOutput.php @@ -2,7 +2,9 @@ namespace App\Dto\Output; +use ApiPlatform\Metadata\ApiProperty; use ApiPlatform\Metadata\Get; +use App\Entity\Hardware; use App\Entity\HardwareProfile; use Symfony\Component\Serializer\Annotation\Groups; @@ -18,6 +20,9 @@ final class HardwareProfileOutput extends AbstractOutput #[Groups(['hardware-profile:read'])] public ?OrganizationalUnitOutput $organizationalUnit = null; + #[Groups(['hardware-profile:read'])] + public ?array $hardwareCollection = []; + #[Groups(['hardware-profile:read'])] public \DateTime $createdAt; @@ -33,6 +38,11 @@ final class HardwareProfileOutput extends AbstractOutput if($hardwareProfile->getOrganizationalUnit()) { $this->organizationalUnit = new OrganizationalUnitOutput($hardwareProfile->getOrganizationalUnit()); } + + $this->hardwareCollection = $hardwareProfile->getHardwareCollection()->map( + fn(Hardware $hardware) => new HardwareOutput($hardware) + )->toArray(); + $this->createdAt = $hardwareProfile->getCreatedAt(); $this->createdBy = $hardwareProfile->getCreatedBy(); } diff --git a/src/Dto/Output/PartitionOutput.php b/src/Dto/Output/PartitionOutput.php index 483aab7..f6eaadf 100644 --- a/src/Dto/Output/PartitionOutput.php +++ b/src/Dto/Output/PartitionOutput.php @@ -28,7 +28,7 @@ class PartitionOutput extends AbstractOutput public ?string $filesystem = null; #[Groups(['partition:read', 'client:read'])] - public ?string $osName = null; + public ?OperativeSystemOutput $operativeSystem = null; #[Groups(['partition:read'])] public ?int $memoryUsage = null; @@ -43,7 +43,9 @@ class PartitionOutput extends AbstractOutput $this->size = $partition->getSize() / 100; $this->cacheContent = $partition->getCacheContent(); $this->filesystem = $partition->getFilesystem(); - $this->osName = $partition->getOsName(); + if ($partition->getOperativeSystem()) { + $this->operativeSystem = new OperativeSystemOutput($partition->getOperativeSystem()); + } $this->memoryUsage = $partition->getMemoryUsage() / 100; } } \ No newline at end of file diff --git a/src/Entity/OperativeSystem.php b/src/Entity/OperativeSystem.php index 063fa5a..1f197fd 100644 --- a/src/Entity/OperativeSystem.php +++ b/src/Entity/OperativeSystem.php @@ -3,10 +3,54 @@ namespace App\Entity; use App\Repository\OperativeSystemRepository; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: OperativeSystemRepository::class)] class OperativeSystem extends AbstractEntity { use NameableTrait; + + /** + * @var Collection + */ + #[ORM\OneToMany(mappedBy: 'operativeSystem', targetEntity: Partition::class)] + private Collection $partitions; + + public function __construct() + { + parent::__construct(); + $this->partitions = new ArrayCollection(); + } + + /** + * @return Collection + */ + public function getPartitions(): Collection + { + return $this->partitions; + } + + public function addPartition(Partition $partition): static + { + if (!$this->partitions->contains($partition)) { + $this->partitions->add($partition); + $partition->setOperativeSystem($this); + } + + return $this; + } + + public function removePartition(Partition $partition): static + { + if ($this->partitions->removeElement($partition)) { + // set the owning side to null (unless already changed) + if ($partition->getOperativeSystem() === $this) { + $partition->setOperativeSystem(null); + } + } + + return $this; + } } diff --git a/src/Entity/Partition.php b/src/Entity/Partition.php index 316eb28..c7af2c1 100644 --- a/src/Entity/Partition.php +++ b/src/Entity/Partition.php @@ -27,15 +27,15 @@ class Partition extends AbstractEntity #[ORM\Column(length: 255, nullable: true)] private ?string $filesystem = null; - #[ORM\Column(length: 255)] - private ?string $osName = null; - #[ORM\ManyToOne(inversedBy: 'partitions')] private ?Client $client = null; #[ORM\Column] private ?int $memoryUsage = null; + #[ORM\ManyToOne(inversedBy: 'partitions')] + private ?OperativeSystem $operativeSystem = null; + public function getDiskNumber(): ?int { return $this->diskNumber; @@ -108,18 +108,6 @@ class Partition extends AbstractEntity return $this; } - public function getOsName(): ?string - { - return $this->osName; - } - - public function setOsName(string $osName): static - { - $this->osName = $osName; - - return $this; - } - public function getClient(): ?Client { return $this->client; @@ -143,4 +131,16 @@ class Partition extends AbstractEntity return $this; } + + public function getOperativeSystem(): ?OperativeSystem + { + return $this->operativeSystem; + } + + public function setOperativeSystem(?OperativeSystem $operativeSystem): static + { + $this->operativeSystem = $operativeSystem; + + return $this; + } } diff --git a/src/Factory/OperativeSystemTypeFactory.php b/src/Factory/OperativeSystemTypeFactory.php new file mode 100644 index 0000000..c7d8f32 --- /dev/null +++ b/src/Factory/OperativeSystemTypeFactory.php @@ -0,0 +1,60 @@ + + */ +final class OperativeSystemTypeFactory extends ModelFactory +{ + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services + * + * @todo inject services if required + */ + public function __construct() + { + parent::__construct(); + } + + public static function class(): string + { + return OperativeSystemType::class; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories + * + * @todo add your default values here + */ + protected function getDefaults(): array + { + return [ + 'createdAt' => self::faker()->dateTime(), + 'name' => self::faker()->text(255), + 'updatedAt' => self::faker()->dateTime(), + ]; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization + */ + protected function initialize(): static + { + return $this + // ->afterInstantiate(function(OperativeSystemType $operativeSystemType): void {}) + ; + } + + protected static function getClass(): string + { + return OperativeSystemType::class; + } +} diff --git a/src/Factory/PartitionFactory.php b/src/Factory/PartitionFactory.php index ba15bc4..397ef82 100644 --- a/src/Factory/PartitionFactory.php +++ b/src/Factory/PartitionFactory.php @@ -39,7 +39,6 @@ final class PartitionFactory extends ModelFactory return [ 'createdAt' => self::faker()->dateTime(), 'memoryUsage' => self::faker()->randomNumber(), - 'osName' => self::faker()->text(255), 'size' => self::faker()->randomNumber(), 'updatedAt' => self::faker()->dateTime() ]; diff --git a/tests/Functional/PartitionTest.php b/tests/Functional/PartitionTest.php index 0265dc6..0c5a577 100644 --- a/tests/Functional/PartitionTest.php +++ b/tests/Functional/PartitionTest.php @@ -4,10 +4,12 @@ namespace Functional; use App\Entity\Client; use App\Entity\Menu; +use App\Entity\OperativeSystem; use App\Entity\Partition; use App\Factory\ClientFactory; use App\Factory\HardwareProfileFactory; use App\Factory\MenuFactory; +use App\Factory\OperativeSystemFactory; use App\Factory\OrganizationalUnitFactory; use App\Factory\PartitionFactory; use App\Factory\UserFactory; @@ -73,9 +75,12 @@ class PartitionTest extends AbstractTest ClientFactory::createOne(['name' => self::CLIENT_CREATE, 'serialNumber' => '123abc', 'organizationalUnit' => $ou, 'hardwareProfile' => $hp]); $iri = $this->findIriBy(Client::class, ['name' => self::CLIENT_CREATE]); + OperativeSystemFactory::createOne(['name' => 'Ubuntu']); + $osIri = $this->findIriBy(OperativeSystem::class, ['name' => 'Ubuntu']); + $this->createClientWithCredentials()->request('POST', '/partitions',['json' => [ 'size' => 100, - 'osName' => 'Ubuntu', + 'operativeSystem' => $osIri, 'client' => $iri, 'memoryUsage' => 100 ]]); @@ -86,7 +91,7 @@ class PartitionTest extends AbstractTest '@context' => '/contexts/PartitionOutput', '@type' => 'Partition', 'size' => 100, - 'osName' => 'Ubuntu', + 'operativeSystem' => $osIri, 'memoryUsage' => 100 ]); } From 14c9f44c63ce47e8577decb5043a06bb2416e869 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Thu, 20 Jun 2024 09:06:48 +0200 Subject: [PATCH 22/35] refs #451. Added postman collection --- README.md | 5 +++++ swagger-assets/ogCore.postman_collection.zip | Bin 0 -> 12332 bytes 2 files changed, 5 insertions(+) create mode 100644 swagger-assets/ogCore.postman_collection.zip diff --git a/README.md b/README.md index df885a9..f9dd15d 100644 --- a/README.md +++ b/README.md @@ -133,3 +133,8 @@ docker exec ogcore-php php bin/console opengnsys:migrate-hardware-profiles #carg docker exec ogcore-php php bin/console opengnsys:migration:clients #cargamos los clientes ``` +## Objetos de interés + +Se ha incluido un .zip con las colecciones de de API de ogCore para poder trabajar, hacer pruebas, y demás en Postman. Para importarlos, tan solo tendremos que ir a la pestaña de importar, y seleccionar el archivo .zip. + +Visualizar [coleccion Postman](swagger-assets/ogCore.postman_collection.zip) diff --git a/swagger-assets/ogCore.postman_collection.zip b/swagger-assets/ogCore.postman_collection.zip new file mode 100644 index 0000000000000000000000000000000000000000..d4b1e5a443c3b7f8a49cbacb7066ea39e6e018af GIT binary patch literal 12332 zcmcJVbx@mY*Y2UXyB05{Sdb(nfzp=Z#l5&EK#RM(6nD2mahDb=?(P(~Vx_oSp@+Wv z`{s1-Gw00S-|TZ|GV|o0%r8%#>t5Gd_oX0>f=Y^ndH)iIPO2mQwlwdr!4M-L90CRb zjA1~202pS>2Y?wNi~xrG5Fi+c070P;LvFaGqnWLhr3Kv5o*RZR1{oUgzyNSVJ|F-L z2Lk~xeggvlKL`OqK;Up*etrno8#^mYo$vu{KORz1FR}f($;$%SV~*U=caO;VLUhrH zem2$OWW~)6@psUimi0xOeQ!LTV^z73A!7x?OD_61WoP4r-dMciMSCH%Oa1WLhMG{l zf9QgP+;+rIVAuD9qc*JJ9Vy^sJ%)LR4hndcJ|>PMai~ggwdK-9rRPTX)Iam8g^J{0 zg5t7b;!5C!f;0xEpMcsy==~4wynieFUvG)V-@PS9R_5k#BYQI|OKt-`uptm^3oqSVW0sQ34=h_qJ?rjXdST zK_3TQszEz2&Fvss`Zc4I(o;*ILL0}TyJbtrHzV1|Aa@qTEXn|&aEsF5vdK4Gf{6lpGPn{oN?u8_mDbdz>_eBir;f4=8n`48LuR>78T*vD>O(t zXO5B37`;{|w{nDi^@unju=dvKWSjSC2_!q>j_BZ#p|?H|*gagkJHm`3Nge@kmjbof z4eCWk7o5>p)F+c|fb^@4ZOWhR zd^F!{q$x`)G?$gduJGGvzRBUtJ}yJ$tO&?%G%;l`znmqo!Wrqt&2DIAvCy&Ry1$?`h)YB2yh;$P?!Y?E6UF9%mY-J*o)N-QY4eaAi^7Nr zJHEsre@|)h!yGGWA?X^1j!?Ib#lqmnsTt5w&iV1P1NkMVlf$J(bESg4ccaVOLHiuw z;%AHWhA(6rR6glV&GSqiRepiI@ul`-{iM3^kmQ?GVun`5%XT^U~W?QE4v`^`hZEFY1>l*E9k1&u8ixF6me^>vcc&qQ{) z^?I&4HQ#Fy15&8)=INWP!+=EWkSCCgOr*Q$_6L?x)CBH&aIU(+oz^i@a0+|0jdj2l zyw|rn5Fx2BA`Iu|($#CMzqCN~OdZny60nI}fv^Ay5)udQzb#-OoF4)O85sj$#-RH> zkRJpE7((GN0E`y_2J!Rr^8#Up|0Q5qt2GGWEeHAtU1~OS$Z4hNsI(7W#pisOdRVVP zNjRX8c+XP*TZ>bHJHt$*V|0zFvI+&!%pR9ZtXyM*#;=ze-{K%bZNICZ|{^#@BDqXLyvUB!H!*@M!!WaQmkM3|{kHGm)uh z*PezBB1b-^8x0-TYcrqTPVZf;8+LTWYQj0L%n|WSogYbM+ZVOd>G`Ql$DSQUL^j%I zLxyc`0`oN^!oc19AF{TM*d59gIM`mf;I$=c8*GrOYdA+~&{`^U{e!}?1#NZ2 z;k7v%3u_d{tC-EpoYa((Ns2x?e>3a>w9qt+?rvkutrl(v z#uZqJm$($2I3;#eTFgDH4DN_lkLqcFVMp2|E)i_okZD6uUf{-1*V-o%A6V7{q;1-7 zdBrkDP6olj`E%Vc=7jAOHhfYi9rpG7P$!zoN2ef~X(yWVV4GGwlccT)*-uG%XR(i0 zmWYisr*pyO83DPv=SeZm#Cm0Q8Jox5&2J^7>|c$W)O7p|zrg7Jz)spHb9aZ~ zsbS!aA8j+{jx!H=EjqtV)+nq13Ju$o!xi)~aiZ3Poia-OYPhYpl-wx}50Yo_{G*#U zzq*|n6G^et&Uo(%y%tv1 z3fE}B>&G@%L+cgMV2c|@b)~Is+qh{FS3PqoyyjlI&N%PXqHo!b5qv!!z<>+_WU;=v z!{8J_Gj`vzW!eTbV<-M_K04|89Qwk>HFd?-tc|oyB;E{zFNKDky;?sMx3HT+>XNoq zPs;h(E&4A7=E}<#+&n-+D#7`;6=-l@KA~^~F8~Mw-kS;oAP)crhl2oMkO4m&1_v4% z^YZ_f0_QD%DUi%(BoFXiIN0;VFq}b%8l&(;X`aWKYHn^OrYQ8YPnOq#g5v|HN?Aw0 zY@v|ruFh|VgEYfq3KB6JH4JNyG!n%Ycj3*$xKt!m$qdK?rcvm~;l?WyqzpNVtY|re ztR1LSQQG^+V+4FEuT{qqD2vX>&x!r!^VoKdOzp98p`&RaT!%_}kHS#*oX|yl``FcE zLfqNWmUp(oNz8j*(iVV zE_MDAz&Z=jy71y6Pvi0Y=dr@L`t`+j(3-j=TyXjhOGskV8?uvQJ}6gKow#AFc*x+ znLj5#;a#o%j^~cBsUh|D+M=2?Vcm8gXRW3_4=+QjcJSE`z|DyUu~pcB239;+Y=i31 z_;c*1o&@7VT>phaur%;ItsxO+IcMS!UaPd1;S&0|K66oKy85QLZ|}@1_Udfc(YD&N zt|_DZNv2nQvzXk0#o(Ldr(I&(`=777>@Fh)+$X+14Puh3eZO0*{T)pS}7$;UFiysUP z6xOrp7s6z}&KOhL%#KqchfhR38gqXj`jf{b*JfuOiKM4><#u-twuCZ9^&|XQ3?f7? zZLAW!hB?lmty{$!9`ln)Q7Gz6GA=0iW90NmX!pFBHS%6&+52dinZ zUu9#0YM&{S!21$usW~ClF;ams(nj*p!`2IY;_cpmc|SC#OUI;qOp59;d6VeuG>>Te}o_QV60 z*88;;okK3CE1mzuQt4VW!p(7WxQS|hZx%eDp{RBioOT)_iopL8Smh*l8nJWYTPk$7 zcu4k%%kc-s>?URp>rfGE+Y^hO967`0OU65zfRTuW(JW>XDGyO(vi+F(RCHy85wF;T zflYt<2Rw(XjwbG!wSjwIf|^l7t+`Z8_aU~adac!Aec*g5BR)8;E&FkEJ3VU5N6CTb z+o-n9?Glu}Jmk!yVbTQ&CGtCZ|9Naht&n-{E0gQ}qx(mE&b4MOom|hlOwtyfvN^9fELZ{jm~@z0DSOvgd7*8zY#Y?+Nae{ zq1OUAW~b^n8|g7N*u0;5hRLPHXV}Xhzi<3ApQVra4yDtr;qw<%2#&BVB+#_w7X5Wi z@@L2DmlSU`>DFZit8jkr>KY@(gksN(1O@d;dJg{6(@EU-bjkMjJ>7VB2zD}@)uYXC zI$To$lFCfpW2q2JiW1e!VlGK?sr7K;RH442}hY>l&9GHaHF z0E_JzOE7^J`*Sl&#pRzNlMjDjO+Ne)I zz3m|vS@gaN>#|YOeBrB(RAWE@n@@&?D2ovmb^w!%T%Sd0;A zMVPLSVxuU)cL+@%&5NxAN9fptc>Mx(N5KDGVhC-rEf)#^r)_NF=t-Wf%q!Vjzfc4 z0%v`bD_GF}#8yP=c>NVBU4>Q^JT}Iv2XO1>{H;Q`dTwGh%U#Y%J^P@AO7GjwWjwiP zRt_?4T~$cg@dBl#%7)9nwk3{PZdv=lXuH)&bbD}JUrRSlI9e)P=@CT+zHRatZ*?}V zV6En*u-cO9_wCcXycaSg;ga-(L0|5va58u5` z;YI+MAq)aA1|xt5P$MWm*Z}c|PF4FN{^KC;hcGN`QcNDW-8#`ywL4FKE7)M=7sz+1jr_M~OB$`zM(HA;TJLkX$9P(c} zydfzi)s-F9h{64(-w0oPE{O_gn{7=4GnYb;yUPE9h^C$B82sdDrp^C?m+M86Up>R{ zE0cv#mq6sU9-Fk~jeXZ|tNFKjucNev(?&l|)@K8^QZ#wcRJox2Z&{P7^j;&2%Td+Y zF%n3P3u8$?u1)zKrBP&8>bEjzGM?Yz@lY%6tiej;lb@CTTYS~|d|?kh%Fw(o^wYP^ zg()UgA-8naB-712{kvRBk6HsGxbKRK!|cqm6+i#+=IXTKWsTN>JgP zge}E2SPl=5wpmCjD#5vj=j27tU4)UEjfQue3QmS18{arbhdASy>`6?0)U64Bjj=Xb zBCl*bZbm|*^(1xt7_lwg$943QD`KYMJ`+aIkn%DNl2s@Fbn?d{SgmzJyuFIJQc;te zc{wE&_5CQ`7vEJm-`uXHzOd{!e8pz6cx}&VVeYv&pO?I96fzcE^g}g*_v{Mr6CXxWVK+DEE?h8w^7)_(OB1*Dk?O%#8I&1c zpx__jv+mIgN-0_Pz>^^P+9}6OcN!$x?d9x6@;0g0$2O8l892mN1RmDhTA*lmHL2!S zEg2E|K}sRGi$pf?L!WU_`v{nGQsuQwZJ zKgfR7V?I?8B7=LK)Bfu=k`DsmGlYW>0Asij7yyOu=RdclP#-6`uMtTMxPr15t>k@A^kzwC1w1IL(%eq$j>H`S^Su6)^S4|aOhbV zv&kufZh7!fs3_08?^@`&!ychy-j#|=6-%;Ga=^zNy0jdn;571noPO+bob&-OG=n*Z z_o>jq#b{XF!v%6j^ox1I27@L|T7raHLb(;`>3uaPk@*sBt?3ovfPp6U}XImcOxqG31pKj9QaU8N2&EO?Z`c*0wm24+4nMU%+4JF$JhTMb2E)i z-9wpNq66f6ncK!j9nQ3cT@b1{A*|%yVQq(fhSu^hT!Ll$s%LZvp8WuMKJ^>4-Sp3^ zAI4?}l@+3WFkJ=uO=E?Soo@k!M)-Y4<=Asx`EaZkM3wfT=65r62)^#7qJ6PHKl+tV z@7zLT>JYW__rYPV3 zDlf~@(%L6xW2^7Hu5|b(ec7VL)p5LK7Z*M z$rkO?D3GmgT}Ct~<7t%GQ0Zl$Ek~`J)jC%mDo%w+V69H|W>I5+IzP|xZ4E>)%04q~z^VDJ z;l#M}RUCDXe78pe`9|8~i%M_=-gMTC5==M&{J1K&n2;pF55@=h{`7gR%yI!WRw_q@ z<*;FV+@bcn$`lYKRU%xCX8O&I&xdIC%tiWOd)-u0GbNI3^E^?ij=g?CCW*_b-sl>h z8r4T!Qwy-WbNhFw5$sTxTSf)sU=T)@AM6U-YEMmmeVYZtk66%_t0{u2xOk6i}q12XI)XX&^ z&VJgtDxk&TMPyppL-XF0lE~*HNl&R)&MIj=f3_!HqqUY>lRfAVw@2%rRBW5}U3jik zx`L8}#cBV2GyM4kk==QPoiY_lJo~(bg}lG8R=z;JRXGcvFV#e$CkWrsXMcZwjkznl`z1#%NOalj@fIL-AsB=Sg%p%1HD)5@c3QDUj>KC38n4ep3S__TL zHxb+`jg8$s_GFxydr~?Zn86kEjS1n)F z+7q`-VBf48Ez_UJTy1`|nfN(XqxF=(jN2G{AP+NUU~R{V_T zp~(%up{oR?=lYa(N~Ah5%BNMzR)iljmsNNOr0muK9hqfROokQmNL=W)AV^S|SG4ee z34?U3mgbdUn4SxLwf1u)@Q63PHhrLC4ZYXVKs1F5(IpuTnBaQbc_Al)N^Bv-GJIZi zEfFD*`!&FVVS$qh@KO>v=Ju8N$yVk}cPAxNaX)?$iV|743Vb-kIT!y2v#-m-hX*#W zZ*6&PJYUP6L~kWY8Fp84OnJp;)?zU8VYSdE9cAM*oXjv2g~*gWmFLN3|0Mlu4dGIYZTXR2gIl<6F4Zl;07H701T9O(oFD{i_= zYdJACSLuQ&?S7BZC{YMjDvD&n+^1`!nOSOdIQhwsFWxV&m`ol$0pnAOL|glBVpS7< z;`GsvMSi~$Qt&gBs+yqBqtnAQR3d5ex;1(Ov{JBU(AI@fa3Zq5v=*fTLQBQGiI51J z9cQX=);4G}DSF$kd0ZHdX~*N8?f%r(6D?Br+GG5ByusY#FvlmD-UgdE^eniwdgZOp zEZwdmoja`cRclw07v>OCwGn6N(X+HWSc>UYp2F>s{q3?Nb`i_N`9QO!oYh1K2s+fIL zwNrc*6CTRNiOi3}7awT0P`&S&TA8l+RHxfBgE!FiwT`#N&-p>- zjpJu$=*OY<+Elzt^|c+{!K*Z#-N9HiDv*-IOw7j6>Mn*4;`0aY84;5FYT0L^rib8m z!hF{2hETR#wpeW*bf)!>*mDZ1&M)zleSloWMVP)jY$VPEbgP*4Lz3>h`t5G?6bHLY z8HAv54KJ$$eW61enrfWoUw*Cf#vXOfW-}lwVC=D4)Wh$sn;%c-6551@r7lL8ga-Oh zRCM|AQlwY_s*rXF5meR0&Q^}q&C`Z?511@`QC zPEQWeYIJ*INVfBHf2{gkCpV((oFw)l+Q#*j`9g;gc4Jddm9eoE^s})GOy=pDhHR6mz-8Rw2Jk0Zu07pBUxbM@m zq~GxPH5Vh4sYRwCD9kgWivc<2CoM(Kv)G@c#gM~uXzlv^ga~qTs!G!E(X2lVMivyI zt-&|=tg)SKOc{N%y8F_oJ3OofF0!yk;&jC`(9Yw8JqRG}8d)SDrUGGBoXJgGHz1~% zESxM}e50(0!TKDSRDZX35m{(MsdQX#A#%;B7?&Qb$yYu5rpUZ#D1_4{et#>(xaY$# zeuv0>&>9hi(sm>3YvZXL$vH0B#8s3N=LvJWT9J)Mmo}Tsbj?l!ZF>_msp)IaNOn}r zgtx(f^x^{Ie#I@k5A76>aoW_&^)M@~nloOv?6{e?OlPhhirSzM=v92n>Uemvv$fZp zPFk$`Uw&TvScvd?@JrEN(HFte_kJ%3?_XCm z$N*{p=i>pu?~_6RFptrFWQZ4r06>6z5MCY_-+c(^j|9-3nvT^xg!Go7}K=bao3&Fi-_7z*2Y~nGM@XC^IS#+a^EAF@E``3FXvtUT3@Eht5q^ zp#zymfplc|lDR?tSmRmq-gNQQ4}BN3yVg(OAHAf{Jq4z$|(ry=J5qC zEu5b}(6C1MXD7$-%QCs`h0m94I7C&hzbx zDimc;?XReR>+Yxe;(+?K+98VhS+jWqVFAERXXQipQihZI*XxiH4=B?4dJ=`}cAHhl z0i)pHg9-7K4kr6GYDt>PQ)8Mww%R2pA9$l^2<@c>3GvnT?lV{O zm-AToCl4Fgc^t1#P)RHlUys4cQY3tHUXppt%=t@l(>Vv))(CWZyv$g%=a+kRZlQcZ zC@Eq@|4n{+Y|Z1R^dS|NX5v!~=7S3a|AAr+nvBo8(RA zX}$3sxcqFob~W!Lf1|E1>0>uNQvo=&v)TQg7jamfjQxr6t#%U?J8dwY292zb1!Tyd zKn8%WbE97pRHP~T1bmp8x_?dU9Qp8i#acgQ@977(pLU-a6}>l@w17X3Nsf_qKDHS4 zf}nRp@Nw{fH;Oo7eexXmJ4khb5FfD;wvTfS9c^g_PA)-y;O?FuOos1t(PmU}43*HN-0M z2iva70R@tm#=*c5!GD~=dQx@U{XSCr{~YD;{@vW1fvu6LnIrr^6<;St`i=HWT(K=( zv9(IHv(wj(%Jf*ca?m6>mTous0Lrv!WyLLP2Wfiw!~r{9ua@TJvKJ?=UUxQEGasIv zYJy$udKod(!dAwfqQ)m6=!hEhmY2OY(4Xtwg>3Ha0k&?>9B4k~=8Z>2!9j%us0Km3ry^i_!7B-^S5PU{`<^lcA%#;exJN6&0Z z9u0T$RK6mPf_qp&(Zkr$)4}#n$igw0IHF524|`?pr7-s}4d=_!@nv6-$jvE`WHt7& z*!mK@R@a`f(6lZGF%|)1u+`+y)xg$^Q+#@>1~Ol!lNEx+XR%FJALyoxUg+{XVAFOd ze4e9OijVzv6pXJwd#y9RFBKA|9UVu9`TdJBba zcCcWIFOZRtRPPVJ6r_ zkld61Esp<5+VZa$zo%FJj4_G&&oTaXX6&yRzn`%G8AA>8pJV*(;LQJl@!N^%pE3CF zh5k?fl)rtr|5uFP4}|`VaftuVG5+>p?O!o|pI84GBZ>H*WBl#2sJ~+TKBN0HhBx^? z$N1Z$^1ovI-VFX3gM|8@WBl#$;9oI*cd&oP;AQyd7=ODD{VPV{Zw2tr7%0sD1B}0G rp8tyR`%eF>+WxVA?V{4Ge-q>P+N&UqhW_g-aPMD$`>SoXU!VRL*Er)z literal 0 HcmV?d00001 From 5d1b553c0b08a42101b3b2c65f0e779814fe1c9f Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Fri, 21 Jun 2024 10:03:59 +0200 Subject: [PATCH 23/35] refs #421. Some improvements --- config/api_platform/OperativeSystem.yaml | 4 +- config/api_platform/OrganizationalUnit.yaml | 7 ++- config/packages/api_platform.yaml | 9 +++- config/services.yaml | 12 ++--- config/services/api_platform.yaml | 13 +++++ migrations/Version20240620095914.php | 33 +++++++++++++ migrations/Version20240620100039.php | 33 +++++++++++++ ...UserAllowedOrganizationalUnitExtension.php | 48 +++++++++++++++++++ src/Entity/Partition.php | 1 + src/Entity/User.php | 4 +- .../Voter/OrganizationalUnitVoter.php | 42 ++++++++++++++++ 11 files changed, 192 insertions(+), 14 deletions(-) create mode 100644 migrations/Version20240620095914.php create mode 100644 migrations/Version20240620100039.php create mode 100644 src/Doctrine/UserAllowedOrganizationalUnitExtension.php create mode 100644 src/Security/Voter/OrganizationalUnitVoter.php diff --git a/config/api_platform/OperativeSystem.yaml b/config/api_platform/OperativeSystem.yaml index 737c8d0..988fed0 100644 --- a/config/api_platform/OperativeSystem.yaml +++ b/config/api_platform/OperativeSystem.yaml @@ -11,8 +11,8 @@ resources: ApiPlatform\Metadata\GetCollection: provider: App\State\Provider\OperativeSystemProvider filters: - - 'api_platform.filter.operative-system.order' - - 'api_platform.filter.operative-system.search' + - 'api_platform.filter.operative_system.order' + - 'api_platform.filter.operative_system.search' ApiPlatform\Metadata\Get: provider: App\State\Provider\OperativeSystemProvider diff --git a/config/api_platform/OrganizationalUnit.yaml b/config/api_platform/OrganizationalUnit.yaml index f161760..e03b552 100644 --- a/config/api_platform/OrganizationalUnit.yaml +++ b/config/api_platform/OrganizationalUnit.yaml @@ -7,13 +7,16 @@ resources: groups: ['default', 'organizational-unit:read'] denormalization_context: groups: ['organizational-unit:write'] - validation_context: - groups: ['organizational-unit:write'] operations: ApiPlatform\Metadata\GetCollection: provider: App\State\Provider\OrganizationalUnitProvider + filters: + - 'api_platform.filter.organizational_unit.order' + - 'api_platform.filter.organizational_unit.search' ApiPlatform\Metadata\Get: + security: 'is_granted("ORGANIZATIONAL_UNIT_VIEW", object)' provider: App\State\Provider\OrganizationalUnitProvider + securityMessage: 'Sorry, but you are not allowed to access this resource.' ApiPlatform\Metadata\Put: provider: App\State\Provider\OrganizationalUnitProvider ApiPlatform\Metadata\Patch: diff --git a/config/packages/api_platform.yaml b/config/packages/api_platform.yaml index 6a6729c..67d91f3 100644 --- a/config/packages/api_platform.yaml +++ b/config/packages/api_platform.yaml @@ -4,7 +4,14 @@ api_platform: version: 1.0.0 path_segment_name_generator: 'api_platform.path_segment_name_generator.dash' formats: - jsonld: ['application/ld+json', 'application/json'] + jsonld: [ 'application/ld+json' ] + jsonhal: [ 'application/hal+json' ] + jsonapi: [ 'application/vnd.api+json' ] + json: [ 'application/json' ] + xml: [ 'application/xml', 'text/xml' ] + yaml: [ 'application/x-yaml' ] + csv: [ 'text/csv' ] + html: [ 'text/html' ] patch_formats: jsonld: ['application/ld+json', 'application/json'] mapping: diff --git a/config/services.yaml b/config/services.yaml index f454029..e9086eb 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -1,8 +1,3 @@ -# This file is the entry point to configure your own services. -# Files in the packages/ subdirectory configure your dependencies. - -# Put parameters here that don't need to change on each machine where the app is deployed -# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration parameters: services: @@ -11,8 +6,6 @@ services: autowire: true # Automatically injects dependencies in your services. autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. - # makes classes in src/ available to be used as services - # this creates a service per class whose id is the fully-qualified class name App\: resource: '../src/' exclude: @@ -20,6 +13,11 @@ services: - '../src/Entity/' - '../src/Kernel.php' + App\Doctrine\UserAllowedOrganizationalUnitExtension: + tags: + - { name: api_platform.doctrine.orm.query_extension.collection } + - { name: api_platform.doctrine.orm.query_extension.item } + App\OpenApi\OpenApiFactory: decorates: 'api_platform.openapi.factory' arguments: [ '@App\OpenApi\OpenApiFactory.inner' ] diff --git a/config/services/api_platform.yaml b/config/services/api_platform.yaml index fd54ddb..f74ee52 100644 --- a/config/services/api_platform.yaml +++ b/config/services/api_platform.yaml @@ -41,6 +41,19 @@ services: tags: - [ 'api_platform.filter' ] + api_platform.filter.organizational_unit.order: + parent: 'api_platform.doctrine.orm.order_filter' + arguments: + $properties: { 'id': ~, 'name': ~, 'type': ~ } + $orderParameterName: 'order' + tags: + - [ 'api_platform.filter' ] + + api_platform.filter.organizational_unit.search: + parent: 'api_platform.doctrine.orm.search_filter' + arguments: [ { 'id': 'exact', 'name': 'exact', 'type': 'exact' } ] + tags: + - [ 'api_platform.filter' ] api_platform.filter.partition.order: parent: 'api_platform.doctrine.orm.order_filter' diff --git a/migrations/Version20240620095914.php b/migrations/Version20240620095914.php new file mode 100644 index 0000000..5e4d7f2 --- /dev/null +++ b/migrations/Version20240620095914.php @@ -0,0 +1,33 @@ +addSql('ALTER TABLE `partition` DROP FOREIGN KEY FK_9EB910E419EB6921'); + $this->addSql('ALTER TABLE `partition` ADD CONSTRAINT FK_9EB910E419EB6921 FOREIGN KEY (client_id) REFERENCES client (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 `partition` DROP FOREIGN KEY FK_9EB910E419EB6921'); + $this->addSql('ALTER TABLE `partition` ADD CONSTRAINT FK_9EB910E419EB6921 FOREIGN KEY (client_id) REFERENCES client (id)'); + } +} diff --git a/migrations/Version20240620100039.php b/migrations/Version20240620100039.php new file mode 100644 index 0000000..7aa27c5 --- /dev/null +++ b/migrations/Version20240620100039.php @@ -0,0 +1,33 @@ +addSql('ALTER TABLE `partition` DROP FOREIGN KEY FK_9EB910E419EB6921'); + $this->addSql('ALTER TABLE `partition` ADD CONSTRAINT FK_9EB910E419EB6921 FOREIGN KEY (client_id) REFERENCES client (id) ON DELETE CASCADE'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE `partition` DROP FOREIGN KEY FK_9EB910E419EB6921'); + $this->addSql('ALTER TABLE `partition` ADD CONSTRAINT FK_9EB910E419EB6921 FOREIGN KEY (client_id) REFERENCES client (id) ON DELETE SET NULL'); + } +} diff --git a/src/Doctrine/UserAllowedOrganizationalUnitExtension.php b/src/Doctrine/UserAllowedOrganizationalUnitExtension.php new file mode 100644 index 0000000..0aa9f25 --- /dev/null +++ b/src/Doctrine/UserAllowedOrganizationalUnitExtension.php @@ -0,0 +1,48 @@ +addWhere($queryBuilder, $resourceClass); + } + + public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, Operation $operation = null, array $context = []): void + { + $this->addWhere($queryBuilder, $resourceClass); + } + + private function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void + { + /** @var User $user */ + $user = $this->security->getUser(); + + if (OrganizationalUnit::class !== $resourceClass || null === $user || in_array('ROLE_SUPER_ADMIN', $user->getRoles())) { + return; + } + $organizationalUnitIds = []; + foreach ($user->getAllowedOrganizationalUnits() as $allowedOrganizationalUnit) { + $organizationalUnitIds[] = $allowedOrganizationalUnit->getId(); + } + + $rootAlias = $queryBuilder->getRootAliases()[0]; + $queryBuilder->andWhere(sprintf('%s.id in (:ou)', $rootAlias)); + $queryBuilder->setParameter('ou', $organizationalUnitIds); + } +} \ No newline at end of file diff --git a/src/Entity/Partition.php b/src/Entity/Partition.php index c7af2c1..7795315 100644 --- a/src/Entity/Partition.php +++ b/src/Entity/Partition.php @@ -28,6 +28,7 @@ class Partition extends AbstractEntity private ?string $filesystem = null; #[ORM\ManyToOne(inversedBy: 'partitions')] + #[ORM\JoinColumn( onDelete: 'CASCADE')] private ?Client $client = null; #[ORM\Column] diff --git a/src/Entity/User.php b/src/Entity/User.php index 8e6e399..c186575 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -17,8 +17,8 @@ class User extends AbstractEntity implements UserInterface, PasswordAuthenticate { use ToggleableTrait; - const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN'; - const ROLE_USER = 'ROLE_USER'; + const string ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN'; + const string ROLE_USER = 'ROLE_USER'; #[ORM\Column(length: 180)] private ?string $username = null; diff --git a/src/Security/Voter/OrganizationalUnitVoter.php b/src/Security/Voter/OrganizationalUnitVoter.php new file mode 100644 index 0000000..1445a7f --- /dev/null +++ b/src/Security/Voter/OrganizationalUnitVoter.php @@ -0,0 +1,42 @@ +getUser(); + + // if the user is anonymous, do not grant access + if (!$user instanceof UserInterface) { + return false; + } + + if ($attribute === 'ORGANIZATIONAL_UNIT_VIEW' ) { + foreach ($user->getAllowedOrganizationalUnits() as $allowedOrganizationalUnit) { + if ($allowedOrganizationalUnit->getId() === $subject->getEntity()->getId()) { + return true; + } + } + } + + return false; + } +} From 74fac8d0af71019680dc0cd01db335b263cca9b4 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Fri, 21 Jun 2024 10:29:33 +0200 Subject: [PATCH 24/35] refs #421. Some improvements in DTO output --- config/api_platform/Client.yaml | 4 ++-- config/api_platform/Hardware.yaml | 4 ++-- config/api_platform/HardwareProfile.yaml | 4 ++-- config/api_platform/HardwareType.yaml | 4 ++-- config/api_platform/Menu.yaml | 4 ++-- config/api_platform/OperativeSystem.yaml | 4 ++-- config/api_platform/OrganizationalUnit.yaml | 2 +- config/api_platform/Partition.yaml | 4 ++-- config/api_platform/User.yaml | 4 ++-- config/api_platform/UserGroup.yaml | 4 ++-- src/Dto/Input/HardwareTypeInput.php | 2 +- src/Dto/Input/OperativeSystemInput.php | 2 +- src/Dto/Output/ClientOutput.php | 2 ++ src/Dto/Output/HardwareOutput.php | 2 +- src/Dto/Output/HardwareProfileOutput.php | 2 +- src/Dto/Output/HardwareTypeOutput.php | 2 +- src/Dto/Output/NetworkSettingsOutput.php | 26 ++++++++++----------- src/Dto/Output/OperativeSystemOutput.php | 2 +- src/Dto/Output/OrganizationalUnitOutput.php | 7 +++--- src/Dto/Output/UserOutput.php | 7 +++++- src/State/Provider/HardwareTypeProvider.php | 2 +- tests/Functional/PartitionTest.php | 1 - 22 files changed, 50 insertions(+), 45 deletions(-) diff --git a/config/api_platform/Client.yaml b/config/api_platform/Client.yaml index 3dc25d5..b61769b 100644 --- a/config/api_platform/Client.yaml +++ b/config/api_platform/Client.yaml @@ -3,9 +3,9 @@ resources: processor: App\State\Processor\ClientProcessor input: App\Dto\Input\ClientInput output: App\Dto\Output\ClientOutput - normalization_context: + normalizationContext: groups: ['default', 'client:read'] - denormalization_context: + denormalizationContext: groups: ['client:write'] operations: ApiPlatform\Metadata\GetCollection: diff --git a/config/api_platform/Hardware.yaml b/config/api_platform/Hardware.yaml index dd3ef97..c932488 100644 --- a/config/api_platform/Hardware.yaml +++ b/config/api_platform/Hardware.yaml @@ -3,9 +3,9 @@ resources: processor: App\State\Processor\HardwareProcessor input: App\Dto\Input\HardwareInput output: App\Dto\Output\HardwareOutput - normalization_context: + normalizationContext: groups: ['default', 'hardware:read'] - denormalization_context: + denormalizationContext: groups: ['hardware:write'] operations: ApiPlatform\Metadata\GetCollection: diff --git a/config/api_platform/HardwareProfile.yaml b/config/api_platform/HardwareProfile.yaml index 5dd6c67..06c3587 100644 --- a/config/api_platform/HardwareProfile.yaml +++ b/config/api_platform/HardwareProfile.yaml @@ -3,9 +3,9 @@ resources: processor: App\State\Processor\HardwareProfileProcessor input: App\Dto\Input\HardwareProfileInput output: App\Dto\Output\HardwareProfileOutput - normalization_context: + normalizationContext: groups: ['default', 'hardware-profile:read'] - denormalization_context: + denormalizationContext: groups: ['hardware-profile:write'] operations: ApiPlatform\Metadata\GetCollection: diff --git a/config/api_platform/HardwareType.yaml b/config/api_platform/HardwareType.yaml index 3223e15..793a9e9 100644 --- a/config/api_platform/HardwareType.yaml +++ b/config/api_platform/HardwareType.yaml @@ -3,9 +3,9 @@ resources: processor: App\State\Processor\HardwareTypeProcessor input: App\Dto\Input\HardwareTypeInput output: App\Dto\Output\HardwareTypeOutput - normalization_context: + normalizationContext: groups: ['default', 'hardware-type:read'] - denormalization_context: + denormalizationContext: groups: ['hardware-type:write'] operations: ApiPlatform\Metadata\GetCollection: diff --git a/config/api_platform/Menu.yaml b/config/api_platform/Menu.yaml index 1fac788..54ab3bf 100644 --- a/config/api_platform/Menu.yaml +++ b/config/api_platform/Menu.yaml @@ -3,9 +3,9 @@ resources: processor: App\State\Processor\MenuProcessor input: App\Dto\Input\MenuInput output: App\Dto\Output\MenuOutput - normalization_context: + normalizationContext: groups: ['default', 'menu:read'] - denormalization_context: + denormalizationContext: groups: ['menu:write'] operations: ApiPlatform\Metadata\GetCollection: diff --git a/config/api_platform/OperativeSystem.yaml b/config/api_platform/OperativeSystem.yaml index 988fed0..ba4ed52 100644 --- a/config/api_platform/OperativeSystem.yaml +++ b/config/api_platform/OperativeSystem.yaml @@ -3,9 +3,9 @@ resources: processor: App\State\Processor\OperativeSystemProcessor input: App\Dto\Input\OperativeSystemInput output: App\Dto\Output\OperativeSystemOutput - normalization_context: + normalizationContext: groups: ['default', 'operative-system:read'] - denormalization_context: + denormalizationContext: groups: ['operative-system:write'] operations: ApiPlatform\Metadata\GetCollection: diff --git a/config/api_platform/OrganizationalUnit.yaml b/config/api_platform/OrganizationalUnit.yaml index e03b552..76424c9 100644 --- a/config/api_platform/OrganizationalUnit.yaml +++ b/config/api_platform/OrganizationalUnit.yaml @@ -3,7 +3,7 @@ resources: processor: App\State\Processor\OrganizationalUnitProcessor output: App\Dto\Output\OrganizationalUnitOutput input: App\Dto\Input\OrganizationalUnitInput - normalization_context: + normalizationContext: groups: ['default', 'organizational-unit:read'] denormalization_context: groups: ['organizational-unit:write'] diff --git a/config/api_platform/Partition.yaml b/config/api_platform/Partition.yaml index 1d270e7..7d09114 100644 --- a/config/api_platform/Partition.yaml +++ b/config/api_platform/Partition.yaml @@ -3,9 +3,9 @@ resources: processor: App\State\Processor\PartitionProcessor input: App\Dto\Input\PartitionInput output: App\Dto\Output\PartitionOutput - normalization_context: + normalizationContext: groups: ['default', 'partition:read'] - denormalization_context: + denormalizationContext: groups: ['partition:write'] operations: ApiPlatform\Metadata\GetCollection: diff --git a/config/api_platform/User.yaml b/config/api_platform/User.yaml index f108627..46719e5 100644 --- a/config/api_platform/User.yaml +++ b/config/api_platform/User.yaml @@ -3,9 +3,9 @@ resources: input: App\Dto\Input\UserInput output: App\Dto\Output\UserOutput processor: App\State\Processor\UserProcessor - normalization_context: + normalizationContext: groups: ['default', 'user:read'] - denormalization_context: + denormalizationContext: groups: ['user:write'] operations: ApiPlatform\Metadata\GetCollection: diff --git a/config/api_platform/UserGroup.yaml b/config/api_platform/UserGroup.yaml index 0f2a80b..796e526 100644 --- a/config/api_platform/UserGroup.yaml +++ b/config/api_platform/UserGroup.yaml @@ -4,9 +4,9 @@ resources: processor: App\State\Processor\UserGroupProcessor input: App\Dto\Input\UserGroupInput output: App\Dto\Output\UserGroupOutput - normalization_context: + normalizationContext: groups: ['default', 'user-group:read'] - denormalization_context: + denormalizationContext: groups: ['user-group:write'] operations: ApiPlatform\Metadata\GetCollection: diff --git a/src/Dto/Input/HardwareTypeInput.php b/src/Dto/Input/HardwareTypeInput.php index 8279a6f..9eb0ae1 100644 --- a/src/Dto/Input/HardwareTypeInput.php +++ b/src/Dto/Input/HardwareTypeInput.php @@ -9,7 +9,7 @@ use Symfony\Component\Validator\Constraints as Assert; class HardwareTypeInput { #[Assert\NotBlank] - #[Groups(['hardware-type:read'])] + #[Groups(['hardware-type:write'])] public ?string $name = null; public function __construct(?HardwareType $hardwareType = null) diff --git a/src/Dto/Input/OperativeSystemInput.php b/src/Dto/Input/OperativeSystemInput.php index e08416d..a38d809 100644 --- a/src/Dto/Input/OperativeSystemInput.php +++ b/src/Dto/Input/OperativeSystemInput.php @@ -9,7 +9,7 @@ use Symfony\Component\Validator\Constraints as Assert; class OperativeSystemInput { #[Assert\NotBlank] - #[Groups(['operative-system:read'])] + #[Groups(['operative-system:write'])] public ?string $name = null; public function __construct(?OperativeSystem $operativeSystem = null) diff --git a/src/Dto/Output/ClientOutput.php b/src/Dto/Output/ClientOutput.php index 2a86bc7..5fc0b26 100644 --- a/src/Dto/Output/ClientOutput.php +++ b/src/Dto/Output/ClientOutput.php @@ -21,6 +21,7 @@ final class ClientOutput extends AbstractOutput public ?string $netiface = ''; #[Groups(['client:read'])] + #[ApiProperty(readableLink: true )] public ?OrganizationalUnitOutput $organizationalUnit = null; #[Groups(['client:read'])] @@ -30,6 +31,7 @@ final class ClientOutput extends AbstractOutput public ?MenuOutput $menu = null; #[Groups(['client:read'])] + #[ApiProperty(readableLink: true )] public ?HardwareProfileOutput $hardwareProfile = null; #[Groups(['client:read'])] diff --git a/src/Dto/Output/HardwareOutput.php b/src/Dto/Output/HardwareOutput.php index 1c0e0b8..3823f33 100644 --- a/src/Dto/Output/HardwareOutput.php +++ b/src/Dto/Output/HardwareOutput.php @@ -10,7 +10,7 @@ use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'Hardware')] final class HardwareOutput extends AbstractOutput { - #[Groups(['hardware:read'])] + #[Groups(['hardware:read', 'hardware-profile:read'])] public string $name; #[Groups(['hardware:read'])] diff --git a/src/Dto/Output/HardwareProfileOutput.php b/src/Dto/Output/HardwareProfileOutput.php index a0a8cac..ba78e6d 100644 --- a/src/Dto/Output/HardwareProfileOutput.php +++ b/src/Dto/Output/HardwareProfileOutput.php @@ -11,7 +11,7 @@ use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'HardwareProfile')] final class HardwareProfileOutput extends AbstractOutput { - #[Groups(['hardware-profile:read'])] + #[Groups(['hardware-profile:read', 'client:read'])] public ?string $description = ''; #[Groups(['hardware-profile:read'])] diff --git a/src/Dto/Output/HardwareTypeOutput.php b/src/Dto/Output/HardwareTypeOutput.php index 29516b0..860e86f 100644 --- a/src/Dto/Output/HardwareTypeOutput.php +++ b/src/Dto/Output/HardwareTypeOutput.php @@ -9,7 +9,7 @@ use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'HardwareType')] final class HardwareTypeOutput extends AbstractOutput { - #[Groups(['hardware-type:read'])] + #[Groups(['hardware-type:read', 'hardware:read'])] public string $name; public function __construct(HardwareType $hardwareType) diff --git a/src/Dto/Output/NetworkSettingsOutput.php b/src/Dto/Output/NetworkSettingsOutput.php index fa90ca2..d909e37 100644 --- a/src/Dto/Output/NetworkSettingsOutput.php +++ b/src/Dto/Output/NetworkSettingsOutput.php @@ -9,46 +9,46 @@ use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'NetworkSettings')] final class NetworkSettingsOutput extends AbstractOutput { - #[Groups(['network-settings:read'])] + #[Groups(['network-settings:read', "organizational-unit:read", "client:read"])] public ?string $proxy = null; - #[Groups(['organizational-unit:read'])] + #[Groups(['network-settings:read', "organizational-unit:read", "client:read"])] public ?string $dns = null; - #[Groups(['organizational-unit:read'])] + #[Groups(['network-settings:read', "organizational-unit:read", "client:read"])] public ?string $netmask = null; - #[Groups(['organizational-unit:read'])] + #[Groups(['network-settings:read', "organizational-unit:read", "client:read"])] public ?string $router = null; - #[Groups(['organizational-unit:read'])] + #[Groups(['network-settings:read', "organizational-unit:read", "client:read"])] public ?string $ntp = null; - #[Groups(['organizational-unit:read'])] + #[Groups(['network-settings:read', "organizational-unit:read", "client:read"])] public ?string $p2pMode = null; - #[Groups(['organizational-unit:read'])] + #[Groups(['network-settings:read', "organizational-unit:read", "client:read"])] public ?int $p2pTime = null; - #[Groups(['organizational-unit:read'])] + #[Groups(['network-settings:read', "organizational-unit:read", "client:read"])] public ?string $mcastIp = null; - #[Groups(['organizational-unit:read'])] + #[Groups(['network-settings:read', "organizational-unit:read", "client:read"])] public ?int $mcastSpeed = null; - #[Groups(['organizational-unit:read'])] + #[Groups(['network-settings:read', "organizational-unit:read", "client:read"])] public ?int $mcastPort = null; - #[Groups(['organizational-unit:read'])] + #[Groups(['network-settings:read', "organizational-unit:read", "client:read"])] public ?string $mcastMode = null; - #[Groups(['organizational-unit:read'])] + #[Groups(['network-settings:read', "organizational-unit:read", "client:read"])] public ?MenuOutput $menu = null; #[Groups(['organizational-unit:read'])] public ?HardwareProfileOutput $hardwareProfile = null; - #[Groups(['organizational-unit:read'])] + #[Groups(['network-settings:read', "organizational-unit:read", "client:read"])] public ?bool $validation = null; #[Groups(['organizational-unit:read'])] diff --git a/src/Dto/Output/OperativeSystemOutput.php b/src/Dto/Output/OperativeSystemOutput.php index 8e9002a..39987c2 100644 --- a/src/Dto/Output/OperativeSystemOutput.php +++ b/src/Dto/Output/OperativeSystemOutput.php @@ -9,7 +9,7 @@ use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'OperativeSystem')] final class OperativeSystemOutput extends AbstractOutput { - #[Groups(['operative-system:read'])] + #[Groups(['operative-system:read', 'partition:read'])] public string $name; public function __construct(OperativeSystem $operativeSystem) diff --git a/src/Dto/Output/OrganizationalUnitOutput.php b/src/Dto/Output/OrganizationalUnitOutput.php index 3dbc75f..c372ac3 100644 --- a/src/Dto/Output/OrganizationalUnitOutput.php +++ b/src/Dto/Output/OrganizationalUnitOutput.php @@ -4,14 +4,13 @@ namespace App\Dto\Output; use ApiPlatform\Metadata\ApiProperty; use ApiPlatform\Metadata\Get; -use App\Entity\ClientProperties; use App\Entity\OrganizationalUnit; use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'OrganizationalUnit')] final class OrganizationalUnitOutput extends AbstractOutput { - #[Groups(['organizational-unit:read'])] + #[Groups(['organizational-unit:read', "client:read", "user:read"])] public string $name; #[Groups(['organizational-unit:read'])] @@ -29,7 +28,7 @@ final class OrganizationalUnitOutput extends AbstractOutput #[Groups(['organizational-unit:read'])] public ?int $capacity = null; - #[Groups(['organizational-unit:read'])] + #[Groups(['organizational-unit:read', "client:read"])] public string $type; #[Groups(['organizational-unit:read'])] @@ -38,7 +37,7 @@ final class OrganizationalUnitOutput extends AbstractOutput #[Groups(['organizational-unit:read'])] public string $path; - #[Groups(['organizational-unit:read'])] + #[Groups(['organizational-unit:read', "client:read"])] #[ApiProperty(readableLink: true)] public ?NetworkSettingsOutput $networkSettings = null; diff --git a/src/Dto/Output/UserOutput.php b/src/Dto/Output/UserOutput.php index 5cd4d72..bd7088b 100644 --- a/src/Dto/Output/UserOutput.php +++ b/src/Dto/Output/UserOutput.php @@ -3,6 +3,7 @@ namespace App\Dto\Output; use ApiPlatform\Metadata\Get; +use App\Entity\OrganizationalUnit; use App\Entity\User; use Symfony\Component\Serializer\Annotation\Groups; @@ -36,7 +37,11 @@ final class UserOutput extends AbstractOutput $this->roles = $user->getRoles(); $this->enabled = $user->isEnabled(); $this->userGroups = $user->getUserGroups()->toArray(); - $this->allowedOrganizationalUnits = $user->getAllowedOrganizationalUnits()->toArray(); + + $this->allowedOrganizationalUnits = $user->getAllowedOrganizationalUnits()->map( + fn(OrganizationalUnit $organizationalUnit) => new OrganizationalUnitOutput($organizationalUnit) + )->toArray(); + $this->createAt = $user->getCreatedAt(); $this->createBy = $user->getCreatedBy(); } diff --git a/src/State/Provider/HardwareTypeProvider.php b/src/State/Provider/HardwareTypeProvider.php index 891097d..f4e78cd 100644 --- a/src/State/Provider/HardwareTypeProvider.php +++ b/src/State/Provider/HardwareTypeProvider.php @@ -59,7 +59,7 @@ class HardwareTypeProvider implements ProviderInterface $item = $this->itemProvider->provide($operation, $uriVariables, $context); if (!$item) { - throw new NotFoundHttpException('Operative system not found'); + throw new NotFoundHttpException('hardware type not found'); } return new HardwareTypeOutput($item); diff --git a/tests/Functional/PartitionTest.php b/tests/Functional/PartitionTest.php index 0c5a577..4bd3f75 100644 --- a/tests/Functional/PartitionTest.php +++ b/tests/Functional/PartitionTest.php @@ -91,7 +91,6 @@ class PartitionTest extends AbstractTest '@context' => '/contexts/PartitionOutput', '@type' => 'Partition', 'size' => 100, - 'operativeSystem' => $osIri, 'memoryUsage' => 100 ]); } From 5168d44fd461f793727fa96cf0acd053c83c75b7 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Fri, 21 Jun 2024 11:02:04 +0200 Subject: [PATCH 25/35] refs #425. OrganizationalUnitParent validator --- migrations/Version20240621085144.php | 33 +++++++++++++++++++ src/Dto/Input/OrganizationalUnitInput.php | 2 ++ src/Entity/OrganizationalUnit.php | 2 +- .../Constraints/OrganizationalUnitParent.php | 24 ++++++++++++++ .../OrganizationalUnitParentValidator.php | 25 ++++++++++++++ 5 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 migrations/Version20240621085144.php create mode 100644 src/Validator/Constraints/OrganizationalUnitParent.php create mode 100644 src/Validator/Constraints/OrganizationalUnitParentValidator.php diff --git a/migrations/Version20240621085144.php b/migrations/Version20240621085144.php new file mode 100644 index 0000000..8286ec6 --- /dev/null +++ b/migrations/Version20240621085144.php @@ -0,0 +1,33 @@ +addSql('DROP INDEX UNIQ_IDENTIFIER_NAME ON organizational_unit'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_NAME ON organizational_unit (name, parent_id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP INDEX UNIQ_IDENTIFIER_NAME ON organizational_unit'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_NAME ON organizational_unit (name)'); + } +} diff --git a/src/Dto/Input/OrganizationalUnitInput.php b/src/Dto/Input/OrganizationalUnitInput.php index 26bf8aa..7ce2c2b 100644 --- a/src/Dto/Input/OrganizationalUnitInput.php +++ b/src/Dto/Input/OrganizationalUnitInput.php @@ -8,10 +8,12 @@ use App\Entity\OrganizationalUnit; use App\Validator\Constraints\OrganizationalUnitMulticastMode; use App\Validator\Constraints\OrganizationalUnitMulticastPort; use App\Validator\Constraints\OrganizationalUnitP2PMode; +use App\Validator\Constraints\OrganizationalUnitParent; use App\Validator\Constraints\OrganizationalUnitType; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; +#[OrganizationalUnitParent] class OrganizationalUnitInput { #[Assert\NotBlank] diff --git a/src/Entity/OrganizationalUnit.php b/src/Entity/OrganizationalUnit.php index 583687a..136cf16 100644 --- a/src/Entity/OrganizationalUnit.php +++ b/src/Entity/OrganizationalUnit.php @@ -11,7 +11,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; #[Gedmo\Tree(type: 'materializedPath')] #[ORM\Entity(repositoryClass: MaterializedPathRepository::class)] -#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_NAME', fields: ['name', 'parent_id'])] +#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_NAME', columns: ['name', 'parent_id'])] #[UniqueEntity(fields: ['name', 'parent'], message: 'This organizational unit already exists.')] class OrganizationalUnit extends AbstractEntity { diff --git a/src/Validator/Constraints/OrganizationalUnitParent.php b/src/Validator/Constraints/OrganizationalUnitParent.php new file mode 100644 index 0000000..7950ac7 --- /dev/null +++ b/src/Validator/Constraints/OrganizationalUnitParent.php @@ -0,0 +1,24 @@ +message = 'Only the root organizational unit can not have a parent.'; + } + + public function getTargets(): array|string + { + return parent::CLASS_CONSTRAINT; + } +} \ No newline at end of file diff --git a/src/Validator/Constraints/OrganizationalUnitParentValidator.php b/src/Validator/Constraints/OrganizationalUnitParentValidator.php new file mode 100644 index 0000000..dccef59 --- /dev/null +++ b/src/Validator/Constraints/OrganizationalUnitParentValidator.php @@ -0,0 +1,25 @@ +parent && in_array($value->type, [OrganizationalUnitTypes::CLASSROOMS_GROUP, OrganizationalUnitTypes::CLASSROOM, OrganizationalUnitTypes::CLIENTS_GROUP])) { + $this->context->buildViolation($constraint->message)->addViolation(); + return; + } + } +} \ No newline at end of file From 43099c6bccd9afb251ac00d6b5d020f46f191aed Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Fri, 21 Jun 2024 11:11:57 +0200 Subject: [PATCH 26/35] refs #423. Some improvements Client Output --- src/Dto/Output/ClientOutput.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Dto/Output/ClientOutput.php b/src/Dto/Output/ClientOutput.php index 5fc0b26..de2a2b7 100644 --- a/src/Dto/Output/ClientOutput.php +++ b/src/Dto/Output/ClientOutput.php @@ -11,9 +11,14 @@ use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'Client')] final class ClientOutput extends AbstractOutput { + CONST string TYPE = 'client'; + #[Groups(['client:read'])] public string $name; + #[Groups(['client:read'])] + public string $type = self::TYPE; + #[Groups(['client:read'])] public ?string $serialNumber = ''; From e727e6caa872d97f1eaad29173e485c8d4fc6c4e Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Fri, 21 Jun 2024 14:58:54 +0200 Subject: [PATCH 27/35] refs #423. Updated Voter secutiry into ORganizationalUnit --- src/Dto/Output/MenuOutput.php | 2 +- src/Security/Voter/OrganizationalUnitVoter.php | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Dto/Output/MenuOutput.php b/src/Dto/Output/MenuOutput.php index 0c55133..309fb45 100644 --- a/src/Dto/Output/MenuOutput.php +++ b/src/Dto/Output/MenuOutput.php @@ -10,7 +10,7 @@ use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'Menu')] final class MenuOutput extends AbstractOutput { - #[Groups(['menu:read'])] + #[Groups(['menu:read', 'organizational-unit:read'])] public string $name; #[Groups(['menu:read'])] diff --git a/src/Security/Voter/OrganizationalUnitVoter.php b/src/Security/Voter/OrganizationalUnitVoter.php index 1445a7f..2fd3112 100644 --- a/src/Security/Voter/OrganizationalUnitVoter.php +++ b/src/Security/Voter/OrganizationalUnitVoter.php @@ -5,6 +5,7 @@ namespace App\Security\Voter; use App\Dto\Output\OrganizationalUnitOutput; use App\Entity\OrganizationalUnit; use App\Entity\User; +use App\Model\UserGroupPermissions; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\Voter; use Symfony\Component\Security\Core\User\UserInterface; @@ -24,11 +25,15 @@ class OrganizationalUnitVoter extends Voter /** @var User $user */ $user = $token->getUser(); - // if the user is anonymous, do not grant access + if (!$user instanceof UserInterface) { return false; } + if (in_array(UserGroupPermissions::ROLE_SUPER_ADMIN, $user->getRoles())) { + return true; + } + if ($attribute === 'ORGANIZATIONAL_UNIT_VIEW' ) { foreach ($user->getAllowedOrganizationalUnits() as $allowedOrganizationalUnit) { if ($allowedOrganizationalUnit->getId() === $subject->getEntity()->getId()) { From 230faaebd3d852b2803c85a17e8f19aa9ce186e9 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Tue, 2 Jul 2024 08:43:02 +0200 Subject: [PATCH 28/35] refs #485. Organizational unit delete funcionality --- config/api_platform/OrganizationalUnit.yaml | 6 ++++ migrations/Version20240701123613.php | 33 +++++++++++++++++++ .../OrganizationalUnitChangeParentAction.php | 26 +++++++++++++++ src/Dto/Output/ClientOutput.php | 8 ++--- src/Dto/Output/OrganizationalUnitOutput.php | 6 +++- src/Entity/Client.php | 1 + .../OrganizationalUnitChangeParentHandler.php | 33 +++++++++++++++++++ src/State/Provider/UserProvider.php | 2 +- 8 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 migrations/Version20240701123613.php create mode 100644 src/Controller/OrganizationalUnitChangeParentAction.php create mode 100644 src/Handler/OrganizationalUnitChangeParentHandler.php diff --git a/config/api_platform/OrganizationalUnit.yaml b/config/api_platform/OrganizationalUnit.yaml index 76424c9..ac90e14 100644 --- a/config/api_platform/OrganizationalUnit.yaml +++ b/config/api_platform/OrganizationalUnit.yaml @@ -25,6 +25,12 @@ resources: groups: ['organizational-unit:patch' ] ApiPlatform\Metadata\Post: ~ ApiPlatform\Metadata\Delete: ~ + change_parent: + class: ApiPlatform\Metadata\Post + method: POST + input: false + uriTemplate: /organizational-units/{uuid}/change-parent + controller: App\Controller\OrganizationalUnitChangeParentAction properties: App\Entity\OrganizationalUnit: diff --git a/migrations/Version20240701123613.php b/migrations/Version20240701123613.php new file mode 100644 index 0000000..e83b75e --- /dev/null +++ b/migrations/Version20240701123613.php @@ -0,0 +1,33 @@ +addSql('ALTER TABLE client DROP FOREIGN KEY FK_C7440455FB84408A'); + $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455FB84408A FOREIGN KEY (organizational_unit_id) REFERENCES organizational_unit (id) ON DELETE CASCADE'); + } + + 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_C7440455FB84408A'); + $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455FB84408A FOREIGN KEY (organizational_unit_id) REFERENCES organizational_unit (id)'); + } +} diff --git a/src/Controller/OrganizationalUnitChangeParentAction.php b/src/Controller/OrganizationalUnitChangeParentAction.php new file mode 100644 index 0000000..7061b22 --- /dev/null +++ b/src/Controller/OrganizationalUnitChangeParentAction.php @@ -0,0 +1,26 @@ +organizationalUnitChangeParentHandler->handle($organizationalUnit); + + return new OrganizationalUnitInput($organizationalUnit); + } +} \ No newline at end of file diff --git a/src/Dto/Output/ClientOutput.php b/src/Dto/Output/ClientOutput.php index de2a2b7..7622bf5 100644 --- a/src/Dto/Output/ClientOutput.php +++ b/src/Dto/Output/ClientOutput.php @@ -13,13 +13,13 @@ final class ClientOutput extends AbstractOutput { CONST string TYPE = 'client'; - #[Groups(['client:read'])] + #[Groups(['client:read', 'organizational-unit:read'])] public string $name; - #[Groups(['client:read'])] + #[Groups(['client:read', 'organizational-unit:read'])] public string $type = self::TYPE; - #[Groups(['client:read'])] + #[Groups(['client:read', 'organizational-unit:read'])] public ?string $serialNumber = ''; #[Groups(['client:read'])] @@ -53,7 +53,7 @@ final class ClientOutput extends AbstractOutput $this->serialNumber = $client->getSerialNumber(); $this->netiface = $client->getNetiface(); - if ($client->getOrganizationalUnit()) { + if ($this->organizationalUnit && $client->getOrganizationalUnit()) { $this->organizationalUnit = new OrganizationalUnitOutput($client->getOrganizationalUnit()); } diff --git a/src/Dto/Output/OrganizationalUnitOutput.php b/src/Dto/Output/OrganizationalUnitOutput.php index c372ac3..83a1941 100644 --- a/src/Dto/Output/OrganizationalUnitOutput.php +++ b/src/Dto/Output/OrganizationalUnitOutput.php @@ -4,6 +4,7 @@ namespace App\Dto\Output; use ApiPlatform\Metadata\ApiProperty; use ApiPlatform\Metadata\Get; +use App\Entity\Client; use App\Entity\OrganizationalUnit; use Symfony\Component\Serializer\Annotation\Groups; @@ -62,7 +63,10 @@ final class OrganizationalUnitOutput extends AbstractOutput $this->capacity = $organizationalUnit->getCapacity(); $this->type = $organizationalUnit->getType(); $this->networkSettings = $organizationalUnit->getNetworkSettings() ? new NetworkSettingsOutput($organizationalUnit->getNetworkSettings()) : null; - $this->clients = $organizationalUnit->getClients()->toArray(); + + $this->clients = $organizationalUnit->getClients()->map( + fn(Client $client) => new ClientOutput($client) + )->toArray(); if ($organizationalUnit->getParent()) { $this->parent = new self($organizationalUnit->getParent()); diff --git a/src/Entity/Client.php b/src/Entity/Client.php index 16dfc1a..867fa3c 100644 --- a/src/Entity/Client.php +++ b/src/Entity/Client.php @@ -36,6 +36,7 @@ class Client extends AbstractEntity private ?string $status = null; #[ORM\ManyToOne(inversedBy: 'clients')] + #[ORM\JoinColumn( onDelete: 'CASCADE')] private ?OrganizationalUnit $organizationalUnit = null; /** diff --git a/src/Handler/OrganizationalUnitChangeParentHandler.php b/src/Handler/OrganizationalUnitChangeParentHandler.php new file mode 100644 index 0000000..b78e651 --- /dev/null +++ b/src/Handler/OrganizationalUnitChangeParentHandler.php @@ -0,0 +1,33 @@ +getParent(); + + if (!$parent) { + return throw new \InvalidArgumentException('The organizational unit has no parent.'); + } + + foreach ($organizationalUnit->getOrganizationalUnits() as $child) { + $child->setParent($parent); + $this->organizationalUnitRepository->save($child); + } + + $this->organizationalUnitRepository->delete($organizationalUnit); + + return $organizationalUnit; + } +} \ No newline at end of file diff --git a/src/State/Provider/UserProvider.php b/src/State/Provider/UserProvider.php index a850ef7..5ef6eda 100644 --- a/src/State/Provider/UserProvider.php +++ b/src/State/Provider/UserProvider.php @@ -30,7 +30,7 @@ class UserProvider implements ProviderInterface return $this->provideCollection($operation, $uriVariables, $context); case $operation instanceof Patch: case $operation instanceof Put: - return $this->provideInput($operation, $uriVariables, $context); + return $this->provideInput($operation, $uriVariables, $context); case $operation instanceof Get: return $this->provideItem($operation, $uriVariables, $context); } From 2267a52e0647181f909a9c32a1b6201809e67816 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Tue, 2 Jul 2024 11:19:55 +0200 Subject: [PATCH 29/35] refs #485. Organizational unit delete funcionality --- src/Dto/Output/ClientOutput.php | 4 ++-- src/Dto/Output/OrganizationalUnitOutput.php | 7 ------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Dto/Output/ClientOutput.php b/src/Dto/Output/ClientOutput.php index 7622bf5..4e378ce 100644 --- a/src/Dto/Output/ClientOutput.php +++ b/src/Dto/Output/ClientOutput.php @@ -25,7 +25,7 @@ final class ClientOutput extends AbstractOutput #[Groups(['client:read'])] public ?string $netiface = ''; - #[Groups(['client:read'])] + #[Groups(['client:read', 'organizational-unit:read'])] #[ApiProperty(readableLink: true )] public ?OrganizationalUnitOutput $organizationalUnit = null; @@ -53,7 +53,7 @@ final class ClientOutput extends AbstractOutput $this->serialNumber = $client->getSerialNumber(); $this->netiface = $client->getNetiface(); - if ($this->organizationalUnit && $client->getOrganizationalUnit()) { + if ($client->getOrganizationalUnit()) { $this->organizationalUnit = new OrganizationalUnitOutput($client->getOrganizationalUnit()); } diff --git a/src/Dto/Output/OrganizationalUnitOutput.php b/src/Dto/Output/OrganizationalUnitOutput.php index 83a1941..f03c657 100644 --- a/src/Dto/Output/OrganizationalUnitOutput.php +++ b/src/Dto/Output/OrganizationalUnitOutput.php @@ -42,9 +42,6 @@ final class OrganizationalUnitOutput extends AbstractOutput #[ApiProperty(readableLink: true)] public ?NetworkSettingsOutput $networkSettings = null; - #[Groups(['organizational-unit:read'])] - public array $clients = []; - #[Groups(['organizational-unit:read'])] public \DateTime $createdAt; @@ -64,10 +61,6 @@ final class OrganizationalUnitOutput extends AbstractOutput $this->type = $organizationalUnit->getType(); $this->networkSettings = $organizationalUnit->getNetworkSettings() ? new NetworkSettingsOutput($organizationalUnit->getNetworkSettings()) : null; - $this->clients = $organizationalUnit->getClients()->map( - fn(Client $client) => new ClientOutput($client) - )->toArray(); - if ($organizationalUnit->getParent()) { $this->parent = new self($organizationalUnit->getParent()); } From 406f135804313ceea253e6ab83d70d37ba349d0d Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Tue, 2 Jul 2024 15:53:23 +0200 Subject: [PATCH 30/35] refs #487. Software and softwaare profile Endpoints and firs logic --- config/api_platform/Software.yaml | 31 ++++++ config/api_platform/SoftwareProfile.yaml | 30 ++++++ config/services.yaml | 10 ++ migrations/Version20240702132742.php | 41 +++++++ src/Dto/Input/SoftwareInput.php | 42 ++++++++ src/Dto/Input/SoftwareProfileInput.php | 51 +++++++++ src/Dto/Output/SoftwareOutput.php | 34 ++++++ src/Dto/Output/SoftwareProfileOutput.php | 49 +++++++++ src/Entity/OrganizationalUnit.php | 37 +++++++ src/Entity/Software.php | 69 ++++++++++++ src/Entity/SoftwareProfile.php | 100 ++++++++++++++++++ src/Model/SoftwareTypes.php | 31 ++++++ src/Repository/SoftwareProfileRepository.php | 18 ++++ src/Repository/SoftwareRepository.php | 18 ++++ src/State/Processor/SoftwareProcessor.php | 68 ++++++++++++ .../Processor/SoftwareProfileProcessor.php | 68 ++++++++++++ .../Provider/SoftwareProfileProvider.php | 71 +++++++++++++ src/State/Provider/SoftwareProvider.php | 71 +++++++++++++ 18 files changed, 839 insertions(+) create mode 100644 config/api_platform/Software.yaml create mode 100644 config/api_platform/SoftwareProfile.yaml create mode 100644 migrations/Version20240702132742.php create mode 100644 src/Dto/Input/SoftwareInput.php create mode 100644 src/Dto/Input/SoftwareProfileInput.php create mode 100644 src/Dto/Output/SoftwareOutput.php create mode 100644 src/Dto/Output/SoftwareProfileOutput.php create mode 100644 src/Entity/Software.php create mode 100644 src/Entity/SoftwareProfile.php create mode 100644 src/Model/SoftwareTypes.php create mode 100644 src/Repository/SoftwareProfileRepository.php create mode 100644 src/Repository/SoftwareRepository.php create mode 100644 src/State/Processor/SoftwareProcessor.php create mode 100644 src/State/Processor/SoftwareProfileProcessor.php create mode 100644 src/State/Provider/SoftwareProfileProvider.php create mode 100644 src/State/Provider/SoftwareProvider.php diff --git a/config/api_platform/Software.yaml b/config/api_platform/Software.yaml new file mode 100644 index 0000000..4e34a66 --- /dev/null +++ b/config/api_platform/Software.yaml @@ -0,0 +1,31 @@ +resources: + App\Entity\Software: + processor: App\State\Processor\SoftwareProcessor + input: App\Dto\Input\SoftwareInput + output: App\Dto\Output\SoftwareOutput + normalizationContext: + groups: ['default', 'software:read'] + denormalizationContext: + groups: ['software:write'] + operations: + ApiPlatform\Metadata\GetCollection: + provider: App\State\Provider\SoftwareProvider + filters: + - 'api_platform.filter.software.order' + - 'api_platform.filter.software.search' + + ApiPlatform\Metadata\Get: + provider: App\State\Provider\SoftwareProvider + ApiPlatform\Metadata\Put: + provider: App\State\Provider\SoftwareProvider + ApiPlatform\Metadata\Patch: + provider: App\State\Provider\SoftwareProvider + ApiPlatform\Metadata\Post: ~ + ApiPlatform\Metadata\Delete: ~ + +properties: + App\Entity\Software: + id: + identifier: false + uuid: + identifier: true \ No newline at end of file diff --git a/config/api_platform/SoftwareProfile.yaml b/config/api_platform/SoftwareProfile.yaml new file mode 100644 index 0000000..f5c544c --- /dev/null +++ b/config/api_platform/SoftwareProfile.yaml @@ -0,0 +1,30 @@ +resources: + App\Entity\SoftwareProfile: + processor: App\State\Processor\SoftwareProfileProcessor + input: App\Dto\Input\SoftwareProfileInput + output: App\Dto\Output\SoftwareProfileOutput + normalizationContext: + groups: ['default', 'software-profile:read'] + denormalizationContext: + groups: ['software-profile:write'] + operations: + ApiPlatform\Metadata\GetCollection: + provider: App\State\Provider\SoftwareProfileProvider + filters: + - 'api_platform.filter.software.order' + - 'api_platform.filter.software.search' + ApiPlatform\Metadata\Get: + provider: App\State\Provider\SoftwareProfileProvider + ApiPlatform\Metadata\Put: + provider: App\State\Provider\SoftwareProfileProvider + ApiPlatform\Metadata\Patch: + provider: App\State\Provider\SoftwareProfileProvider + ApiPlatform\Metadata\Post: ~ + ApiPlatform\Metadata\Delete: ~ + +properties: + App\Entity\SoftwareProfile: + id: + identifier: false + uuid: + identifier: true \ No newline at end of file diff --git a/config/services.yaml b/config/services.yaml index e9086eb..6b82216 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -69,6 +69,16 @@ services: $itemProvider: '@api_platform.doctrine.orm.state.item_provider' App\State\Provider\HardwareTypeProvider: + bind: + $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' + $itemProvider: '@api_platform.doctrine.orm.state.item_provider' + + App\State\Provider\SoftwareProvider: + bind: + $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' + $itemProvider: '@api_platform.doctrine.orm.state.item_provider' + + App\State\Provider\SoftwareProfileProvider: bind: $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' $itemProvider: '@api_platform.doctrine.orm.state.item_provider' \ No newline at end of file diff --git a/migrations/Version20240702132742.php b/migrations/Version20240702132742.php new file mode 100644 index 0000000..91069d5 --- /dev/null +++ b/migrations/Version20240702132742.php @@ -0,0 +1,41 @@ +addSql('CREATE TABLE software (id INT AUTO_INCREMENT 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, description VARCHAR(255) DEFAULT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_77D068CFD17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE software_profile (id INT AUTO_INCREMENT NOT NULL, organizational_unit_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, description VARCHAR(255) DEFAULT NULL, comments VARCHAR(255) DEFAULT NULL, UNIQUE INDEX UNIQ_B70C3C9BD17F50A6 (uuid), INDEX IDX_B70C3C9BFB84408A (organizational_unit_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE software_profile_software (software_profile_id INT NOT NULL, software_id INT NOT NULL, INDEX IDX_3DDFEC7ED42A742 (software_profile_id), INDEX IDX_3DDFEC7D7452741 (software_id), PRIMARY KEY(software_profile_id, software_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE software_profile ADD CONSTRAINT FK_B70C3C9BFB84408A FOREIGN KEY (organizational_unit_id) REFERENCES organizational_unit (id)'); + $this->addSql('ALTER TABLE software_profile_software ADD CONSTRAINT FK_3DDFEC7ED42A742 FOREIGN KEY (software_profile_id) REFERENCES software_profile (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE software_profile_software ADD CONSTRAINT FK_3DDFEC7D7452741 FOREIGN KEY (software_id) REFERENCES software (id) ON DELETE CASCADE'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE software_profile DROP FOREIGN KEY FK_B70C3C9BFB84408A'); + $this->addSql('ALTER TABLE software_profile_software DROP FOREIGN KEY FK_3DDFEC7ED42A742'); + $this->addSql('ALTER TABLE software_profile_software DROP FOREIGN KEY FK_3DDFEC7D7452741'); + $this->addSql('DROP TABLE software'); + $this->addSql('DROP TABLE software_profile'); + $this->addSql('DROP TABLE software_profile_software'); + } +} diff --git a/src/Dto/Input/SoftwareInput.php b/src/Dto/Input/SoftwareInput.php new file mode 100644 index 0000000..624a94c --- /dev/null +++ b/src/Dto/Input/SoftwareInput.php @@ -0,0 +1,42 @@ +name = $software->getName(); + $this->description = $software->getDescription(); + } + + public function createOrUpdateEntity(?Software $software = null): Software + { + if (!$software) { + $software = new Software(); + } + + $software->setName($this->name); + $software->setDescription($this->description); + + return $software; + } +} \ No newline at end of file diff --git a/src/Dto/Input/SoftwareProfileInput.php b/src/Dto/Input/SoftwareProfileInput.php new file mode 100644 index 0000000..c803d82 --- /dev/null +++ b/src/Dto/Input/SoftwareProfileInput.php @@ -0,0 +1,51 @@ +description = $softwareProfile->getDescription(); + $this->comments = $softwareProfile->getComments(); + if($softwareProfile->getOrganizationalUnit()) { + $this->organizationalUnit = new OrganizationalUnitOutput($softwareProfile->getOrganizationalUnit()); + } + } + + public function createOrUpdateEntity(?SoftwareProfile $softwareProfile = null): SoftwareProfile + { + if (!$softwareProfile) { + $softwareProfile = new SoftwareProfile(); + } + + $softwareProfile->setDescription($this->description); + $softwareProfile->setComments($this->comments); + if ($this->organizationalUnit) { + $softwareProfile->setOrganizationalUnit($this->organizationalUnit->getEntity()); + } + + return $softwareProfile; + } +} \ No newline at end of file diff --git a/src/Dto/Output/SoftwareOutput.php b/src/Dto/Output/SoftwareOutput.php new file mode 100644 index 0000000..07a4fee --- /dev/null +++ b/src/Dto/Output/SoftwareOutput.php @@ -0,0 +1,34 @@ +name = $software->getName(); + $this->description = $software->getDescription(); + $this->createdAt = $software->getCreatedAt(); + $this->createdBy = $software->getCreatedBy(); + } +} \ No newline at end of file diff --git a/src/Dto/Output/SoftwareProfileOutput.php b/src/Dto/Output/SoftwareProfileOutput.php new file mode 100644 index 0000000..5dc21e0 --- /dev/null +++ b/src/Dto/Output/SoftwareProfileOutput.php @@ -0,0 +1,49 @@ +description = $softwareProfile->getDescription(); + $this->comments = $softwareProfile->getComments(); + if($softwareProfile->getOrganizationalUnit()) { + $this->organizationalUnit = new OrganizationalUnitOutput($softwareProfile->getOrganizationalUnit()); + } + + $this->softwareCollection = $softwareProfile->getSoftwareCollection()->map( + fn(Software $hardware) => new SoftwareOutput($hardware) + )->toArray(); + + $this->createdAt = $softwareProfile->getCreatedAt(); + $this->createdBy = $softwareProfile->getCreatedBy(); + } +} \ No newline at end of file diff --git a/src/Entity/OrganizationalUnit.php b/src/Entity/OrganizationalUnit.php index 136cf16..469a9f5 100644 --- a/src/Entity/OrganizationalUnit.php +++ b/src/Entity/OrganizationalUnit.php @@ -78,12 +78,19 @@ class OrganizationalUnit extends AbstractEntity #[ORM\Column(nullable: true)] private ?int $capacity = null; + /** + * @var Collection + */ + #[ORM\OneToMany(mappedBy: 'organizationalUnit', targetEntity: SoftwareProfile::class)] + private Collection $softwareProfiles; + public function __construct() { parent::__construct(); $this->organizationalUnits = new ArrayCollection(); $this->users = new ArrayCollection(); $this->clients = new ArrayCollection(); + $this->softwareProfiles = new ArrayCollection(); } public function getDescription(): ?string @@ -331,4 +338,34 @@ class OrganizationalUnit extends AbstractEntity $childUnit->updateNetworkSettingsRecursively($networkSettings); } } + + /** + * @return Collection + */ + public function getSoftwareProfiles(): Collection + { + return $this->softwareProfiles; + } + + public function addSoftwareProfile(SoftwareProfile $softwareProfile): static + { + if (!$this->softwareProfiles->contains($softwareProfile)) { + $this->softwareProfiles->add($softwareProfile); + $softwareProfile->setOrganizationalUnit($this); + } + + return $this; + } + + public function removeSoftwareProfile(SoftwareProfile $softwareProfile): static + { + if ($this->softwareProfiles->removeElement($softwareProfile)) { + // set the owning side to null (unless already changed) + if ($softwareProfile->getOrganizationalUnit() === $this) { + $softwareProfile->setOrganizationalUnit(null); + } + } + + return $this; + } } diff --git a/src/Entity/Software.php b/src/Entity/Software.php new file mode 100644 index 0000000..1723483 --- /dev/null +++ b/src/Entity/Software.php @@ -0,0 +1,69 @@ + + */ + #[ORM\ManyToMany(targetEntity: SoftwareProfile::class, mappedBy: 'softwareCollection')] + private Collection $softwareProfiles; + + public function __construct() + { + parent::__construct(); + $this->softwareProfiles = new ArrayCollection(); + } + + + public function getDescription(): ?string + { + return $this->description; + } + + public function setDescription(?string $description): static + { + $this->description = $description; + + return $this; + } + + /** + * @return Collection + */ + public function getSoftwareProfiles(): Collection + { + return $this->softwareProfiles; + } + + public function addSoftwareProfile(SoftwareProfile $softwareProfile): static + { + if (!$this->softwareProfiles->contains($softwareProfile)) { + $this->softwareProfiles->add($softwareProfile); + $softwareProfile->addSoftwareCollection($this); + } + + return $this; + } + + public function removeSoftwareProfile(SoftwareProfile $softwareProfile): static + { + if ($this->softwareProfiles->removeElement($softwareProfile)) { + $softwareProfile->removeSoftwareCollection($this); + } + + return $this; + } +} diff --git a/src/Entity/SoftwareProfile.php b/src/Entity/SoftwareProfile.php new file mode 100644 index 0000000..bc0f968 --- /dev/null +++ b/src/Entity/SoftwareProfile.php @@ -0,0 +1,100 @@ + + */ + #[ORM\ManyToMany(targetEntity: Software::class, inversedBy: 'softwareProfiles')] + private Collection $softwareCollection; + + public function __construct() + { + parent::__construct(); + + $this->softwareCollection = new ArrayCollection(); + } + + public function getId(): ?int + { + return $this->id; + } + + public function getDescription(): ?string + { + return $this->description; + } + + public function setDescription(?string $description): static + { + $this->description = $description; + + return $this; + } + + public function getComments(): ?string + { + return $this->comments; + } + + public function setComments(?string $comments): static + { + $this->comments = $comments; + + return $this; + } + + public function getOrganizationalUnit(): ?OrganizationalUnit + { + return $this->organizationalUnit; + } + + public function setOrganizationalUnit(?OrganizationalUnit $organizationalUnit): static + { + $this->organizationalUnit = $organizationalUnit; + + return $this; + } + + /** + * @return Collection + */ + public function getSoftwareCollection(): Collection + { + return $this->softwareCollection; + } + + public function addSoftwareCollection(Software $softwareCollection): static + { + if (!$this->softwareCollection->contains($softwareCollection)) { + $this->softwareCollection->add($softwareCollection); + } + + return $this; + } + + public function removeSoftwareCollection(Software $softwareCollection): static + { + $this->softwareCollection->removeElement($softwareCollection); + + return $this; + } +} diff --git a/src/Model/SoftwareTypes.php b/src/Model/SoftwareTypes.php new file mode 100644 index 0000000..afe552a --- /dev/null +++ b/src/Model/SoftwareTypes.php @@ -0,0 +1,31 @@ + 'Sistema Operativo', + self::FILE => 'Fichero', + self::APPLICATION => 'Aplicación', + ]; + + public static function getSoftwareTypes(): array + { + return self::SOFTWARE_TYPES; + } + + public static function getSoftwareType(string $software): ?string + { + return self::SOFTWARE_TYPES[$software] ?? null; + } + + public static function getSoftwareTypeKeys(): array + { + return array_keys(self::SOFTWARE_TYPES); + } +} \ No newline at end of file diff --git a/src/Repository/SoftwareProfileRepository.php b/src/Repository/SoftwareProfileRepository.php new file mode 100644 index 0000000..72fded4 --- /dev/null +++ b/src/Repository/SoftwareProfileRepository.php @@ -0,0 +1,18 @@ + + */ +class SoftwareProfileRepository extends AbstractRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, SoftwareProfile::class); + } +} diff --git a/src/Repository/SoftwareRepository.php b/src/Repository/SoftwareRepository.php new file mode 100644 index 0000000..9b7f49f --- /dev/null +++ b/src/Repository/SoftwareRepository.php @@ -0,0 +1,18 @@ + + */ +class SoftwareRepository extends AbstractRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Software::class); + } +} diff --git a/src/State/Processor/SoftwareProcessor.php b/src/State/Processor/SoftwareProcessor.php new file mode 100644 index 0000000..3730595 --- /dev/null +++ b/src/State/Processor/SoftwareProcessor.php @@ -0,0 +1,68 @@ +processCreateOrUpdate($data, $operation, $uriVariables, $context); + case $operation instanceof Delete: + return $this->processDelete($data, $operation, $uriVariables, $context); + } + } + + /** + * @throws \Exception + */ + private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): SoftwareOutput + { + if (!($data instanceof SoftwareInput)) { + throw new \Exception(sprintf('data is not instance of %s', SoftwareInput::class)); + } + + $entity = null; + if (isset($uriVariables['uuid'])) { + $entity = $this->softwareRepository->findOneByUuid($uriVariables['uuid']); + } + + $software = $data->createOrUpdateEntity($entity); + $this->validator->validate($software); + $this->softwareRepository->save($software); + + return new SoftwareOutput($software); + } + + private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null + { + $user = $this->softwareRepository->findOneByUuid($uriVariables['uuid']); + $this->softwareRepository->delete($user); + + return null; + } +} diff --git a/src/State/Processor/SoftwareProfileProcessor.php b/src/State/Processor/SoftwareProfileProcessor.php new file mode 100644 index 0000000..7368d4d --- /dev/null +++ b/src/State/Processor/SoftwareProfileProcessor.php @@ -0,0 +1,68 @@ +processCreateOrUpdate($data, $operation, $uriVariables, $context); + case $operation instanceof Delete: + return $this->processDelete($data, $operation, $uriVariables, $context); + } + } + + /** + * @throws \Exception + */ + private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): SoftwareProfileOutput + { + if (!($data instanceof SoftwareProfileInput)) { + throw new \Exception(sprintf('data is not instance of %s', SoftwareProfileInput::class)); + } + + $entity = null; + if (isset($uriVariables['uuid'])) { + $entity = $this->softwareProfileRepository->findOneByUuid($uriVariables['uuid']); + } + + $softwareProfile = $data->createOrUpdateEntity($entity); + $this->validator->validate($softwareProfile); + $this->softwareProfileRepository->save($softwareProfile); + + return new SoftwareProfileOutput($softwareProfile); + } + + private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null + { + $user = $this->softwareProfileRepository->findOneByUuid($uriVariables['uuid']); + $this->softwareProfileRepository->delete($user); + + return null; + } +} diff --git a/src/State/Provider/SoftwareProfileProvider.php b/src/State/Provider/SoftwareProfileProvider.php new file mode 100644 index 0000000..94f9aed --- /dev/null +++ b/src/State/Provider/SoftwareProfileProvider.php @@ -0,0 +1,71 @@ +provideCollection($operation, $uriVariables, $context); + case $operation instanceof Patch: + case $operation instanceof Put: + return $this->provideInput($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 SoftwareProfileInput($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('Software profile not found'); + } + + return new SoftwareProfileOutput($item); + } + + public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + if (isset($uriVariables['uuid'])) { + $item = $this->itemProvider->provide($operation, $uriVariables, $context); + + return $item !== null ? new SoftwareProfileInput($item) : null; + } + + return new SoftwareProfileInput(); + } +} diff --git a/src/State/Provider/SoftwareProvider.php b/src/State/Provider/SoftwareProvider.php new file mode 100644 index 0000000..9459b09 --- /dev/null +++ b/src/State/Provider/SoftwareProvider.php @@ -0,0 +1,71 @@ +provideCollection($operation, $uriVariables, $context); + case $operation instanceof Patch: + case $operation instanceof Put: + return $this->provideInput($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 SoftwareOutput($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('Software not found'); + } + + return new SoftwareOutput($item); + } + + public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + if (isset($uriVariables['uuid'])) { + $item = $this->itemProvider->provide($operation, $uriVariables, $context); + + return $item !== null ? new SoftwareInput($item) : null; + } + + return new SoftwareInput(); + } +} From 04b3bb72c7062747e727e96e5450729521897872 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Thu, 4 Jul 2024 08:29:24 +0200 Subject: [PATCH 31/35] refs #487. Added image model and endpoint --- config/api_platform/Image.yaml | 30 ++++ config/services.yaml | 7 +- migrations/Version20240703090301.php | 35 ++++ ...grateSoftwareAndSoftwareProfileCommand.php | 57 +++++++ src/Dto/Input/ImageInput.php | 92 +++++++++++ src/Dto/Output/ImageOutput.php | 57 +++++++ src/Entity/Image.php | 149 ++++++++++++++++++ src/Entity/SoftwareProfile.php | 1 + src/Repository/ImageRepository.php | 18 +++ src/State/Processor/ImageProcessor.php | 68 ++++++++ .../Provider/HardwareProfileProvider.php | 9 +- src/State/Provider/HardwareProvider.php | 8 +- src/State/Provider/HardwareTypeProvider.php | 13 +- src/State/Provider/ImageProvider.php | 71 +++++++++ src/State/Provider/MenuProvider.php | 4 - .../Provider/OperativeSystemProvider.php | 11 +- .../Provider/OrganizationalUnitProvider.php | 13 +- src/State/Provider/PartitionProvider.php | 12 +- 18 files changed, 602 insertions(+), 53 deletions(-) create mode 100644 config/api_platform/Image.yaml create mode 100644 migrations/Version20240703090301.php create mode 100644 src/Command/Migration/MigrateSoftwareAndSoftwareProfileCommand.php create mode 100644 src/Dto/Input/ImageInput.php create mode 100644 src/Dto/Output/ImageOutput.php create mode 100644 src/Entity/Image.php create mode 100644 src/Repository/ImageRepository.php create mode 100644 src/State/Processor/ImageProcessor.php create mode 100644 src/State/Provider/ImageProvider.php diff --git a/config/api_platform/Image.yaml b/config/api_platform/Image.yaml new file mode 100644 index 0000000..37ab891 --- /dev/null +++ b/config/api_platform/Image.yaml @@ -0,0 +1,30 @@ +resources: + App\Entity\Image: + processor: App\State\Processor\ImageProcessor + input: App\Dto\Input\ImageInput + output: App\Dto\Output\ImageOutput + normalizationContext: + groups: ['default', 'image:read'] + denormalizationContext: + groups: ['image:write'] + operations: + ApiPlatform\Metadata\GetCollection: + provider: App\State\Provider\ImageProvider + filters: + - 'api_platform.filter.image.order' + - 'api_platform.filter.image.search' + ApiPlatform\Metadata\Get: + provider: App\State\Provider\ImageProvider + ApiPlatform\Metadata\Put: + provider: App\State\Provider\ImageProvider + ApiPlatform\Metadata\Patch: + provider: App\State\Provider\ImageProvider + ApiPlatform\Metadata\Post: ~ + ApiPlatform\Metadata\Delete: ~ + +properties: + App\Entity\Image: + id: + identifier: false + uuid: + identifier: true \ No newline at end of file diff --git a/config/services.yaml b/config/services.yaml index 6b82216..1c97d41 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -81,4 +81,9 @@ services: App\State\Provider\SoftwareProfileProvider: bind: $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' - $itemProvider: '@api_platform.doctrine.orm.state.item_provider' \ No newline at end of file + $itemProvider: '@api_platform.doctrine.orm.state.item_provider' + + App\State\Provider\ImageProvider: + bind: + $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' + $itemProvider: '@api_platform.doctrine.orm.state.item_provider' diff --git a/migrations/Version20240703090301.php b/migrations/Version20240703090301.php new file mode 100644 index 0000000..9a7588b --- /dev/null +++ b/migrations/Version20240703090301.php @@ -0,0 +1,35 @@ +addSql('CREATE TABLE image (id INT AUTO_INCREMENT NOT NULL, client_id INT NOT NULL, software_profile_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, description VARCHAR(255) DEFAULT NULL, comments VARCHAR(255) DEFAULT NULL, path VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL, revision VARCHAR(255) DEFAULT NULL, info VARCHAR(255) DEFAULT NULL, size INT NOT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_C53D045FD17F50A6 (uuid), INDEX IDX_C53D045F19EB6921 (client_id), INDEX IDX_C53D045FED42A742 (software_profile_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE image ADD CONSTRAINT FK_C53D045F19EB6921 FOREIGN KEY (client_id) REFERENCES client (id)'); + $this->addSql('ALTER TABLE image ADD CONSTRAINT FK_C53D045FED42A742 FOREIGN KEY (software_profile_id) REFERENCES software_profile (id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE image DROP FOREIGN KEY FK_C53D045F19EB6921'); + $this->addSql('ALTER TABLE image DROP FOREIGN KEY FK_C53D045FED42A742'); + $this->addSql('DROP TABLE image'); + } +} diff --git a/src/Command/Migration/MigrateSoftwareAndSoftwareProfileCommand.php b/src/Command/Migration/MigrateSoftwareAndSoftwareProfileCommand.php new file mode 100644 index 0000000..6daf869 --- /dev/null +++ b/src/Command/Migration/MigrateSoftwareAndSoftwareProfileCommand.php @@ -0,0 +1,57 @@ +doctrine->getManager('og_1'); + + $organizationalUnitRepository = $this->entityManager->getRepository(OrganizationalUnit::class); + $softwareProfileRepository = $this->entityManager->getRepository(SoftwareProfile::class); + $softwareRepository = $this->entityManager->getRepository(Software::class); + + /** Obtener los perfiles software de la base de datos antigua **/ + $rsmSoftware = new ResultSetMapping(); + $rsmSoftware->addScalarResult('idtiposoftware', 'idtiposoftware'); + $rsmSoftware->addScalarResult('descripcion', 'descripcion'); + + $softwareQuery = $oldDatabaseEntityManager->createNativeQuery('SELECT idtiposoftware, descripcion FROM softwares', $rsmSoftware); + $softwareCollection = $softwareQuery->getResult(); + + foreach ($softwareCollection as $software) { + $softwareEntity = null; + $softwareEntity = $softwareRepository->findOneBy(['migrationId' => $software['idtiposoftware']]); + if (!$softwareEntity) { + $softwareEntity = new Software(); + $softwareEntity->setMigrationId($software['idtiposoftware']); + $softwareEntity->setName($software['descripcion']); + $softwareEntity->setDescription($software['descripcion']); + } + + $this->entityManager->persist($softwareEntity); + } + } +} \ No newline at end of file diff --git a/src/Dto/Input/ImageInput.php b/src/Dto/Input/ImageInput.php new file mode 100644 index 0000000..d6623ab --- /dev/null +++ b/src/Dto/Input/ImageInput.php @@ -0,0 +1,92 @@ +name = $image->getName(); + $this->description = $image->getDescription(); + $this->comments = $image->getComments(); + $this->type = $image->getType(); + $this->path = $image->getPath(); + $this->revision = $image->getRevision(); + $this->info = $image->getInfo(); + $this->size = $image->getSize(); + $this->client = new ClientOutput($image->getClient()); + $this->softwareProfile = new SoftwareProfileOutput($image->getSoftwareProfile()); + } + + public function createOrUpdateEntity(?Image $image = null): Image + { + if (!$image) { + $image = new Image(); + } + + $image->setName($this->name); + $image->setDescription($this->description); + $image->setComments($this->comments); + $image->setType($this->type); + $image->setPath($this->path); + $image->setRevision($this->revision); + $image->setInfo($this->info); + $image->setSize($this->size); + $image->setClient($this->client->getEntity()); + $image->setSoftwareProfile($this->softwareProfile->getEntity()); + + return $image; + } +} \ No newline at end of file diff --git a/src/Dto/Output/ImageOutput.php b/src/Dto/Output/ImageOutput.php new file mode 100644 index 0000000..f14e16a --- /dev/null +++ b/src/Dto/Output/ImageOutput.php @@ -0,0 +1,57 @@ +name = $image->getName(); + $this->description = $image->getDescription(); + $this->comments = $image->getComments(); + $this->type = $image->getType(); + $this->path = $image->getPath(); + $this->revision = $image->getRevision(); + $this->info = $image->getInfo(); + $this->size = $image->getSize(); + $this->clientOutput = new ClientOutput($image->getClient()); + $this->softwareProfile = new SoftwareProfileOutput($image->getSoftwareProfile()); + } +} \ No newline at end of file diff --git a/src/Entity/Image.php b/src/Entity/Image.php new file mode 100644 index 0000000..5d41052 --- /dev/null +++ b/src/Entity/Image.php @@ -0,0 +1,149 @@ +description; + } + + public function setDescription(?string $description): static + { + $this->description = $description; + + return $this; + } + + public function getComments(): ?string + { + return $this->comments; + } + + public function setComments(?string $comments): static + { + $this->comments = $comments; + + return $this; + } + + public function getPath(): ?string + { + return $this->path; + } + + public function setPath(string $path): static + { + $this->path = $path; + + return $this; + } + + public function getType(): ?string + { + return $this->type; + } + + public function setType(string $type): static + { + $this->type = $type; + + return $this; + } + + public function getRevision(): ?string + { + return $this->revision; + } + + public function setRevision(?string $revision): static + { + $this->revision = $revision; + + return $this; + } + + public function getInfo(): ?string + { + return $this->info; + } + + public function setInfo(?string $info): static + { + $this->info = $info; + + return $this; + } + + public function getSize(): ?int + { + return $this->size; + } + + public function setSize(int $size): static + { + $this->size = $size; + + return $this; + } + + public function getClient(): ?Client + { + return $this->client; + } + + public function setClient(?Client $client): static + { + $this->client = $client; + + return $this; + } + + public function getSoftwareProfile(): ?SoftwareProfile + { + return $this->softwareProfile; + } + + public function setSoftwareProfile(?SoftwareProfile $softwareProfile): static + { + $this->softwareProfile = $softwareProfile; + + return $this; + } +} diff --git a/src/Entity/SoftwareProfile.php b/src/Entity/SoftwareProfile.php index bc0f968..4ac75b8 100644 --- a/src/Entity/SoftwareProfile.php +++ b/src/Entity/SoftwareProfile.php @@ -20,6 +20,7 @@ class SoftwareProfile extends AbstractEntity #[ORM\JoinColumn(nullable: false)] private ?OrganizationalUnit $organizationalUnit = null; + /** * @var Collection */ diff --git a/src/Repository/ImageRepository.php b/src/Repository/ImageRepository.php new file mode 100644 index 0000000..b20b95b --- /dev/null +++ b/src/Repository/ImageRepository.php @@ -0,0 +1,18 @@ + + */ +class ImageRepository extends AbstractRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Image::class); + } +} diff --git a/src/State/Processor/ImageProcessor.php b/src/State/Processor/ImageProcessor.php new file mode 100644 index 0000000..8506b70 --- /dev/null +++ b/src/State/Processor/ImageProcessor.php @@ -0,0 +1,68 @@ +processCreateOrUpdate($data, $operation, $uriVariables, $context); + case $operation instanceof Delete: + return $this->processDelete($data, $operation, $uriVariables, $context); + } + } + + /** + * @throws \Exception + */ + private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): ImageOutput + { + if (!($data instanceof ImageInput)) { + throw new \Exception(sprintf('data is not instance of %s', ImageInput::class)); + } + + $entity = null; + if (isset($uriVariables['uuid'])) { + $entity = $this->imageRepository->findOneByUuid($uriVariables['uuid']); + } + + $image = $data->createOrUpdateEntity($entity); + $this->validator->validate($image); + $this->imageRepository->save($image); + + return new ImageOutput($image); + } + + private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null + { + $user = $this->imageRepository->findOneByUuid($uriVariables['uuid']); + $this->imageRepository->delete($user); + + return null; + } +} diff --git a/src/State/Provider/HardwareProfileProvider.php b/src/State/Provider/HardwareProfileProvider.php index 241fda1..553b004 100644 --- a/src/State/Provider/HardwareProfileProvider.php +++ b/src/State/Provider/HardwareProfileProvider.php @@ -9,19 +9,16 @@ use ApiPlatform\Metadata\Patch; use ApiPlatform\Metadata\Put; use ApiPlatform\State\Pagination\TraversablePaginator; use ApiPlatform\State\ProviderInterface; -use App\Dto\Input\ClientInput; use App\Dto\Input\HardwareInput; use App\Dto\Input\HardwareProfileInput; -use App\Dto\Output\ClientOutput; -use App\Dto\Output\HardwareOutput; use App\Dto\Output\HardwareProfileOutput; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -class HardwareProfileProvider implements ProviderInterface +readonly class HardwareProfileProvider implements ProviderInterface { public function __construct( - private readonly ProviderInterface $collectionProvider, - private readonly ProviderInterface $itemProvider + private ProviderInterface $collectionProvider, + private ProviderInterface $itemProvider ) { } diff --git a/src/State/Provider/HardwareProvider.php b/src/State/Provider/HardwareProvider.php index 0342d64..93c91af 100644 --- a/src/State/Provider/HardwareProvider.php +++ b/src/State/Provider/HardwareProvider.php @@ -9,17 +9,15 @@ use ApiPlatform\Metadata\Patch; use ApiPlatform\Metadata\Put; use ApiPlatform\State\Pagination\TraversablePaginator; use ApiPlatform\State\ProviderInterface; -use App\Dto\Input\ClientInput; use App\Dto\Input\HardwareInput; -use App\Dto\Output\ClientOutput; use App\Dto\Output\HardwareOutput; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -class HardwareProvider implements ProviderInterface +readonly class HardwareProvider implements ProviderInterface { public function __construct( - private readonly ProviderInterface $collectionProvider, - private readonly ProviderInterface $itemProvider + private ProviderInterface $collectionProvider, + private ProviderInterface $itemProvider ) { } diff --git a/src/State/Provider/HardwareTypeProvider.php b/src/State/Provider/HardwareTypeProvider.php index f4e78cd..4a5835b 100644 --- a/src/State/Provider/HardwareTypeProvider.php +++ b/src/State/Provider/HardwareTypeProvider.php @@ -9,22 +9,15 @@ use ApiPlatform\Metadata\Patch; use ApiPlatform\Metadata\Put; use ApiPlatform\State\Pagination\TraversablePaginator; use ApiPlatform\State\ProviderInterface; -use App\Dto\Input\ClientInput; -use App\Dto\Input\HardwareInput; use App\Dto\Input\HardwareTypeInput; -use App\Dto\Input\OperativeSystemInput; -use App\Dto\Output\ClientOutput; -use App\Dto\Output\HardwareOutput; use App\Dto\Output\HardwareTypeOutput; -use App\Dto\Output\NetworkSettingsOutput; -use App\Dto\Output\OperativeSystemOutput; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -class HardwareTypeProvider implements ProviderInterface +readonly class HardwareTypeProvider implements ProviderInterface { public function __construct( - private readonly ProviderInterface $collectionProvider, - private readonly ProviderInterface $itemProvider + private ProviderInterface $collectionProvider, + private ProviderInterface $itemProvider ) { } diff --git a/src/State/Provider/ImageProvider.php b/src/State/Provider/ImageProvider.php new file mode 100644 index 0000000..d807b4a --- /dev/null +++ b/src/State/Provider/ImageProvider.php @@ -0,0 +1,71 @@ +provideCollection($operation, $uriVariables, $context); + case $operation instanceof Patch: + case $operation instanceof Put: + return $this->provideInput($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 ImageOutput($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('Menu not found'); + } + + return new ImageOutput($item); + } + + public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + if (isset($uriVariables['uuid'])) { + $item = $this->itemProvider->provide($operation, $uriVariables, $context); + + return $item !== null ? new ImageInput($item) : null; + } + + return new ImageInput(); + } +} diff --git a/src/State/Provider/MenuProvider.php b/src/State/Provider/MenuProvider.php index 71359bc..f82cbe6 100644 --- a/src/State/Provider/MenuProvider.php +++ b/src/State/Provider/MenuProvider.php @@ -9,11 +9,7 @@ use ApiPlatform\Metadata\Patch; use ApiPlatform\Metadata\Put; use ApiPlatform\State\Pagination\TraversablePaginator; use ApiPlatform\State\ProviderInterface; -use App\Dto\Input\ClientInput; -use App\Dto\Input\HardwareInput; use App\Dto\Input\MenuInput; -use App\Dto\Output\ClientOutput; -use App\Dto\Output\HardwareOutput; use App\Dto\Output\MenuOutput; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; diff --git a/src/State/Provider/OperativeSystemProvider.php b/src/State/Provider/OperativeSystemProvider.php index 6b0535c..9245913 100644 --- a/src/State/Provider/OperativeSystemProvider.php +++ b/src/State/Provider/OperativeSystemProvider.php @@ -9,20 +9,15 @@ use ApiPlatform\Metadata\Patch; use ApiPlatform\Metadata\Put; use ApiPlatform\State\Pagination\TraversablePaginator; use ApiPlatform\State\ProviderInterface; -use App\Dto\Input\ClientInput; -use App\Dto\Input\HardwareInput; use App\Dto\Input\OperativeSystemInput; -use App\Dto\Output\ClientOutput; -use App\Dto\Output\HardwareOutput; -use App\Dto\Output\NetworkSettingsOutput; use App\Dto\Output\OperativeSystemOutput; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -class OperativeSystemProvider implements ProviderInterface +readonly class OperativeSystemProvider implements ProviderInterface { public function __construct( - private readonly ProviderInterface $collectionProvider, - private readonly ProviderInterface $itemProvider + private ProviderInterface $collectionProvider, + private ProviderInterface $itemProvider ) { } diff --git a/src/State/Provider/OrganizationalUnitProvider.php b/src/State/Provider/OrganizationalUnitProvider.php index 23703f9..25267a2 100644 --- a/src/State/Provider/OrganizationalUnitProvider.php +++ b/src/State/Provider/OrganizationalUnitProvider.php @@ -9,23 +9,16 @@ use ApiPlatform\Metadata\Patch; use ApiPlatform\Metadata\Put; use ApiPlatform\State\Pagination\TraversablePaginator; use ApiPlatform\State\ProviderInterface; -use App\Dto\Input\OrganizationalUnitClassroomGroupInput; -use App\Dto\Input\OrganizationalUnitClassroomInput; -use App\Dto\Input\OrganizationalUnitClientGroupInput; use App\Dto\Input\OrganizationalUnitInput; -use App\Dto\Input\OrganizationalUnitRootInput; -use App\Dto\Input\PartitionInput; -use App\Dto\Input\UserGroupInput; use App\Dto\Output\OrganizationalUnitOutput; use App\Entity\OrganizationalUnit; -use App\Model\OrganizationalUnitTypes; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -class OrganizationalUnitProvider implements ProviderInterface +readonly class OrganizationalUnitProvider implements ProviderInterface { public function __construct( - private readonly ProviderInterface $collectionProvider, - private readonly ProviderInterface $itemProvider + private ProviderInterface $collectionProvider, + private ProviderInterface $itemProvider ) { } diff --git a/src/State/Provider/PartitionProvider.php b/src/State/Provider/PartitionProvider.php index ae6abe8..f4cfb17 100644 --- a/src/State/Provider/PartitionProvider.php +++ b/src/State/Provider/PartitionProvider.php @@ -9,21 +9,15 @@ use ApiPlatform\Metadata\Patch; use ApiPlatform\Metadata\Put; use ApiPlatform\State\Pagination\TraversablePaginator; use ApiPlatform\State\ProviderInterface; -use App\Dto\Input\ClientInput; -use App\Dto\Input\HardwareInput; -use App\Dto\Input\MenuInput; use App\Dto\Input\PartitionInput; -use App\Dto\Output\ClientOutput; -use App\Dto\Output\HardwareOutput; -use App\Dto\Output\MenuOutput; use App\Dto\Output\PartitionOutput; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -class PartitionProvider implements ProviderInterface +readonly class PartitionProvider implements ProviderInterface { public function __construct( - private readonly ProviderInterface $collectionProvider, - private readonly ProviderInterface $itemProvider + private ProviderInterface $collectionProvider, + private ProviderInterface $itemProvider ) { } From f9bf9b61904792d473b22679f2d8454a1c239a1f Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Thu, 4 Jul 2024 11:07:55 +0200 Subject: [PATCH 32/35] refs #488. Testing --- src/Dto/Input/HardwareInput.php | 1 + src/Entity/HardwareProfile.php | 1 + src/Entity/SoftwareProfile.php | 1 - src/Factory/ClientFactory.php | 5 - src/Factory/HardwareFactory.php | 61 ++++++++ src/Factory/HardwareProfileFactory.php | 2 + src/Factory/HardwareTypeFactory.php | 21 --- src/Factory/ImageFactory.php | 60 ++++++++ src/Factory/MenuFactory.php | 5 - src/Factory/PartitionFactory.php | 4 +- src/Factory/SoftwareFactory.php | 60 ++++++++ src/Factory/SoftwareProfileFactory.php | 57 ++++++++ src/State/Processor/HardwareProcessor.php | 2 +- .../Processor/HardwareProfileProcessor.php | 2 +- src/State/Processor/ImageProcessor.php | 2 +- src/State/Processor/SoftwareProcessor.php | 2 +- .../Processor/SoftwareProfileProcessor.php | 2 +- tests/Functional/ClientTest.php | 2 + tests/Functional/HardwareProfileTest.php | 124 ++++++++++++++++ tests/Functional/HardwareTest.php | 125 ++++++++++++++++ tests/Functional/ImageTest.php | 136 ++++++++++++++++++ tests/Functional/PartitionTest.php | 33 ++++- tests/Functional/SoftwareProfileTest.php | 124 ++++++++++++++++ tests/Functional/SoftwareTest.php | 118 +++++++++++++++ 24 files changed, 906 insertions(+), 44 deletions(-) create mode 100644 src/Factory/HardwareFactory.php create mode 100644 src/Factory/ImageFactory.php create mode 100644 src/Factory/SoftwareFactory.php create mode 100644 src/Factory/SoftwareProfileFactory.php create mode 100644 tests/Functional/HardwareProfileTest.php create mode 100644 tests/Functional/HardwareTest.php create mode 100644 tests/Functional/ImageTest.php create mode 100644 tests/Functional/SoftwareProfileTest.php create mode 100644 tests/Functional/SoftwareTest.php diff --git a/src/Dto/Input/HardwareInput.php b/src/Dto/Input/HardwareInput.php index 0e41d38..7674310 100644 --- a/src/Dto/Input/HardwareInput.php +++ b/src/Dto/Input/HardwareInput.php @@ -19,6 +19,7 @@ final class HardwareInput #[ApiProperty(description: 'The description of the hardware', example: "Hardware 1 description")] public ?string $description = null; + #[Assert\NotNull] #[Groups(['hardware:write'])] #[ApiProperty(description: 'The type of the hardware', example: "Server")] public ?HardwareTypeOutput $type = null; diff --git a/src/Entity/HardwareProfile.php b/src/Entity/HardwareProfile.php index 253a7fd..3538baf 100644 --- a/src/Entity/HardwareProfile.php +++ b/src/Entity/HardwareProfile.php @@ -17,6 +17,7 @@ class HardwareProfile extends AbstractEntity private ?string $comments = null; #[ORM\ManyToOne(targetEntity: OrganizationalUnit::class)] + #[ORM\JoinColumn(nullable: false)] private ?OrganizationalUnit $organizationalUnit = null; /** diff --git a/src/Entity/SoftwareProfile.php b/src/Entity/SoftwareProfile.php index 4ac75b8..bc0f968 100644 --- a/src/Entity/SoftwareProfile.php +++ b/src/Entity/SoftwareProfile.php @@ -20,7 +20,6 @@ class SoftwareProfile extends AbstractEntity #[ORM\JoinColumn(nullable: false)] private ?OrganizationalUnit $organizationalUnit = null; - /** * @var Collection */ diff --git a/src/Factory/ClientFactory.php b/src/Factory/ClientFactory.php index a967161..56e28da 100644 --- a/src/Factory/ClientFactory.php +++ b/src/Factory/ClientFactory.php @@ -21,11 +21,6 @@ final class ClientFactory extends ModelFactory parent::__construct(); } - public static function class(): string - { - return Client::class; - } - /** * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories * diff --git a/src/Factory/HardwareFactory.php b/src/Factory/HardwareFactory.php new file mode 100644 index 0000000..24f68c2 --- /dev/null +++ b/src/Factory/HardwareFactory.php @@ -0,0 +1,61 @@ + + */ +final class HardwareFactory extends ModelFactory +{ + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services + * + * @todo inject services if required + */ + public function __construct() + { + parent::__construct(); + } + + public static function class(): string + { + return Hardware::class; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories + * + * @todo add your default values here + */ + protected function getDefaults(): array + { + return [ + 'createdAt' => self::faker()->dateTime(), + 'name' => self::faker()->text(255), + 'updatedAt' => self::faker()->dateTime(), + 'type' => HardwareTypeFactory::new() + ]; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization + */ + protected function initialize(): self + { + return $this + // ->afterInstantiate(function(Hardware $hardware): void {}) + ; + } + + protected static function getClass(): string + { + return Hardware::class; + } +} diff --git a/src/Factory/HardwareProfileFactory.php b/src/Factory/HardwareProfileFactory.php index eacb105..fe3148b 100644 --- a/src/Factory/HardwareProfileFactory.php +++ b/src/Factory/HardwareProfileFactory.php @@ -3,6 +3,7 @@ namespace App\Factory; use App\Entity\HardwareProfile; +use App\Model\OrganizationalUnitTypes; use Zenstruck\Foundry\ModelFactory; use Zenstruck\Foundry\Persistence\PersistentProxyObjectFactory; @@ -37,6 +38,7 @@ final class HardwareProfileFactory extends ModelFactory 'createdAt' => self::faker()->dateTime(), 'updatedAt' => self::faker()->dateTime(), 'description' => self::faker()->text(255), + 'organizationalUnit' => OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT])->_save(), ]; } diff --git a/src/Factory/HardwareTypeFactory.php b/src/Factory/HardwareTypeFactory.php index b307824..10788fe 100644 --- a/src/Factory/HardwareTypeFactory.php +++ b/src/Factory/HardwareTypeFactory.php @@ -11,22 +11,6 @@ use Zenstruck\Foundry\Persistence\ProxyRepositoryDecorator; /** * @extends PersistentProxyObjectFactory - * - * @method HardwareType|Proxy create(array|callable $attributes = []) - * @method static HardwareType|Proxy createOne(array $attributes = []) - * @method static HardwareType|Proxy find(object|array|mixed $criteria) - * @method static HardwareType|Proxy findOrCreate(array $attributes) - * @method static HardwareType|Proxy first(string $sortedField = 'id') - * @method static HardwareType|Proxy last(string $sortedField = 'id') - * @method static HardwareType|Proxy random(array $attributes = []) - * @method static HardwareType|Proxy randomOrCreate(array $attributes = []) - * @method static HardwareTypeRepository|ProxyRepositoryDecorator repository() - * @method static HardwareType[]|Proxy[] all() - * @method static HardwareType[]|Proxy[] createMany(int $number, array|callable $attributes = []) - * @method static HardwareType[]|Proxy[] createSequence(iterable|callable $sequence) - * @method static HardwareType[]|Proxy[] findBy(array $attributes) - * @method static HardwareType[]|Proxy[] randomRange(int $min, int $max, array $attributes = []) - * @method static HardwareType[]|Proxy[] randomSet(int $number, array $attributes = []) */ final class HardwareTypeFactory extends ModelFactory { @@ -40,11 +24,6 @@ final class HardwareTypeFactory extends ModelFactory parent::__construct(); } - public static function class(): string - { - return HardwareType::class; - } - /** * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories * diff --git a/src/Factory/ImageFactory.php b/src/Factory/ImageFactory.php new file mode 100644 index 0000000..3a4962d --- /dev/null +++ b/src/Factory/ImageFactory.php @@ -0,0 +1,60 @@ + + */ +final class ImageFactory extends ModelFactory +{ + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services + * + * @todo inject services if required + */ + public function __construct() + { + parent::__construct(); + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories + * + * @todo add your default values here + */ + protected function getDefaults(): array + { + return [ + 'client' => ClientFactory::new(), + 'createdAt' => self::faker()->dateTime(), + 'name' => self::faker()->text(255), + 'path' => self::faker()->text(255), + 'size' => self::faker()->randomNumber(), + 'softwareProfile' => SoftwareProfileFactory::new(), + 'type' => self::faker()->text(255), + 'updatedAt' => self::faker()->dateTime(), + ]; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization + */ + protected function initialize(): self + { + return $this + // ->afterInstantiate(function(Image $image): void {}) + ; + } + + protected static function getClass(): string + { + return Image::class; + } +} diff --git a/src/Factory/MenuFactory.php b/src/Factory/MenuFactory.php index e5762ca..37f8125 100644 --- a/src/Factory/MenuFactory.php +++ b/src/Factory/MenuFactory.php @@ -24,11 +24,6 @@ final class MenuFactory extends ModelFactory parent::__construct(); } - public static function class(): string - { - return Menu::class; - } - /** * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories */ diff --git a/src/Factory/PartitionFactory.php b/src/Factory/PartitionFactory.php index 397ef82..bb3d736 100644 --- a/src/Factory/PartitionFactory.php +++ b/src/Factory/PartitionFactory.php @@ -40,7 +40,9 @@ final class PartitionFactory extends ModelFactory 'createdAt' => self::faker()->dateTime(), 'memoryUsage' => self::faker()->randomNumber(), 'size' => self::faker()->randomNumber(), - 'updatedAt' => self::faker()->dateTime() + 'updatedAt' => self::faker()->dateTime(), + 'operativeSystem' => OperativeSystemFactory::new(), + 'client' => ClientFactory::new(), ]; } diff --git a/src/Factory/SoftwareFactory.php b/src/Factory/SoftwareFactory.php new file mode 100644 index 0000000..7d59325 --- /dev/null +++ b/src/Factory/SoftwareFactory.php @@ -0,0 +1,60 @@ + + */ +final class SoftwareFactory extends ModelFactory +{ + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services + * + * @todo inject services if required + */ + public function __construct() + { + parent::__construct(); + } + + public static function class(): string + { + return Software::class; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories + * + * @todo add your default values here + */ + protected function getDefaults(): array + { + return [ + 'createdAt' => self::faker()->dateTime(), + 'name' => self::faker()->text(255), + 'updatedAt' => self::faker()->dateTime(), + ]; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization + */ + protected function initialize(): self + { + return $this + // ->afterInstantiate(function(Software $software): void {}) + ; + } + + protected static function getClass(): string + { + return Software::class; + } +} diff --git a/src/Factory/SoftwareProfileFactory.php b/src/Factory/SoftwareProfileFactory.php new file mode 100644 index 0000000..5a05ae4 --- /dev/null +++ b/src/Factory/SoftwareProfileFactory.php @@ -0,0 +1,57 @@ + + */ +final class SoftwareProfileFactory extends ModelFactory +{ + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services + * + * @todo inject services if required + */ + public function __construct() + { + parent::__construct(); + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories + * + * @todo add your default values here + */ + protected function getDefaults(): array + { + return [ + 'createdAt' => self::faker()->dateTime(), + 'description' => self::faker()->text(255), + 'updatedAt' => self::faker()->dateTime(), + 'organizationalUnit' => OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT])->_save(), + ]; + } + + /** + * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization + */ + protected function initialize(): self + { + return $this + // ->afterInstantiate(function(SoftwareProfile $softwareProfile): void {}) + ; + } + + protected static function getClass(): string + { + return SoftwareProfile::class; + } +} diff --git a/src/State/Processor/HardwareProcessor.php b/src/State/Processor/HardwareProcessor.php index 971fb3d..ff54e13 100644 --- a/src/State/Processor/HardwareProcessor.php +++ b/src/State/Processor/HardwareProcessor.php @@ -26,7 +26,7 @@ class HardwareProcessor implements ProcessorInterface /** * @throws \Exception */ - public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): HardwareOutput + public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): HardwareOutput|null { switch ($operation){ case $operation instanceof Post: diff --git a/src/State/Processor/HardwareProfileProcessor.php b/src/State/Processor/HardwareProfileProcessor.php index ed6ccf8..f68c3a8 100644 --- a/src/State/Processor/HardwareProfileProcessor.php +++ b/src/State/Processor/HardwareProfileProcessor.php @@ -26,7 +26,7 @@ readonly class HardwareProfileProcessor implements ProcessorInterface /** * @throws \Exception */ - public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): HardwareProfileOutput + public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): HardwareProfileOutput|null { switch ($operation){ case $operation instanceof Post: diff --git a/src/State/Processor/ImageProcessor.php b/src/State/Processor/ImageProcessor.php index 8506b70..833225d 100644 --- a/src/State/Processor/ImageProcessor.php +++ b/src/State/Processor/ImageProcessor.php @@ -25,7 +25,7 @@ readonly class ImageProcessor implements ProcessorInterface /** * @throws \Exception */ - public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ImageOutput + public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ImageOutput|null { switch ($operation){ case $operation instanceof Post: diff --git a/src/State/Processor/SoftwareProcessor.php b/src/State/Processor/SoftwareProcessor.php index 3730595..9109b7b 100644 --- a/src/State/Processor/SoftwareProcessor.php +++ b/src/State/Processor/SoftwareProcessor.php @@ -25,7 +25,7 @@ readonly class SoftwareProcessor implements ProcessorInterface /** * @throws \Exception */ - public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): SoftwareOutput + public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): SoftwareOutput|null { switch ($operation){ case $operation instanceof Post: diff --git a/src/State/Processor/SoftwareProfileProcessor.php b/src/State/Processor/SoftwareProfileProcessor.php index 7368d4d..21bde82 100644 --- a/src/State/Processor/SoftwareProfileProcessor.php +++ b/src/State/Processor/SoftwareProfileProcessor.php @@ -25,7 +25,7 @@ readonly class SoftwareProfileProcessor implements ProcessorInterface /** * @throws \Exception */ - public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): SoftwareProfileOutput + public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): SoftwareProfileOutput|null { switch ($operation){ case $operation instanceof Post: diff --git a/tests/Functional/ClientTest.php b/tests/Functional/ClientTest.php index f28429a..82d8055 100644 --- a/tests/Functional/ClientTest.php +++ b/tests/Functional/ClientTest.php @@ -4,11 +4,13 @@ namespace Functional; use App\Entity\Client; use App\Entity\HardwareProfile; +use App\Entity\HardwareType; use App\Entity\OrganizationalUnit; use App\Entity\User; use App\Entity\UserGroup; use App\Factory\ClientFactory; use App\Factory\HardwareProfileFactory; +use App\Factory\HardwareTypeFactory; use App\Factory\OrganizationalUnitFactory; use App\Factory\UserFactory; use App\Factory\UserGroupFactory; diff --git a/tests/Functional/HardwareProfileTest.php b/tests/Functional/HardwareProfileTest.php new file mode 100644 index 0000000..6d710b8 --- /dev/null +++ b/tests/Functional/HardwareProfileTest.php @@ -0,0 +1,124 @@ + self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + HardwareProfileFactory::createMany(10); + + $this->createClientWithCredentials()->request('GET', '/hardware-profiles'); + $this->assertResponseStatusCodeSame(Response::HTTP_OK); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/HardwareProfile', + '@id' => '/hardware-profiles', + '@type' => 'hydra:Collection', + 'hydra:totalItems' => 10, + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testCreateHardwareProfile(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); + $ouIri = $this->findIriBy(OrganizationalUnit::class, ['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); + + $this->createClientWithCredentials()->request('POST', '/hardware-profiles',['json' => [ + 'description' => self::HW_PROFILE_CREATE, + 'organizationalUnit' => $ouIri + ]]); + + $this->assertResponseStatusCodeSame(201); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/HardwareProfileOutput', + '@type' => 'HardwareProfile', + 'description' => self::HW_PROFILE_CREATE + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testUpdateHardwareProfile(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + HardwareProfileFactory::createOne(['description' => self::HW_PROFILE_CREATE]); + $iri = $this->findIriBy(HardwareProfile::class, ['description' => self::HW_PROFILE_CREATE]); + + $this->createClientWithCredentials()->request('PUT', $iri, ['json' => [ + 'description' => self::HW_PROFILE_UPDATE, + ]]); + + $this->assertResponseIsSuccessful(); + $this->assertJsonContains([ + '@id' => $iri, + 'description' => self::HW_PROFILE_UPDATE, + ]); + } + + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + */ + public function testDeleteHardwareProfile(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + HardwareProfileFactory::createOne(['description' => self::HW_PROFILE_DELETE]); + $iri = $this->findIriBy(HardwareProfile::class, ['description' => self::HW_PROFILE_DELETE]); + + $this->createClientWithCredentials()->request('DELETE', $iri); + $this->assertResponseStatusCodeSame(204); + $this->assertNull( + static::getContainer()->get('doctrine')->getRepository(HardwareProfile::class)->findOneBy(['description' => self::HW_PROFILE_DELETE]) + ); + } +} \ No newline at end of file diff --git a/tests/Functional/HardwareTest.php b/tests/Functional/HardwareTest.php new file mode 100644 index 0000000..1726ae7 --- /dev/null +++ b/tests/Functional/HardwareTest.php @@ -0,0 +1,125 @@ + self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + HardwareFactory::createMany(10); + + $this->createClientWithCredentials()->request('GET', '/hardware'); + $this->assertResponseStatusCodeSame(Response::HTTP_OK); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/Hardware', + '@id' => '/hardware', + '@type' => 'hydra:Collection', + 'hydra:totalItems' => 10, + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testCreateHardware(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + HardwareTypeFactory::createOne(['name' => self::HW_TYPE]); + $hwIri = $this->findIriBy(HardwareType::class, ['name' => self::HW_TYPE]); + + $this->createClientWithCredentials()->request('POST', '/hardware',['json' => [ + 'name' => self::HW_CREATE, + 'type' => $hwIri + ]]); + + $this->assertResponseStatusCodeSame(201); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/HardwareOutput', + '@type' => 'Hardware', + 'name' => self::HW_CREATE + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testUpdateHardware(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + HardwareFactory::createOne(['name' => self::HW_CREATE]); + $iri = $this->findIriBy(Hardware::class, ['name' => self::HW_CREATE]); + + $this->createClientWithCredentials()->request('PUT', $iri, ['json' => [ + 'name' => self::HW_UPDATE, + ]]); + + $this->assertResponseIsSuccessful(); + $this->assertJsonContains([ + '@id' => $iri, + 'name' => self::HW_UPDATE, + ]); + } + + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + */ + public function testDeleteHardware(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + HardwareFactory::createOne(['name' => self::HW_DELETE]); + $iri = $this->findIriBy(Hardware::class, ['name' => self::HW_DELETE]); + + $this->createClientWithCredentials()->request('DELETE', $iri); + $this->assertResponseStatusCodeSame(204); + $this->assertNull( + static::getContainer()->get('doctrine')->getRepository(Hardware::class)->findOneBy(['name' => self::HW_DELETE]) + ); + } +} \ No newline at end of file diff --git a/tests/Functional/ImageTest.php b/tests/Functional/ImageTest.php new file mode 100644 index 0000000..b4e95fc --- /dev/null +++ b/tests/Functional/ImageTest.php @@ -0,0 +1,136 @@ + self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + ImageFactory::createMany(10); + + $this->createClientWithCredentials()->request('GET', '/images'); + $this->assertResponseStatusCodeSame(Response::HTTP_OK); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/Image', + '@id' => '/images', + '@type' => 'hydra:Collection', + 'hydra:totalItems' => 10, + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testCreateImage(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + ClientFactory::createOne(['name' => self::CLIENT]); + $clientIri = $this->findIriBy(Client::class, ['name' => self::CLIENT]); + + SoftwareProfileFactory::createOne(['description' => self::SOFTWARE_PROFILE]); + $swPIri = $this->findIriBy(SoftwareProfile::class, ['description' => self::SOFTWARE_PROFILE]); + + $this->createClientWithCredentials()->request('POST', '/images',['json' => [ + 'name' => self::IMAGE_CREATE, + 'size' => 123, + 'path' => '/path/to/image', + 'type' => 'type', + 'client' => $clientIri, + 'softwareProfile' => $swPIri + ]]); + + $this->assertResponseStatusCodeSame(201); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/ImageOutput', + '@type' => 'Image', + 'name' => self::IMAGE_CREATE, + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testUpdateImage(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + ImageFactory::createOne(['name' => self::IMAGE_CREATE]); + $iri = $this->findIriBy(Image::class, ['name' => self::IMAGE_CREATE]); + + $this->createClientWithCredentials()->request('PUT', $iri, ['json' => [ + 'name' => self::IMAGE_UPDATE, + 'size' => 123 + ]]); + + $this->assertResponseIsSuccessful(); + $this->assertJsonContains([ + '@id' => $iri, + 'name' => self::IMAGE_UPDATE, + 'size' => 123 + ]); + } + + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + */ + public function testDeleteImage(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + ImageFactory::createOne(['name' => self::IMAGE_DELETE]); + $iri = $this->findIriBy(Image::class, ['name' => self::IMAGE_DELETE]); + + $this->createClientWithCredentials()->request('DELETE', $iri); + $this->assertResponseStatusCodeSame(204); + $this->assertNull( + static::getContainer()->get('doctrine')->getRepository(Client::class)->findOneBy(['name' => self::IMAGE_DELETE]) + ); + } +} \ No newline at end of file diff --git a/tests/Functional/PartitionTest.php b/tests/Functional/PartitionTest.php index 4bd3f75..39debe4 100644 --- a/tests/Functional/PartitionTest.php +++ b/tests/Functional/PartitionTest.php @@ -40,12 +40,7 @@ class PartitionTest extends AbstractTest { UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); - $ou = OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); - $hp = HardwareProfileFactory::createOne(['description' => self::HW_PROFILE]); - - $client = ClientFactory::createOne(['name' => self::CLIENT_CREATE, 'serialNumber' => '123abc', 'organizationalUnit' => $ou, 'hardwareProfile' => $hp]); - - PartitionFactory::createMany(10, ['client' => $client]); + PartitionFactory::createMany(10); $this->createClientWithCredentials()->request('GET', '/partitions'); $this->assertResponseStatusCodeSame(Response::HTTP_OK); @@ -95,4 +90,30 @@ class PartitionTest extends AbstractTest ]); } + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testUpdatePartition(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + PartitionFactory::createOne(['size' => 100, 'memoryUsage' => 100]); + $iri = $this->findIriBy(Partition::class, ['size' => 100, 'memoryUsage' => 100]); + + $this->createClientWithCredentials()->request('PUT', $iri, ['json' => [ + 'size' => 200, + 'memoryUsage' => 300 + ]]); + + $this->assertResponseIsSuccessful(); + $this->assertJsonContains([ + '@id' => $iri, + 'size' => 200, + 'memoryUsage' => 300 + ]); + } } \ No newline at end of file diff --git a/tests/Functional/SoftwareProfileTest.php b/tests/Functional/SoftwareProfileTest.php new file mode 100644 index 0000000..8d2ac62 --- /dev/null +++ b/tests/Functional/SoftwareProfileTest.php @@ -0,0 +1,124 @@ + self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + SoftwareProfileFactory::createMany(10); + + $this->createClientWithCredentials()->request('GET', '/software-profiles'); + $this->assertResponseStatusCodeSame(Response::HTTP_OK); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/SoftwareProfile', + '@id' => '/software-profiles', + '@type' => 'hydra:Collection', + 'hydra:totalItems' => 10, + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testCreateSoftwareProfile(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); + $ouIri = $this->findIriBy(OrganizationalUnit::class, ['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); + + $this->createClientWithCredentials()->request('POST', '/software-profiles',['json' => [ + 'description' => self::SW_PROFILE_CREATE, + 'organizationalUnit' => $ouIri + ]]); + + $this->assertResponseStatusCodeSame(201); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/SoftwareProfileOutput', + '@type' => 'SoftwareProfile', + 'description' => self::SW_PROFILE_CREATE + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testUpdateSoftwareProfile(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + SoftwareProfileFactory::createOne(['description' => self::SW_PROFILE_CREATE]); + $iri = $this->findIriBy(SoftwareProfile::class, ['description' => self::SW_PROFILE_CREATE]); + + $this->createClientWithCredentials()->request('PUT', $iri, ['json' => [ + 'description' => self::SW_PROFILE_UPDATE, + ]]); + + $this->assertResponseIsSuccessful(); + $this->assertJsonContains([ + '@id' => $iri, + 'description' => self::SW_PROFILE_UPDATE, + ]); + } + + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + */ + public function testDeleteSoftwareProfile(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + SoftwareProfileFactory::createOne(['description' => self::SW_PROFILE_DELETE]); + $iri = $this->findIriBy(SoftwareProfile::class, ['description' => self::SW_PROFILE_DELETE]); + + $this->createClientWithCredentials()->request('DELETE', $iri); + $this->assertResponseStatusCodeSame(204); + $this->assertNull( + static::getContainer()->get('doctrine')->getRepository(SoftwareProfile::class)->findOneBy(['description' => self::SW_PROFILE_DELETE]) + ); + } +} \ No newline at end of file diff --git a/tests/Functional/SoftwareTest.php b/tests/Functional/SoftwareTest.php new file mode 100644 index 0000000..07f41dd --- /dev/null +++ b/tests/Functional/SoftwareTest.php @@ -0,0 +1,118 @@ + self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + SoftwareFactory::createMany(10); + + $this->createClientWithCredentials()->request('GET', '/software'); + $this->assertResponseStatusCodeSame(Response::HTTP_OK); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/Software', + '@id' => '/software', + '@type' => 'hydra:Collection', + 'hydra:totalItems' => 10, + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testCreateSoftware(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + $this->createClientWithCredentials()->request('POST', '/software',['json' => [ + 'name' => self::SW_CREATE, + ]]); + + $this->assertResponseStatusCodeSame(201); + $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); + $this->assertJsonContains([ + '@context' => '/contexts/SoftwareOutput', + '@type' => 'Software', + 'name' => self::SW_CREATE + ]); + } + + /** + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + */ + public function testUpdateSoftware(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + SoftwareFactory::createOne(['name' => self::SW_CREATE]); + $iri = $this->findIriBy(Software::class, ['name' => self::SW_CREATE]); + + $this->createClientWithCredentials()->request('PUT', $iri, ['json' => [ + 'name' => self::SW_UPDATE, + ]]); + + $this->assertResponseIsSuccessful(); + $this->assertJsonContains([ + '@id' => $iri, + 'name' => self::SW_UPDATE, + ]); + } + + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws DecodingExceptionInterface + * @throws ClientExceptionInterface + */ + public function testDeleteSoftware(): void + { + UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); + + SoftwareFactory::createOne(['name' => self::SW_DELETE]); + $iri = $this->findIriBy(Software::class, ['name' => self::SW_DELETE]); + + $this->createClientWithCredentials()->request('DELETE', $iri); + $this->assertResponseStatusCodeSame(204); + $this->assertNull( + static::getContainer()->get('doctrine')->getRepository(Software::class)->findOneBy(['name' => self::SW_DELETE]) + ); + } +} \ No newline at end of file From e4e9e3c07f9af7da7c797fc9c36ed108fbefdbde Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Fri, 12 Jul 2024 13:11:38 +0200 Subject: [PATCH 33/35] refs #436. Improvements --- config/packages/api_platform.yaml | 3 ++ config/services.yaml | 3 ++ config/services/api_platform.yaml | 52 +++++++------------ ...grateHardwareAndHardwareProfileCommand.php | 5 +- ...UserAllowedOrganizationalUnitExtension.php | 15 +++++- src/Dto/Input/UserInput.php | 19 +++++-- src/Dto/Output/ClientOutput.php | 12 ++++- src/Dto/Output/OrganizationalUnitOutput.php | 20 ++++++- .../OrganizationalUnitChangeParentHandler.php | 6 +-- src/Security/Voter/ClientVoter.php | 48 +++++++++++++++++ .../Provider/OrganizationalUnitProvider.php | 4 +- 11 files changed, 138 insertions(+), 49 deletions(-) create mode 100644 src/Security/Voter/ClientVoter.php diff --git a/config/packages/api_platform.yaml b/config/packages/api_platform.yaml index 67d91f3..8871ca7 100644 --- a/config/packages/api_platform.yaml +++ b/config/packages/api_platform.yaml @@ -17,6 +17,9 @@ api_platform: mapping: paths: ['%kernel.project_dir%/config/api_platform', '%kernel.project_dir%/src/Dto'] use_symfony_listeners: true + collection: + pagination: + items_per_page_parameter_name: 'itemsPerPage' defaults: pagination_client_items_per_page: true denormalization_context: diff --git a/config/services.yaml b/config/services.yaml index 1c97d41..a26d706 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -1,3 +1,6 @@ +imports: + - { resource: 'services/api_platform.yaml' } + parameters: services: diff --git a/config/services/api_platform.yaml b/config/services/api_platform.yaml index f74ee52..d8f0fa4 100644 --- a/config/services/api_platform.yaml +++ b/config/services/api_platform.yaml @@ -4,109 +4,93 @@ services: arguments: $properties: { 'id': ~, 'name': ~, 'serialNumber': ~ } $orderParameterName: 'order' - tags: - - [ 'api_platform.filter' ] + tags: [ 'api_platform.filter' ] api_platform.filter.client.search: parent: 'api_platform.doctrine.orm.search_filter' - arguments: [ { 'id': 'exact', 'name': 'partial', 'serialNumber': 'exact' } ] - tags: - - [ 'api_platform.filter' ] + arguments: [ { 'id': 'exact', 'name': 'partial', 'serialNumber': 'exact', organizationalUnit.id: 'exact' } ] + tags: [ 'api_platform.filter' ] api_platform.filter.hardware.order: parent: 'api_platform.doctrine.orm.order_filter' arguments: $properties: { 'id': ~, 'name': ~ } $orderParameterName: 'order' - tags: - - [ 'api_platform.filter' ] + tags: [ 'api_platform.filter' ] api_platform.filter.hardware.search: parent: 'api_platform.doctrine.orm.search_filter' arguments: [ { 'id': 'exact', 'name': 'partial' } ] - tags: - - [ 'api_platform.filter' ] + tags: [ 'api_platform.filter' ] api_platform.filter.menu.order: parent: 'api_platform.doctrine.orm.order_filter' arguments: $properties: { 'id': ~, 'name': ~, 'title': ~ } $orderParameterName: 'order' - tags: - - [ 'api_platform.filter' ] + tags: [ 'api_platform.filter' ] api_platform.filter.menu.search: parent: 'api_platform.doctrine.orm.search_filter' arguments: [ { 'id': 'exact', 'name': 'exact', 'title': 'exact' } ] - tags: - - [ 'api_platform.filter' ] + tags: [ 'api_platform.filter' ] api_platform.filter.organizational_unit.order: parent: 'api_platform.doctrine.orm.order_filter' arguments: $properties: { 'id': ~, 'name': ~, 'type': ~ } $orderParameterName: 'order' - tags: - - [ 'api_platform.filter' ] + tags: [ 'api_platform.filter' ] api_platform.filter.organizational_unit.search: parent: 'api_platform.doctrine.orm.search_filter' - arguments: [ { 'id': 'exact', 'name': 'exact', 'type': 'exact' } ] - tags: - - [ 'api_platform.filter' ] + arguments: [ { id: 'exact', name: 'partial', type: 'exact', parent.id: 'exact'} ] + tags: [ 'api_platform.filter' ] api_platform.filter.partition.order: parent: 'api_platform.doctrine.orm.order_filter' arguments: $properties: { 'id': ~, 'usage': ~ } $orderParameterName: 'order' - tags: - - [ 'api_platform.filter' ] + tags: [ 'api_platform.filter' ] api_platform.filter.partition.search: parent: 'api_platform.doctrine.orm.search_filter' arguments: [ { 'id': 'exact', 'usage': 'exact', 'diskNumber': 'exact' } ] - tags: - - [ 'api_platform.filter' ] + tags: [ 'api_platform.filter' ] api_platform.filter.user.order: parent: 'api_platform.doctrine.orm.order_filter' arguments: $properties: { 'id': ~, 'username': ~ } $orderParameterName: 'order' - tags: - - [ 'api_platform.filter' ] + tags: [ 'api_platform.filter' ] api_platform.filter.user.search: parent: 'api_platform.doctrine.orm.search_filter' arguments: [ { 'id': 'exact', 'username': 'partial' } ] - tags: - - [ 'api_platform.filter' ] + tags: [ 'api_platform.filter' ] api_platform.filter.user.boolean: parent: 'api_platform.doctrine.orm.boolean_filter' arguments: [ { 'enabled': ~ } ] - tags: - - [ 'api_platform.filter' ] + tags: [ 'api_platform.filter' ] api_platform.filter.user_group.order: parent: 'api_platform.doctrine.orm.order_filter' arguments: $properties: { 'id': ~, 'name': ~ } $orderParameterName: 'order' - tags: - - [ 'api_platform.filter' ] + tags: [ 'api_platform.filter' ] api_platform.filter.user_group.search: parent: 'api_platform.doctrine.orm.search_filter' arguments: [ { 'id': 'exact', 'name': 'partial' } ] - tags: - - [ 'api_platform.filter' ] + tags: [ 'api_platform.filter' ] api_platform.filter.user_group.boolean: parent: 'api_platform.doctrine.orm.boolean_filter' arguments: [ { 'enabled': ~ } ] - tags: - - [ 'api_platform.filter' ] + tags: [ 'api_platform.filter' ] diff --git a/src/Command/Migration/MigrateHardwareAndHardwareProfileCommand.php b/src/Command/Migration/MigrateHardwareAndHardwareProfileCommand.php index 9ae4946..0fdfd04 100644 --- a/src/Command/Migration/MigrateHardwareAndHardwareProfileCommand.php +++ b/src/Command/Migration/MigrateHardwareAndHardwareProfileCommand.php @@ -87,9 +87,10 @@ class MigrateHardwareAndHardwareProfileCommand extends Command $migrationId = $hardware['hardwares.grupoid'] === 0 ? $hardware['hardwares.idcentro'] : $hardware['hardwares.grupoid']; $organizationalUnit = $organizationalUnitRepository->findOneBy(['migrationId' => $migrationId]); + /* if ($organizationalUnit){ $hardwareEntity->setOrganizationalUnit($organizationalUnit); - } + }*/ $this->entityManager->persist($hardwareEntity); } @@ -142,8 +143,8 @@ class MigrateHardwareAndHardwareProfileCommand extends Command if ($hardwareProfileEntity && $hardwareEntity){ $hardwareProfileEntity->addHardwareCollection($hardwareEntity); + $this->entityManager->persist($hardwareProfileEntity); } - $this->entityManager->persist($hardwareProfileEntity); } diff --git a/src/Doctrine/UserAllowedOrganizationalUnitExtension.php b/src/Doctrine/UserAllowedOrganizationalUnitExtension.php index 0aa9f25..54f081e 100644 --- a/src/Doctrine/UserAllowedOrganizationalUnitExtension.php +++ b/src/Doctrine/UserAllowedOrganizationalUnitExtension.php @@ -36,13 +36,26 @@ readonly class UserAllowedOrganizationalUnitExtension implements QueryCollection if (OrganizationalUnit::class !== $resourceClass || null === $user || in_array('ROLE_SUPER_ADMIN', $user->getRoles())) { return; } + $organizationalUnitIds = []; foreach ($user->getAllowedOrganizationalUnits() as $allowedOrganizationalUnit) { - $organizationalUnitIds[] = $allowedOrganizationalUnit->getId(); + $this->addOrganizationalUnitAndChildrenIds($allowedOrganizationalUnit, $organizationalUnitIds); } $rootAlias = $queryBuilder->getRootAliases()[0]; $queryBuilder->andWhere(sprintf('%s.id in (:ou)', $rootAlias)); $queryBuilder->setParameter('ou', $organizationalUnitIds); } + + private function addOrganizationalUnitAndChildrenIds(OrganizationalUnit $organizationalUnit, array &$organizationalUnitIds): void + { + if (!in_array($organizationalUnit->getId(), $organizationalUnitIds)) { + $organizationalUnitIds[] = $organizationalUnit->getId(); + } + + foreach ($organizationalUnit->getOrganizationalUnits() as $child) { + $this->addOrganizationalUnitAndChildrenIds($child, $organizationalUnitIds); + } + } + } \ No newline at end of file diff --git a/src/Dto/Input/UserInput.php b/src/Dto/Input/UserInput.php index 8b37575..5ecc8bb 100644 --- a/src/Dto/Input/UserInput.php +++ b/src/Dto/Input/UserInput.php @@ -3,6 +3,7 @@ namespace App\Dto\Input; use ApiPlatform\Metadata\ApiProperty; +use App\Dto\Output\OrganizationalUnitOutput; use App\Dto\Output\UserGroupOutput; use App\Entity\OrganizationalUnit; use App\Entity\User; @@ -17,7 +18,7 @@ final class UserInput public ?string $username = null; /** - * @var OrganizationalUnit[] + * @var OrganizationalUnitOutput[] */ #[Groups('user:write')] #[ApiProperty(readableLink: false, writableLink: false)] @@ -33,7 +34,7 @@ final class UserInput public ?bool $enabled = true; /** - * @var UserGroup[] + * @var UserGroupOutput[] */ #[Groups('user:write')] #[ApiProperty(readableLink: false, writableLink: false)] @@ -62,8 +63,18 @@ final class UserInput $this->username = $user->getUsername(); $this->enabled= $user->isEnabled(); - $this->userGroups = $user->getUserGroups()->toArray(); - $this->allowedOrganizationalUnits = $user->getAllowedOrganizationalUnits()->toArray(); + + if ($user->getUserGroups()) { + foreach ($user->getUserGroups() as $userGroup) { + $this->userGroups[] = new UserGroupOutput($userGroup); + } + } + + if ($user->getAllowedOrganizationalUnits()) { + foreach ($user->getAllowedOrganizationalUnits() as $allowedOrganizationalUnit) { + $this->allowedOrganizationalUnits[] = new OrganizationalUnitOutput($allowedOrganizationalUnit); + } + } } public function createOrUpdateEntity(?User $user = null): User diff --git a/src/Dto/Output/ClientOutput.php b/src/Dto/Output/ClientOutput.php index 4e378ce..fb4249b 100644 --- a/src/Dto/Output/ClientOutput.php +++ b/src/Dto/Output/ClientOutput.php @@ -19,14 +19,20 @@ final class ClientOutput extends AbstractOutput #[Groups(['client:read', 'organizational-unit:read'])] public string $type = self::TYPE; + #[Groups(['client:read', 'organizational-unit:read'])] + public ?string $ip = ''; + + #[Groups(['client:read', 'organizational-unit:read'])] + public ?string $mac = ''; + #[Groups(['client:read', 'organizational-unit:read'])] public ?string $serialNumber = ''; #[Groups(['client:read'])] public ?string $netiface = ''; - #[Groups(['client:read', 'organizational-unit:read'])] - #[ApiProperty(readableLink: true )] + #[Groups(['client:read'])] + #[ApiProperty(readableLink: true)] public ?OrganizationalUnitOutput $organizationalUnit = null; #[Groups(['client:read'])] @@ -51,6 +57,8 @@ final class ClientOutput extends AbstractOutput $this->name = $client->getName(); $this->serialNumber = $client->getSerialNumber(); + $this->mac = $client->getMac(); + $this->ip = $client->getIp(); $this->netiface = $client->getNetiface(); if ($client->getOrganizationalUnit()) { diff --git a/src/Dto/Output/OrganizationalUnitOutput.php b/src/Dto/Output/OrganizationalUnitOutput.php index f03c657..89ba2f6 100644 --- a/src/Dto/Output/OrganizationalUnitOutput.php +++ b/src/Dto/Output/OrganizationalUnitOutput.php @@ -42,13 +42,19 @@ final class OrganizationalUnitOutput extends AbstractOutput #[ApiProperty(readableLink: true)] public ?NetworkSettingsOutput $networkSettings = null; + #[Groups(['organizational-unit:read'])] + public array $children = []; + + #[Groups(['organizational-unit:read'])] + public array $clients = []; + #[Groups(['organizational-unit:read'])] public \DateTime $createdAt; #[Groups(['organizational-unit:read'])] public ?string $createdBy = null; - public function __construct(OrganizationalUnit $organizationalUnit) + public function __construct(OrganizationalUnit $organizationalUnit, array $context = []) { parent::__construct($organizationalUnit); @@ -65,6 +71,18 @@ final class OrganizationalUnitOutput extends AbstractOutput $this->parent = new self($organizationalUnit->getParent()); } + if (isset($context['groups']) && in_array('organizational-unit:read', $context['groups'])) { + $this->children = $organizationalUnit->getOrganizationalUnits()->map( + fn(OrganizationalUnit $organizationalUnit) => new self($organizationalUnit, $context) + )->toArray(); + } + + if (isset($context['groups']) && in_array('organizational-unit:read', $context['groups'])) { + $this->clients = $organizationalUnit->getClients()->map( + fn(Client $client) => new ClientOutput($client) + )->toArray(); + } + $this->path = $organizationalUnit->getPath(); $this->createdAt = $organizationalUnit->getCreatedAt(); $this->createdBy = $organizationalUnit->getCreatedBy(); diff --git a/src/Handler/OrganizationalUnitChangeParentHandler.php b/src/Handler/OrganizationalUnitChangeParentHandler.php index b78e651..9a58f45 100644 --- a/src/Handler/OrganizationalUnitChangeParentHandler.php +++ b/src/Handler/OrganizationalUnitChangeParentHandler.php @@ -21,9 +21,9 @@ readonly class OrganizationalUnitChangeParentHandler return throw new \InvalidArgumentException('The organizational unit has no parent.'); } - foreach ($organizationalUnit->getOrganizationalUnits() as $child) { - $child->setParent($parent); - $this->organizationalUnitRepository->save($child); + foreach ($organizationalUnit->getClients() as $client) { + $client->setOrganizationalUnit($parent); + $this->organizationalUnitRepository->save($client); } $this->organizationalUnitRepository->delete($organizationalUnit); diff --git a/src/Security/Voter/ClientVoter.php b/src/Security/Voter/ClientVoter.php new file mode 100644 index 0000000..4be0a12 --- /dev/null +++ b/src/Security/Voter/ClientVoter.php @@ -0,0 +1,48 @@ +getUser(); + + + if (!$user instanceof UserInterface) { + return false; + } + + if (in_array(UserGroupPermissions::ROLE_SUPER_ADMIN, $user->getRoles())) { + return true; + } + + if ($attribute === 'CLIENT_VIEW') { + foreach ($user->getAllowedOrganizationalUnits() as $allowedOrganizationalUnit) { + if ($allowedOrganizationalUnit->getId() === $subject->getOrganizationalUnit()->getEntity()->getId()) { + return true; + } + } + } + + return false; + } +} diff --git a/src/State/Provider/OrganizationalUnitProvider.php b/src/State/Provider/OrganizationalUnitProvider.php index 25267a2..7475e68 100644 --- a/src/State/Provider/OrganizationalUnitProvider.php +++ b/src/State/Provider/OrganizationalUnitProvider.php @@ -42,7 +42,7 @@ readonly class OrganizationalUnitProvider implements ProviderInterface $items = new \ArrayObject(); foreach ($paginator->getIterator() as $item){ - $items[] = new OrganizationalUnitOutput($item); + $items[] = new OrganizationalUnitOutput($item, $context); } return new TraversablePaginator($items, $paginator->getCurrentPage(), $paginator->getItemsPerPage(), $paginator->getTotalItems()); @@ -56,7 +56,7 @@ readonly class OrganizationalUnitProvider implements ProviderInterface throw new NotFoundHttpException('Organizational unit not found'); } - return new OrganizationalUnitOutput($item); + return new OrganizationalUnitOutput($item, $context); } public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null From 8e8947cdfaa857a2e24683516c3b1f047c73044f Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Mon, 15 Jul 2024 08:16:37 +0200 Subject: [PATCH 34/35] refs #436. Change parent ou --- src/Controller/OrganizationalUnitChangeParentAction.php | 7 +++++-- src/Dto/Output/ClientOutput.php | 4 ++++ src/Dto/Output/HardwareProfileOutput.php | 2 +- src/Dto/Output/NetworkSettingsOutput.php | 2 +- src/Dto/Output/OrganizationalUnitOutput.php | 4 ++++ src/Handler/OrganizationalUnitChangeParentHandler.php | 6 ++++-- src/Repository/AbstractRepository.php | 2 +- 7 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/Controller/OrganizationalUnitChangeParentAction.php b/src/Controller/OrganizationalUnitChangeParentAction.php index 7061b22..478d702 100644 --- a/src/Controller/OrganizationalUnitChangeParentAction.php +++ b/src/Controller/OrganizationalUnitChangeParentAction.php @@ -3,10 +3,13 @@ namespace App\Controller; use App\Dto\Input\OrganizationalUnitInput; +use App\Dto\Output\OrganizationalUnitOutput; use App\Entity\OrganizationalUnit; use App\Handler\OrganizationalUnitChangeParentHandler; use App\Repository\OrganizationalUnitRepository; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Response; class OrganizationalUnitChangeParentAction extends AbstractController { @@ -17,10 +20,10 @@ class OrganizationalUnitChangeParentAction extends AbstractController } - public function __invoke(OrganizationalUnit $organizationalUnit): OrganizationalUnitInput + public function __invoke(OrganizationalUnit $organizationalUnit): JsonResponse { $this->organizationalUnitChangeParentHandler->handle($organizationalUnit); - return new OrganizationalUnitInput($organizationalUnit); + return new JsonResponse(data: 'Organizational unit parent changed successfully', status: Response::HTTP_OK); } } \ No newline at end of file diff --git a/src/Dto/Output/ClientOutput.php b/src/Dto/Output/ClientOutput.php index fb4249b..a7b49e3 100644 --- a/src/Dto/Output/ClientOutput.php +++ b/src/Dto/Output/ClientOutput.php @@ -31,6 +31,9 @@ final class ClientOutput extends AbstractOutput #[Groups(['client:read'])] public ?string $netiface = ''; + #[Groups(['client:read'])] + public ?string $netDriver = ''; + #[Groups(['client:read'])] #[ApiProperty(readableLink: true)] public ?OrganizationalUnitOutput $organizationalUnit = null; @@ -60,6 +63,7 @@ final class ClientOutput extends AbstractOutput $this->mac = $client->getMac(); $this->ip = $client->getIp(); $this->netiface = $client->getNetiface(); + $this->netDriver = $client->getNetDriver(); if ($client->getOrganizationalUnit()) { $this->organizationalUnit = new OrganizationalUnitOutput($client->getOrganizationalUnit()); diff --git a/src/Dto/Output/HardwareProfileOutput.php b/src/Dto/Output/HardwareProfileOutput.php index ba78e6d..128f2c8 100644 --- a/src/Dto/Output/HardwareProfileOutput.php +++ b/src/Dto/Output/HardwareProfileOutput.php @@ -11,7 +11,7 @@ use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'HardwareProfile')] final class HardwareProfileOutput extends AbstractOutput { - #[Groups(['hardware-profile:read', 'client:read'])] + #[Groups(['hardware-profile:read', 'client:read', 'organizational-unit:read'])] public ?string $description = ''; #[Groups(['hardware-profile:read'])] diff --git a/src/Dto/Output/NetworkSettingsOutput.php b/src/Dto/Output/NetworkSettingsOutput.php index d909e37..9c0b66d 100644 --- a/src/Dto/Output/NetworkSettingsOutput.php +++ b/src/Dto/Output/NetworkSettingsOutput.php @@ -45,7 +45,7 @@ final class NetworkSettingsOutput extends AbstractOutput #[Groups(['network-settings:read', "organizational-unit:read", "client:read"])] public ?MenuOutput $menu = null; - #[Groups(['organizational-unit:read'])] + #[Groups(['network-settings:read', "organizational-unit:read", "client:read"])] public ?HardwareProfileOutput $hardwareProfile = null; #[Groups(['network-settings:read', "organizational-unit:read", "client:read"])] diff --git a/src/Dto/Output/OrganizationalUnitOutput.php b/src/Dto/Output/OrganizationalUnitOutput.php index 89ba2f6..a51a5c0 100644 --- a/src/Dto/Output/OrganizationalUnitOutput.php +++ b/src/Dto/Output/OrganizationalUnitOutput.php @@ -17,6 +17,9 @@ final class OrganizationalUnitOutput extends AbstractOutput #[Groups(['organizational-unit:read'])] public ?string $comments = null; + #[Groups(['organizational-unit:read'])] + public ?string $description = null; + #[Groups(['organizational-unit:read'])] public ?string $location = null; @@ -60,6 +63,7 @@ final class OrganizationalUnitOutput extends AbstractOutput $this->name = $organizationalUnit->getName(); $this->comments = $organizationalUnit->getComments(); + $this->description = $organizationalUnit->getDescription(); $this->location = $organizationalUnit->getLocation(); $this->projector = $organizationalUnit->isProjector(); $this->board = $organizationalUnit->isBoard(); diff --git a/src/Handler/OrganizationalUnitChangeParentHandler.php b/src/Handler/OrganizationalUnitChangeParentHandler.php index 9a58f45..0e1ee64 100644 --- a/src/Handler/OrganizationalUnitChangeParentHandler.php +++ b/src/Handler/OrganizationalUnitChangeParentHandler.php @@ -3,12 +3,14 @@ namespace App\Handler; use App\Entity\OrganizationalUnit; +use App\Repository\ClientRepository; use App\Repository\OrganizationalUnitRepository; readonly class OrganizationalUnitChangeParentHandler { public function __construct( - private OrganizationalUnitRepository $organizationalUnitRepository + private OrganizationalUnitRepository $organizationalUnitRepository, + private ClientRepository $clientRepository ) { } @@ -23,7 +25,7 @@ readonly class OrganizationalUnitChangeParentHandler foreach ($organizationalUnit->getClients() as $client) { $client->setOrganizationalUnit($parent); - $this->organizationalUnitRepository->save($client); + $this->clientRepository->save($client); } $this->organizationalUnitRepository->delete($organizationalUnit); diff --git a/src/Repository/AbstractRepository.php b/src/Repository/AbstractRepository.php index ff14f0b..2eb3b12 100644 --- a/src/Repository/AbstractRepository.php +++ b/src/Repository/AbstractRepository.php @@ -24,7 +24,7 @@ abstract class AbstractRepository extends ServiceEntityRepository } } - public function delete (AbstractEntity $entity, bool $flush = true): void + public function delete(AbstractEntity $entity, bool $flush = true): void { $this->getEntityManager()->remove($entity); From 14ace8fdbf5b8728d191df7107cfd2b9e65117f3 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Mon, 15 Jul 2024 11:15:53 +0200 Subject: [PATCH 35/35] refs #422. Model change --- migrations/Version20240715084147.php | 43 ++++++++++++++++++++++++++++ src/Dto/Output/UserGroupOutput.php | 10 +++---- src/Dto/Output/UserOutput.php | 14 +++++---- src/Entity/User.php | 4 +-- src/Entity/UserGroup.php | 2 +- 5 files changed, 60 insertions(+), 13 deletions(-) create mode 100644 migrations/Version20240715084147.php diff --git a/migrations/Version20240715084147.php b/migrations/Version20240715084147.php new file mode 100644 index 0000000..0db212c --- /dev/null +++ b/migrations/Version20240715084147.php @@ -0,0 +1,43 @@ +addSql('CREATE TABLE user_user_group (user_id INT NOT NULL, user_group_id INT NOT NULL, INDEX IDX_28657971A76ED395 (user_id), INDEX IDX_286579711ED93D47 (user_group_id), PRIMARY KEY(user_id, user_group_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE user_user_group ADD CONSTRAINT FK_28657971A76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE user_user_group ADD CONSTRAINT FK_286579711ED93D47 FOREIGN KEY (user_group_id) REFERENCES user_group (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE user_group_user DROP FOREIGN KEY FK_3AE4BD51ED93D47'); + $this->addSql('ALTER TABLE user_group_user DROP FOREIGN KEY FK_3AE4BD5A76ED395'); + $this->addSql('DROP TABLE user_group_user'); + $this->addSql('ALTER TABLE hardware_profile CHANGE organizational_unit_id organizational_unit_id INT NOT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE TABLE user_group_user (user_group_id INT NOT NULL, user_id INT NOT NULL, INDEX IDX_3AE4BD5A76ED395 (user_id), INDEX IDX_3AE4BD51ED93D47 (user_group_id), PRIMARY KEY(user_group_id, user_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'\' '); + $this->addSql('ALTER TABLE user_group_user ADD CONSTRAINT FK_3AE4BD51ED93D47 FOREIGN KEY (user_group_id) REFERENCES user_group (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE user_group_user ADD CONSTRAINT FK_3AE4BD5A76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE user_user_group DROP FOREIGN KEY FK_28657971A76ED395'); + $this->addSql('ALTER TABLE user_user_group DROP FOREIGN KEY FK_286579711ED93D47'); + $this->addSql('DROP TABLE user_user_group'); + $this->addSql('ALTER TABLE hardware_profile CHANGE organizational_unit_id organizational_unit_id INT DEFAULT NULL'); + } +} diff --git a/src/Dto/Output/UserGroupOutput.php b/src/Dto/Output/UserGroupOutput.php index 1b1308d..3892d4b 100644 --- a/src/Dto/Output/UserGroupOutput.php +++ b/src/Dto/Output/UserGroupOutput.php @@ -10,7 +10,7 @@ use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'UserGroup')] final class UserGroupOutput extends AbstractOutput { - #[Groups(['user-group:read'])] + #[Groups(['user-group:read', 'user:read'])] public string $name; #[Groups(['user-group:read'])] @@ -20,10 +20,10 @@ final class UserGroupOutput extends AbstractOutput public bool $enabled; #[Groups(['user-group:read'])] - public \DateTime $createAt; + public \DateTime $createdAt; #[Groups(['user-group:read'])] - public ?string $createBy = null; + public ?string $createdBy = null; public function __construct(UserGroup $userGroup) { @@ -32,7 +32,7 @@ final class UserGroupOutput extends AbstractOutput $this->name = $userGroup->getName(); $this->permissions = $userGroup->getPermissions(); $this->enabled = $userGroup->isEnabled(); - $this->createAt = $userGroup->getCreatedAt(); - $this->createBy = $userGroup->getCreatedBy(); + $this->createdAt = $userGroup->getCreatedAt(); + $this->createdBy = $userGroup->getCreatedBy(); } } \ No newline at end of file diff --git a/src/Dto/Output/UserOutput.php b/src/Dto/Output/UserOutput.php index bd7088b..7960699 100644 --- a/src/Dto/Output/UserOutput.php +++ b/src/Dto/Output/UserOutput.php @@ -5,6 +5,7 @@ namespace App\Dto\Output; use ApiPlatform\Metadata\Get; use App\Entity\OrganizationalUnit; use App\Entity\User; +use App\Entity\UserGroup; use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'User')] @@ -24,10 +25,10 @@ final class UserOutput extends AbstractOutput public array $userGroups; #[Groups(['user:read'])] - public \DateTime $createAt; + public \DateTime $createdAt; #[Groups(['user:read'])] - public ?string $createBy = null; + public ?string $createdBy = null; public function __construct(User $user) { @@ -36,13 +37,16 @@ final class UserOutput extends AbstractOutput $this->username = $user->getUsername(); $this->roles = $user->getRoles(); $this->enabled = $user->isEnabled(); - $this->userGroups = $user->getUserGroups()->toArray(); + + $this->userGroups = $user->getUserGroups()->map( + fn(UserGroup $userGroup) => new UserGroupOutput($userGroup) + )->toArray(); $this->allowedOrganizationalUnits = $user->getAllowedOrganizationalUnits()->map( fn(OrganizationalUnit $organizationalUnit) => new OrganizationalUnitOutput($organizationalUnit) )->toArray(); - $this->createAt = $user->getCreatedAt(); - $this->createBy = $user->getCreatedBy(); + $this->createdAt = $user->getCreatedAt(); + $this->createdBy = $user->getCreatedBy(); } } \ No newline at end of file diff --git a/src/Entity/User.php b/src/Entity/User.php index c186575..4b821ce 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -38,7 +38,7 @@ class User extends AbstractEntity implements UserInterface, PasswordAuthenticate /** * @var Collection */ - #[ORM\ManyToMany(targetEntity: UserGroup::class, mappedBy: 'users')] + #[ORM\ManyToMany(targetEntity: UserGroup::class, inversedBy: 'users')] private Collection $userGroups; /** @@ -160,7 +160,7 @@ class User extends AbstractEntity implements UserInterface, PasswordAuthenticate { if (!$this->userGroups->contains($userGroup)) { $this->userGroups->add($userGroup); - $userGroup->addUser($this); + } return $this; diff --git a/src/Entity/UserGroup.php b/src/Entity/UserGroup.php index a017aa9..03cef94 100644 --- a/src/Entity/UserGroup.php +++ b/src/Entity/UserGroup.php @@ -23,7 +23,7 @@ class UserGroup extends AbstractEntity /** * @var Collection */ - #[ORM\ManyToMany(targetEntity: User::class, inversedBy: 'userGroups')] + #[ORM\ManyToMany(targetEntity: User::class, mappedBy: 'userGroups')] private Collection $users; public function __construct()