diff --git a/config/api_platform/ImageImageRepository.yaml b/config/api_platform/ImageImageRepository.yaml index 279d72a..b2d3d73 100644 --- a/config/api_platform/ImageImageRepository.yaml +++ b/config/api_platform/ImageImageRepository.yaml @@ -64,6 +64,14 @@ resources: uriTemplate: /image-image-repositories/{uuid}/convert-image-to-virtual controller: App\Controller\OgRepository\Image\ConvertImageToVirtualAction + rename_image_ogrepository: + shortName: OgRepository Server + class: ApiPlatform\Metadata\Post + method: POST + input: App\Dto\Input\RenameImageInput + uriTemplate: /image-image-repositories/{uuid}/rename-image + controller: App\Controller\OgRepository\Image\RenameAction + trash_delete_image_ogrepository: shortName: OgRepository Server description: Delete Image in OgRepository diff --git a/migrations/Version20250409093554.php b/migrations/Version20250409093554.php new file mode 100644 index 0000000..4993a74 --- /dev/null +++ b/migrations/Version20250409093554.php @@ -0,0 +1,31 @@ +addSql('ALTER TABLE image_image_repository ADD 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 image_image_repository DROP name'); + } +} diff --git a/src/Controller/OgRepository/Image/RenameAction.php b/src/Controller/OgRepository/Image/RenameAction.php index d66ac9c..6e41e16 100644 --- a/src/Controller/OgRepository/Image/RenameAction.php +++ b/src/Controller/OgRepository/Image/RenameAction.php @@ -4,8 +4,10 @@ namespace App\Controller\OgRepository\Image; use App\Controller\OgRepository\AbstractOgRepositoryController; use App\Dto\Input\DeployImageInput; +use App\Dto\Input\RenameImageInput; use App\Entity\Image; use App\Entity\ImageImageRepository; +use App\Entity\ImageRepository; use App\Model\CommandTypes; use App\Model\ImageStatus; use App\Model\TraceStatus; @@ -28,59 +30,96 @@ class RenameAction extends AbstractOgRepositoryController * @throws RedirectionExceptionInterface * @throws ClientExceptionInterface */ - public function __invoke(Image $image): JsonResponse + public function __invoke(RenameImageInput $input, ImageImageRepository $imageImageRepository): JsonResponse { - $repositories = $image->getImageImageRepositories(); + $image = $imageImageRepository->getImage(); - if ($repositories->count() === 0) { - return new JsonResponse(data: ['error' => 'Image is not in any repository', 'code' => Response::HTTP_INTERNAL_SERVER_ERROR], status: Response::HTTP_BAD_REQUEST); - } + if ($image->isGlobal()) { + $repositories = $image->getImageImageRepositories(); - $allGood = true; - foreach ($repositories as $repository) { - try { - $content = $this->createRequest('GET', 'http://'.$repository->getRepository()->getIp(). ':8006/ogrepository/v1/status'); - } catch (TransportExceptionInterface $e) { - $allGood = false; - break; + if ($repositories->count() === 0) { + return $this->jsonError('Image is not in any repository'); } + + if (!$this->isAvailableInAllRepositories($repositories)) { + $this->logger->info('Image is not available in all repositories', ['image' => $image->getName()]); + return $this->jsonError('Image is not available in all repositories'); + } + + $repoWithImage = $this->entityManager + ->getRepository(ImageImageRepository::class) + ->findBy(['image' => $image, 'repository' => $imageImageRepository->getRepository()]); + } else { + $repoWithImage = [$imageImageRepository]; } - if (!$allGood) { - $this->logger->info('Image is not available in all repositories', ['image' => $image->getName()]); - return new JsonResponse(data: ['error' => 'Image is not available in all repositories', 'code' => Response::HTTP_INTERNAL_SERVER_ERROR], status: Response::HTTP_BAD_REQUEST); - } - - $image->setVersion($image->getVersion() + 1); - $this->entityManager->persist($image); - - $conditional = false; - - $latestImageRepo = $this->entityManager->getRepository(ImageImageRepository::class)->findLatestVersion(); - $repoWithImage = $this->entityManager->getRepository(ImageImageRepository::class)->findBy(['image' => $image, 'version' => $latestImageRepo->getVersion()]); - + $hasError = false; foreach ($repoWithImage as $repository) { - $params = [ - 'json' => [ - 'ID_img' => $repository->getImageFullsum(), - 'image_new_name' => $image->getName().'_v'.$image->getVersion(), - ] - ]; + $content = $this->renameImageInRepository($repository, $input->newName); - $content = $this->createRequest('PUT', 'http://'.$repository->getRepository()->getIp().':8006/ogrepository/v1/images/rename', $params); - - if (isset($content['error']) && $content['code'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { - $conditional = true; + if (isset($content['error']) && $content['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) { + $hasError = true; } - } - if ($conditional) { - return new JsonResponse(data: ['error' => 'Error renaming image'], status: Response::HTTP_INTERNAL_SERVER_ERROR); + $repository->setName($input->newName); + $this->entityManager->persist($repository); } $this->entityManager->flush(); - return new JsonResponse(data: [], status: Response::HTTP_OK); + if ($hasError) { + return new JsonResponse(['error' => 'Error renaming image'], Response::HTTP_INTERNAL_SERVER_ERROR); + } + + return new JsonResponse([], Response::HTTP_OK); } + + /** + * @throws RedirectionExceptionInterface + * @throws ClientExceptionInterface + * @throws ServerExceptionInterface + */ + private function isAvailableInAllRepositories($repositories): bool + { + foreach ($repositories as $repository) { + try { + $this->createRequest('GET', 'http://' . $repository->getRepository()->getIp() . ':8006/ogrepository/v1/status'); + } catch (TransportExceptionInterface $e) { + return false; + } + } + return true; + } + + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ClientExceptionInterface + */ + private function renameImageInRepository(ImageImageRepository $repository, string $newName): array + { + $params = [ + 'json' => [ + 'ID_img' => $repository->getImageFullsum(), + 'image_new_name' => $newName, + ] + ]; + + return $this->createRequest( + 'PUT', + 'http://' . $repository->getRepository()->getIp() . ':8006/ogrepository/v1/images/rename', + $params + ); + } + + private function jsonError(string $message): JsonResponse + { + return new JsonResponse( + ['error' => $message, 'code' => Response::HTTP_INTERNAL_SERVER_ERROR], + Response::HTTP_BAD_REQUEST + ); + } + } \ No newline at end of file diff --git a/src/Dto/Input/RenameImageInput.php b/src/Dto/Input/RenameImageInput.php new file mode 100644 index 0000000..7fa128d --- /dev/null +++ b/src/Dto/Input/RenameImageInput.php @@ -0,0 +1,13 @@ + + */ +final class ImageImageRepositoryFactory 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(), + 'image' => ImageFactory::new(), + 'name' => self::faker()->text(255), + 'repository' => ImageRepositoryFactory::new(), + 'status' => 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(ImageImageRepository $imageImageRepository): void {}) + ; + } + + protected static function getClass(): string + { + return ImageImageRepository::class; + } +} diff --git a/tests/Functional/ImageTest.php b/tests/Functional/ImageTest.php index 9b323c7..419d86d 100644 --- a/tests/Functional/ImageTest.php +++ b/tests/Functional/ImageTest.php @@ -9,6 +9,7 @@ use App\Entity\OrganizationalUnit; use App\Entity\SoftwareProfile; use App\Factory\ClientFactory; use App\Factory\ImageFactory; +use App\Factory\ImageImageRepositoryFactory; use App\Factory\ImageRepositoryFactory; use App\Factory\OrganizationalUnitFactory; use App\Factory\SoftwareProfileFactory; @@ -70,12 +71,12 @@ class ImageTest extends AbstractTest SoftwareProfileFactory::createOne(['description' => self::SOFTWARE_PROFILE]); $swPIri = $this->findIriBy(SoftwareProfile::class, ['description' => self::SOFTWARE_PROFILE]); - $imageRepositories = ImageRepositoryFactory::createMany(5); + $imageRepositories = ImageImageRepositoryFactory::createMany(5); $this->createClientWithCredentials()->request('POST', '/images',['json' => [ 'name' => self::IMAGE_CREATE, 'softwareProfile' => $swPIri, - 'imageRepositories' => array_map(fn($repo) => '/image-repositories/'. $repo->getUuid(), $imageRepositories) + 'imageImageRepositories' => array_map(fn($repo) => '/image-repositories/'. $repo->getUuid(), $imageRepositories) ]]); $this->assertResponseStatusCodeSame(201); @@ -102,11 +103,11 @@ class ImageTest extends AbstractTest ImageFactory::createOne(['name' => self::IMAGE_CREATE]); $iri = $this->findIriBy(Image::class, ['name' => self::IMAGE_CREATE]); - $imageRepositories = ImageRepositoryFactory::createMany(5); + $imageRepositories = ImageImageRepositoryFactory::createMany(5); $this->createClientWithCredentials()->request('PUT', $iri, ['json' => [ 'name' => self::IMAGE_UPDATE, - 'imageRepositories' => array_map(fn($repo) => '/image-repositories/'. $repo->getUuid(), $imageRepositories) + 'imageImageRepositories' => array_map(fn($repo) => '/image-repositories/'. $repo->getUuid(), $imageRepositories) ]]); $this->assertResponseIsSuccessful();