Merge branch 'feature/integration-dhcp' into develop

develop-jenkins
Manuel Aranda Rosales 2024-09-30 11:14:31 +02:00
commit 7ab7738f7e
86 changed files with 4280 additions and 178 deletions

4
.env
View File

@ -40,3 +40,7 @@ JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=8b9154df37ffa91ef9186ce095324e39e50ff3b023bb1ed34383abd019ba4515
###< lexik/jwt-authentication-bundle ###
OGBOOT_API_URL=http://localhost:8085
OGDHCP_API_URL=http://localhost:8085

View File

@ -25,6 +25,7 @@
"symfony/expression-language": "6.4.*",
"symfony/flex": "^2",
"symfony/framework-bundle": "6.4.*",
"symfony/http-client": "6.4.*",
"symfony/property-access": "6.4.*",
"symfony/property-info": "6.4.*",
"symfony/runtime": "6.4.*",
@ -89,7 +90,6 @@
"phpunit/phpunit": "^9.5",
"symfony/browser-kit": "6.4.*",
"symfony/css-selector": "6.4.*",
"symfony/http-client": "6.4.*",
"symfony/maker-bundle": "^1.59",
"symfony/phpunit-bridge": "^7.0",
"symfony/web-profiler-bundle": "^6.4",

344
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "bf1165324e27bddd1a412f25e438fc4c",
"content-hash": "788f45c89f13c815d43700e8374bf655",
"packages": [
{
"name": "api-platform/core",
@ -4477,6 +4477,177 @@
],
"time": "2024-05-31T14:49:08+00:00"
},
{
"name": "symfony/http-client",
"version": "v6.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client.git",
"reference": "b5e498f763e0bf5eed8dcd946e50a3b3f71d4ded"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client/zipball/b5e498f763e0bf5eed8dcd946e50a3b3f71d4ded",
"reference": "b5e498f763e0bf5eed8dcd946e50a3b3f71d4ded",
"shasum": ""
},
"require": {
"php": ">=8.1",
"psr/log": "^1|^2|^3",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/http-client-contracts": "^3.4.1",
"symfony/service-contracts": "^2.5|^3"
},
"conflict": {
"php-http/discovery": "<1.15",
"symfony/http-foundation": "<6.3"
},
"provide": {
"php-http/async-client-implementation": "*",
"php-http/client-implementation": "*",
"psr/http-client-implementation": "1.0",
"symfony/http-client-implementation": "3.0"
},
"require-dev": {
"amphp/amp": "^2.5",
"amphp/http-client": "^4.2.1",
"amphp/http-tunnel": "^1.0",
"amphp/socket": "^1.1",
"guzzlehttp/promises": "^1.4|^2.0",
"nyholm/psr7": "^1.0",
"php-http/httplug": "^1.0|^2.0",
"psr/http-client": "^1.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/http-kernel": "^5.4|^6.0|^7.0",
"symfony/messenger": "^5.4|^6.0|^7.0",
"symfony/process": "^5.4|^6.0|^7.0",
"symfony/stopwatch": "^5.4|^6.0|^7.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\HttpClient\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
"homepage": "https://symfony.com",
"keywords": [
"http"
],
"support": {
"source": "https://github.com/symfony/http-client/tree/v6.4.10"
},
"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-07-15T09:26:24+00:00"
},
{
"name": "symfony/http-client-contracts",
"version": "v3.5.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client-contracts.git",
"reference": "20414d96f391677bf80078aa55baece78b82647d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/20414d96f391677bf80078aa55baece78b82647d",
"reference": "20414d96f391677bf80078aa55baece78b82647d",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\HttpClient\\": ""
},
"exclude-from-classmap": [
"/Test/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to HTTP clients",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/http-client-contracts/tree/v3.5.0"
},
"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:32:20+00:00"
},
{
"name": "symfony/http-foundation",
"version": "v6.4.8",
@ -9224,177 +9395,6 @@
],
"time": "2024-05-31T14:49:08+00:00"
},
{
"name": "symfony/http-client",
"version": "v6.4.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client.git",
"reference": "61faba993e620fc22d4f0ab3b6bcf8fbb0d44b05"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client/zipball/61faba993e620fc22d4f0ab3b6bcf8fbb0d44b05",
"reference": "61faba993e620fc22d4f0ab3b6bcf8fbb0d44b05",
"shasum": ""
},
"require": {
"php": ">=8.1",
"psr/log": "^1|^2|^3",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/http-client-contracts": "^3.4.1",
"symfony/service-contracts": "^2.5|^3"
},
"conflict": {
"php-http/discovery": "<1.15",
"symfony/http-foundation": "<6.3"
},
"provide": {
"php-http/async-client-implementation": "*",
"php-http/client-implementation": "*",
"psr/http-client-implementation": "1.0",
"symfony/http-client-implementation": "3.0"
},
"require-dev": {
"amphp/amp": "^2.5",
"amphp/http-client": "^4.2.1",
"amphp/http-tunnel": "^1.0",
"amphp/socket": "^1.1",
"guzzlehttp/promises": "^1.4|^2.0",
"nyholm/psr7": "^1.0",
"php-http/httplug": "^1.0|^2.0",
"psr/http-client": "^1.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/http-kernel": "^5.4|^6.0|^7.0",
"symfony/messenger": "^5.4|^6.0|^7.0",
"symfony/process": "^5.4|^6.0|^7.0",
"symfony/stopwatch": "^5.4|^6.0|^7.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\HttpClient\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
"homepage": "https://symfony.com",
"keywords": [
"http"
],
"support": {
"source": "https://github.com/symfony/http-client/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/http-client-contracts",
"version": "v3.5.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client-contracts.git",
"reference": "20414d96f391677bf80078aa55baece78b82647d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/20414d96f391677bf80078aa55baece78b82647d",
"reference": "20414d96f391677bf80078aa55baece78b82647d",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\HttpClient\\": ""
},
"exclude-from-classmap": [
"/Test/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to HTTP clients",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/http-client-contracts/tree/v3.5.0"
},
"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:32:20+00:00"
},
{
"name": "symfony/maker-bundle",
"version": "v1.60.0",

View File

@ -0,0 +1,94 @@
resources:
App\Entity\OgLive:
processor: App\State\Processor\OgLiveProcessor
input: App\Dto\Input\OgLiveInput
output: App\Dto\Output\OgLiveOutput
normalizationContext:
groups: ['default', 'og-live:read']
denormalizationContext:
groups: ['og-live:write']
operations:
ApiPlatform\Metadata\GetCollection:
provider: App\State\Provider\OgLiveProvider
filters:
- 'api_platform.filter.og_live.order'
- 'api_platform.filter.og_live.search'
ApiPlatform\Metadata\Get:
provider: App\State\Provider\OgLiveProvider
ApiPlatform\Metadata\Put:
provider: App\State\Provider\OgLiveProvider
ApiPlatform\Metadata\Patch:
provider: App\State\Provider\OgLiveProvider
ApiPlatform\Metadata\Post: ~
ApiPlatform\Metadata\Delete: ~
get_collection:
shortName: OgLive Server
description: Get collection of OgLive
class: ApiPlatform\Metadata\GetCollection
method: GET
input: false
uriTemplate: /og-lives/server/get-collection
controller: App\Controller\OgBoot\OgLive\GetCollectionAction
get:
shortName: OgLive Server
description: Get OgLive
class: ApiPlatform\Metadata\Get
method: GET
input: false
uriTemplate: /og-lives/server/{uuid}/get
controller: App\Controller\OgBoot\OgLive\GetAction
get_isos:
shortName: OgLive Server
description: Get Isos of OgLive
class: ApiPlatform\Metadata\GetCollection
method: GET
input: false
uriTemplate: /og-lives/server/get-isos
controller: App\Controller\OgBoot\OgLive\GetIsosAction
get_default:
shortName: OgLive Server
description: Get default OgLive
class: ApiPlatform\Metadata\GetCollection
method: GET
input: false
uriTemplate: /og-lives/server/get-default
controller: App\Controller\OgBoot\OgLive\GetDefaultAction
set_default:
shortName: OgLive Server
description: Set default OgLive
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /og-lives/server/{uuid}/set-default
controller: App\Controller\OgBoot\OgLive\SetDefaultAction
install:
shortName: OgLive Server
description: Install OgLive
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /og-lives/server/{uuid}/install
controller: App\Controller\OgBoot\OgLive\InstallAction
uninstall:
shortName: OgLive Server
description: Uninstall OgLive
class: ApiPlatform\Metadata\Get
method: GET
input: false
uriTemplate: /og-lives/server/{uuid}/uninstall
controller: App\Controller\OgBoot\OgLive\UninstallAction
properties:
App\Entity\OgLive:
id:
identifier: false
uuid:
identifier: true

View File

@ -0,0 +1,31 @@
resources:
App\Entity\PxeBootFile:
processor: App\State\Processor\PxeBootFileProcessor
input: App\Dto\Input\PxeBootFileInput
output: App\Dto\Output\PxeBootFileOutput
normalizationContext:
groups: ['default', 'pxe-boot-file:read']
denormalizationContext:
groups: ['pxe-boot-file:write']
operations:
ApiPlatform\Metadata\GetCollection:
provider: App\State\Provider\PxeBootFileProvider
filters:
- 'api_platform.filter.pxe_boot_file.order'
- 'api_platform.filter.pxe_boot_file.search'
ApiPlatform\Metadata\Get:
provider: App\State\Provider\PxeTemplateProvider
ApiPlatform\Metadata\Put:
provider: App\State\Provider\PxeTemplateProvider
ApiPlatform\Metadata\Patch:
provider: App\State\Provider\PxeTemplateProvider
ApiPlatform\Metadata\Post: ~
ApiPlatform\Metadata\Delete: ~
properties:
App\Entity\PxeBootFile:
id:
identifier: false
uuid:
identifier: true

View File

@ -0,0 +1,67 @@
resources:
App\Entity\PxeTemplate:
processor: App\State\Processor\PxeTemplateProcessor
input: App\Dto\Input\PxeTemplateInput
output: App\Dto\Output\PxeTemplateOutput
normalizationContext:
groups: ['default', 'pxe-template:read']
denormalizationContext:
groups: ['pxe-template:write']
operations:
ApiPlatform\Metadata\GetCollection:
provider: App\State\Provider\PxeTemplateProvider
filters:
- 'api_platform.filter.pxe_template.order'
- 'api_platform.filter.pxe_template.search'
ApiPlatform\Metadata\Get:
provider: App\State\Provider\PxeTemplateProvider
ApiPlatform\Metadata\Put:
provider: App\State\Provider\PxeTemplateProvider
ApiPlatform\Metadata\Patch:
provider: App\State\Provider\PxeTemplateProvider
ApiPlatform\Metadata\Post: ~
ApiPlatform\Metadata\Delete: ~
get_collection_templates:
shortName: PxeTemplate Server
description: Get collection of PxeTemplate
class: ApiPlatform\Metadata\GetCollection
method: GET
input: false
uriTemplate: /pxe-templates/server/get-collection
controller: App\Controller\OgBoot\PxeTemplate\GetCollectionAction
get_template:
shortName: PxeTemplate Server
description: Get PxeTemplate
class: ApiPlatform\Metadata\Get
method: GET
input: false
uriTemplate: /pxe-templates/server/{uuid}/get
controller: App\Controller\OgBoot\PxeTemplate\GetAction
post_template:
shortName: PxeTemplate Server
description: Create PxeTemplate
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /pxe-templates/server/{uuid}/post
controller: App\Controller\OgBoot\PxeTemplate\PostAction
delete_template:
shortName: PxeTemplate Server
description: Delete PxeTemplate
class: ApiPlatform\Metadata\Get
method: GET
input: false
uriTemplate: /pxe-templates/server/{uuid}/delete
controller: App\Controller\OgBoot\PxeTemplate\DeleteAction
properties:
App\Entity\PxeTemplate:
id:
identifier: false
uuid:
identifier: true

View File

@ -0,0 +1,130 @@
resources:
App\Entity\Subnet:
processor: App\State\Processor\SubnetProcessor
input: App\Dto\Input\SubnetInput
output: App\Dto\Output\SubnetOutput
normalizationContext:
groups: ['default', 'subnet:read']
denormalizationContext:
groups: ['subnet:write']
operations:
ApiPlatform\Metadata\GetCollection:
provider: App\State\Provider\SubnetProvider
filters:
- 'api_platform.filter.subnet.order'
- 'api_platform.filter.subnet.search'
ApiPlatform\Metadata\Get:
provider: App\State\Provider\SubnetProvider
ApiPlatform\Metadata\Put:
provider: App\State\Provider\SubnetProvider
ApiPlatform\Metadata\Patch:
provider: App\State\Provider\SubnetProvider
ApiPlatform\Metadata\Post: ~
ApiPlatform\Metadata\Delete: ~
get_collection_subnets:
shortName: Subnet Server
description: Get collection of Subnet
class: ApiPlatform\Metadata\GetCollection
method: GET
input: false
uriTemplate: /og-dhcp/server/get-collection
controller: App\Controller\OgDhcp\Subnet\GetCollectionAction
get_subnet:
shortName: Subnet Server
description: Get Subnet
class: ApiPlatform\Metadata\Get
method: GET
input: false
uriTemplate: /og-dhcp/server/{uuid}/get
controller: App\Controller\OgDhcp\Subnet\GetAction
post_subnet:
shortName: Subnet Server
description: Create Subnet
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /og-dhcp/server/{uuid}/post
controller: App\Controller\OgDhcp\Subnet\PostAction
put_subnet:
shortName: Subnet Server
description: Create Subnet
class: ApiPlatform\Metadata\Put
method: PUT
input: false
uriTemplate: /og-dhcp/server/{uuid}/put
controller: App\Controller\OgDhcp\Subnet\PutAction
delete_subnet:
shortName: Subnet Server
description: Delete Subnet
class: ApiPlatform\Metadata\Delete
method: DELETE
input: false
uriTemplate: /og-dhcp/server/{uuid}/delete
controller: App\Controller\OgDhcp\Subnet\DeleteAction
add_single_host:
shortName: Subnet Server Hosts
description: Add Single Host to Subnet
class: ApiPlatform\Metadata\Post
method: POST
input: App\Dto\Input\SubnetAddSingleHostInput
uriTemplate: /og-dhcp/server/{uuid}/add-single-host
controller: App\Controller\OgDhcp\Subnet\AddSingleHostAction
post_host:
shortName: Subnet Server Hosts
description: Post Host to Subnet
class: ApiPlatform\Metadata\Post
method: POST
input: App\Dto\Input\SubnetAddHostInput
uriTemplate: /og-dhcp/server/{uuid}/post-host
controller: App\Controller\OgDhcp\Subnet\PostHostAction
get_hosts:
shortName: Subnet Server Hosts
description: Get Hosts of Subnet
class: ApiPlatform\Metadata\Get
method: GET
input: false
uriTemplate: /og-dhcp/server/{uuid}/get-hosts
controller: App\Controller\OgDhcp\Subnet\GetHostsAction
put_host:
shortName: Subnet Server Hosts
description: Put Host of Subnet
class: ApiPlatform\Metadata\Put
method: PUT
input: false
uriTemplate: /og-dhcp/server/{uuid}/put-host
controller: App\Controller\OgDhcp\Subnet\PutHostAction
delete_host:
shortName: Subnet Server Hosts
description: Delete Host of Subnet
class: ApiPlatform\Metadata\Delete
method: DELETE
input: false
uriTemplate: /og-dhcp/server/{uuid}/delete-host
controller: App\Controller\OgDhcp\Subnet\DeleteHostAction
add_single_organizational_unit:
shortName: Subnet Server Organizational Units
description: Add Single Organizational Unit to Subnet
class: ApiPlatform\Metadata\Post
method: POST
input: App\Dto\Input\SubnetAddSingleOrganizationalUnitInput
uriTemplate: /og-dhcp/server/{uuid}/add-single-organizational-unit
controller: App\Controller\OgDhcp\Subnet\AddSingleOrganizationalUnitAction
properties:
App\Entity\Subnet:
id:
identifier: false
uuid:
identifier: true

View File

@ -4,11 +4,14 @@ imports:
parameters:
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
bind:
$ogBootApiUrl: '%env(OGBOOT_API_URL)%'
$ogDhcpApiUrl: '%env(OGDHCP_API_URL)%'
App\:
resource: '../src/'
exclude:
@ -101,3 +104,23 @@ services:
bind:
$collectionProvider: '@api_platform.doctrine.orm.state.collection_provider'
$itemProvider: '@api_platform.doctrine.orm.state.item_provider'
App\State\Provider\OgLiveProvider:
bind:
$collectionProvider: '@api_platform.doctrine.orm.state.collection_provider'
$itemProvider: '@api_platform.doctrine.orm.state.item_provider'
App\State\Provider\PxeTemplateProvider:
bind:
$collectionProvider: '@api_platform.doctrine.orm.state.collection_provider'
$itemProvider: '@api_platform.doctrine.orm.state.item_provider'
App\State\Provider\PxeBootFileProvider:
bind:
$collectionProvider: '@api_platform.doctrine.orm.state.collection_provider'
$itemProvider: '@api_platform.doctrine.orm.state.item_provider'
App\State\Provider\SubnetProvider:
bind:
$collectionProvider: '@api_platform.doctrine.orm.state.collection_provider'
$itemProvider: '@api_platform.doctrine.orm.state.item_provider'

View File

@ -28,3 +28,14 @@ RUN apk del -f .build-deps
COPY ./docker/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini
# Generate SSH keys
RUN ssh-keygen -t rsa -b 4096 -f /root/.ssh/id_rsa -N ""
# Optionally, copy public key to a specific location
RUN cp /root/.ssh/id_rsa.pub /root/.ssh/authorized_keys
# Expose any ports you may need
EXPOSE 9000
# Command to run the PHP-FPM server
CMD ["php-fpm"]

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240808140716 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE og_live (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, download_url VARCHAR(255) DEFAULT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_3D6B7739D17F50A6 (uuid), UNIQUE INDEX UNIQ_IDENTIFIER_NAME (name), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE og_live');
}
}

