From bfadb922f64bb8317491d3fc115a3b03374c6508 Mon Sep 17 00:00:00 2001 From: Marco Perberschlager Date: Thu, 18 Dec 2025 08:27:22 +0100 Subject: [PATCH 1/5] Added delete endpoint --- .../Studio/Config/DeleteController.php | 81 +++++++++++++++++++ .../translations/studio_api_docs.en.yaml | 7 +- src/Service/Studio/ConfigurationService.php | 31 +++++++ .../Studio/ConfigurationServiceInterface.php | 5 ++ 4 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 src/Controller/Studio/Config/DeleteController.php diff --git a/src/Controller/Studio/Config/DeleteController.php b/src/Controller/Studio/Config/DeleteController.php new file mode 100644 index 00000000..a4eaa0a7 --- /dev/null +++ b/src/Controller/Studio/Config/DeleteController.php @@ -0,0 +1,81 @@ +value] + )] + #[IdParameter( + type: 'configuration', + schema: new Schema(type: 'string'), + name: 'name', + )] + #[SuccessResponse( + description: 'bundle_data_hub_config_delete_success_response', + )] + #[IsGranted(PermissionConstants::PLUGIN_DATA_HUB_CONFIG)] + #[DefaultResponses([ + HttpResponseCodes::UNAUTHORIZED, + HttpResponseCodes::NOT_FOUND, + ])] + public function deleteConfiguration(string $name): Response + { + $this->configurationService->deleteConfiguration($name); + + return new Response(); + } +} + diff --git a/src/Resources/translations/studio_api_docs.en.yaml b/src/Resources/translations/studio_api_docs.en.yaml index 902f125f..c0d93210 100644 --- a/src/Resources/translations/studio_api_docs.en.yaml +++ b/src/Resources/translations/studio_api_docs.en.yaml @@ -2,4 +2,9 @@ bundle_tag_data_hub_description: Operations related to Data Hub Bundle pimcore_studio_api_data_hub_config_collection: Data Hub Config Collection bundle_data_hub_config_collection: Data Hub Config Collection bundle_data_hub_config_collection_description: Data Hub Config Collection -bundle_data_hub_config_collection_summary: Data Hub Config Collection \ No newline at end of file +bundle_data_hub_config_collection_summary: Data Hub Config Collection +pimcore_studio_api_data_hub_config_delete: Delete Data Hub Configuration +bundle_data_hub_config_delete: Delete Data Hub Configuration +bundle_data_hub_config_delete_description: Delete a Data Hub configuration by name +bundle_data_hub_config_delete_summary: Delete Data Hub Configuration +bundle_data_hub_config_delete_success_response: Data Hub configuration successfully deleted diff --git a/src/Service/Studio/ConfigurationService.php b/src/Service/Studio/ConfigurationService.php index 72f6a3b1..fd3cde5e 100644 --- a/src/Service/Studio/ConfigurationService.php +++ b/src/Service/Studio/ConfigurationService.php @@ -19,8 +19,13 @@ use Pimcore\Bundle\DataHubBundle\Event\Studio\PreResponse\ConfigurationEvent; use Pimcore\Bundle\DataHubBundle\Hydrator\ConfigurationHydratorInterface; use Pimcore\Bundle\DataHubBundle\Schema\Configuration as HydratedConfiguration; +use Pimcore\Bundle\DataHubBundle\WorkspaceHelper; +use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ForbiddenException; +use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotWriteableException; +use RuntimeException; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\GenericEvent; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** @internal */ final readonly class ConfigurationService implements ConfigurationServiceInterface @@ -65,6 +70,32 @@ public function getConfigurations(): array return array_values($hydratedConfigs); } + /** + * @throws \Exception + */ + public function deleteConfiguration(string $name): void + { + $config = Configuration::getByName($name); + + if (!$config instanceof Configuration) { + throw new NotFoundHttpException('Configuration does not exist.'); + } + + if ($config->isWriteable() === false) { + throw new NotWriteableException( + 'delete', + 'Cant delete configuration "' . $name . '" as it is not writeable.' + ); + } + + if (!$config->isAllowed('delete')) { + throw new ForbiddenException('Permission denied to delete the configuration.'); + } + + WorkspaceHelper::deleteConfiguration($config); + $config->delete(); + } + private function resolveConfigurationList(array $configs): iterable { $event = new GenericEvent($this, ['list' => $configs]); diff --git a/src/Service/Studio/ConfigurationServiceInterface.php b/src/Service/Studio/ConfigurationServiceInterface.php index 2e8b4c8d..4b5c215c 100644 --- a/src/Service/Studio/ConfigurationServiceInterface.php +++ b/src/Service/Studio/ConfigurationServiceInterface.php @@ -23,4 +23,9 @@ interface ConfigurationServiceInterface * @return Configuration[] */ public function getConfigurations(): array; + + /** + * @throws \Exception + */ + public function deleteConfiguration(string $name): void; } From a865a073f8c655f2b69af0dbe632364529abce87 Mon Sep 17 00:00:00 2001 From: Marco Perberschlager Date: Thu, 18 Dec 2025 09:25:11 +0100 Subject: [PATCH 2/5] Improvements to permission checks. Added add endpoint --- .../Studio/Config/AddController.php | 82 +++++++++++++++++++ .../Studio/Config/CollectionController.php | 1 - .../Studio/Config/DeleteController.php | 2 +- .../translations/studio_api_docs.en.yaml | 5 ++ src/Schema/AddConfiguration.php | 43 ++++++++++ src/Service/Studio/ConfigurationService.php | 33 +++++++- .../Studio/ConfigurationServiceInterface.php | 5 ++ src/Utils/Constants/PermissionConstants.php | 6 +- 8 files changed, 172 insertions(+), 5 deletions(-) create mode 100644 src/Controller/Studio/Config/AddController.php create mode 100644 src/Schema/AddConfiguration.php diff --git a/src/Controller/Studio/Config/AddController.php b/src/Controller/Studio/Config/AddController.php new file mode 100644 index 00000000..caf99a15 --- /dev/null +++ b/src/Controller/Studio/Config/AddController.php @@ -0,0 +1,82 @@ +value] + )] + #[StringParameter('name', 'assets', 'The name of the configuration')] + #[StringParameter('type', 'graphql', 'Type of the adapter')] + #[StringParameter('path', '', 'Configuration path', false)] + #[CreatedResponse( + description: 'bundle_data_hub_config_add_success_response' + )] + #[DefaultResponses([ + HttpResponseCodes::UNAUTHORIZED, + HttpResponseCodes::NOT_FOUND, + ])] + public function addConfiguration( + #[MapQueryString] AddConfiguration $addConfiguration + ): Response { + $this->configurationService->addConfiguration( + $addConfiguration->getName(), + $addConfiguration->getType(), + $addConfiguration->getPath() + ); + + return new Response(); + } +} + diff --git a/src/Controller/Studio/Config/CollectionController.php b/src/Controller/Studio/Config/CollectionController.php index 2dbe3bcc..fa4338ce 100644 --- a/src/Controller/Studio/Config/CollectionController.php +++ b/src/Controller/Studio/Config/CollectionController.php @@ -67,7 +67,6 @@ public function __construct( description: 'bundle_copilot_actions_success_response', content: new CollectionJson(new GenericCollection(Configuration::class)), )] - #[IsGranted(PermissionConstants::PLUGIN_DATA_HUB_CONFIG)] #[DefaultResponses([ HttpResponseCodes::UNAUTHORIZED, HttpResponseCodes::NOT_FOUND, diff --git a/src/Controller/Studio/Config/DeleteController.php b/src/Controller/Studio/Config/DeleteController.php index a4eaa0a7..3b6a370c 100644 --- a/src/Controller/Studio/Config/DeleteController.php +++ b/src/Controller/Studio/Config/DeleteController.php @@ -34,7 +34,7 @@ */ final class DeleteController extends AbstractApiController { - private const string ROUTE = '/config/{name}'; + private const string ROUTE = '/config/delete/{name}'; public function __construct( SerializerInterface $serializer, diff --git a/src/Resources/translations/studio_api_docs.en.yaml b/src/Resources/translations/studio_api_docs.en.yaml index c0d93210..87fc1cca 100644 --- a/src/Resources/translations/studio_api_docs.en.yaml +++ b/src/Resources/translations/studio_api_docs.en.yaml @@ -8,3 +8,8 @@ bundle_data_hub_config_delete: Delete Data Hub Configuration bundle_data_hub_config_delete_description: Delete a Data Hub configuration by name bundle_data_hub_config_delete_summary: Delete Data Hub Configuration bundle_data_hub_config_delete_success_response: Data Hub configuration successfully deleted +pimcore_studio_api_data_hub_config_add: Add Data Hub Configuration +bundle_data_hub_config_add: Add Data Hub Configuration +bundle_data_hub_config_add_description: Create a new Data Hub configuration +bundle_data_hub_config_add_summary: Add Data Hub Configuration +bundle_data_hub_config_add_success_response: Data Hub configuration successfully created diff --git a/src/Schema/AddConfiguration.php b/src/Schema/AddConfiguration.php new file mode 100644 index 00000000..3de7a6b5 --- /dev/null +++ b/src/Schema/AddConfiguration.php @@ -0,0 +1,43 @@ +name; + } + + public function getType(): string + { + return $this->type; + } + + public function getPath(): string + { + return $this->path; + } +} + diff --git a/src/Service/Studio/ConfigurationService.php b/src/Service/Studio/ConfigurationService.php index fd3cde5e..e8c1a948 100644 --- a/src/Service/Studio/ConfigurationService.php +++ b/src/Service/Studio/ConfigurationService.php @@ -19,10 +19,12 @@ use Pimcore\Bundle\DataHubBundle\Event\Studio\PreResponse\ConfigurationEvent; use Pimcore\Bundle\DataHubBundle\Hydrator\ConfigurationHydratorInterface; use Pimcore\Bundle\DataHubBundle\Schema\Configuration as HydratedConfiguration; +use Pimcore\Bundle\DataHubBundle\Utils\Constants\PermissionConstants; use Pimcore\Bundle\DataHubBundle\WorkspaceHelper; +use Pimcore\Bundle\PortalEngineBundle\Enum\Collection\Permission; +use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ElementExistsException; use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ForbiddenException; use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotWriteableException; -use RuntimeException; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\GenericEvent; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -42,7 +44,10 @@ public function getConfigurations(): array $configs = $this->resolveConfigurationList(Configuration::getList()); foreach ($configs as $config) { - if (!$config instanceof Configuration) { + if ( + !$config instanceof Configuration || + !$config->isAllowed(PermissionConstants::PLUGIN_DATA_HUB_PERMISSION_READ) + ){ continue; } @@ -96,6 +101,30 @@ public function deleteConfiguration(string $name): void $config->delete(); } + /** + * @throws \Exception + */ + public function addConfiguration(string $name, string $type, string $path): string + { + if (new Configuration(null, null)->isWriteable() === false) { + throw new NotWriteableException( + 'create', + 'Cannot create configuration as configurations are not writeable.' + ); + } + + $config = Configuration::getByName($name); + + if ($config instanceof Configuration) { + throw new ElementExistsException('Configuration with name "' . $name . '" already exists.'); + } + + $config = new Configuration($type, $path, $name); + $config->save(); + + return $name; + } + private function resolveConfigurationList(array $configs): iterable { $event = new GenericEvent($this, ['list' => $configs]); diff --git a/src/Service/Studio/ConfigurationServiceInterface.php b/src/Service/Studio/ConfigurationServiceInterface.php index 4b5c215c..c5568c07 100644 --- a/src/Service/Studio/ConfigurationServiceInterface.php +++ b/src/Service/Studio/ConfigurationServiceInterface.php @@ -28,4 +28,9 @@ public function getConfigurations(): array; * @throws \Exception */ public function deleteConfiguration(string $name): void; + + /** + * @throws \Exception + */ + public function addConfiguration(string $name, string $type, string $path): string; } diff --git a/src/Utils/Constants/PermissionConstants.php b/src/Utils/Constants/PermissionConstants.php index fc2ab185..b692fa8a 100644 --- a/src/Utils/Constants/PermissionConstants.php +++ b/src/Utils/Constants/PermissionConstants.php @@ -18,5 +18,9 @@ */ class PermissionConstants { - public const PLUGIN_DATA_HUB_CONFIG = 'plugin_datahub_config'; + public const string PLUGIN_DATA_HUB_CONFIG = 'plugin_datahub_config'; + public const string PLUGIN_DATA_HUB_ADMIN = 'plugin_datahub_admin'; + public const string PLUGIN_DATA_HUB_ADAPTER_PREFIX = 'plugin_datahub_adapter_'; + public const string PLUGIN_DATA_HUB_PERMISSION_READ = 'read'; + } From fb1d2877d7055ab763e537653506a1cfa6e0aabe Mon Sep 17 00:00:00 2001 From: Marco Perberschlager Date: Thu, 18 Dec 2025 14:37:00 +0100 Subject: [PATCH 3/5] Added get endpoint --- .../Studio/Config/AddController.php | 2 +- .../Studio/Config/GetController.php | 80 ++++++++ src/Hydrator/ConfigurationDetailHydrator.php | 40 ++++ .../ConfigurationDetailHydratorInterface.php | 30 +++ src/Resources/config/studio_backend.yaml | 5 +- .../translations/studio_api_docs.en.yaml | 5 + src/Schema/AddConfiguration.php | 4 +- src/Schema/ConfigurationDetail.php | 61 ++++++ src/Service/Studio/ConfigurationService.php | 180 ++++++++++++++++-- .../Studio/ConfigurationServiceInterface.php | 6 + src/Utils/Constants/PermissionConstants.php | 4 +- 11 files changed, 391 insertions(+), 26 deletions(-) create mode 100644 src/Controller/Studio/Config/GetController.php create mode 100644 src/Hydrator/ConfigurationDetailHydrator.php create mode 100644 src/Hydrator/ConfigurationDetailHydratorInterface.php create mode 100644 src/Schema/ConfigurationDetail.php diff --git a/src/Controller/Studio/Config/AddController.php b/src/Controller/Studio/Config/AddController.php index caf99a15..9279663b 100644 --- a/src/Controller/Studio/Config/AddController.php +++ b/src/Controller/Studio/Config/AddController.php @@ -73,7 +73,7 @@ public function addConfiguration( $this->configurationService->addConfiguration( $addConfiguration->getName(), $addConfiguration->getType(), - $addConfiguration->getPath() + $addConfiguration->getPath() ?? '' ); return new Response(); diff --git a/src/Controller/Studio/Config/GetController.php b/src/Controller/Studio/Config/GetController.php new file mode 100644 index 00000000..79dcfdc7 --- /dev/null +++ b/src/Controller/Studio/Config/GetController.php @@ -0,0 +1,80 @@ +value] + )] + #[IdParameter( + type: 'configuration', + name: 'name', + )] + #[SuccessResponse( + description: 'bundle_data_hub_config_get_success_response', + )] + #[IsGranted(PermissionConstants::PLUGIN_DATA_HUB_CONFIG)] + #[DefaultResponses([ + HttpResponseCodes::UNAUTHORIZED, + HttpResponseCodes::NOT_FOUND, + ])] + public function getConfiguration(string $name): JsonResponse + { + return $this->jsonResponse( + $this->configurationService->getConfiguration($name) + ); + } +} + diff --git a/src/Hydrator/ConfigurationDetailHydrator.php b/src/Hydrator/ConfigurationDetailHydrator.php new file mode 100644 index 00000000..bee95469 --- /dev/null +++ b/src/Hydrator/ConfigurationDetailHydrator.php @@ -0,0 +1,40 @@ +getName(), + $configuration->getConfiguration(), + $configuration->getPermissionsConfig(), + $supportedQueryDataTypes, + $supportedMutationDataTypes, + $configuration->getModificationDate() + ); + } +} + diff --git a/src/Hydrator/ConfigurationDetailHydratorInterface.php b/src/Hydrator/ConfigurationDetailHydratorInterface.php new file mode 100644 index 00000000..a1cca7ef --- /dev/null +++ b/src/Hydrator/ConfigurationDetailHydratorInterface.php @@ -0,0 +1,30 @@ +type; } - public function getPath(): string + public function getPath(): ?string { return $this->path; } diff --git a/src/Schema/ConfigurationDetail.php b/src/Schema/ConfigurationDetail.php new file mode 100644 index 00000000..b0600baf --- /dev/null +++ b/src/Schema/ConfigurationDetail.php @@ -0,0 +1,61 @@ +name; + } + + public function getConfiguration(): array + { + return $this->configuration; + } + + public function getUserPermissions(): array + { + return $this->userPermissions; + } + + public function getSupportedGraphQLQueryDataTypes(): array + { + return $this->supportedGraphQLQueryDataTypes; + } + + public function getSupportedGraphQLMutationDataTypes(): array + { + return $this->supportedGraphQLMutationDataTypes; + } + + public function getModificationDate(): int + { + return $this->modificationDate; + } +} + diff --git a/src/Service/Studio/ConfigurationService.php b/src/Service/Studio/ConfigurationService.php index e8c1a948..ec95e45d 100644 --- a/src/Service/Studio/ConfigurationService.php +++ b/src/Service/Studio/ConfigurationService.php @@ -14,17 +14,23 @@ namespace Pimcore\Bundle\DataHubBundle\Service\Studio; +use Pimcore\Bundle\DataHubBundle\ConfigEvents; use Pimcore\Bundle\DataHubBundle\Configuration; use Pimcore\Bundle\DataHubBundle\Event\AdminEvents; +use Pimcore\Bundle\DataHubBundle\Event\Config\SpecialEntitiesEvent; use Pimcore\Bundle\DataHubBundle\Event\Studio\PreResponse\ConfigurationEvent; +use Pimcore\Bundle\DataHubBundle\GraphQL\Service; +use Pimcore\Bundle\DataHubBundle\Hydrator\ConfigurationDetailHydratorInterface; use Pimcore\Bundle\DataHubBundle\Hydrator\ConfigurationHydratorInterface; +use Pimcore\Bundle\DataHubBundle\Model\SpecialEntitySetting; use Pimcore\Bundle\DataHubBundle\Schema\Configuration as HydratedConfiguration; +use Pimcore\Bundle\DataHubBundle\Schema\ConfigurationDetail; use Pimcore\Bundle\DataHubBundle\Utils\Constants\PermissionConstants; use Pimcore\Bundle\DataHubBundle\WorkspaceHelper; -use Pimcore\Bundle\PortalEngineBundle\Enum\Collection\Permission; use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ElementExistsException; use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ForbiddenException; use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotWriteableException; +use Pimcore\Bundle\StudioBackendBundle\Security\Service\SecurityServiceInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\GenericEvent; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -35,6 +41,9 @@ public function __construct( private EventDispatcherInterface $eventDispatcher, private ConfigurationHydratorInterface $configurationHydrator, + private ConfigurationDetailHydratorInterface $configurationDetailHydrator, + private Service $graphQlService, + private SecurityServiceInterface $securityService ) { } @@ -78,27 +87,22 @@ public function getConfigurations(): array /** * @throws \Exception */ - public function deleteConfiguration(string $name): void + public function getConfiguration(string $name): ConfigurationDetail { - $config = Configuration::getByName($name); - - if (!$config instanceof Configuration) { - throw new NotFoundHttpException('Configuration does not exist.'); - } + $configuration = $this->fetchConfiguration($name); + $config = $this->normalizeConfigurationSchema($configuration->getConfiguration()); + $config = $this->processSpecialEntities($config); - if ($config->isWriteable() === false) { - throw new NotWriteableException( - 'delete', - 'Cant delete configuration "' . $name . '" as it is not writeable.' - ); - } + $configuration->setConfiguration($config); - if (!$config->isAllowed('delete')) { - throw new ForbiddenException('Permission denied to delete the configuration.'); - } + $supportedQueryDataTypes = $this->graphQlService->getSupportedDataObjectQueryDataTypes(); + $supportedMutationDataTypes = $this->graphQlService->getSupportedDataObjectMutationDataTypes(); - WorkspaceHelper::deleteConfiguration($config); - $config->delete(); + return $this->configurationDetailHydrator->hydrate( + $configuration, + $supportedQueryDataTypes, + $supportedMutationDataTypes + ); } /** @@ -108,14 +112,16 @@ public function addConfiguration(string $name, string $type, string $path): stri { if (new Configuration(null, null)->isWriteable() === false) { throw new NotWriteableException( - 'create', + PermissionConstants::PLUGIN_DATA_HUB_PERMISSION_CREATE, 'Cannot create configuration as configurations are not writeable.' ); } - $config = Configuration::getByName($name); + $this->checkUserPermission( + PermissionConstants::PLUGIN_DATA_HUB_CONFIG + ); - if ($config instanceof Configuration) { + if ($this->configExists($name)) { throw new ElementExistsException('Configuration with name "' . $name . '" already exists.'); } @@ -125,6 +131,129 @@ public function addConfiguration(string $name, string $type, string $path): stri return $name; } + /** + * @throws \Exception + */ + public function deleteConfiguration(string $name): void + { + $config = $this->fetchConfiguration($name); + + if ($config->isWriteable() === false) { + throw new NotWriteableException( + PermissionConstants::PLUGIN_DATA_HUB_PERMISSION_DELETE, + 'Cant delete configuration "' . $name . '" as it is not writeable.' + ); + } + + $this->checkConfigPermission($config, PermissionConstants::PLUGIN_DATA_HUB_PERMISSION_DELETE); + + WorkspaceHelper::deleteConfiguration($config); + $config->delete(); + } + + private function checkConfigPermission( + Configuration $configuration, + string $permission + ): void { + if (!$configuration->isAllowed($permission)) { + throw new ForbiddenException('Permission denied: ' . $permission); + } + } + + private function fetchConfiguration(string $name): Configuration + { + $configuration = Configuration::getByName($name); + + if (!$configuration instanceof Configuration) { + throw new NotFoundHttpException('Datahub configuration ' . $name . ' does not exist.'); + } + + $this->checkConfigPermission($configuration, PermissionConstants::PLUGIN_DATA_HUB_PERMISSION_READ); + + return $configuration; + } + + private function configExists(string $name): bool + { + $configuration = Configuration::getByName($name); + return $configuration instanceof Configuration; + } + + private function normalizeConfigurationSchema(array $config): array + { + $config['schema']['queryEntities'] = array_values($config['schema']['queryEntities'] ?? []); + $config['schema']['mutationEntities'] = array_values($config['schema']['mutationEntities'] ?? []); + $config['schema']['specialEntities'] = $config['schema']['specialEntities'] ?? []; + + return $config; + } + + private function processSpecialEntities(array $config): array + { + $coreSettings = $this->buildCoreSpecialEntitySettings($config['schema']['specialEntities']); + $specialSettingsEvent = new SpecialEntitiesEvent($coreSettings, $config); + $this->eventDispatcher->dispatch($specialSettingsEvent, ConfigEvents::SPECIAL_ENTITIES); + + $config['schema']['specialEntities'] = $specialSettingsEvent->getSpecialSettings(); + + return $config; + } + + /** + * @return SpecialEntitySetting[] + */ + private function buildCoreSpecialEntitySettings(array $specialEntities): array + { + return [ + $this->createSpecialEntitySetting('document', true, true, true, true, $specialEntities), + $this->createSpecialEntitySetting('document_folder', true, false, false, true, $specialEntities), + $this->createSpecialEntitySetting('asset', true, true, true, true, $specialEntities), + $this->createSpecialEntitySetting('asset_folder', true, true, true, true, $specialEntities), + $this->createSpecialEntitySetting('asset_listing', true, true, true, true, $specialEntities), + $this->createSpecialEntitySetting('object_folder', true, true, true, true, $specialEntities), + $this->createTranslationSpecialEntitySetting('translation', $specialEntities), + $this->createTranslationSpecialEntitySetting('translation_listing', $specialEntities), + ]; + } + + private function createSpecialEntitySetting( + string $name, + bool $read, + bool $create, + bool $update, + bool $delete, + array $specialEntities + ): SpecialEntitySetting { + return new SpecialEntitySetting( + $name, + $read, + $create, + $update, + $delete, + $specialEntities[$name]['read'] ?? false, + $specialEntities[$name]['create'] ?? false, + $specialEntities[$name]['update'] ?? false, + $specialEntities[$name]['delete'] ?? false + ); + } + + private function createTranslationSpecialEntitySetting( + string $name, + array $specialEntities + ): SpecialEntitySetting { + return new SpecialEntitySetting( + $name, + true, + false, + false, + false, + $specialEntities['translation_listing']['read'] ?? false, + $specialEntities['translation_listing']['create'] ?? false, + $specialEntities['translation_listing']['update'] ?? false, + $specialEntities['translation_listing']['delete'] ?? false + ); + } + private function resolveConfigurationList(array $configs): iterable { $event = new GenericEvent($this, ['list' => $configs]); @@ -146,4 +275,13 @@ private function addHydratedConfiguration( $hydratedConfigs[] = $hydratedItem; } + + private function checkUserPermission(string $permission): void + { + if(!$this->securityService->getCurrentUser()->isAllowed( + $permission + )) { + throw new ForbiddenException('Permission denied: ' . $permission); + } + } } diff --git a/src/Service/Studio/ConfigurationServiceInterface.php b/src/Service/Studio/ConfigurationServiceInterface.php index c5568c07..20f2e44d 100644 --- a/src/Service/Studio/ConfigurationServiceInterface.php +++ b/src/Service/Studio/ConfigurationServiceInterface.php @@ -15,6 +15,7 @@ namespace Pimcore\Bundle\DataHubBundle\Service\Studio; use Pimcore\Bundle\DataHubBundle\Schema\Configuration; +use Pimcore\Bundle\DataHubBundle\Schema\ConfigurationDetail; /** @internal */ interface ConfigurationServiceInterface @@ -33,4 +34,9 @@ public function deleteConfiguration(string $name): void; * @throws \Exception */ public function addConfiguration(string $name, string $type, string $path): string; + + /** + * @throws \Exception + */ + public function getConfiguration(string $name): ConfigurationDetail; } diff --git a/src/Utils/Constants/PermissionConstants.php b/src/Utils/Constants/PermissionConstants.php index b692fa8a..29212a23 100644 --- a/src/Utils/Constants/PermissionConstants.php +++ b/src/Utils/Constants/PermissionConstants.php @@ -22,5 +22,7 @@ class PermissionConstants public const string PLUGIN_DATA_HUB_ADMIN = 'plugin_datahub_admin'; public const string PLUGIN_DATA_HUB_ADAPTER_PREFIX = 'plugin_datahub_adapter_'; public const string PLUGIN_DATA_HUB_PERMISSION_READ = 'read'; - + public const string PLUGIN_DATA_HUB_PERMISSION_DELETE = 'delete'; + public const string PLUGIN_DATA_HUB_PERMISSION_UPDATE = 'update'; + public const string PLUGIN_DATA_HUB_PERMISSION_CREATE = 'create'; } From 39e81f7b88c3e724da5f338527bbf99093043728 Mon Sep 17 00:00:00 2001 From: Marco Perberschlager Date: Fri, 19 Dec 2025 09:31:11 +0100 Subject: [PATCH 4/5] Fixed type mismatch in OpenAPI schema --- src/Controller/Studio/Config/GetController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Controller/Studio/Config/GetController.php b/src/Controller/Studio/Config/GetController.php index 79dcfdc7..734e1794 100644 --- a/src/Controller/Studio/Config/GetController.php +++ b/src/Controller/Studio/Config/GetController.php @@ -14,7 +14,7 @@ namespace Pimcore\Bundle\DataHubBundle\Controller\Studio\Config; use OpenApi\Attributes\Get; -use OpenApi\Attributes\JsonContent; +use OpenApi\Attributes\Schema; use Pimcore\Bundle\DataHubBundle\OpenApi\Config\Prefix; use Pimcore\Bundle\DataHubBundle\OpenApi\Config\Tags; use Pimcore\Bundle\DataHubBundle\Service\Studio\ConfigurationServiceInterface; @@ -60,6 +60,7 @@ public function __construct( )] #[IdParameter( type: 'configuration', + schema: new Schema(type: 'string'), name: 'name', )] #[SuccessResponse( From f8b5f443eb695dca8b562fa9f68cb7edde7cb703 Mon Sep 17 00:00:00 2001 From: Marco Perberschlager Date: Fri, 19 Dec 2025 09:40:54 +0100 Subject: [PATCH 5/5] Fixed parenthesis in ConfigurationService --- src/Service/Studio/ConfigurationService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Service/Studio/ConfigurationService.php b/src/Service/Studio/ConfigurationService.php index ec95e45d..057be822 100644 --- a/src/Service/Studio/ConfigurationService.php +++ b/src/Service/Studio/ConfigurationService.php @@ -110,7 +110,7 @@ public function getConfiguration(string $name): ConfigurationDetail */ public function addConfiguration(string $name, string $type, string $path): string { - if (new Configuration(null, null)->isWriteable() === false) { + if ((new Configuration(null, null))->isWriteable() === false) { throw new NotWriteableException( PermissionConstants::PLUGIN_DATA_HUB_PERMISSION_CREATE, 'Cannot create configuration as configurations are not writeable.'