diff --git a/composer.json b/composer.json index a96e951..3312f07 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ "doctrine/dbal": "^3", "doctrine/doctrine-bundle": "^2.12", "doctrine/doctrine-migrations-bundle": "^3.3", - "doctrine/orm": "^3.1", + "doctrine/orm": "^2.19.5", "gesdinet/jwt-refresh-token-bundle": "^1.3", "lexik/jwt-authentication-bundle": "^3.0", "nelmio/cors-bundle": "^2.4", diff --git a/composer.lock b/composer.lock index e4e592c..ef16494 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "8a178ee08c8bef147097b85e84af9dd7", + "content-hash": "a03ea4d76774164d557cb2ecb327de33", "packages": [ { "name": "api-platform/core", @@ -303,82 +303,6 @@ ], "time": "2023-11-29T23:19:16+00:00" }, - { - "name": "doctrine/annotations", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f", - "reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f", - "shasum": "" - }, - "require": { - "doctrine/lexer": "^2 || ^3", - "ext-tokenizer": "*", - "php": "^7.2 || ^8.0", - "psr/cache": "^1 || ^2 || ^3" - }, - "require-dev": { - "doctrine/cache": "^2.0", - "doctrine/coding-standard": "^10", - "phpstan/phpstan": "^1.8.0", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "symfony/cache": "^5.4 || ^6", - "vimeo/psalm": "^4.10" - }, - "suggest": { - "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Docblock Annotations Parser", - "homepage": "https://www.doctrine-project.org/projects/annotations.html", - "keywords": [ - "annotations", - "docblock", - "parser" - ], - "support": { - "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/2.0.1" - }, - "time": "2023-02-02T22:02:53+00:00" - }, { "name": "doctrine/cache", "version": "2.2.0", @@ -1023,16 +947,16 @@ }, { "name": "doctrine/event-manager", - "version": "2.0.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/doctrine/event-manager.git", - "reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32" + "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/750671534e0241a7c50ea5b43f67e23eb5c96f32", - "reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/b680156fa328f1dfd874fd48c7026c41570b9c6e", + "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e", "shasum": "" }, "require": { @@ -1042,10 +966,10 @@ "doctrine/common": "<2.9" }, "require-dev": { - "doctrine/coding-standard": "^10", + "doctrine/coding-standard": "^12", "phpstan/phpstan": "^1.8.8", - "phpunit/phpunit": "^9.5", - "vimeo/psalm": "^4.28" + "phpunit/phpunit": "^10.5", + "vimeo/psalm": "^5.24" }, "type": "library", "autoload": { @@ -1094,7 +1018,7 @@ ], "support": { "issues": "https://github.com/doctrine/event-manager/issues", - "source": "https://github.com/doctrine/event-manager/tree/2.0.0" + "source": "https://github.com/doctrine/event-manager/tree/2.0.1" }, "funding": [ { @@ -1110,7 +1034,7 @@ "type": "tidelift" } ], - "time": "2022-10-12T20:59:15+00:00" + "time": "2024-05-22T20:47:39+00:00" }, { "name": "doctrine/inflector", @@ -1454,48 +1378,61 @@ }, { "name": "doctrine/orm", - "version": "3.1.3", + "version": "2.19.5", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "8ca99fdfdca3dc129ed93124e95e7f88b791a354" + "reference": "94986af28452da42a46a4489d1c958a2e5d710e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/8ca99fdfdca3dc129ed93124e95e7f88b791a354", - "reference": "8ca99fdfdca3dc129ed93124e95e7f88b791a354", + "url": "https://api.github.com/repos/doctrine/orm/zipball/94986af28452da42a46a4489d1c958a2e5d710e5", + "reference": "94986af28452da42a46a4489d1c958a2e5d710e5", "shasum": "" }, "require": { "composer-runtime-api": "^2", - "doctrine/collections": "^2.2", - "doctrine/dbal": "^3.8.2 || ^4", + "doctrine/cache": "^1.12.1 || ^2.1.1", + "doctrine/collections": "^1.5 || ^2.1", + "doctrine/common": "^3.0.3", + "doctrine/dbal": "^2.13.1 || ^3.2", "doctrine/deprecations": "^0.5.3 || ^1", "doctrine/event-manager": "^1.2 || ^2", "doctrine/inflector": "^1.4 || ^2.0", "doctrine/instantiator": "^1.3 || ^2", - "doctrine/lexer": "^3", - "doctrine/persistence": "^3.3.1", + "doctrine/lexer": "^2 || ^3", + "doctrine/persistence": "^2.4 || ^3", "ext-ctype": "*", - "php": "^8.1", + "php": "^7.1 || ^8.0", "psr/cache": "^1 || ^2 || ^3", - "symfony/console": "^5.4 || ^6.0 || ^7.0", - "symfony/var-exporter": "^6.3.9 || ^7.0" + "symfony/console": "^4.2 || ^5.0 || ^6.0 || ^7.0", + "symfony/polyfill-php72": "^1.23", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "doctrine/annotations": "<1.13 || >= 3.0" }, "require-dev": { - "doctrine/coding-standard": "^12.0", - "phpbench/phpbench": "^1.0", - "phpstan/phpstan": "1.10.59", - "phpunit/phpunit": "^10.4.0", + "doctrine/annotations": "^1.13 || ^2", + "doctrine/coding-standard": "^9.0.2 || ^12.0", + "phpbench/phpbench": "^0.16.10 || ^1.0", + "phpstan/phpstan": "~1.4.10 || 1.10.59", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6", "psr/log": "^1 || ^2 || ^3", "squizlabs/php_codesniffer": "3.7.2", - "symfony/cache": "^5.4 || ^6.2 || ^7.0", - "vimeo/psalm": "5.22.2" + "symfony/cache": "^4.4 || ^5.4 || ^6.4 || ^7.0", + "symfony/var-exporter": "^4.4 || ^5.4 || ^6.2 || ^7.0", + "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0", + "vimeo/psalm": "4.30.0 || 5.22.2" }, "suggest": { "ext-dom": "Provides support for XSD validation for XML mapping files", - "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0" + "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0", + "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" }, + "bin": [ + "bin/doctrine" + ], "type": "library", "autoload": { "psr-4": { @@ -1536,9 +1473,9 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/3.1.3" + "source": "https://github.com/doctrine/orm/tree/2.19.5" }, - "time": "2024-04-30T07:14:13+00:00" + "time": "2024-04-30T06:49:54+00:00" }, { "name": "doctrine/persistence", @@ -1695,49 +1632,50 @@ }, { "name": "gedmo/doctrine-extensions", - "version": "v3.14.0", + "version": "v3.15.0", "source": { "type": "git", "url": "https://github.com/doctrine-extensions/DoctrineExtensions.git", - "reference": "3b5b5cba476b4ae32a55ef69ef2e59d64d5893cf" + "reference": "2a89103f4984d8970f3855284c8c04e6e6a63c0f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine-extensions/DoctrineExtensions/zipball/3b5b5cba476b4ae32a55ef69ef2e59d64d5893cf", - "reference": "3b5b5cba476b4ae32a55ef69ef2e59d64d5893cf", + "url": "https://api.github.com/repos/doctrine-extensions/DoctrineExtensions/zipball/2a89103f4984d8970f3855284c8c04e6e6a63c0f", + "reference": "2a89103f4984d8970f3855284c8c04e6e6a63c0f", "shasum": "" }, "require": { "behat/transliterator": "^1.2", - "doctrine/annotations": "^1.13 || ^2.0", "doctrine/collections": "^1.2 || ^2.0", "doctrine/common": "^2.13 || ^3.0", + "doctrine/deprecations": "^1.0", "doctrine/event-manager": "^1.2 || ^2.0", "doctrine/persistence": "^2.2 || ^3.0", "php": "^7.4 || ^8.0", "psr/cache": "^1 || ^2 || ^3", - "symfony/cache": "^5.4 || ^6.0 || ^7.0", - "symfony/deprecation-contracts": "^2.1 || ^3.0" + "psr/clock": "^1", + "symfony/cache": "^5.4 || ^6.0 || ^7.0" }, "conflict": { - "doctrine/dbal": "<3.2", - "doctrine/mongodb-odm": "<2.3", - "doctrine/orm": "<2.14.0 || 2.16.0 || 2.16.1", - "sebastian/comparator": "<2.0" + "doctrine/annotations": "<1.13 || >=3.0", + "doctrine/dbal": "<3.2 || >=4.0", + "doctrine/mongodb-odm": "<2.3 || >=3.0", + "doctrine/orm": "<2.14.0 || 2.16.0 || 2.16.1 || >=3.0" }, "require-dev": { + "doctrine/annotations": "^1.13 || ^2.0", "doctrine/cache": "^1.11 || ^2.0", "doctrine/dbal": "^3.2", "doctrine/doctrine-bundle": "^2.3", "doctrine/mongodb-odm": "^2.3", "doctrine/orm": "^2.14.0", "friendsofphp/php-cs-fixer": "^3.14.0", - "nesbot/carbon": "^2.71 || 3.x-dev as 3.0", + "nesbot/carbon": "^2.71 || ^3.0", "phpstan/phpstan": "^1.10.2", "phpstan/phpstan-doctrine": "^1.0", "phpstan/phpstan-phpunit": "^1.0", "phpunit/phpunit": "^9.6", - "rector/rector": "^0.18", + "rector/rector": "^0.19", "symfony/console": "^5.4 || ^6.0 || ^7.0", "symfony/phpunit-bridge": "^6.0 || ^7.0", "symfony/yaml": "^5.4 || ^6.0 || ^7.0" @@ -1797,7 +1735,7 @@ "support": { "email": "gediminas.morkevicius@gmail.com", "issues": "https://github.com/doctrine-extensions/DoctrineExtensions/issues", - "source": "https://github.com/doctrine-extensions/DoctrineExtensions/tree/v3.14.0", + "source": "https://github.com/doctrine-extensions/DoctrineExtensions/tree/v3.15.0", "wiki": "https://github.com/Atlantic18/DoctrineExtensions/tree/main/doc" }, "funding": [ @@ -1818,7 +1756,7 @@ "type": "github" } ], - "time": "2023-12-03T09:10:34+00:00" + "time": "2024-02-12T15:17:22+00:00" }, { "name": "gesdinet/jwt-refresh-token-bundle", @@ -2269,16 +2207,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.4.0", + "version": "5.4.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "298d2febfe79d03fe714eb871d5538da55205b1a" + "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/298d2febfe79d03fe714eb871d5538da55205b1a", - "reference": "298d2febfe79d03fe714eb871d5538da55205b1a", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", + "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", "shasum": "" }, "require": { @@ -2327,9 +2265,9 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.0" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.1" }, - "time": "2024-04-09T21:13:58+00:00" + "time": "2024-05-21T05:55:05+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -3012,21 +2950,21 @@ }, { "name": "stof/doctrine-extensions-bundle", - "version": "v1.10.1", + "version": "v1.11.0", "source": { "type": "git", "url": "https://github.com/stof/StofDoctrineExtensionsBundle.git", - "reference": "299d5333ce83941069852be36b949abbc776bf1d" + "reference": "9f7023e4c8a1c00a5627d41c1027a3f89e477630" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/stof/StofDoctrineExtensionsBundle/zipball/299d5333ce83941069852be36b949abbc776bf1d", - "reference": "299d5333ce83941069852be36b949abbc776bf1d", + "url": "https://api.github.com/repos/stof/StofDoctrineExtensionsBundle/zipball/9f7023e4c8a1c00a5627d41c1027a3f89e477630", + "reference": "9f7023e4c8a1c00a5627d41c1027a3f89e477630", "shasum": "" }, "require": { - "gedmo/doctrine-extensions": "^3.5.0", - "php": "^7.2.5 || ^8.0", + "gedmo/doctrine-extensions": "^3.15.0", + "php": "^7.4 || ^8.0", "symfony/cache": "^5.4 || ^6.0 || ^7.0", "symfony/config": "^5.4 || ^6.0 || ^7.0", "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", @@ -3034,6 +2972,11 @@ "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0" }, "require-dev": { + "phpstan/phpstan": "^1.10", + "phpstan/phpstan-deprecation-rules": "^1.1", + "phpstan/phpstan-phpunit": "^1.3", + "phpstan/phpstan-strict-rules": "^1.5", + "phpstan/phpstan-symfony": "^1.3", "symfony/mime": "^5.4 || ^6.0 || ^7.0", "symfony/phpunit-bridge": "^v6.4.1 || ^7.0.1", "symfony/security-core": "^5.4 || ^6.0 || ^7.0" @@ -3081,9 +3024,9 @@ ], "support": { "issues": "https://github.com/stof/StofDoctrineExtensionsBundle/issues", - "source": "https://github.com/stof/StofDoctrineExtensionsBundle/tree/v1.10.1" + "source": "https://github.com/stof/StofDoctrineExtensionsBundle/tree/v1.11.0" }, - "time": "2023-12-09T09:33:39+00:00" + "time": "2024-02-13T14:43:20+00:00" }, { "name": "symfony/asset", @@ -6866,16 +6809,16 @@ }, { "name": "twig/twig", - "version": "v3.10.2", + "version": "v3.10.3", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "7aaed0b8311a557cc8c4047a71fd03153a00e755" + "reference": "67f29781ffafa520b0bbfbd8384674b42db04572" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/7aaed0b8311a557cc8c4047a71fd03153a00e755", - "reference": "7aaed0b8311a557cc8c4047a71fd03153a00e755", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/67f29781ffafa520b0bbfbd8384674b42db04572", + "reference": "67f29781ffafa520b0bbfbd8384674b42db04572", "shasum": "" }, "require": { @@ -6929,7 +6872,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.10.2" + "source": "https://github.com/twigphp/Twig/tree/v3.10.3" }, "funding": [ { @@ -6941,7 +6884,7 @@ "type": "tidelift" } ], - "time": "2024-05-14T06:04:16+00:00" + "time": "2024-05-16T10:04:27+00:00" }, { "name": "webmozart/assert", diff --git a/config/api_platform/User.yaml b/config/api_platform/User.yaml index e1dd16e..5fdb06b 100644 --- a/config/api_platform/User.yaml +++ b/config/api_platform/User.yaml @@ -1,18 +1,24 @@ resources: App\Entity\User: + processor: App\State\Processor\UserProcessor + input: App\Dto\Input\UserInput + output: App\Dto\Output\UserOutput normalization_context: - groups: ['user:read'] + groups: ['default', 'user:read'] denormalization_context: - groups: ['user:write'] operations: ApiPlatform\Metadata\GetCollection: + provider: App\State\Provider\UserProvider filters: - 'api_platform.filter.user.order' - 'api_platform.filter.user.search' - ApiPlatform\Metadata\Get: ~ - ApiPlatform\Metadata\Put: ~ - ApiPlatform\Metadata\Patch: ~ + ApiPlatform\Metadata\Get: + provider: App\State\Provider\UserProvider + ApiPlatform\Metadata\Put: + provider: App\State\Provider\UserProvider + ApiPlatform\Metadata\Patch: + provider: App\State\Provider\UserProvider ApiPlatform\Metadata\Post: ~ ApiPlatform\Metadata\Delete: ~ diff --git a/config/api_platform/UserGroup.yaml b/config/api_platform/UserGroup.yaml index bb6931c..9602c01 100644 --- a/config/api_platform/UserGroup.yaml +++ b/config/api_platform/UserGroup.yaml @@ -1,7 +1,7 @@ resources: App\Entity\UserGroup: normalization_context: - groups: ['user-group:read'] + groups: ['default', 'user-group:read'] denormalization_context: groups: ['user-group:write'] operations: diff --git a/config/packages/api_platform.yaml b/config/packages/api_platform.yaml index 00c8296..5efaf99 100644 --- a/config/packages/api_platform.yaml +++ b/config/packages/api_platform.yaml @@ -4,19 +4,15 @@ api_platform: version: 1.0.0 path_segment_name_generator: 'api_platform.path_segment_name_generator.dash' formats: - jsonld: ['application/ld+json'] + jsonld: ['application/ld+json', 'application/json'] mapping: - paths: ['%kernel.project_dir%/config/api_platform'] + paths: ['%kernel.project_dir%/config/api_platform', '%kernel.project_dir%/src/Dto'] defaults: pagination_client_items_per_page: true docs_formats: jsonld: ['application/ld+json'] jsonopenapi: ['application/vnd.openapi+json'] html: ['text/html'] - keep_legacy_inflector: false - use_symfony_listeners: true - graphql: - enabled: true swagger: versions: [3] api_keys: diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index 75ec9e8..b247cd0 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -1,13 +1,10 @@ doctrine: dbal: url: '%env(resolve:DATABASE_URL)%' - - # IMPORTANT: You MUST configure your server version, - # either here or in the DATABASE_URL env var (see .env file) - #server_version: '16' - profiling_collect_backtrace: '%kernel.debug%' use_savepoints: true + mapping_types: + enum: string orm: auto_generate_proxy_classes: true enable_lazy_ghost_objects: true diff --git a/config/packages/stof_doctrine_extensions.yaml b/config/packages/stof_doctrine_extensions.yaml index b258add..1432072 100644 --- a/config/packages/stof_doctrine_extensions.yaml +++ b/config/packages/stof_doctrine_extensions.yaml @@ -1,4 +1,6 @@ -# Read the documentation: https://symfony.com/doc/current/bundles/StofDoctrineExtensionsBundle/index.html -# See the official DoctrineExtensions documentation for more details: https://github.com/doctrine-extensions/DoctrineExtensions/tree/main/doc stof_doctrine_extensions: - default_locale: en_US + default_locale: es_ES + orm: + default: + timestampable: true + blameable: true \ No newline at end of file diff --git a/config/services.yaml b/config/services.yaml index 9650227..e5006be 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -24,3 +24,8 @@ services: decorates: 'api_platform.openapi.factory' arguments: [ '@App\OpenApi\OpenApiFactory.inner' ] autoconfigure: false + + App\State\Provider\UserProvider: + bind: + $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' + $itemProvider: '@api_platform.doctrine.orm.state.item_provider' diff --git a/migrations/Version20240524063952.php b/migrations/Version20240524063952.php new file mode 100644 index 0000000..f3f4231 --- /dev/null +++ b/migrations/Version20240524063952.php @@ -0,0 +1,33 @@ +addSql('CREATE TABLE organizational_unit (id INT AUTO_INCREMENT NOT NULL, parent_id INT DEFAULT NULL, uuid CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\', migration_id VARCHAR(255) DEFAULT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, created_by VARCHAR(255) DEFAULT NULL, updated_by VARCHAR(255) DEFAULT NULL, description VARCHAR(255) DEFAULT NULL, comments VARCHAR(255) DEFAULT NULL, UNIQUE INDEX UNIQ_749AEB2DD17F50A6 (uuid), INDEX IDX_749AEB2D727ACA70 (parent_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D727ACA70 FOREIGN KEY (parent_id) REFERENCES organizational_unit (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_749AEB2D727ACA70'); + $this->addSql('DROP TABLE organizational_unit'); + } +} diff --git a/migrations/Version20240524065625.php b/migrations/Version20240524065625.php new file mode 100644 index 0000000..6941a70 --- /dev/null +++ b/migrations/Version20240524065625.php @@ -0,0 +1,38 @@ +addSql('CREATE TABLE network_settings (id INT AUTO_INCREMENT NOT NULL, uuid CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\', migration_id VARCHAR(255) DEFAULT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, created_by VARCHAR(255) DEFAULT NULL, updated_by VARCHAR(255) DEFAULT NULL, proxy VARCHAR(255) DEFAULT NULL, dns VARCHAR(255) DEFAULT NULL, netmask VARCHAR(255) DEFAULT NULL, router VARCHAR(255) DEFAULT NULL, ntp VARCHAR(255) DEFAULT NULL, p2p_time INT DEFAULT NULL, p2p_mode VARCHAR(255) DEFAULT NULL, mcast_ip VARCHAR(255) DEFAULT NULL, mcast_speed INT NOT NULL, mcast_mode VARCHAR(255) DEFAULT NULL, mcast_port INT DEFAULT NULL, UNIQUE INDEX UNIQ_48869B54D17F50A6 (uuid), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + + $this->addSql('ALTER TABLE organizational_unit ADD network_settings_id INT DEFAULT NULL, ADD path VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE organizational_unit ADD CONSTRAINT FK_749AEB2D9B9A36D0 FOREIGN KEY (network_settings_id) REFERENCES network_settings (id)'); + $this->addSql('CREATE INDEX IDX_749AEB2D9B9A36D0 ON organizational_unit (network_settings_id)'); + } + + 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_749AEB2D9B9A36D0'); + $this->addSql('DROP TABLE network_settings'); + $this->addSql('DROP INDEX IDX_749AEB2D9B9A36D0 ON organizational_unit'); + $this->addSql('ALTER TABLE organizational_unit DROP network_settings_id, DROP path'); + } +} diff --git a/migrations/Version20240524083309.php b/migrations/Version20240524083309.php new file mode 100644 index 0000000..cee2d72 --- /dev/null +++ b/migrations/Version20240524083309.php @@ -0,0 +1,35 @@ +addSql('CREATE TABLE user_organizational_unit (user_id INT NOT NULL, organizational_unit_id INT NOT NULL, INDEX IDX_5E59845FA76ED395 (user_id), INDEX IDX_5E59845FFB84408A (organizational_unit_id), PRIMARY KEY(user_id, organizational_unit_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE user_organizational_unit ADD CONSTRAINT FK_5E59845FA76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE user_organizational_unit ADD CONSTRAINT FK_5E59845FFB84408A FOREIGN KEY (organizational_unit_id) REFERENCES organizational_unit (id) ON DELETE CASCADE'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE user_organizational_unit DROP FOREIGN KEY FK_5E59845FA76ED395'); + $this->addSql('ALTER TABLE user_organizational_unit DROP FOREIGN KEY FK_5E59845FFB84408A'); + $this->addSql('DROP TABLE user_organizational_unit'); + } +} diff --git a/src/Dto/Input/UserGroupInput.php b/src/Dto/Input/UserGroupInput.php new file mode 100644 index 0000000..8902d95 --- /dev/null +++ b/src/Dto/Input/UserGroupInput.php @@ -0,0 +1,32 @@ +name = $userGroup->getName(); + $this->roles = $userGroup->getRoles(); + $this->enabled= $userGroup->isEnabled(); + } +} \ No newline at end of file diff --git a/src/Dto/Input/UserInput.php b/src/Dto/Input/UserInput.php new file mode 100644 index 0000000..45479b0 --- /dev/null +++ b/src/Dto/Input/UserInput.php @@ -0,0 +1,69 @@ +username = $user->getUsername(); + $this->roles = $user->getRoles(); + $this->enabled= $user->isEnabled(); + $this->userGroups = $user->getUserGroups()->toArray(); + $this->allowedOrganizationalUnits = $user->getAllowedOrganizationalUnits()->toArray(); + } + + public function createOrUpdateEntity(?User $user = null): User + { + if (!$user) { + $user = new User(); + } + + $user->setUsername($this->username); + $user->setRoles($this->roles); + $user->setPassword($this->password); + $user->setEnabled($this->enabled); + $user->setUserGroups($this->userGroups); + //$user->setAllowedOrganizationalUnits($this->allowedOrganizationalUnits); + + return $user; + } +} \ No newline at end of file diff --git a/src/Dto/Output/AbstractOutput.php b/src/Dto/Output/AbstractOutput.php new file mode 100644 index 0000000..b5b0c56 --- /dev/null +++ b/src/Dto/Output/AbstractOutput.php @@ -0,0 +1,25 @@ +uuid = $entity->getUuid(); + $this->id = $entity->getId(); + } +} \ No newline at end of file diff --git a/src/Dto/Output/UserOutput.php b/src/Dto/Output/UserOutput.php new file mode 100644 index 0000000..ec66afe --- /dev/null +++ b/src/Dto/Output/UserOutput.php @@ -0,0 +1,40 @@ +username = $user->getUsername(); + $this->roles = $user->getRoles(); + $this->enabled = $user->isEnabled(); + $this->allowedOrganizationalUnits = $user->getAllowedOrganizationalUnits()->toArray(); + $this->createAt = $user->getCreatedAt(); + $this->createBy = $user->getCreatedBy(); + } +} \ No newline at end of file diff --git a/src/Entity/AbstractEntity.php b/src/Entity/AbstractEntity.php index a59a32d..031fc7f 100644 --- a/src/Entity/AbstractEntity.php +++ b/src/Entity/AbstractEntity.php @@ -36,6 +36,11 @@ abstract class AbstractEntity return $this->id; } + public function getUuid(): UuidInterface + { + return $this->uuid; + } + public function getMigrationId(): ?string { return $this->migrationId; diff --git a/src/Entity/NameableTrait.php b/src/Entity/NameableTrait.php new file mode 100644 index 0000000..5510771 --- /dev/null +++ b/src/Entity/NameableTrait.php @@ -0,0 +1,23 @@ +name; + } + + public function setName(string $name): static + { + $this->name = $name; + + return $this; + } + + +} \ No newline at end of file diff --git a/src/Entity/NetworkSettings.php b/src/Entity/NetworkSettings.php new file mode 100644 index 0000000..7f36461 --- /dev/null +++ b/src/Entity/NetworkSettings.php @@ -0,0 +1,224 @@ + + */ + #[ORM\OneToMany(targetEntity: OrganizationalUnit::class, mappedBy: 'networkSettings')] + private Collection $organizationalUnits; + + public function __construct() + { + parent::__construct(); + $this->organizationalUnits = new ArrayCollection(); + } + + public function getId(): ?int + { + return $this->id; + } + + public function getProxy(): ?string + { + return $this->proxy; + } + + public function setProxy(?string $proxy): static + { + $this->proxy = $proxy; + + return $this; + } + + public function getDns(): ?string + { + return $this->dns; + } + + public function setDns(?string $dns): static + { + $this->dns = $dns; + + return $this; + } + + public function getNetmask(): ?string + { + return $this->netmask; + } + + public function setNetmask(?string $netmask): static + { + $this->netmask = $netmask; + + return $this; + } + + public function getRouter(): ?string + { + return $this->router; + } + + public function setRouter(?string $router): static + { + $this->router = $router; + + return $this; + } + + public function getNtp(): ?string + { + return $this->ntp; + } + + public function setNtp(?string $ntp): static + { + $this->ntp = $ntp; + + return $this; + } + + public function getP2pTime(): ?int + { + return $this->p2pTime; + } + + public function setP2pTime(?int $p2pTime): static + { + $this->p2pTime = $p2pTime; + + return $this; + } + + public function getP2pMode(): ?string + { + return $this->p2pMode; + } + + public function setP2pMode(?string $p2pMode): static + { + $this->p2pMode = $p2pMode; + + return $this; + } + + public function getMcastIp(): ?string + { + return $this->mcastIp; + } + + public function setMcastIp(?string $mcastIp): static + { + $this->mcastIp = $mcastIp; + + return $this; + } + + public function getMcastSpeed(): ?int + { + return $this->mcastSpeed; + } + + public function setMcastSpeed(int $mcastSpeed): static + { + $this->mcastSpeed = $mcastSpeed; + + return $this; + } + + public function getMcastMode(): ?string + { + return $this->mcastMode; + } + + public function setMcastMode(?string $mcastMode): static + { + $this->mcastMode = $mcastMode; + + return $this; + } + + public function getMcastPort(): ?int + { + return $this->mcastPort; + } + + public function setMcastPort(?int $mcastPort): static + { + $this->mcastPort = $mcastPort; + + return $this; + } + + /** + * @return Collection + */ + public function getOrganizationalUnits(): Collection + { + return $this->organizationalUnits; + } + + public function addOrganizationalUnit(OrganizationalUnit $organizationalUnit): static + { + if (!$this->organizationalUnits->contains($organizationalUnit)) { + $this->organizationalUnits->add($organizationalUnit); + $organizationalUnit->setNetworkSettings($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->getNetworkSettings() === $this) { + $organizationalUnit->setNetworkSettings(null); + } + } + + return $this; + } +} diff --git a/src/Entity/OrganizationalUnit.php b/src/Entity/OrganizationalUnit.php new file mode 100644 index 0000000..6de54da --- /dev/null +++ b/src/Entity/OrganizationalUnit.php @@ -0,0 +1,169 @@ + + */ + #[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')] + private Collection $organizationalUnits; + + #[ORM\ManyToOne(inversedBy: 'organizationalUnits')] + private ?NetworkSettings $networkSettings = null; + + /** + * @var Collection + */ + #[ORM\ManyToMany(targetEntity: User::class, mappedBy: 'allowedOrganizationalUnits')] + private Collection $users; + + public function __construct() + { + parent::__construct(); + $this->organizationalUnits = new ArrayCollection(); + $this->users = new ArrayCollection(); + } + + public function getDescription(): ?string + { + return $this->description; + } + + public function setDescription(?string $description): static + { + $this->description = $description; + + return $this; + } + + public function getComments(): ?string + { + return $this->comments; + } + + public function setComments(?string $comments): static + { + $this->comments = $comments; + + return $this; + } + + public function getPath(): ?string + { + return $this->path; + } + + public function setPath(?string $path): static + { + $this->path = $path; + + return $this; + } + + public function getParent(): ?self + { + return $this->parent; + } + + public function setParent(?self $parent): static + { + $this->parent = $parent; + + return $this; + } + + /** + * @return Collection + */ + public function getOrganizationalUnits(): Collection + { + return $this->organizationalUnits; + } + + public function addOrganizationalUnit(self $organizationalUnit): static + { + if (!$this->organizationalUnits->contains($organizationalUnit)) { + $this->organizationalUnits->add($organizationalUnit); + $organizationalUnit->setParent($this); + } + + return $this; + } + + public function removeOrganizationalUnit(self $organizationalUnit): static + { + if ($this->organizationalUnits->removeElement($organizationalUnit)) { + // set the owning side to null (unless already changed) + if ($organizationalUnit->getParent() === $this) { + $organizationalUnit->setParent(null); + } + } + + return $this; + } + + public function getNetworkSettings(): ?NetworkSettings + { + return $this->networkSettings; + } + + public function setNetworkSettings(?NetworkSettings $networkSettings): static + { + $this->networkSettings = $networkSettings; + + return $this; + } + + /** + * @return Collection + */ + public function getUsers(): Collection + { + return $this->users; + } + + public function addUser(User $user): static + { + if (!$this->users->contains($user)) { + $this->users->add($user); + $user->addAllowedOrganizationalUnit($this); + } + + return $this; + } + + public function removeUser(User $user): static + { + if ($this->users->removeElement($user)) { + $user->removeAllowedOrganizationalUnit($this); + } + + return $this; + } +} diff --git a/src/Entity/ToggleableTrait.php b/src/Entity/ToggleableTrait.php new file mode 100644 index 0000000..5e724da --- /dev/null +++ b/src/Entity/ToggleableTrait.php @@ -0,0 +1,21 @@ +enabled; + } + + public function setEnabled(bool $enabled): static + { + $this->enabled = $enabled; + + return $this; + } +} diff --git a/src/Entity/User.php b/src/Entity/User.php index 62daf7f..3fd9a92 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -13,6 +13,11 @@ use Symfony\Component\Security\Core\User\UserInterface; #[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_USERNAME', fields: ['username'])] class User extends AbstractEntity implements UserInterface, PasswordAuthenticatedUserInterface { + use ToggleableTrait; + + const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN'; + const ROLE_USER = 'ROLE_USER'; + #[ORM\Column(length: 180)] private ?string $username = null; @@ -34,10 +39,17 @@ class User extends AbstractEntity implements UserInterface, PasswordAuthenticate #[ORM\ManyToMany(targetEntity: UserGroup::class, mappedBy: 'users')] private Collection $userGroups; + /** + * @var Collection + */ + #[ORM\ManyToMany(targetEntity: OrganizationalUnit::class, inversedBy: 'users')] + private Collection $allowedOrganizationalUnits; + public function __construct() { parent::__construct(); $this->userGroups = new ArrayCollection(); + $this->allowedOrganizationalUnits = new ArrayCollection(); } public function getUsername(): ?string @@ -70,10 +82,18 @@ class User extends AbstractEntity implements UserInterface, PasswordAuthenticate public function getRoles(): array { $roles = $this->roles; - // guarantee every user at least has ROLE_USER - $roles[] = 'ROLE_USER'; - return array_unique($roles); + if (!array_search(self::ROLE_USER, $roles, true)){ + $roles[] = self::ROLE_USER; + } + + foreach ($this->getUserGroups() as $userGroup) { + if ($userGroup->isEnabled()){ + $roles = array_merge($roles, $userGroup->getRoles()); + } + } + + return array_merge(array_unique($roles)); } /** @@ -118,6 +138,17 @@ class User extends AbstractEntity implements UserInterface, PasswordAuthenticate return $this->userGroups; } + public function setUserGroups(array $userGroup): static + { + $this->userGroups->clear(); + + foreach ($userGroup as $group){ + $this->addUserGroup($group); + } + + return $this; + } + public function addUserGroup(UserGroup $userGroup): static { if (!$this->userGroups->contains($userGroup)) { @@ -136,4 +167,28 @@ class User extends AbstractEntity implements UserInterface, PasswordAuthenticate return $this; } + + /** + * @return Collection + */ + public function getAllowedOrganizationalUnits(): Collection + { + return $this->allowedOrganizationalUnits; + } + + public function addAllowedOrganizationalUnit(OrganizationalUnit $allowedOrganizationalUnit): static + { + if (!$this->allowedOrganizationalUnits->contains($allowedOrganizationalUnit)) { + $this->allowedOrganizationalUnits->add($allowedOrganizationalUnit); + } + + return $this; + } + + public function removeAllowedOrganizationalUnit(OrganizationalUnit $allowedOrganizationalUnit): static + { + $this->allowedOrganizationalUnits->removeElement($allowedOrganizationalUnit); + + return $this; + } } diff --git a/src/Entity/UserGroup.php b/src/Entity/UserGroup.php index 2962b4b..b6c47c3 100644 --- a/src/Entity/UserGroup.php +++ b/src/Entity/UserGroup.php @@ -11,6 +11,8 @@ use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: UserGroupRepository::class)] class UserGroup extends AbstractEntity { + use ToggleableTrait; + #[ORM\Column(length: 255)] private ?string $name = null; diff --git a/src/Repository/.gitignore b/src/Repository/.gitignore deleted file mode 100644 index e69de29..0000000 diff --git a/src/Repository/AbstractRepository.php b/src/Repository/AbstractRepository.php new file mode 100644 index 0000000..ff14f0b --- /dev/null +++ b/src/Repository/AbstractRepository.php @@ -0,0 +1,35 @@ +getEntityManager()->persist($entity); + + if ($flush) { + $this->getEntityManager()->flush(); + } + } + + public function delete (AbstractEntity $entity, bool $flush = true): void + { + $this->getEntityManager()->remove($entity); + + if ($flush) { + $this->getEntityManager()->flush(); + } + } +} \ No newline at end of file diff --git a/src/Repository/NetworkSettingsRepository.php b/src/Repository/NetworkSettingsRepository.php new file mode 100644 index 0000000..66a3251 --- /dev/null +++ b/src/Repository/NetworkSettingsRepository.php @@ -0,0 +1,43 @@ + + */ +class NetworkSettingsRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, NetworkSettings::class); + } + +// /** +// * @return NetworkSettings[] Returns an array of NetworkSettings objects +// */ +// public function findByExampleField($value): array +// { +// return $this->createQueryBuilder('n') +// ->andWhere('n.exampleField = :val') +// ->setParameter('val', $value) +// ->orderBy('n.id', 'ASC') +// ->setMaxResults(10) +// ->getQuery() +// ->getResult() +// ; +// } + +// public function findOneBySomeField($value): ?NetworkSettings +// { +// return $this->createQueryBuilder('n') +// ->andWhere('n.exampleField = :val') +// ->setParameter('val', $value) +// ->getQuery() +// ->getOneOrNullResult() +// ; +// } +} diff --git a/src/Repository/OrganizationalUnitRepository.php b/src/Repository/OrganizationalUnitRepository.php new file mode 100644 index 0000000..591f292 --- /dev/null +++ b/src/Repository/OrganizationalUnitRepository.php @@ -0,0 +1,43 @@ + + */ +class OrganizationalUnitRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, OrganizationalUnit::class); + } + + // /** + // * @return OrganizationalUnit[] Returns an array of OrganizationalUnit objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('o') + // ->andWhere('o.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('o.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?OrganizationalUnit + // { + // return $this->createQueryBuilder('o') + // ->andWhere('o.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php index 4f2804e..dc47b0b 100644 --- a/src/Repository/UserRepository.php +++ b/src/Repository/UserRepository.php @@ -12,7 +12,7 @@ use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; /** * @extends ServiceEntityRepository */ -class UserRepository extends ServiceEntityRepository implements PasswordUpgraderInterface +class UserRepository extends AbstractRepository implements PasswordUpgraderInterface { public function __construct(ManagerRegistry $registry) { @@ -32,29 +32,4 @@ class UserRepository extends ServiceEntityRepository implements PasswordUpgrader $this->getEntityManager()->persist($user); $this->getEntityManager()->flush(); } - - // /** - // * @return User[] Returns an array of User objects - // */ - // public function findByExampleField($value): array - // { - // return $this->createQueryBuilder('u') - // ->andWhere('u.exampleField = :val') - // ->setParameter('val', $value) - // ->orderBy('u.id', 'ASC') - // ->setMaxResults(10) - // ->getQuery() - // ->getResult() - // ; - // } - - // public function findOneBySomeField($value): ?User - // { - // return $this->createQueryBuilder('u') - // ->andWhere('u.exampleField = :val') - // ->setParameter('val', $value) - // ->getQuery() - // ->getOneOrNullResult() - // ; - // } } diff --git a/src/State/Processor/UserProcessor.php b/src/State/Processor/UserProcessor.php new file mode 100644 index 0000000..20077be --- /dev/null +++ b/src/State/Processor/UserProcessor.php @@ -0,0 +1,62 @@ +processCreateOrUpdate($data, $operation, $uriVariables, $context); + case $operation instanceof Delete: + return $this->processDelete($data, $operation, $uriVariables, $context); + } + } + + private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): UserOutput + { + if (!($data instanceof UserInput)) { + throw new \Exception(sprintf('data is not instance of %s', UserInput::class)); + } + + $entity = null; + if (isset($uriVariables['uuid'])) { + $entity = $this->userRepository->findOneByUuid($uriVariables['id']); + } + + $user = $data->createOrUpdateEntity($entity); + $this->validator->validate($user); + $this->userRepository->save($user); + + return new UserOutput($user); + } + + private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null + { + $user = $this->userRepository->findOneByUuid($uriVariables['id']); + $this->userRepository->delete($user); + + return null; + } +} diff --git a/src/State/Provider/UserProvider.php b/src/State/Provider/UserProvider.php new file mode 100644 index 0000000..19a7eea --- /dev/null +++ b/src/State/Provider/UserProvider.php @@ -0,0 +1,71 @@ +provideCollection($operation, $uriVariables, $context); + case $operation instanceof Patch: + case $operation instanceof Put: + return $this->provideInput($operation, $uriVariables, $context); + case $operation instanceof Get: + return $this->provideItem($operation, $uriVariables, $context); + } + } + + private function provideCollection(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + $paginator = $this->collectionProvider->provide($operation, $uriVariables, $context); + + $items = new \ArrayObject(); + foreach ($paginator->getIterator() as $item){ + $items[] = new UserOutput($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('User not found'); + } + + return new UserOutput($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 ? new UserInput($item) : null; + } + + return new UserInput(); + } +} diff --git a/symfony.lock b/symfony.lock index 956ed64..dce74d3 100644 --- a/symfony.lock +++ b/symfony.lock @@ -13,15 +13,6 @@ "src/ApiResource/.gitignore" ] }, - "doctrine/annotations": { - "version": "2.0", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "1.10", - "ref": "64d8583af5ea57b7afa4aba4b159907f3a148b05" - } - }, "doctrine/doctrine-bundle": { "version": "2.12", "recipe": {