View File

@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240812095940 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE pxe_boot_file (id INT AUTO_INCREMENT NOT NULL, template_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, UNIQUE INDEX UNIQ_7FD1F34BD17F50A6 (uuid), INDEX IDX_7FD1F34B5DA0FB8 (template_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE pxe_template (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, template_content VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_73197554D17F50A6 (uuid), UNIQUE INDEX UNIQ_IDENTIFIER_NAME (name), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE pxe_boot_file ADD CONSTRAINT FK_7FD1F34B5DA0FB8 FOREIGN KEY (template_id) REFERENCES pxe_template (id)');
$this->addSql('ALTER TABLE client ADD pxe_boot_file_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455D4CBF752 FOREIGN KEY (pxe_boot_file_id) REFERENCES pxe_boot_file (id)');
$this->addSql('CREATE INDEX IDX_C7440455D4CBF752 ON client (pxe_boot_file_id)');
$this->addSql('ALTER TABLE og_live ADD checksum VARCHAR(255) DEFAULT NULL, ADD distribution VARCHAR(255) DEFAULT NULL, ADD kernel VARCHAR(255) DEFAULT NULL, ADD architecture VARCHAR(255) DEFAULT NULL, ADD revision VARCHAR(255) DEFAULT NULL, ADD directory VARCHAR(255) DEFAULT NULL, ADD filename VARCHAR(255) DEFAULT NULL, ADD installed 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 FOREIGN KEY FK_C7440455D4CBF752');
$this->addSql('ALTER TABLE pxe_boot_file DROP FOREIGN KEY FK_7FD1F34B5DA0FB8');
$this->addSql('DROP TABLE pxe_boot_file');
$this->addSql('DROP TABLE pxe_template');
$this->addSql('ALTER TABLE og_live DROP checksum, DROP distribution, DROP kernel, DROP architecture, DROP revision, DROP directory, DROP filename, DROP installed');
$this->addSql('DROP INDEX IDX_C7440455D4CBF752 ON client');
$this->addSql('ALTER TABLE client DROP pxe_boot_file_id');
}
}

View File

@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240812135824 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE og_repository (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, ip_address VARCHAR(255) NOT NULL, description VARCHAR(255) DEFAULT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_2E0FDA37D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE client ADD repository_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C744045550C9D4F7 FOREIGN KEY (repository_id) REFERENCES og_repository (id)');
$this->addSql('CREATE INDEX IDX_C744045550C9D4F7 ON client (repository_id)');
$this->addSql('ALTER TABLE network_settings ADD repository_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE network_settings ADD CONSTRAINT FK_48869B5450C9D4F7 FOREIGN KEY (repository_id) REFERENCES og_repository (id)');
$this->addSql('CREATE INDEX IDX_48869B5450C9D4F7 ON network_settings (repository_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_C744045550C9D4F7');
$this->addSql('ALTER TABLE network_settings DROP FOREIGN KEY FK_48869B5450C9D4F7');
$this->addSql('DROP TABLE og_repository');
$this->addSql('DROP INDEX IDX_48869B5450C9D4F7 ON network_settings');
$this->addSql('ALTER TABLE network_settings DROP repository_id');
$this->addSql('DROP INDEX IDX_C744045550C9D4F7 ON client');
$this->addSql('ALTER TABLE client DROP repository_id');
}
}

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240827102833 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE subnet (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, netmask VARCHAR(255) NOT NULL, ip_address VARCHAR(255) NOT NULL, next_server VARCHAR(255) NOT NULL, boot_file_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_91C24216D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE subnet');
}
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240902124157 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE network_settings ADD next_server VARCHAR(255) DEFAULT NULL, ADD boot_file_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 network_settings ADD og_live_id INT DEFAULT NULL, DROP next_server, DROP boot_file_name');
$this->addSql('ALTER TABLE network_settings ADD CONSTRAINT FK_48869B54F7E54CF3 FOREIGN KEY (og_live_id) REFERENCES og_live (id)');
}
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240903081001 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE organizational_unit ADD subnet_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2DC9CF9478 FOREIGN KEY (subnet_id) REFERENCES subnet (id)');
$this->addSql('CREATE INDEX IDX_749AEB2DC9CF9478 ON organizational_unit (subnet_id)');
}
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_749AEB2DC9CF9478');
$this->addSql('DROP INDEX IDX_749AEB2DC9CF9478 ON organizational_unit');
$this->addSql('ALTER TABLE organizational_unit DROP subnet_id');
}
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240904134540 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE client CHANGE og_live_id subnet_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455C9CF9478 FOREIGN KEY (subnet_id) REFERENCES subnet (id)');
$this->addSql('CREATE INDEX IDX_C7440455C9CF9478 ON client (subnet_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_C7440455C9CF9478');
$this->addSql('DROP INDEX IDX_C7440455C9CF9478 ON client');
$this->addSql('ALTER TABLE client CHANGE subnet_id og_live_id INT DEFAULT NULL');
}
}

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace App\Controller\OgBoot;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpKernel\Attribute\AsController;
#[AsController]
abstract class AbstractOgLiveController extends AbstractController
{
public function __construct(
protected readonly string $ogBootApiUrl,
protected readonly EntityManagerInterface $entityManager
)
{
}
}

