diff --git a/migrations/Version20241211074943.php b/migrations/Version20241211074943.php new file mode 100644 index 0000000..106d91e --- /dev/null +++ b/migrations/Version20241211074943.php @@ -0,0 +1,33 @@ +addSql('DROP INDEX UNIQ_IDENTIFIER_NAME ON og_live'); + $this->addSql('ALTER TABLE og_live DROP name'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE og_live ADD name VARCHAR(255) NOT NULL'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_NAME ON og_live (name)'); + } +} diff --git a/migrations/Version20241211075520.php b/migrations/Version20241211075520.php new file mode 100644 index 0000000..76ebb2f --- /dev/null +++ b/migrations/Version20241211075520.php @@ -0,0 +1,33 @@ +addSql('ALTER TABLE network_settings DROP FOREIGN KEY FK_48869B54F7E54CF3'); + $this->addSql('ALTER TABLE network_settings ADD CONSTRAINT FK_48869B54F7E54CF3 FOREIGN KEY (og_live_id) REFERENCES og_live (id) ON DELETE SET NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE network_settings DROP FOREIGN KEY FK_48869B54F7E54CF3'); + $this->addSql('ALTER TABLE network_settings ADD CONSTRAINT FK_48869B54F7E54CF3 FOREIGN KEY (og_live_id) REFERENCES og_live (id)'); + } +} diff --git a/migrations/Version20241211080733.php b/migrations/Version20241211080733.php new file mode 100644 index 0000000..2b6b1c8 --- /dev/null +++ b/migrations/Version20241211080733.php @@ -0,0 +1,33 @@ +addSql('ALTER TABLE og_live CHANGE filename filename VARCHAR(255) NOT NULL'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_FILENAME ON og_live (filename)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP INDEX UNIQ_IDENTIFIER_FILENAME ON og_live'); + $this->addSql('ALTER TABLE og_live CHANGE filename filename VARCHAR(255) DEFAULT NULL'); + } +} diff --git a/src/Controller/OgBoot/OgLive/SyncAction.php b/src/Controller/OgBoot/OgLive/SyncAction.php index 1165dfd..9cc2a43 100644 --- a/src/Controller/OgBoot/OgLive/SyncAction.php +++ b/src/Controller/OgBoot/OgLive/SyncAction.php @@ -32,14 +32,22 @@ class SyncAction extends AbstractOgBootController foreach ($content['message']['installed_ogLives'] as $ogLive) { $ogLiveEntity = $this->entityManager->getRepository(OgLive::class)->findOneBy(['checksum' => $ogLive['id']]); + if (!$ogLiveEntity) { - $ogLiveEntity = new OgLive(); + $ogLiveEntity = $this->entityManager->getRepository(OgLive::class)->findOneBy(['filename' => str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory'])]); + + if (!$ogLiveEntity) { + $ogLiveEntity = new OgLive(); + } } $this->extracted($ogLiveEntity, $ogLive); $this->entityManager->persist($ogLiveEntity); } $this->entityManager->flush(); - //$this->serDefaultOgLive($content['default_oglive']); + + if (isset($content['message']['default_oglive'])) { + $this->serDefaultOgLive($content['message']['default_oglive']); + } return new JsonResponse(data: $content, status: Response::HTTP_OK); } @@ -51,13 +59,10 @@ class SyncAction extends AbstractOgBootController */ private function extracted(OgLive $ogLiveEntity, mixed $ogLive): void { - if (!$ogLiveEntity->getId()){ - $ogLiveEntity->setName(str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory'])); - } $ogLiveEntity->setInstalled(true); $ogLiveEntity->setArchitecture($ogLive['architecture']); $ogLiveEntity->setDistribution($ogLive['distribution']); - $ogLiveEntity->setFilename($ogLive['directory']); + $ogLiveEntity->setFilename(str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory'])); $ogLiveEntity->setKernel($ogLive['kernel']); $ogLiveEntity->setRevision($ogLive['revision']); $ogLiveEntity->setDirectory($ogLive['directory']); @@ -67,7 +72,7 @@ class SyncAction extends AbstractOgBootController private function serDefaultOgLive(string $defaultOgLive): void { - $ogLiveEntity = $this->entityManager->getRepository(OgLive::class)->findOneBy(['name' => $defaultOgLive]); + $ogLiveEntity = $this->entityManager->getRepository(OgLive::class)->findOneBy(['filename' => $defaultOgLive]); if (!$ogLiveEntity) { return; diff --git a/src/Controller/OgBoot/OgLive/Webhook/InstallOgLiveResponseAction.php b/src/Controller/OgBoot/OgLive/Webhook/InstallOgLiveResponseAction.php index db90e58..b0aa21c 100644 --- a/src/Controller/OgBoot/OgLive/Webhook/InstallOgLiveResponseAction.php +++ b/src/Controller/OgBoot/OgLive/Webhook/InstallOgLiveResponseAction.php @@ -24,8 +24,7 @@ class InstallOgLiveResponseAction extends AbstractController { public CONST string OG_LIVE_INSTALL_SUCCESS = 'success'; public CONST string OG_LIVE_INSTALL_FAILED = 'failure'; - - + const string OG_BOOT_DIRECTORY = '/opt/opengnsys/ogboot/tftpboot//'; public function __construct( protected readonly EntityManagerInterface $entityManager @@ -70,6 +69,7 @@ class InstallOgLiveResponseAction extends AbstractController private function updateOgLive (OgLive $ogLive, array $details, string $status): void { if ($status === self::OG_LIVE_INSTALL_SUCCESS) { + $ogLive->setFilename(str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory'])); $ogLive->setInstalled(true); $ogLive->setSynchronized(true); $ogLive->setChecksum($details['id']); diff --git a/src/Dto/Input/OgLiveInput.php b/src/Dto/Input/OgLiveInput.php index 2c86228..ff75678 100644 --- a/src/Dto/Input/OgLiveInput.php +++ b/src/Dto/Input/OgLiveInput.php @@ -10,10 +10,7 @@ use Symfony\Component\Validator\Constraints as Assert; final class OgLiveInput { - #[Assert\NotBlank(message: 'validators.hardware.name.not_blank')] - #[Groups(['og-live:write'])] - #[ApiProperty(description: 'The name of the ogLive', example: "OgLive 1")] - public ?string $name = null; + const string DOWNLOAD_URL = 'https://ognproject.evlt.uma.es/oglive//'; #[Groups(['og-live:write'])] #[ApiProperty(description: 'The download url of the ogLive', example: "http://example.com/oglive1.iso")] @@ -25,7 +22,6 @@ final class OgLiveInput return; } - $this->name = $ogLive->getName(); $this->downloadUrl = $ogLive->getDownloadUrl(); } @@ -35,7 +31,13 @@ final class OgLiveInput $ogLive = new OgLive(); } - $ogLive->setName($this->name); + $filename = str_replace(self::DOWNLOAD_URL, '', $this->downloadUrl); + + if (str_ends_with($filename, '.iso')) { + $filename = substr($filename, 0, -4); + } + + $ogLive->setFilename($filename); $ogLive->setDownloadUrl($this->downloadUrl); $ogLive->setStatus(OgLiveStatus::INACTIVE); diff --git a/src/Dto/Output/OgLiveOutput.php b/src/Dto/Output/OgLiveOutput.php index c6ccde9..1068846 100644 --- a/src/Dto/Output/OgLiveOutput.php +++ b/src/Dto/Output/OgLiveOutput.php @@ -10,9 +10,6 @@ use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'OgLive')] final class OgLiveOutput extends AbstractOutput { - #[Groups(['og-live:read', 'client:read', "organizational-unit:read"])] - public string $name; - #[Groups(['og-live:read'])] public ?bool $synchronized = false; @@ -37,8 +34,8 @@ final class OgLiveOutput extends AbstractOutput #[Groups(['og-live:read'])] public ?string $revision = ''; - #[Groups(['og-live:read'])] - public ?string $filename = ''; + #[Groups(['og-live:read', 'client:read', "organizational-unit:read"])] + public ?string $filename = null; #[Groups(['og-live:read'])] public ?string $kernel = ''; @@ -56,7 +53,6 @@ final class OgLiveOutput extends AbstractOutput { parent::__construct($ogLive); - $this->name = $ogLive->getName(); $this->synchronized = $ogLive->isSynchronized(); $this->installed = $ogLive->isInstalled(); $this->isDefault = $ogLive->getIsDefault(); diff --git a/src/Entity/NetworkSettings.php b/src/Entity/NetworkSettings.php index 8ba83ee..deecf79 100644 --- a/src/Entity/NetworkSettings.php +++ b/src/Entity/NetworkSettings.php @@ -70,6 +70,7 @@ class NetworkSettings extends AbstractEntity private ?ImageRepository $repository = null; #[ORM\ManyToOne] + #[ORM\JoinColumn( onDelete: 'SET NULL')] private ?OgLive $ogLive = null; #[ORM\Column(length: 255, nullable: true)] diff --git a/src/Entity/OgLive.php b/src/Entity/OgLive.php index df0f872..4e01da1 100644 --- a/src/Entity/OgLive.php +++ b/src/Entity/OgLive.php @@ -9,11 +9,10 @@ use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; #[ORM\Entity(repositoryClass: OgLiveRepository::class)] -#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_NAME', fields: ['name'])] -#[UniqueEntity(fields: ['name'], message: 'validators.og_live.name.unique')] +#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_FILENAME', fields: ['filename'])] +#[UniqueEntity(fields: ['filename'], message: 'validators.og_live.filename.unique')] class OgLive extends AbstractEntity { - use NameableTrait; use SynchronizedTrait; #[ORM\Column(length: 255, nullable: true)] @@ -37,7 +36,7 @@ class OgLive extends AbstractEntity #[ORM\Column(length: 255, nullable: true)] private ?string $directory = null; - #[ORM\Column(length: 255, nullable: true)] + #[ORM\Column(length: 255, nullable: false)] private ?string $filename = null; #[ORM\Column(nullable: true)] diff --git a/src/Factory/OgLiveFactory.php b/src/Factory/OgLiveFactory.php index bfe05a8..2faad27 100644 --- a/src/Factory/OgLiveFactory.php +++ b/src/Factory/OgLiveFactory.php @@ -34,8 +34,7 @@ final class OgLiveFactory extends ModelFactory { return [ 'createdAt' => self::faker()->dateTime(), - 'name' => self::faker()->text(255), - 'downloadUrl' => self::faker()->text(255), + 'filename' => self::faker()->text(255), 'status' => OgLiveStatus::ACTIVE, 'updatedAt' => self::faker()->dateTime(), ]; diff --git a/tests/Functional/OgLiveTest.php b/tests/Functional/OgLiveTest.php index 95b2490..883b9a1 100644 --- a/tests/Functional/OgLiveTest.php +++ b/tests/Functional/OgLiveTest.php @@ -61,8 +61,8 @@ class OgLiveTest extends AbstractTest UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); $this->createClientWithCredentials()->request('POST', '/og-lives',['json' => [ - 'name' => self::OGLIVE_CREATE, - 'downloadUrl' => 'http://example.com', + 'filename' => self::OGLIVE_CREATE, + 'downloadUrl' => self::OGLIVE_CREATE ]]); $this->assertResponseStatusCodeSame(201); @@ -70,8 +70,7 @@ class OgLiveTest extends AbstractTest $this->assertJsonContains([ '@context' => '/contexts/OgLiveOutput', '@type' => 'OgLive', - 'name' => self::OGLIVE_CREATE, - 'downloadUrl' => 'http://example.com', + 'filename' => self::OGLIVE_CREATE, 'status' => OgLiveStatus::INACTIVE ]); } @@ -87,19 +86,17 @@ class OgLiveTest extends AbstractTest { UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); - OgLiveFactory::createOne(['name' => self::OGLIVE_CREATE, 'downloadUrl' => 'http://example.com']); - $iri = $this->findIriBy(OgLive::class, ['name' => self::OGLIVE_CREATE]); + OgLiveFactory::createOne(['filename' => self::OGLIVE_CREATE, 'downloadUrl' => self::OGLIVE_UPDATE]); + $iri = $this->findIriBy(OgLive::class, ['filename' => self::OGLIVE_CREATE]); $this->createClientWithCredentials()->request('PUT', $iri, ['json' => [ - 'name' => self::OGLIVE_UPDATE, - 'downloadUrl' => 'http://example-2.com', + 'filename' => self::OGLIVE_UPDATE, ]]); $this->assertResponseIsSuccessful(); $this->assertJsonContains([ '@id' => $iri, - 'name' => self::OGLIVE_UPDATE, - 'downloadUrl' => 'http://example-2.com', + 'filename' => self::OGLIVE_UPDATE, ]); } @@ -114,13 +111,13 @@ class OgLiveTest extends AbstractTest { UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); - OgLiveFactory::createOne(['name' => self::OGLIVE_CREATE, 'downloadUrl' => 'http://example.com']); - $iri = $this->findIriBy(OgLive::class, ['name' => self::OGLIVE_CREATE]); + OgLiveFactory::createOne(['filename' => self::OGLIVE_CREATE, 'downloadUrl' => 'http://example.com']); + $iri = $this->findIriBy(OgLive::class, ['filename' => self::OGLIVE_CREATE]); $this->createClientWithCredentials()->request('DELETE', $iri); $this->assertResponseStatusCodeSame(204); $this->assertNull( - static::getContainer()->get('doctrine')->getRepository(OgLive::class)->findOneBy(['name' => self::OGLIVE_CREATE]) + static::getContainer()->get('doctrine')->getRepository(OgLive::class)->findOneBy(['filename' => self::OGLIVE_CREATE]) ); } } \ No newline at end of file diff --git a/translations/validators.en.yaml b/translations/validators.en.yaml index 03f3bd3..2ea7718 100644 --- a/translations/validators.en.yaml +++ b/translations/validators.en.yaml @@ -52,7 +52,7 @@ validators: not_blank: 'The name should not be blank.' og_live: - name: + filename: not_blank: 'The name should not be blank.' unique: 'The name should be unique.' diff --git a/translations/validators.es.yaml b/translations/validators.es.yaml index 0f307d3..d3b821e 100644 --- a/translations/validators.es.yaml +++ b/translations/validators.es.yaml @@ -39,6 +39,11 @@ validators: not_blank: 'El nombre no debería estar vacío.' unique: 'El nombre debería ser único. Ya existe una imagen con ese nombre.' + og_live: + filename: + not_blank: 'El nombre no debería estar vacío.' + unique: 'El nombre debería ser único. Ya existe un archivo con ese nombre.' + network_settings: ip_address: invalid: 'La dirección IP "{{ value }}" no es válida.'