View File

@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
namespace App\Controller\OgBoot;
use App\Service\OgBoot\ConfigService;
use App\Service\OgBoot\StatusService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[Route('/og-boot')]
#[AsController]
class OgBootController extends AbstractController
{
public function __construct(
private readonly StatusService $ogbootStatusService,
private readonly ConfigService $ogbootConfigService,
)
{
}
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
#[Route('/status', name: 'ogboot_status', methods: ['GET'])]
public function status(): JsonResponse
{
$data = $this->ogbootStatusService->__invoke();
return new JsonResponse( data: $data, status: Response::HTTP_OK);
}
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
#[Route('/config', name: 'ogboot_config', methods: ['GET'])]
public function config(): JsonResponse
{
$data = $this->ogbootConfigService->__invoke();
return new JsonResponse( data: $data, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\Controller\OgBoot\OgLive;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Entity\OgLive;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetAction extends AbstractOgLiveController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(OgLive $data, HttpClientInterface $httpClient): JsonResponse
{
try {
$response = $httpClient->request('GET', $this->ogBootApiUrl.'/ogboot/v1/oglives/'.$data->getChecksum(), [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$data = json_decode($response->getContent(), true);
return new JsonResponse( data: $data, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\Controller\OgBoot\OgLive;
use App\Controller\OgBoot\AbstractOgLiveController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetCollectionAction extends AbstractOgLiveController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(HttpClientInterface $httpClient): JsonResponse
{
try {
$response = $httpClient->request('GET', $this->ogBootApiUrl.'/ogboot/v1/oglives', [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$data = json_decode($response->getContent(), true);
return new JsonResponse( data: $data, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\Controller\OgBoot\OgLive;
use App\Controller\OgBoot\AbstractOgLiveController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetDefaultAction extends AbstractOgLiveController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(HttpClientInterface $httpClient): JsonResponse
{
try {
$response = $httpClient->request('GET', $this->ogBootApiUrl.'/ogboot/v1/oglives/default', [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$data = json_decode($response->getContent(), true);
return new JsonResponse( data: $data, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,72 @@
<?php
namespace App\Controller\OgBoot\OgLive;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Entity\OgLive;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetIsosAction extends AbstractOgLiveController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(HttpClientInterface $httpClient): JsonResponse
{
$ogLivesInserted = 0;
try {
$response = $httpClient->request('GET', $this->ogBootApiUrl.'/ogboot/v1/oglives/isos', [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$data = json_decode($response->getContent(), true);
if (!empty($data['downloads'])) {
$ogLivesInserted = $this->insertOglives($data);
}
return new JsonResponse( data: [ 'data' => $data, 'ogLivesInserted' => $ogLivesInserted], status: Response::HTTP_OK);
}
public function insertOglives(array $data): int
{
$count = 0;
foreach ($data['downloads'] as $ogLive ) {
$ogLiveEntity = $this->entityManager->getRepository(OgLive::class)->findOneBy(['name' => $ogLive['filename']]);
if ($ogLiveEntity) {
continue;
}
$ogLiveEntity = new OgLive();
$ogLiveEntity->setName($ogLive['filename']);
$ogLiveEntity->setInstalled($ogLive['installed']);
$ogLiveEntity->setFilename($ogLive['filename']);
$this->entityManager->persist($ogLiveEntity);
$count++;
}
$this->entityManager->flush();
return $count;
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace App\Controller\OgBoot\OgLive;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Entity\OgLive;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class InstallAction extends AbstractOgLiveController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(OgLive $data, HttpClientInterface $httpClient): JsonResponse
{
try {
$response = $httpClient->request('POST', $this->ogBootApiUrl.'/ogboot/v1/oglives/install', [
'headers' => [
'accept' => 'application/json',
'Content-Type' => 'application/json',
],
'json' => [
'isoname' => $data->getName()
]
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$data = json_decode($response->getContent(), true);
return new JsonResponse( data: $data, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace App\Controller\OgBoot\OgLive;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Entity\OgLive;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class SetDefaultAction extends AbstractOgLiveController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(OgLive $data, HttpClientInterface $httpClient): JsonResponse
{
try {
$response = $httpClient->request('POST', $this->ogBootApiUrl.'/ogboot/v1/oglives/default', [
'headers' => [
'accept' => 'application/json',
],
'json' => [
'checksum' => $data->getChecksum()
]
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$data = json_decode($response->getContent(), true);
return new JsonResponse( data: $data, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\Controller\OgBoot\OgLive;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Entity\OgLive;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class UninstallAction extends AbstractOgLiveController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(OgLive $data, HttpClientInterface $httpClient): JsonResponse
{
try {
$response = $httpClient->request('DELETE', $this->ogBootApiUrl.'/ogboot/v1/oglives/'.$data->getChecksum(), [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$data = json_decode($response->getContent(), true);
return new JsonResponse( data: $data, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace App\Controller\OgBoot\PxeBootFile;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Entity\PxeBootFile;
use App\Entity\PxeTemplate;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetAction extends AbstractOgLiveController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(PxeBootFile $data, HttpClientInterface $httpClient): JsonResponse
{
try {
$response = $httpClient->request('GET', $this->ogBootApiUrl.'/ogboot/v1/pxes/'.$data->getName(), [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$data = json_decode($response->getContent(), true);
return new JsonResponse( data: $data, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace App\Controller\OgBoot\PxeTemplate;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Entity\PxeTemplate;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class DeleteAction extends AbstractOgLiveController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(PxeTemplate $data, HttpClientInterface $httpClient): JsonResponse
{
try {
$response = $httpClient->request('DELETE', $this->ogBootApiUrl.'/ogboot/v1/pxe-templates/'.$data->getName(), [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$data = json_decode($response->getContent(), true);
return new JsonResponse( data: $data, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace App\Controller\OgBoot\PxeTemplate;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Entity\PxeTemplate;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetAction extends AbstractOgLiveController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(PxeTemplate $data, HttpClientInterface $httpClient): JsonResponse
{
try {
$response = $httpClient->request('GET', $this->ogBootApiUrl.'/ogboot/v1/pxe-templates/'.$data->getName(), [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$data = json_decode($response->getContent(), true);
return new JsonResponse( data: $data, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\Controller\OgBoot\PxeTemplate;
use App\Controller\OgBoot\AbstractOgLiveController;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetCollectionAction extends AbstractOgLiveController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(HttpClientInterface $httpClient): JsonResponse
{
try {
$response = $httpClient->request('GET', $this->ogBootApiUrl.'/ogboot/v1/pxe-templates', [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$data = json_decode($response->getContent(), true);
return new JsonResponse( data: $data, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,55 @@
<?php
namespace App\Controller\OgBoot\PxeTemplate;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Entity\PxeTemplate;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class PostAction extends AbstractOgLiveController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(PxeTemplate $data, HttpClientInterface $httpClient): JsonResponse
{
try {
$response = $httpClient->request('POST', $this->ogBootApiUrl.'/ogboot/v1/pxe-templates', [
'headers' => [
'accept' => 'application/json',
'Content-Type' => 'application/json',
],
'json' => [
'name_template' => $data->getName(),
'content_template' => $data->getTemplateContent(),
],
]);
$data = json_decode($response->getContent(), true);
return new JsonResponse($data, Response::HTTP_OK);
} catch (ClientExceptionInterface $e) {
$errorResponse = $e->getResponse();
$errorContent = $errorResponse ? $errorResponse->getContent(false) : 'Client error occurred';
return new JsonResponse(['error' => $errorContent], Response::HTTP_BAD_REQUEST);
} catch (ServerExceptionInterface $e) {
$errorResponse = $e->getResponse();
$errorContent = $errorResponse ? $errorResponse->getContent(false) : 'Server error occurred';
return new JsonResponse(['error' => $errorContent], Response::HTTP_INTERNAL_SERVER_ERROR);
} catch (TransportExceptionInterface $e) {
return new JsonResponse(['error' => 'Transport error occurred'], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
}

View File

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace App\Controller\OgDhcp;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
abstract class AbstractOgDhcpController extends AbstractController
{
public function __construct(
protected readonly string $ogDhcpApiUrl,
protected readonly EntityManagerInterface $entityManager
)
{
}
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function createRequest (HttpClientInterface $httpClient, string $method, string $url, array $params = []): JsonResponse|array
{
$params = array_merge($params, [
'headers' => [
'accept' => 'application/json',
'Content-Type' => 'application/json'
],
]);
try {
$response = $httpClient->request($method, $url, $params);
return json_decode($response->getContent(), true);
} catch (ClientExceptionInterface | ServerExceptionInterface $e) {
$response = $e->getResponse();
$content = json_decode($response->getContent(false), true);
throw new HttpException($response->getStatusCode(), $content['error'] ?? 'An error occurred');
} catch (TransportExceptionInterface $e) {
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, $e->getMessage());
}
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace App\Controller\OgDhcp\Subnet;
use App\Controller\OgDhcp\AbstractOgDhcpController;
use App\Dto\Input\SubnetAddSingleHostInput;
use App\Entity\Client;
use App\Entity\Subnet;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Validator\Exception\ValidatorException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class AddSingleHostAction extends AbstractOgDhcpController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(SubnetAddSingleHostInput $input, Subnet $subnet, HttpClientInterface $httpClient): JsonResponse
{
$client = $input->client;
/** @var Client $clientEntity */
$clientEntity = $client->getEntity();
$params = [
'json' => [
'host' => $clientEntity->getName(),
'macAddress' => $clientEntity->getMac(),
'address' => $clientEntity->getIp(),
]
];
$content = $this->createRequest($httpClient, 'POST', $this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$subnet->getId().'/hosts', $params);
if ($content->getStatusCode() === 200) {
$subnet->addClient($clientEntity);
$this->entityManager->persist($subnet);
$this->entityManager->flush();
}
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace App\Controller\OgDhcp\Subnet;
use App\Controller\OgDhcp\AbstractOgDhcpController;
use App\Dto\Input\SubnetAddSingleHostInput;
use App\Dto\Input\SubnetAddSingleOrganizationalUnitInput;
use App\Entity\Client;
use App\Entity\OrganizationalUnit;
use App\Entity\Subnet;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Validator\Exception\ValidatorException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class AddSingleOrganizationalUnitAction extends AbstractOgDhcpController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(SubnetAddSingleOrganizationalUnitInput $input, Subnet $subnet, HttpClientInterface $httpClient): JsonResponse
{
$ou = $input->organizationalUnitOutput;
/** @var OrganizationalUnit $organizationalUnitEntity */
$organizationalUnitEntity = $ou->getEntity();
$params = [
'json' => [
'name' => $organizationalUnitEntity->getId(),
'nextServer' => $organizationalUnitEntity->getNetworkSettings()?->getNextServer(),
'bootFileName' => $organizationalUnitEntity->getNetworkSettings()?->getBootFileName(),
]
];
$content = $this->createRequest($httpClient, 'POST', $this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$subnet->getId().'/classroom', $params);
if ($content->getStatusCode() === 200) {
$subnet->addOrganizationalUnit($organizationalUnitEntity);
$this->entityManager->persist($subnet);
$this->entityManager->flush();
}
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace App\Controller\OgDhcp\Subnet;
use App\Controller\OgDhcp\AbstractOgDhcpController;
use App\Entity\Subnet;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Validator\Exception\ValidatorException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class DeleteAction extends AbstractOgDhcpController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Subnet $data, HttpClientInterface $httpClient): JsonResponse
{
if (!$data->getId()) {
throw new ValidatorException('Data Id is required');
}
$content = $this->createRequest($httpClient, 'DELETE', $this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$data->getId());
$this->entityManager->remove($data);
$this->entityManager->flush();
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace App\Controller\OgDhcp\Subnet;
use App\Controller\OgDhcp\AbstractOgDhcpController;
use App\Entity\Subnet;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Validator\Exception\ValidatorException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class DeleteHostAction extends AbstractOgDhcpController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Subnet $data, HttpClientInterface $httpClient): JsonResponse
{
if (!$data->getId()) {
throw new ValidatorException('Data URL is required');
}
$params = [
'json' => [
'host' => '',
]
];
$content = $this->createRequest($httpClient, 'POST', $this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$data->getId().'/hosts', $params);
$this->entityManager->persist($data);
$this->entityManager->flush();
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace App\Controller\OgDhcp\Subnet;
use App\Controller\OgDhcp\AbstractOgDhcpController;
use App\Entity\Subnet;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Validator\Exception\ValidatorException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetAction extends AbstractOgDhcpController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Subnet $data, HttpClientInterface $httpClient): JsonResponse
{
if (!$data->getId()) {
throw new ValidatorException('Checksum is required');
}
$content = $this->createRequest($httpClient, 'GET', $this->ogDhcpApiUrl.'/opengnsys3/rest/dhcp/subnets/'.$data->getId());
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Controller\OgDhcp\Subnet;
use App\Controller\OgDhcp\AbstractOgDhcpController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetCollectionAction extends AbstractOgDhcpController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(HttpClientInterface $httpClient): JsonResponse
{
$content = $this->createRequest($httpClient, 'GET', $this->ogDhcpApiUrl . '/ogdhcp/v1/subnets');
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace App\Controller\OgDhcp\Subnet;
use App\Controller\OgDhcp\AbstractOgDhcpController;
use App\Entity\Subnet;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Validator\Exception\ValidatorException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetHostsAction extends AbstractOgDhcpController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Subnet $data, HttpClientInterface $httpClient): JsonResponse
{
if (!$data->getId()) {
throw new ValidatorException('Checksum is required');
}
$content = $this->createRequest($httpClient, 'GET', $this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$data->getId().'/hosts');
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace App\Controller\OgDhcp\Subnet;
use App\Controller\OgDhcp\AbstractOgDhcpController;
use App\Entity\Subnet;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Validator\Exception\ValidatorException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class PostAction extends AbstractOgDhcpController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Subnet $data, HttpClientInterface $httpClient): JsonResponse
{
$params = [
'json' => [
'subnetId' => $data->getId(),
'mask' => $data->getNetmask(),
'address' => $data->getIpAddress(),
'nextServer' => $data->getNextServer(),
'bootFileName' => $data->getBootFileName(),
]
];
$content = $this->createRequest($httpClient, 'POST', $this->ogDhcpApiUrl.'/ogdhcp/v1/subnets' , $params);
$this->entityManager->persist($data);
$this->entityManager->flush();
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,57 @@
<?php
namespace App\Controller\OgDhcp\Subnet;
use App\Controller\OgDhcp\AbstractOgDhcpController;
use App\Dto\Input\SubnetAddHostInput;
use App\Dto\Output\ClientOutput;
use App\Entity\Client;
use App\Entity\Subnet;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Validator\Exception\ValidatorException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class PostHostAction extends AbstractOgDhcpController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(SubnetAddHostInput $input, Subnet $subnet, HttpClientInterface $httpClient): JsonResponse
{
$clients = $input->clients;
$subnet->setClients($clients);
$this->entityManager->persist($subnet);
$this->entityManager->flush();
foreach ($clients as $client) {
/** @var Client $clientEntity */
$clientEntity = $client->getEntity();
$data = [
'host' => $clientEntity->getName(),
'macAddress' => $clientEntity->getMac(),
'address' => $clientEntity->getIp(),
];
$params = [
'json' => $data
];
$content = $this->createRequest($httpClient, 'POST', $this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$subnet->getId().'/hosts', $params);
}
return new JsonResponse(status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,48 @@
<?php
namespace App\Controller\OgDhcp\Subnet;
use App\Controller\OgDhcp\AbstractOgDhcpController;
use App\Entity\Subnet;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Validator\Exception\ValidatorException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class PutAction extends AbstractOgDhcpController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Subnet $data, HttpClientInterface $httpClient): JsonResponse
{
if (!$data->getId()) {
throw new ValidatorException('Id is required');
}
$params = [
'json' => [
'mask' => $data->getNetmask(),
'address' => $data->getIpAddress(),
'nextServer' => $data->getNextServer(),
'bootFileName' => $data->getBootFileName(),
]
];
$content = $this->createRequest($httpClient, 'PUT', $this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$data->getId(), $params);
$this->entityManager->persist($data);
$this->entityManager->flush();
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Controller\OgDhcp\Subnet;
use App\Controller\OgDhcp\AbstractOgDhcpController;
use App\Dto\Input\SubnetAddHostInput;
use App\Entity\Client;
use App\Entity\Subnet;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class PutHostAction extends AbstractOgDhcpController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(SubnetAddHostInput $input, Subnet $subnet, HttpClientInterface $httpClient): JsonResponse
{
$clients = $input->clients;
foreach ($clients as $client) {
/** @var Client $clientEntity */
$clientEntity = $client->getEntity();
$data = [
'host' => $clientEntity->getName(),
'oldMacAddress' => '',
'macAddress' => '',
'address' => '',
];
$params = [
'json' => $data
];
$content = $this->createRequest($httpClient, 'PUT', $this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$subnet->getId().'/hosts', $params);
}
return new JsonResponse(status: Response::HTTP_OK);
}
}

View File

@ -7,6 +7,7 @@ use App\Dto\Output\HardwareProfileOutput;
use App\Dto\Output\MenuOutput;
use App\Dto\Output\OrganizationalUnitOutput;
use App\Entity\Client;
use App\Entity\OgRepository;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
@ -77,10 +78,16 @@ final class ClientInput
#[Groups(['client:write'])]
#[ApiProperty(
description: 'descriptions.client.validation'
description: 'La posición del cliente dentro del aula'
)]
public ?array $position = ['x' => 0, 'y' => 0];
#[Groups(['client:write'])]
#[ApiProperty(
description: 'descriptions.client.validation'
)]
public ?OgRepository $repository = null;
public function __construct(?Client $client = null)
{
if (!$client) {

View File

@ -15,6 +15,12 @@ use Symfony\Component\Validator\Constraints as Assert;
class NetworkSettingsInput
{
#[Groups(['organizational-unit:write'])]
public ?string $nextServer = null;
#[Groups(['organizational-unit:write'])]
public ?string $bootFileName = null;
#[Groups(['organizational-unit:write'])]
public ?string $proxy = null;
@ -71,6 +77,8 @@ class NetworkSettingsInput
return;
}
$this->nextServer = $networkSettings->getNextServer();
$this->bootFileName = $networkSettings->getBootFileName();
$this->proxy = $networkSettings->getProxy();
$this->dns = $networkSettings->getDns();
$this->netmask = $networkSettings->getNetmask();
@ -100,6 +108,8 @@ class NetworkSettingsInput
$networkSettings = new NetworkSettings();
}
$networkSettings->setNextServer($this->nextServer);
$networkSettings->setBootFileName($this->bootFileName);
$networkSettings->setProxy($this->proxy);
$networkSettings->setDns($this->dns);
$networkSettings->setNetmask($this->netmask);

View File

@ -0,0 +1,42 @@
<?php
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Entity\OgLive;
use Symfony\Component\Serializer\Annotation\Groups;
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;
#[Groups(['og-live:write'])]
#[ApiProperty(description: 'The download url of the ogLive', example: "http://example.com/oglive1.iso")]
public ?string $downloadUrl = null;
public function __construct(?OgLive $ogLive = null)
{
if (!$ogLive) {
return;
}
$this->name = $ogLive->getName();
$this->downloadUrl = $ogLive->getDownloadUrl();
}
public function createOrUpdateEntity(?OgLive $ogLive = null): OgLive
{
if (!$ogLive) {
$ogLive = new OgLive();
}
$ogLive->setName($this->name);
$ogLive->setDownloadUrl($this->downloadUrl);
return $ogLive;
}
}

View File

@ -0,0 +1,55 @@
<?php
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\ClientOutput;
use App\Dto\Output\PxeTemplateOutput;
use App\Entity\PxeBootFile;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
final class PxeBootFileInput
{
#[Assert\NotNull(message: 'validators.pxe_boot_file.template.not_null')]
#[Groups(['pxe-boot-file:write'])]
#[ApiProperty(description: 'The pxeTemplate of the pxeBootFile', example: "PxeTemplate 1")]
public ?PxeTemplateOutput $template = null;
/**
* @var ClientOutput[]
*/
#[Groups(['pxe-boot-file:write'])]
#[ApiProperty(description: 'The clients of the pxeBootFile', readableLink: false, writableLink: false, example: "Client 1")]
public array $clients = [];
public function __construct(?PxeBootFile $bootFile = null)
{
if (!$bootFile) {
return;
}
$this->template = $bootFile->getTemplate();
if ($bootFile->getClients()) {
foreach ($bootFile->getClients() as $client) {
$this->clients[] = new ClientOutput($client);
}
}
}
public function createOrUpdateEntity(?PxeBootFile $bootFile = null): PxeBootFile
{
if (!$bootFile) {
$bootFile = new PxeBootFile();
}
$bootFile->setTemplate($this->template);
foreach ($this->clients as $client) {
$clientsToAdd[] = $client->getEntity();
}
$bootFile->setClients( $clientsToAdd ?? [] );
return $bootFile;
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Entity\PxeTemplate;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
final class PxeTemplateInput
{
#[Assert\NotBlank(message: 'validators.pxe_template.name.not_blank')]
#[Groups(['pxe-template:write'])]
#[ApiProperty(description: 'The name of the pxeTemplate', example: "PxeTemplate 1")]
public ?string $name = null;
#[Groups(['pxe-template:write'])]
#[ApiProperty(description: 'The content of the pxeTemplate', example: "content of the pxeTemplate 1")]
public ?string $templateContent = null;
public function __construct(?PxeTemplate $pxeTemplate = null)
{
if (!$pxeTemplate) {
return;
}
$this->name = $pxeTemplate->getName();
$this->templateContent = $pxeTemplate->getTemplateContent();
}
public function createOrUpdateEntity(?PxeTemplate $pxeTemplate = null): PxeTemplate
{
if (!$pxeTemplate) {
$pxeTemplate = new PxeTemplate();
}
$pxeTemplate->setName($this->name);
$pxeTemplate->setTemplateContent($this->templateContent);
return $pxeTemplate;
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\ClientOutput;
use App\Dto\Output\PxeTemplateOutput;
use App\Dto\Output\SubnetOutput;
use App\Entity\PxeBootFile;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
final class SubnetAddHostInput
{
/**
* @var ClientOutput[]
*/
#[Groups(['subnet:write'])]
#[ApiProperty(description: 'The clients of the subnet', readableLink: false, writableLink: false, example: "Client 1")]
public array $clients = [];
}

View File

@ -0,0 +1,15 @@
<?php
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\ClientOutput;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
final class SubnetAddSingleHostInput
{
#[Assert\NotNull]
#[Groups(['subnet:write'])]
public ?ClientOutput $client = null;
}

View File

@ -0,0 +1,15 @@
<?php
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\OrganizationalUnitOutput;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
final class SubnetAddSingleOrganizationalUnitInput
{
#[Assert\NotNull]
#[Groups(['subnet:write'])]
public ?OrganizationalUnitOutput $organizationalUnitOutput = null;
}

View File

@ -0,0 +1,84 @@
<?php
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\OrganizationalUnitOutput;
use App\Dto\Output\SubnetOutput;
use App\Entity\Subnet;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
final class SubnetInput
{
#[Assert\NotBlank(message: 'validators.subnet.name.not_blank')]
#[Groups(['subnet:write'])]
#[ApiProperty(description: 'The name of the subnet', example: "Subnet 1")]
public ?string $name = null;
#[Assert\NotBlank(message: 'validators.subnet.netmask.not_blank')]
#[Groups(['subnet:write'])]
#[ApiProperty(description: 'The netmask of the subnet', example: "")]
public ?string $netmask = null;
#[Assert\NotBlank(message: 'validators.subnet.ip_address.not_blank')]
#[Groups(['subnet:write'])]
#[ApiProperty(description: 'The ip address of the subnet', example: "")]
public ?string $ipAddress = null;
#[Assert\NotBlank(message: 'validators.subnet.next_server.not_blank')]
#[Groups(['subnet:write'])]
#[ApiProperty(description: 'The next server of the subnet', example: "")]
public ?string $nextServer = null;
#[Assert\NotBlank(message: 'validators.subnet.boot_file_name.not_blank')]
#[Groups(['subnet:write'])]
#[ApiProperty(description: 'The boot file name of the subnet', example: "")]
public ?string $bootFileName = null;
/**
* @var OrganizationalUnitOutput[]
*/
#[Groups('user:write')]
#[ApiProperty(readableLink: false, writableLink: false)]
public array $organizationalUnits = [];
public function __construct(?Subnet $subnet = null)
{
if (!$subnet) {
return;
}
$this->name = $subnet->getName();
$this->netmask = $subnet->getNetmask();
$this->ipAddress = $subnet->getIpAddress();
$this->nextServer = $subnet->getNextServer();
$this->bootFileName = $subnet->getBootFileName();
if ($subnet->getOrganizationalUnits()) {
foreach ($subnet->getOrganizationalUnits() as $organizationalUnit) {
$this->organizationalUnits[] = new OrganizationalUnitOutput($organizationalUnit);
}
}
}
public function createOrUpdateEntity(?Subnet $subnet = null): Subnet
{
if (!$subnet) {
$subnet = new Subnet();
}
$subnet->setName($this->name);
$subnet->setNetmask($this->netmask);
$subnet->setIpAddress($this->ipAddress);
$subnet->setNextServer($this->nextServer);
$subnet->setBootFileName($this->bootFileName);
foreach ($this->organizationalUnits as $organizationalUnit) {
$organizationalUnitToAdd[] = $organizationalUnit->getEntity();
}
$subnet->setOrganizationalUnits($organizationalUnitToAdd ?? [] );
return $subnet;
}
}

View File

@ -9,6 +9,12 @@ use Symfony\Component\Serializer\Annotation\Groups;
#[Get(shortName: 'NetworkSettings')]
final class NetworkSettingsOutput extends AbstractOutput
{
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
public ?string $nextServer = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
public ?string $bootFileName = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
public ?string $proxy = null;
@ -61,6 +67,8 @@ final class NetworkSettingsOutput extends AbstractOutput
{
parent::__construct($networkSettings);
$this->nextServer = $networkSettings->getNextServer();
$this->bootFileName = $networkSettings->getBootFileName();
$this->proxy = $networkSettings->getProxy();
$this->dns = $networkSettings->getDns();
$this->netmask = $networkSettings->getNetmask();

View File

@ -0,0 +1,34 @@
<?php
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\OgLive;
use Symfony\Component\Serializer\Annotation\Groups;
#[Get(shortName: 'OgLive')]
final class OgLiveOutput extends AbstractOutput
{
#[Groups(['og-live:read'])]
public string $name;
#[Groups(['og-live:read'])]
public ?string $downloadUrl = '';
#[Groups(['og-live:read'])]
public \DateTime $createdAt;
#[Groups(['og-live:read'])]
public ?string $createdBy = null;
public function __construct(OgLive $ogLive)
{
parent::__construct($ogLive);
$this->name = $ogLive->getName();
$this->downloadUrl = $ogLive->getDownloadUrl();
$this->createdAt = $ogLive->getCreatedAt();
$this->createdBy = $ogLive->getCreatedBy();
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\Client;
use App\Entity\PxeBootFile;
use Symfony\Component\Serializer\Annotation\Groups;
#[Get(shortName: 'PxeBootFile')]
final class PxeBootFileOutput extends AbstractOutput
{
#[Groups(['pxe-boot-file:read'])]
public PxeTemplateOutput $template;
#[Groups(['pxe-boot-file:read'])]
public array $clients;
#[Groups(['pxe-boot-file:read'])]
public \DateTime $createdAt;
#[Groups(['pxe-boot-file:read'])]
public ?string $createdBy = null;
public function __construct(PxeBootFile $bootFile)
{
parent::__construct($bootFile);
$this->template = new PxeTemplateOutput($bootFile->getTemplate());
$this->clients = $bootFile->getClients()->map(
fn(Client $client) => new ClientOutput($client)
)->toArray();
$this->createdAt = $bootFile->getCreatedAt();
$this->createdBy = $bootFile->getCreatedBy();
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\PxeTemplate;
use Symfony\Component\Serializer\Annotation\Groups;
#[Get(shortName: 'PxeTemplate')]
final class PxeTemplateOutput extends AbstractOutput
{
#[Groups(['pxe-template:read'])]
public string $name;
#[Groups(['pxe-template:read'])]
public ?string $templateContent = '';
#[Groups(['pxe-template:read'])]
public \DateTime $createdAt;
#[Groups(['pxe-template:read'])]
public ?string $createdBy = null;
public function __construct(PxeTemplate $pxeTemplate)
{
parent::__construct($pxeTemplate);
$this->name = $pxeTemplate->getName();
$this->templateContent = $pxeTemplate->getTemplateContent();
$this->createdAt = $pxeTemplate->getCreatedAt();
$this->createdBy = $pxeTemplate->getCreatedBy();
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace App\Dto\Output;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Get;
use App\Entity\OrganizationalUnit;
use App\Entity\Subnet;
use Symfony\Component\Serializer\Annotation\Groups;
#[Get(shortName: 'Subnet')]
final class SubnetOutput extends AbstractOutput
{
#[Groups(['subnet:read'])]
public string $name;
#[Groups(['subnet:read'])]
public string $netmask;
#[Groups(['subnet:read'])]
public string $ipAddress;
#[Groups(['subnet:read'])]
public string $nextServer;
#[Groups(['subnet:read'])]
public string $bootFileName;
#[Groups(['subnet:read'])]
public array $organizationalUnits;
#[Groups(['subnet:read'])]
public \DateTime $createdAt;
#[Groups(['subnet:read'])]
public ?string $createdBy = null;
public function __construct(Subnet $subnet)
{
parent::__construct($subnet);
$this->name = $subnet->getName();
$this->netmask = $subnet->getNetmask();
$this->ipAddress = $subnet->getIpAddress();
$this->nextServer = $subnet->getNextServer();
$this->bootFileName = $subnet->getBootFileName();
$this->organizationalUnits = $subnet->getOrganizationalUnits()->map(
fn(OrganizationalUnit $organizationalUnit) => new OrganizationalUnitOutput($organizationalUnit)
)->toArray();
$this->createdAt = $subnet->getCreatedAt();
$this->createdBy = $subnet->getCreatedBy();
}
}

View File

@ -57,6 +57,15 @@ class Client extends AbstractEntity
#[ORM\Column(nullable: true)]
private ?array $position = ['x' => 0, 'y' => 0];
#[ORM\ManyToOne(inversedBy: 'clients')]
private ?PxeBootFile $pxeBootFile = null;
#[ORM\ManyToOne(inversedBy: 'clients')]
private ?OgRepository $repository = null;
#[ORM\ManyToOne(inversedBy: 'clients')]
private ?Subnet $subnet = null;
public function __construct()
{
parent::__construct();
@ -224,4 +233,40 @@ class Client extends AbstractEntity
return $this;
}
public function getPxeBootFile(): ?PxeBootFile
{
return $this->pxeBootFile;
}
public function setPxeBootFile(?PxeBootFile $pxeBootFile): static
{
$this->pxeBootFile = $pxeBootFile;
return $this;
}
public function getRepository(): ?OgRepository
{
return $this->repository;
}
public function setRepository(?OgRepository $repository): static
{
$this->repository = $repository;
return $this;
}
public function getSubnet(): ?Subnet
{
return $this->subnet;
}
public function setSubnet(?Subnet $subnet): static
{
$this->subnet = $subnet;
return $this;
}
}

View File

@ -10,6 +10,12 @@ use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: NetworkSettingsRepository::class)]
class NetworkSettings extends AbstractEntity
{
#[ORM\Column(length: 255, nullable: true)]
private ?string $nextServer = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $bootFileName = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $proxy = null;
@ -60,15 +66,35 @@ class NetworkSettings extends AbstractEntity
#[ORM\Column(nullable: true)]
private ?bool $validation = null;
#[ORM\ManyToOne]
private ?OgRepository $repository = null;
public function __construct()
{
parent::__construct();
$this->organizationalUnits = new ArrayCollection();
}
public function getId(): ?int
public function getNextServer(): ?string
{
return $this->id;
return $this->nextServer;
}
public function setNextServer(?string $nextServer): void
{
$this->nextServer = $nextServer;
}
public function getBootFileName(): ?string
{
return $this->bootFileName;
}
public function setBootFileName(?string $bootFileName): static
{
$this->bootFileName = $bootFileName;
return $this;
}
public function getProxy(): ?string
@ -268,4 +294,16 @@ class NetworkSettings extends AbstractEntity
return $this;
}
public function getRepository(): ?OgRepository
{
return $this->repository;
}
public function setRepository(?OgRepository $repository): static
{
$this->repository = $repository;
return $this;
}
}

View File

@ -0,0 +1,150 @@
<?php
namespace App\Entity;
use App\Repository\OgLiveRepository;
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')]
class OgLive extends AbstractEntity
{
use NameableTrait;
#[ORM\Column(length: 255, nullable: true)]
private ?string $downloadUrl = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $checksum = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $distribution = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $kernel = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $architecture = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $revision = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $directory = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $filename = null;
#[ORM\Column(nullable: true)]
private ?bool $installed = null;
public function getDownloadUrl(): ?string
{
return $this->downloadUrl;
}
public function setDownloadUrl(?string $downloadUrl): static
{
$this->downloadUrl = $downloadUrl;
return $this;
}
public function getChecksum(): ?string
{
return $this->checksum;
}
public function setChecksum(?string $checksum): static
{
$this->checksum = $checksum;
return $this;
}
public function getDistribution(): ?string
{
return $this->distribution;
}
public function setDistribution(?string $distribution): static
{
$this->distribution = $distribution;
return $this;
}
public function getKernel(): ?string
{
return $this->kernel;
}
public function setKernel(?string $kernel): static
{
$this->kernel = $kernel;
return $this;
}
public function getArchitecture(): ?string
{
return $this->architecture;
}
public function setArchitecture(?string $architecture): static
{
$this->architecture = $architecture;
return $this;
}
public function getRevision(): ?string
{
return $this->revision;
}
public function setRevision(?string $revision): static
{
$this->revision = $revision;
return $this;
}
public function getDirectory(): ?string
{
return $this->directory;
}
public function setDirectory(?string $directory): static
{
$this->directory = $directory;
return $this;
}
public function getFilename(): ?string
{
return $this->filename;
}
public function setFilename(?string $filename): static
{
$this->filename = $filename;
return $this;
}
public function isInstalled(): ?bool
{
return $this->installed;
}
public function setInstalled(?bool $installed): static
{
$this->installed = $installed;
return $this;
}
}

View File

@ -0,0 +1,86 @@
<?php
namespace App\Entity;
use App\Repository\OgRepositoryRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: OgRepositoryRepository::class)]
class OgRepository extends AbstractEntity
{
use NameableTrait;
#[ORM\Column(length: 255)]
private ?string $ipAddress = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $description = null;
/**
* @var Collection<int, Client>
*/
#[ORM\OneToMany(mappedBy: 'repository', targetEntity: Client::class)]
private Collection $clients;
public function __construct()
{
parent::__construct();
$this->clients = new ArrayCollection();
}
public function getIpAddress(): ?string
{
return $this->ipAddress;
}
public function setIpAddress(string $ipAddress): static
{
$this->ipAddress = $ipAddress;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): static
{
$this->description = $description;
return $this;
}
/**
* @return Collection<int, Client>
*/
public function getClients(): Collection
{
return $this->clients;
}
public function addClient(Client $client): static
{
if (!$this->clients->contains($client)) {
$this->clients->add($client);
$client->setRepository($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->getRepository() === $this) {
$client->setRepository(null);
}
}
return $this;
}
}

View File

@ -84,6 +84,9 @@ class OrganizationalUnit extends AbstractEntity
#[ORM\OneToMany(mappedBy: 'organizationalUnit', targetEntity: SoftwareProfile::class)]
private Collection $softwareProfiles;
#[ORM\ManyToOne(inversedBy: 'organizationalUnits')]
private ?Subnet $subnet = null;
public function __construct()
{
parent::__construct();
@ -368,4 +371,16 @@ class OrganizationalUnit extends AbstractEntity
return $this;
}
public function getSubnet(): ?Subnet
{
return $this->subnet;
}
public function setSubnet(?Subnet $subnet): static
{
$this->subnet = $subnet;
return $this;
}
}

View File

@ -0,0 +1,80 @@
<?php
namespace App\Entity;
use App\Repository\PxeBootFileRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: PxeBootFileRepository::class)]
class PxeBootFile extends AbstractEntity
{
#[ORM\ManyToOne]
private ?PxeTemplate $template = null;
/**
* @var Collection<int, Client>
*/
#[ORM\OneToMany(mappedBy: 'pxeBootFile', targetEntity: Client::class)]
private Collection $clients;
public function __construct()
{
parent::__construct();
$this->clients = new ArrayCollection();
}
public function getTemplate(): ?PxeTemplate
{
return $this->template;
}
public function setTemplate(?PxeTemplate $template): static
{
$this->template = $template;
return $this;
}
/**
* @return Collection<int, Client>
*/
public function getClients(): Collection
{
return $this->clients;
}
public function addClient(Client $client): static
{
if (!$this->clients->contains($client)) {
$this->clients->add($client);
$client->setPxeBootFile($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->getPxeBootFile() === $this) {
$client->setPxeBootFile(null);
}
}
return $this;
}
public function setClients(array $clients): static
{
$this->clients->clear();
foreach ($clients as $client){
$this->addClient($client);
}
return $this;
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Entity;
use App\Repository\PxeTemplateRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
#[ORM\Entity(repositoryClass: PxeTemplateRepository::class)]
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_NAME', fields: ['name'])]
#[UniqueEntity(fields: ['name'], message: 'validators.pxe_template.name.unique')]
class PxeTemplate extends AbstractEntity
{
use NameableTrait;
#[ORM\Column(length: 255)]
private ?string $templateContent = null;
public function getTemplateContent(): ?string
{
return $this->templateContent;
}
public function setTemplateContent(string $templateContent): static
{
$this->templateContent = $templateContent;
return $this;
}
}

View File

@ -0,0 +1,175 @@
<?php
namespace App\Entity;
use App\Repository\SubnetRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: SubnetRepository::class)]
class Subnet extends AbstractEntity
{
use NameableTrait;
#[ORM\Column(length: 255)]
private ?string $netmask = null;
#[ORM\Column(length: 255)]
private ?string $ipAddress = null;
#[ORM\Column(length: 255)]
private ?string $nextServer = null;
#[ORM\Column(length: 255)]
private ?string $bootFileName = null;
/**
* @var Collection<int, OrganizationalUnit>
*/
#[ORM\OneToMany(mappedBy: 'subnet', targetEntity: OrganizationalUnit::class)]
private Collection $organizationalUnits;
/**
* @var Collection<int, Client>
*/
#[ORM\OneToMany(mappedBy: 'subnet', targetEntity: Client::class)]
private Collection $clients;
public function __construct()
{
parent::__construct();
$this->organizationalUnits = new ArrayCollection();
$this->clients = new ArrayCollection();
}
public function getNetmask(): ?string
{
return $this->netmask;
}
public function setNetmask(string $netmask): static
{
$this->netmask = $netmask;
return $this;
}
public function getIpAddress(): ?string
{
return $this->ipAddress;
}
public function setIpAddress(string $ipAddress): static
{
$this->ipAddress = $ipAddress;
return $this;
}
public function getNextServer(): ?string
{
return $this->nextServer;
}
public function setNextServer(string $nextServer): static
{
$this->nextServer = $nextServer;
return $this;
}
public function getBootFileName(): ?string
{
return $this->bootFileName;
}
public function setBootFileName(string $bootFileName): static
{
$this->bootFileName = $bootFileName;
return $this;
}
/**
* @return Collection<int, OrganizationalUnit>
*/
public function getOrganizationalUnits(): Collection
{
return $this->organizationalUnits;
}
public function setOrganizationalUnits(array $organizationalUnits): static
{
$this->organizationalUnits->clear();
foreach ($organizationalUnits as $organizationalUnit){
$this->addOrganizationalUnit($organizationalUnit);
}
return $this;
}
public function addOrganizationalUnit(OrganizationalUnit $organizationalUnit): static
{
if (!$this->organizationalUnits->contains($organizationalUnit)) {
$this->organizationalUnits->add($organizationalUnit);
$organizationalUnit->setSubnet($this);
}
return $this;
}
public function removeOrganizationalUnit(OrganizationalUnit $organizationalUnit): static
{
if ($this->organizationalUnits->removeElement($organizationalUnit)) {
// set the owning side to null (unless already changed)
if ($organizationalUnit->getSubnet() === $this) {
$organizationalUnit->setSubnet(null);
}
}
return $this;
}
/**
* @return Collection<int, Client>
*/
public function getClients(): Collection
{
return $this->clients;
}
public function setClients(array $clients): static
{
$this->clients->clear();
foreach ($clients as $client){
$this->addClient($client);
}
return $this;
}
public function addClient(Client $client): static
{
if (!$this->clients->contains($client)) {
$this->clients->add($client);
$client->setSubnet($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->getSubnet() === $this) {
$client->setSubnet(null);
}
}
return $this;
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace App\Factory;
use App\Entity\OgLive;
use App\Repository\OgLiveRepository;
use Zenstruck\Foundry\ModelFactory;
use Zenstruck\Foundry\Persistence\PersistentProxyObjectFactory;
use Zenstruck\Foundry\Persistence\Proxy;
use Zenstruck\Foundry\Persistence\ProxyRepositoryDecorator;
/**
* @extends PersistentProxyObjectFactory<OgLive>
*/
final class OgLiveFactory 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(),
'name' => self::faker()->text(255),
'downloadUrl' => 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(OgLive $ogLive): void {})
;
}
protected static function getClass(): string
{
return OgLive::class;
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace App\Factory;
use App\Entity\PxeTemplate;
use App\Repository\PxeTemplateRepository;
use Zenstruck\Foundry\ModelFactory;
use Zenstruck\Foundry\Persistence\PersistentProxyObjectFactory;
use Zenstruck\Foundry\Persistence\Proxy;
use Zenstruck\Foundry\Persistence\ProxyRepositoryDecorator;
/**
* @extends PersistentProxyObjectFactory<PxeTemplate>
*/
final class PxeTemplateFactory 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(),
'name' => self::faker()->text(255),
'templateContent' => 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(PxeTemplate $pxeTemplate): void {})
;
}
protected static function getClass(): string
{
return PxeTemplate::class;
}
}

View File

@ -0,0 +1,58 @@
<?php
namespace App\Factory;
use App\Entity\Subnet;
use App\Repository\SubnetRepository;
use Zenstruck\Foundry\ModelFactory;
use Zenstruck\Foundry\Persistence\PersistentProxyObjectFactory;
use Zenstruck\Foundry\Persistence\Proxy;
use Zenstruck\Foundry\Persistence\ProxyRepositoryDecorator;
/**
* @extends PersistentProxyObjectFactory<Subnet>
*/
final class SubnetFactory 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 [
'bootFileName' => self::faker()->text(255),
'createdAt' => self::faker()->dateTime(),
'ipAddress' => self::faker()->text(255),
'netmask' => self::faker()->text(255),
'nextServer' => 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(Subnet $subnet): void {})
;
}
protected static function getClass(): string
{
return Subnet::class;
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Repository;
use App\Entity\OgLive;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<OgLive>
*/
class OgLiveRepository extends AbstractRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, OgLive::class);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Repository;
use App\Entity\OgRepository;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<OgRepositoryRepository>
*/
class OgRepositoryRepository extends AbstractRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, self::class);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Repository;
use App\Entity\PxeBootFile;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<PxeBootFile>
*/
class PxeBootFileRepository extends AbstractRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, PxeBootFile::class);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Repository;
use App\Entity\PxeTemplate;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<PxeTemplate>
*/
class PxeTemplateRepository extends AbstractRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, PxeTemplate::class);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Repository;
use App\Entity\Subnet;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Subnet>
*/
class SubnetRepository extends AbstractRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Subnet::class);
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace App\Service\OgBoot;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
readonly class ConfigService
{
public function __construct(
private string $ogBootApiUrl
)
{
}
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke()
{
$httpClient = HttpClient::create([
'verify_peer' => false, // Ignorar la verificación del certificado SSL
'verify_host' => false, // Ignorar la verificación del nombre del host
]);
try {
$response = $httpClient->request('GET', $this->ogBootApiUrl.'/ogboot/v1/config', [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
return json_decode($response->getContent(), true);
}
}

View File

@ -0,0 +1,70 @@
<?php
namespace App\Service\OgBoot\PxeBootFile;
use App\Entity\PxeBootFile;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
readonly class PostService
{
public function __construct(
private string $ogBootApiUrl
)
{
}
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(PxeBootFile $bootFile)
{
$httpClient = HttpClient::create([
'verify_peer' => false, // Ignorar la verificación del certificado SSL
'verify_host' => false, // Ignorar la verificación del nombre del host
]);
foreach ($bootFile->getClients() as $client) {
$data = [
'template_name' => $bootFile->getTemplate()->getName(),
'mac' => $client->getMac(),
'ip' => $client->getIp(),
'server_ip' => '',
'router' => $client->getOrganizationalUnit()->getNetworkSettings()->getRouter(),
'netmask' => $client->getOrganizationalUnit()->getNetworkSettings()->getNetmask(),
'computer_name' => $client->getName(),
'netiface' => $client->getNetiface(),
'group' => $client->getOrganizationalUnit()->getName(),
'ogrepo' => $client->getRepository() ? $client->getRepository()->getIpAddress() : $client->getOrganizationalUnit()->getNetworkSettings()->getRepository()->getIpAddress(),
'oglive' => '',
'ogdns' => $client->getOrganizationalUnit()->getNetworkSettings()->getDns(),
'ogProxy' => $client->getOrganizationalUnit()->getNetworkSettings()->getProxy(),
'ogunit' => ''
];
try {
$response = $httpClient->request('POST', $this->ogBootApiUrl.'/ogboot/v1/pxes', [
'headers' => [
'accept' => 'application/json',
],
'json' => $data
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
return json_decode($response->getContent(), true);
}
return 1;
}
}

View File

@ -0,0 +1,48 @@
<?php
namespace App\Service\OgBoot;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Component\HttpClient\HttpClient;
readonly class StatusService
{
public function __construct(
private string $ogBootApiUrl
)
{
}
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke()
{
$httpClient = HttpClient::create([
'verify_peer' => false, // Ignorar la verificación del certificado SSL
'verify_host' => false, // Ignorar la verificación del nombre del host
]);
try {
$response = $httpClient->request('GET', $this->ogBootApiUrl.'/ogboot/v1/status', [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
return json_decode($response->getContent(), true);
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace App\State\Processor;
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\OgLiveInput;
use App\Dto\Output\OgLiveOutput;
use App\Repository\OgLiveRepository;
readonly class OgLiveProcessor implements ProcessorInterface
{
public function __construct(
private OgLiveRepository $ogLiveRepository,
private ValidatorInterface $validator
)
{
}
/**
* @throws \Exception
*/
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): OgLiveOutput|null
{
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 = []): OgLiveOutput
{
if (!($data instanceof OgLiveInput)) {
throw new \Exception(sprintf('data is not instance of %s', OgLiveInput::class));
}
$entity = null;
if (isset($uriVariables['uuid'])) {
$entity = $this->ogLiveRepository->findOneByUuid($uriVariables['uuid']);
}
$ogLive = $data->createOrUpdateEntity($entity);
$this->validator->validate($ogLive);
$this->ogLiveRepository->save($ogLive);
return new OgLiveOutput($ogLive);
}
private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null
{
$ogLive = $this->ogLiveRepository->findOneByUuid($uriVariables['uuid']);
$this->ogLiveRepository->delete($ogLive);
return null;
}
}

View File

@ -0,0 +1,72 @@
<?php
namespace App\State\Processor;
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\PxeBootFileInput;
use App\Dto\Output\PxeBootFileOutput;
use App\Repository\PxeBootFileRepository;
use App\Service\OgBoot\PxeBootFile\PostService;
readonly class PxeBootFileProcessor implements ProcessorInterface
{
public function __construct(
private PxeBootFileRepository $bootFileRepository,
private ValidatorInterface $validator,
private PostService $postService
)
{
}
/**
* @throws \Exception
*/
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): PxeBootFileOutput|null
{
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 = []): PxeBootFileOutput
{
if (!($data instanceof PxeBootFileInput)) {
throw new \Exception(sprintf('data is not instance of %s', PxeBootFileInput::class));
}
$entity = null;
if (isset($uriVariables['uuid'])) {
$entity = $this->bootFileRepository->findOneByUuid($uriVariables['uuid']);
}
$pxeTemplate = $data->createOrUpdateEntity($entity);
$this->validator->validate($pxeTemplate);
$this->bootFileRepository->save($pxeTemplate);
$this->postService->__invoke($pxeTemplate);
return new PxeBootFileOutput($pxeTemplate);
}
private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null
{
$bootFile = $this->bootFileRepository->findOneByUuid($uriVariables['uuid']);
$this->bootFileRepository->delete($bootFile);
return null;
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace App\State\Processor;
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\PxeTemplateInput;
use App\Dto\Output\PxeTemplateOutput;
use App\Repository\PxeTemplateRepository;
readonly class PxeTemplateProcessor implements ProcessorInterface
{
public function __construct(
private PxeTemplateRepository $pxeTemplateRepository,
private ValidatorInterface $validator
)
{
}
/**
* @throws \Exception
*/
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): PxeTemplateOutput|null
{
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 = []): PxeTemplateOutput
{
if (!($data instanceof PxeTemplateInput)) {
throw new \Exception(sprintf('data is not instance of %s', PxeTemplateInput::class));
}
$entity = null;
if (isset($uriVariables['uuid'])) {
$entity = $this->pxeTemplateRepository->findOneByUuid($uriVariables['uuid']);
}
$pxeTemplate = $data->createOrUpdateEntity($entity);
$this->validator->validate($pxeTemplate);
$this->pxeTemplateRepository->save($pxeTemplate);
return new PxeTemplateOutput($pxeTemplate);
}
private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null
{
$pxeTemplate = $this->pxeTemplateRepository->findOneByUuid($uriVariables['uuid']);
$this->pxeTemplateRepository->delete($pxeTemplate);
return null;
}
}

View File

@ -0,0 +1,69 @@
<?php
namespace App\State\Processor;
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\SubnetInput;
use App\Dto\Output\SubnetOutput;
use App\Repository\SubnetRepository;
use App\Service\OgBoot\PxeBootFile\PostService;
readonly class SubnetProcessor implements ProcessorInterface
{
public function __construct(
private SubnetRepository $subnetRepository,
private ValidatorInterface $validator
)
{
}
/**
* @throws \Exception
*/
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): SubnetOutput|null
{
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 = []): SubnetOutput
{
if (!($data instanceof SubnetInput)) {
throw new \Exception(sprintf('data is not instance of %s', SubnetInput::class));
}
$entity = null;
if (isset($uriVariables['uuid'])) {
$entity = $this->subnetRepository->findOneByUuid($uriVariables['uuid']);
}
$subnet = $data->createOrUpdateEntity($entity);
$this->validator->validate($subnet);
$this->subnetRepository->save($subnet);
return new SubnetOutput($subnet);
}
private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null
{
$bootFile = $this->subnetRepository->findOneByUuid($uriVariables['uuid']);
$this->subnetRepository->delete($bootFile);
return null;
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace App\State\Provider;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Put;
use ApiPlatform\State\Pagination\TraversablePaginator;
use ApiPlatform\State\ProviderInterface;
use App\Dto\Input\OgLiveInput;
use App\Dto\Output\OgLiveOutput;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
readonly class OgLiveProvider implements ProviderInterface
{
public function __construct(
private ProviderInterface $collectionProvider,
private ProviderInterface $itemProvider
)
{
}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
{
switch ($operation){
case $operation instanceof GetCollection:
return $this->provideCollection($operation, $uriVariables, $context);
case $operation instanceof 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 OgLiveOutput($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('OgLive not found');
}
return new OgLiveOutput($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 OgLiveInput($item) : null;
}
return new OgLiveInput();
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace App\State\Provider;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Put;
use ApiPlatform\State\Pagination\TraversablePaginator;
use ApiPlatform\State\ProviderInterface;
use App\Dto\Input\PxeBootFileInput;
use App\Dto\Output\PxeBootFileOutput;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
readonly class PxeBootFileProvider implements ProviderInterface
{
public function __construct(
private ProviderInterface $collectionProvider,
private ProviderInterface $itemProvider
)
{
}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
{
switch ($operation){
case $operation instanceof GetCollection:
return $this->provideCollection($operation, $uriVariables, $context);
case $operation instanceof 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 PxeBootFileOutput($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('PxeBootFile not found');
}
return new PxeBootFileOutput($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 PxeBootFileInput($item) : null;
}
return new PxeBootFileInput();
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace App\State\Provider;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Put;
use ApiPlatform\State\Pagination\TraversablePaginator;
use ApiPlatform\State\ProviderInterface;
use App\Dto\Input\PxeTemplateInput;
use App\Dto\Output\PxeTemplateOutput;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
readonly class PxeTemplateProvider implements ProviderInterface
{
public function __construct(
private ProviderInterface $collectionProvider,
private ProviderInterface $itemProvider
)
{
}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
{
switch ($operation){
case $operation instanceof GetCollection:
return $this->provideCollection($operation, $uriVariables, $context);
case $operation instanceof 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 PxeTemplateOutput($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('PxeTemplate not found');
}
return new PxeTemplateOutput($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 PxeTemplateInput($item) : null;
}
return new PxeTemplateInput();
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace App\State\Provider;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Put;
use ApiPlatform\State\Pagination\TraversablePaginator;
use ApiPlatform\State\ProviderInterface;
use App\Dto\Input\SubnetInput;
use App\Dto\Output\SubnetOutput;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
readonly class SubnetProvider implements ProviderInterface
{
public function __construct(
private ProviderInterface $collectionProvider,
private ProviderInterface $itemProvider
)
{
}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
{
switch ($operation){
case $operation instanceof GetCollection:
return $this->provideCollection($operation, $uriVariables, $context);
case $operation instanceof 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 SubnetOutput($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('Subnet not found');
}
return new SubnetOutput($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 SubnetInput($item) : null;
}
return new SubnetInput();
}
}

View File

@ -0,0 +1,124 @@
<?php
namespace Functional;
use App\Entity\Client;
use App\Entity\HardwareProfile;
use App\Entity\OgLive;
use App\Entity\User;
use App\Factory\HardwareProfileFactory;
use App\Factory\OgLiveFactory;
use App\Factory\UserFactory;
use App\Model\UserGroupPermissions;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
class OgLiveTest extends AbstractTest
{
CONST string USER_ADMIN = 'ogadmin';
CONST string OGLIVE_CREATE = 'test-oglive-create';
CONST string OGLIVE_UPDATE = 'test-oglive-update';
CONST string OGLIVE_DELETE = 'test-oglive-delete';
/**
* @throws RedirectionExceptionInterface
* @throws DecodingExceptionInterface
* @throws ClientExceptionInterface
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
*/
public function testGetCollectionOgLives(): void
{
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
OgLiveFactory::createMany(10);
$this->createClientWithCredentials()->request('GET', '/og-lives');
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains([
'@context' => '/contexts/OgLive',
'@id' => '/og-lives',
'@type' => 'hydra:Collection',
'hydra:totalItems' => 10,
]);
}
/**
* @throws RedirectionExceptionInterface
* @throws DecodingExceptionInterface
* @throws ClientExceptionInterface
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
*/
public function testCreateOgLive(): void
{
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'
]]);
$this->assertResponseStatusCodeSame(201);
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains([
'@context' => '/contexts/OgLiveOutput',
'@type' => 'OgLive',
'name' => self::OGLIVE_CREATE,
'downloadUrl' => 'http://example.com'
]);
}
/**
* @throws RedirectionExceptionInterface
* @throws DecodingExceptionInterface
* @throws ClientExceptionInterface
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
*/
public function testUpdateOgLive(): void
{
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]);
$this->createClientWithCredentials()->request('PUT', $iri, ['json' => [
'name' => self::OGLIVE_UPDATE,
'downloadUrl' => 'http://example-2.com',
]]);
$this->assertResponseIsSuccessful();
$this->assertJsonContains([
'@id' => $iri,
'name' => self::OGLIVE_UPDATE,
'downloadUrl' => 'http://example-2.com',
]);
}
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws DecodingExceptionInterface
* @throws ClientExceptionInterface
*/
public function testDeleteOgLive(): void
{
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]);
$this->createClientWithCredentials()->request('DELETE', $iri);
$this->assertResponseStatusCodeSame(204);
$this->assertNull(
static::getContainer()->get('doctrine')->getRepository(OgLive::class)->findOneBy(['name' => self::OGLIVE_CREATE])
);
}
}

View File

@ -0,0 +1,122 @@
<?php
namespace Functional;
use App\Entity\Client;
use App\Entity\PxeTemplate;
use App\Entity\User;
use App\Factory\PxeTemplateFactory;
use App\Factory\UserFactory;
use App\Model\UserGroupPermissions;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
class PxeTemplateTest extends AbstractTest
{
CONST string USER_ADMIN = 'ogadmin';
CONST string PXE_TEMPLATE_CREATE = 'test-pxetemplate-create';
CONST string PXE_TEMPLATE_UPDATE = 'test-pxetemplate-update';
CONST string PXE_TEMPLATE_DELETE = 'test-pxetemplate-delete';
/**
* @throws RedirectionExceptionInterface
* @throws DecodingExceptionInterface
* @throws ClientExceptionInterface
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
*/
public function testGetCollectionPxeTemplates(): void
{
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
PxeTemplateFactory::createMany(10);
$this->createClientWithCredentials()->request('GET', '/pxe-templates');
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains([
'@context' => '/contexts/PxeTemplate',
'@id' => '/pxe-templates',
'@type' => 'hydra:Collection',
'hydra:totalItems' => 10,
]);
}
/**
* @throws RedirectionExceptionInterface
* @throws DecodingExceptionInterface
* @throws ClientExceptionInterface
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
*/
public function testCreatePxeTemplate(): void
{
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
$this->createClientWithCredentials()->request('POST', '/pxe-templates',['json' => [
'name' => self::PXE_TEMPLATE_CREATE,
'templateContent' => 'content'
]]);
$this->assertResponseStatusCodeSame(201);
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains([
'@context' => '/contexts/PxeTemplateOutput',
'@type' => 'PxeTemplate',
'name' => self::PXE_TEMPLATE_CREATE,
'templateContent' => 'content'
]);
}
/**
* @throws RedirectionExceptionInterface
* @throws DecodingExceptionInterface
* @throws ClientExceptionInterface
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
*/
public function testUpdatePxeTemplate(): void
{
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
PxeTemplateFactory::createOne(['name' => self::PXE_TEMPLATE_CREATE, 'templateContent' => 'content']);
$iri = $this->findIriBy(PxeTemplate::class, ['name' => self::PXE_TEMPLATE_CREATE]);
$this->createClientWithCredentials()->request('PUT', $iri, ['json' => [
'name' => self::PXE_TEMPLATE_UPDATE,
'templateContent' => 'updated-content',
]]);
$this->assertResponseIsSuccessful();
$this->assertJsonContains([
'@id' => $iri,
'name' => self::PXE_TEMPLATE_UPDATE,
'templateContent' => 'updated-content',
]);
}
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws DecodingExceptionInterface
* @throws ClientExceptionInterface
*/
public function testDeletePxeTemplate(): void
{
UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]);
PxeTemplateFactory::createOne(['name' => self::PXE_TEMPLATE_DELETE, 'templateContent' => 'content']);
$iri = $this->findIriBy(PxeTemplate::class, ['name' => self::PXE_TEMPLATE_DELETE]);
$this->createClientWithCredentials()->request('DELETE', $iri);
$this->assertResponseStatusCodeSame(204);
$this->assertNull(
static::getContainer()->get('doctrine')->getRepository(PxeTemplate::class)->findOneBy(['name' => self::PXE_TEMPLATE_DELETE])
);
}
}

View File

@ -36,4 +36,9 @@ validators:
operative_system:
name:
not_blank: 'The name should not be blank.'
not_blank: 'The name should not be blank.'
og_live:
name:
not_blank: 'The name should not be blank.'
unique: 'The name should be unique.'