From 9b04a3e57bf2545de7a41ea632a76fa8de65e95d Mon Sep 17 00:00:00 2001 From: Syndesi Date: Fri, 11 Aug 2023 22:31:21 +0200 Subject: [PATCH] Replaced configuration, documentation WIP. --- CHANGELOG.md | 2 + config/custom-parameters.yaml | 1 - config/default-parameters.yaml | 59 ------ config/internal-parameters.yaml | 2 + config/packages/ember_nexus.yaml | 4 - config/services.yaml | 2 - .../src/DependencyInjection/Configuration.php | 33 +-- .../src/Service/EmberNexusConfiguration.php | 191 ++++++++++++------ .../GetInstanceConfigurationController.php | 42 +--- src/Controller/PostIndexController.php | 10 + .../User/PostRegisterController.php | 20 +- ...ropertyElementFragmentizeEventListener.php | 12 +- .../ElementToRawEventListener.php | 6 + ...ropertyElementFragmentizeEventListener.php | 6 + ...ropertyElementFragmentizeEventListener.php | 12 +- ...ropertyElementFragmentizeEventListener.php | 17 +- src/Response/JsonResponse.php | 1 + src/Security/TokenGenerator.php | 10 +- src/Service/CollectionService.php | 35 +--- .../_E3_01_PutNodeTest.php | 1 + 20 files changed, 224 insertions(+), 242 deletions(-) delete mode 100644 config/custom-parameters.yaml delete mode 100644 config/default-parameters.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cd3c78e..0a19f0dd 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Reword application configuration, via internal Symfony bundle. - Switch datetime format from temporary string type to datetime. +- Change default JSON encoding options. +- Replaced configuration, documentation WIP. ## 0.0.19 - 2023-08-10 ### Added diff --git a/config/custom-parameters.yaml b/config/custom-parameters.yaml deleted file mode 100644 index 9631d44c..00000000 --- a/config/custom-parameters.yaml +++ /dev/null @@ -1 +0,0 @@ -parameters: diff --git a/config/default-parameters.yaml b/config/default-parameters.yaml deleted file mode 100644 index 2b6c510a..00000000 --- a/config/default-parameters.yaml +++ /dev/null @@ -1,59 +0,0 @@ -parameters: - - # Affects how many elements can be returned in collection responses. - pageSize: - - # Minimum number of elements which are always returned, if they exist. - min: 5 - - # Default number of elements which are returned if they exist. - default: 25 - - # Maximum number of elements which are returned in a single response. Should not be way more than 100, as - # performance problems may arise. - max: 100 - - # Null can be replaced by links to redirect to external problem documentation sites. - problemInstanceLinks: - 404-not-found: null - - # Handles the /register endpoint. - register: - - # If true, the /register endpoint is active and anonymous users can create accounts. - enabled: true - - # The property name of the identifier. Identifier must be unique across the API, usually the email. - uniqueIdentifier: email - - # Either false or a regex for checking the identifier content. - uniqueIdentifierRegex: false - - # Configures the /instance-configuration endpoint - instanceConfiguration: - - # If true, enables the endpoint. If false, 403 error messages are returned. - enabled: true - - # If false, the version number is omitted. - showVersion: true - - token: - - # Minimum lifetime of created tokens. - # 30 minutes. - minLifetimeInSeconds: 1800 - - # Default lifetime of created tokens. - # 3 hours. - defaultLifetimeInSeconds: 10800 - - # Maximum lifetime of created tokens. - # Can be set to false to disable maximum limit. - # 13 months. - maxLifetimeInSeconds: 34214400 - - # Expired tokens will be deleted after at least x seconds. - # Can be set to false to disable auto delete feature. - # 14 days. - deleteExpiredTokensAutomaticallyInSeconds: 1209600 diff --git a/config/internal-parameters.yaml b/config/internal-parameters.yaml index b5a16b03..5ff7ab08 100644 --- a/config/internal-parameters.yaml +++ b/config/internal-parameters.yaml @@ -2,3 +2,5 @@ parameters: _dev_version: 'dev' version: '%env(default:_dev_version:VERSION)%' anonymousUserUUID: '%env(ANONYMOUS_USER_UUID)%' + problemInstanceLinks: + 404-not-found: null diff --git a/config/packages/ember_nexus.yaml b/config/packages/ember_nexus.yaml index 271f1626..f4068350 100644 --- a/config/packages/ember_nexus.yaml +++ b/config/packages/ember_nexus.yaml @@ -1,5 +1 @@ ember_nexus: - register: - enabled: true - instanceConfiguration: - showVersion: false diff --git a/config/services.yaml b/config/services.yaml index 5bfdd4c0..5a679a06 100755 --- a/config/services.yaml +++ b/config/services.yaml @@ -3,8 +3,6 @@ imports: - {resource: internal-parameters.yaml} - - {resource: default-parameters.yaml} - - {resource: custom-parameters.yaml} services: # default configuration for services in *this* file diff --git a/lib/EmberNexusBundle/src/DependencyInjection/Configuration.php b/lib/EmberNexusBundle/src/DependencyInjection/Configuration.php index e0a3e415..8f6af4f4 100644 --- a/lib/EmberNexusBundle/src/DependencyInjection/Configuration.php +++ b/lib/EmberNexusBundle/src/DependencyInjection/Configuration.php @@ -2,6 +2,7 @@ namespace EmberNexusBundle\DependencyInjection; +use EmberNexusBundle\Service\EmberNexusConfiguration; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; @@ -19,21 +20,21 @@ public function getConfigTreeBuilder(): TreeBuilder $rootNode ->children() - ->arrayNode('pageSize') + ->arrayNode(EmberNexusConfiguration::PAGE_SIZE) ->info('Affects how many elements can be returned in collection responses.') ->addDefaultsIfNotSet() ->children() - ->integerNode('min') + ->integerNode(EmberNexusConfiguration::PAGE_SIZE_MIN) ->info('Minimum number of elements which are always returned, if they exist.') ->min(1) ->defaultValue(5) ->end() - ->integerNode('default') + ->integerNode(EmberNexusConfiguration::PAGE_SIZE_DEFAULT) ->info('Default number of elements which are returned if they exist.') ->min(1) ->defaultValue(25) ->end() - ->integerNode('max') + ->integerNode(EmberNexusConfiguration::PAGE_SIZE_MAX) ->info('Maximum number of elements which are returned in a single response. Should not be way more than 100, as performance problems may arise.') ->min(1) ->defaultValue(100) @@ -41,57 +42,57 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->end() - ->arrayNode('register') + ->arrayNode(EmberNexusConfiguration::REGISTER) ->info('Handles the /register endpoint.') ->addDefaultsIfNotSet() ->children() - ->booleanNode('enabled') + ->booleanNode(EmberNexusConfiguration::REGISTER_ENABLED) ->info('If true, the /register endpoint is active and anonymous users can create accounts.') ->defaultTrue() ->end() - ->scalarNode('uniqueIdentifier') + ->scalarNode(EmberNexusConfiguration::REGISTER_UNIQUE_IDENTIFIER) ->info('The property name of the identifier. Identifier must be unique across the API, usually the email.') ->defaultValue('email') ->end() - ->integerNode('uniqueIdentifierRegex') + ->scalarNode(EmberNexusConfiguration::REGISTER_UNIQUE_IDENTIFIER_REGEX) ->info('Either false or a regex for checking the identifier content.') ->defaultFalse() ->end() ->end() ->end() - ->arrayNode('instanceConfiguration') + ->arrayNode(EmberNexusConfiguration::INSTANCE_CONFIGURATION) ->info('Configures the /instance-configuration endpoint') ->addDefaultsIfNotSet() ->children() - ->booleanNode('enabled') + ->booleanNode(EmberNexusConfiguration::INSTANCE_CONFIGURATION_ENABLED) ->info('If true, enables the endpoint. If false, 403 error messages are returned.') ->defaultTrue() ->end() - ->scalarNode('showVersion') + ->booleanNode(EmberNexusConfiguration::INSTANCE_CONFIGURATION_SHOW_VERSION) ->info('If false, the version number is omitted.') ->defaultTrue() ->end() ->end() ->end() - ->arrayNode('token') + ->arrayNode(EmberNexusConfiguration::TOKEN) ->info('Configures the /instance-configuration endpoint') ->addDefaultsIfNotSet() ->children() - ->integerNode('minLifetimeInSeconds') + ->integerNode(EmberNexusConfiguration::TOKEN_MIN_LIFETIME_IN_SECONDS) ->info('Minimum lifetime of created tokens.') ->defaultValue(self::HALF_AN_HOUR_IN_SECONDS) ->end() - ->integerNode('defaultLifetimeInSeconds') + ->integerNode(EmberNexusConfiguration::TOKEN_DEFAULT_LIFETIME_IN_SECONDS) ->info('Default lifetime of created tokens.') ->defaultValue(self::THREE_HOURS_IN_SECONDS) ->end() - ->scalarNode('maxLifetimeInSeconds') + ->scalarNode(EmberNexusConfiguration::TOKEN_MAX_LIFETIME_IN_SECONDS) ->info('Maximum lifetime of created tokens. Can be set to false to disable maximum limit.') ->defaultValue(self::THIRTEEN_MONTHS_IN_SECONDS) ->end() - ->scalarNode('deleteExpiredTokensAutomaticallyInSeconds') + ->scalarNode(EmberNexusConfiguration::TOKEN_DELETE_EXPIRED_TOKENS_AUTOMATICALLY_IN_SECONDS) ->info('Expired tokens will be deleted after defined time. Can be set to false to disable auto delete feature.') ->defaultValue(self::TWO_WEEKS_IN_SECONDS) ->end() diff --git a/lib/EmberNexusBundle/src/Service/EmberNexusConfiguration.php b/lib/EmberNexusBundle/src/Service/EmberNexusConfiguration.php index 3c53cf41..9f6b9e78 100644 --- a/lib/EmberNexusBundle/src/Service/EmberNexusConfiguration.php +++ b/lib/EmberNexusBundle/src/Service/EmberNexusConfiguration.php @@ -4,12 +4,32 @@ class EmberNexusConfiguration { + public const PAGE_SIZE = 'pageSize'; + public const PAGE_SIZE_MIN = 'min'; + public const PAGE_SIZE_DEFAULT = 'default'; + public const PAGE_SIZE_MAX = 'max'; + + public const REGISTER = 'register'; + public const REGISTER_ENABLED = 'enabled'; + public const REGISTER_UNIQUE_IDENTIFIER = 'uniqueIdentifier'; + public const REGISTER_UNIQUE_IDENTIFIER_REGEX = 'uniqueIdentifierRegex'; + + public const INSTANCE_CONFIGURATION = 'instanceConfiguration'; + public const INSTANCE_CONFIGURATION_ENABLED = 'enabled'; + public const INSTANCE_CONFIGURATION_SHOW_VERSION = 'showVersion'; + + public const TOKEN = 'token'; + public const TOKEN_MIN_LIFETIME_IN_SECONDS = 'minLifetimeInSeconds'; + public const TOKEN_DEFAULT_LIFETIME_IN_SECONDS = 'defaultLifetimeInSeconds'; + public const TOKEN_MAX_LIFETIME_IN_SECONDS = 'maxLifetimeInSeconds'; + public const TOKEN_DELETE_EXPIRED_TOKENS_AUTOMATICALLY_IN_SECONDS = 'tokenDeleteExpiredTokensAutomaticallyInSeconds'; + private int $pageSizeMin; private int $pageSizeDefault; private int $pageSizeMax; private bool $registerEnabled; private string $registerUniqueIdentifier; - private ?string $registerUniqueIdentifierRegex; + private string|false $registerUniqueIdentifierRegex; private bool $instanceConfigurationEnabled; private bool $instanceConfigurationShowVersion; private int $tokenMinLifetimeInSeconds; @@ -17,25 +37,45 @@ class EmberNexusConfiguration private int|false $tokenMaxLifetimeInSeconds; private int|false $tokenDeleteExpiredTokensAutomaticallyInSeconds; + private static function getValueFromConfig(array $configuration, array $keyParts): mixed + { + $currentKeyParts = []; + foreach ($keyParts as $i => $keyPart) { + $currentKeyParts[] = $keyPart; + if (!array_key_exists($keyPart, $configuration)) { + throw new \Exception(sprintf("Configuration must contain key '%s'.", implode('.', $currentKeyParts))); + } + $configuration = $configuration[$keyPart]; + } + + return $configuration; + } + public static function createFromConfiguration(array $configuration): self { $emberNexusConfiguration = new EmberNexusConfiguration(); - if (!array_key_exists('pageSize', $configuration)) { - throw new \Exception("Configuration must contain key 'pageSize'."); - } - if (!array_key_exists('min', $configuration['pageSize'])) { - throw new \Exception("Configuration must contain key 'pageSize.min'."); - } - $emberNexusConfiguration->setPageSizeMin((int) $configuration['pageSize']['min']); - if (!array_key_exists('default', $configuration['pageSize'])) { - throw new \Exception("Configuration must contain key 'pageSize.default'."); - } - $emberNexusConfiguration->setPageSizeDefault((int) $configuration['pageSize']['default']); - if (!array_key_exists('max', $configuration['pageSize'])) { - throw new \Exception("Configuration must contain key 'pageSize.max'."); - } - $emberNexusConfiguration->setPageSizeMax((int) $configuration['pageSize']['max']); + $emberNexusConfiguration->setPageSizeMin((int) self::getValueFromConfig( + $configuration, + [ + self::PAGE_SIZE, + self::PAGE_SIZE_MIN, + ] + )); + $emberNexusConfiguration->setPageSizeDefault((int) self::getValueFromConfig( + $configuration, + [ + self::PAGE_SIZE, + self::PAGE_SIZE_DEFAULT, + ] + )); + $emberNexusConfiguration->setPageSizeMax((int) self::getValueFromConfig( + $configuration, + [ + self::PAGE_SIZE, + self::PAGE_SIZE_MAX, + ] + )); if ($emberNexusConfiguration->getPageSizeMax() < $emberNexusConfiguration->getPageSizeMin()) { throw new \Exception('pagesize max must be smaller or equal to pagesize min.'); @@ -47,57 +87,76 @@ public static function createFromConfiguration(array $configuration): self throw new \Exception('default page size must be equal or less than max page size.'); } - if (!array_key_exists('register', $configuration)) { - throw new \Exception("Configuration must contain key 'register'."); - } - if (!array_key_exists('enabled', $configuration['register'])) { - throw new \Exception("Configuration must contain key 'register.enabled'."); - } - $emberNexusConfiguration->setRegisterEnabled((bool) $configuration['register']['enabled']); - if (!array_key_exists('uniqueIdentifier', $configuration['register'])) { - throw new \Exception("Configuration must contain key 'register.uniqueIdentifier'."); - } - $emberNexusConfiguration->setRegisterUniqueIdentifier((string) $configuration['register']['uniqueIdentifier']); - if (!array_key_exists('uniqueIdentifierRegex', $configuration['register'])) { - throw new \Exception("Configuration must contain key 'register.uniqueIdentifierRegex'."); - } - $emberNexusConfiguration->setRegisterUniqueIdentifierRegex((string) $configuration['register']['uniqueIdentifierRegex']); - - if (!array_key_exists('instanceConfiguration', $configuration)) { - throw new \Exception("Configuration must contain key 'instanceConfiguration'."); - } - if (!array_key_exists('enabled', $configuration['instanceConfiguration'])) { - throw new \Exception("Configuration must contain key 'instanceConfiguration.enabled'."); - } - $emberNexusConfiguration->setInstanceConfigurationEnabled((bool) $configuration['instanceConfiguration']['enabled']); - if (!array_key_exists('showVersion', $configuration['instanceConfiguration'])) { - throw new \Exception("Configuration must contain key 'instanceConfiguration.showVersion'."); - } - $emberNexusConfiguration->setInstanceConfigurationShowVersion((bool) $configuration['instanceConfiguration']['showVersion']); - - if (!array_key_exists('token', $configuration)) { - throw new \Exception("Configuration must contain key 'token'."); - } - if (!array_key_exists('minLifetimeInSeconds', $configuration['token'])) { - throw new \Exception("Configuration must contain key 'token.minLifetimeInSeconds'."); - } - $emberNexusConfiguration->setTokenMinLifetimeInSeconds((int) $configuration['token']['minLifetimeInSeconds']); - if (!array_key_exists('defaultLifetimeInSeconds', $configuration['token'])) { - throw new \Exception("Configuration must contain key 'token.defaultLifetimeInSeconds'."); - } - $emberNexusConfiguration->setTokenDefaultLifetimeInSeconds((int) $configuration['token']['defaultLifetimeInSeconds']); - if (!array_key_exists('maxLifetimeInSeconds', $configuration['token'])) { - throw new \Exception("Configuration must contain key 'token.maxLifetimeInSeconds'."); - } - $value = $configuration['token']['maxLifetimeInSeconds']; + $emberNexusConfiguration->setRegisterEnabled((bool) self::getValueFromConfig( + $configuration, + [ + self::REGISTER, + self::REGISTER_ENABLED, + ] + )); + $emberNexusConfiguration->setRegisterUniqueIdentifier((string) self::getValueFromConfig( + $configuration, + [ + self::REGISTER, + self::REGISTER_UNIQUE_IDENTIFIER, + ] + )); + $value = self::getValueFromConfig( + $configuration, + [ + self::REGISTER, + self::REGISTER_UNIQUE_IDENTIFIER_REGEX, + ] + ); if (false !== $value) { - $value = (int) $value; + $value = (string) $value; } + $emberNexusConfiguration->setRegisterUniqueIdentifierRegex($value); + + $emberNexusConfiguration->setInstanceConfigurationEnabled((bool) self::getValueFromConfig( + $configuration, + [ + self::INSTANCE_CONFIGURATION, + self::INSTANCE_CONFIGURATION_ENABLED, + ] + )); + $emberNexusConfiguration->setInstanceConfigurationShowVersion((bool) self::getValueFromConfig( + $configuration, + [ + self::INSTANCE_CONFIGURATION, + self::INSTANCE_CONFIGURATION_SHOW_VERSION, + ] + )); + + $emberNexusConfiguration->setTokenMinLifetimeInSeconds((int) self::getValueFromConfig( + $configuration, + [ + self::TOKEN, + self::TOKEN_MIN_LIFETIME_IN_SECONDS, + ] + )); + $emberNexusConfiguration->setTokenDefaultLifetimeInSeconds((int) self::getValueFromConfig( + $configuration, + [ + self::TOKEN, + self::TOKEN_DEFAULT_LIFETIME_IN_SECONDS, + ] + )); + $value = self::getValueFromConfig( + $configuration, + [ + self::TOKEN, + self::TOKEN_MAX_LIFETIME_IN_SECONDS, + ] + ); $emberNexusConfiguration->setTokenMaxLifetimeInSeconds($value); - if (!array_key_exists('deleteExpiredTokensAutomaticallyInSeconds', $configuration['token'])) { - throw new \Exception("Configuration must contain key 'token.deleteExpiredTokensAutomaticallyInSeconds'."); - } - $value = $configuration['token']['deleteExpiredTokensAutomaticallyInSeconds']; + $value = self::getValueFromConfig( + $configuration, + [ + self::TOKEN, + self::TOKEN_DELETE_EXPIRED_TOKENS_AUTOMATICALLY_IN_SECONDS, + ] + ); if (false !== $value) { $value = (int) $value; } @@ -181,12 +240,12 @@ public function setRegisterUniqueIdentifier(string $registerUniqueIdentifier): E return $this; } - public function getRegisterUniqueIdentifierRegex(): ?string + public function getRegisterUniqueIdentifierRegex(): string|false { return $this->registerUniqueIdentifierRegex; } - public function setRegisterUniqueIdentifierRegex(?string $registerUniqueIdentifierRegex): EmberNexusConfiguration + public function setRegisterUniqueIdentifierRegex(string|false $registerUniqueIdentifierRegex): EmberNexusConfiguration { $this->registerUniqueIdentifierRegex = $registerUniqueIdentifierRegex; diff --git a/src/Controller/GetInstanceConfigurationController.php b/src/Controller/GetInstanceConfigurationController.php index 0a6d3c26..2a4911f6 100644 --- a/src/Controller/GetInstanceConfigurationController.php +++ b/src/Controller/GetInstanceConfigurationController.php @@ -4,6 +4,7 @@ use App\Exception\ClientForbiddenException; use App\Response\JsonResponse; +use EmberNexusBundle\Service\EmberNexusConfiguration; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\HttpFoundation\Response; @@ -12,6 +13,7 @@ class GetInstanceConfigurationController extends AbstractController { public function __construct( + private EmberNexusConfiguration $emberNexusConfiguration, private ParameterBagInterface $bag ) { } @@ -23,49 +25,25 @@ public function __construct( )] public function getInstanceConfiguration(): Response { - $instanceConfigurationConfig = $this->bag->get('instanceConfiguration'); - if (null === $instanceConfigurationConfig) { - throw new \Exception("Unable to get unique identifier from config; key 'instanceConfiguration' must exist."); - } - if (!is_array($instanceConfigurationConfig)) { - throw new \Exception("Configuration key 'instanceConfiguration' must be an array."); - } - - if (true !== $instanceConfigurationConfig['enabled']) { + if (!$this->emberNexusConfiguration->isInstanceConfigurationEnabled()) { throw new ClientForbiddenException(); } - $pageSizeConfig = $this->bag->get('pageSize'); - if (null === $pageSizeConfig) { - throw new \Exception("Unable to get unique identifier from config; key 'pageSize' must exist."); - } - if (!is_array($pageSizeConfig)) { - throw new \Exception("Configuration key 'pageSize' must be an array."); - } - - $registerConfig = $this->bag->get('register'); - if (null === $registerConfig) { - throw new \Exception("Unable to get unique identifier from config; key 'register' must exist."); - } - if (!is_array($registerConfig)) { - throw new \Exception("Configuration key 'register' must be an array."); - } - $instanceConfiguration = [ 'version' => null, 'pageSize' => [ - 'min' => $pageSizeConfig['min'], - 'default' => $pageSizeConfig['default'], - 'max' => $pageSizeConfig['max'], + 'min' => $this->emberNexusConfiguration->getPageSizeMin(), + 'default' => $this->emberNexusConfiguration->getPageSizeDefault(), + 'max' => $this->emberNexusConfiguration->getPageSizeMax(), ], 'register' => [ - 'enabled' => $registerConfig['enabled'], - 'uniqueIdentifier' => $registerConfig['uniqueIdentifier'], - 'uniqueIdentifierRegex' => $registerConfig['uniqueIdentifierRegex'], + 'enabled' => $this->emberNexusConfiguration->isRegisterEnabled(), + 'uniqueIdentifier' => $this->emberNexusConfiguration->getRegisterUniqueIdentifier(), + 'uniqueIdentifierRegex' => $this->emberNexusConfiguration->getRegisterUniqueIdentifierRegex(), ], ]; - if (true === $instanceConfigurationConfig['showVersion']) { + if ($this->emberNexusConfiguration->isInstanceConfigurationShowVersion()) { $instanceConfiguration['version'] = $this->bag->get('version'); } diff --git a/src/Controller/PostIndexController.php b/src/Controller/PostIndexController.php index 8538c73e..2668a3f1 100755 --- a/src/Controller/PostIndexController.php +++ b/src/Controller/PostIndexController.php @@ -53,6 +53,16 @@ public function postIndex(Request $request): Response $data = []; if (array_key_exists('data', $body)) { $data = $body['data']; + foreach ($data as $key => $value) { + if (is_string($value)) { + if (strlen($value) >= 22 && strlen($value) <= 26) { + $possibleDate = \DateTime::createFromFormat(\DateTime::ATOM, $value); + if (false !== $possibleDate) { + $data[$key] = $possibleDate; + } + } + } + } } $startId = null; diff --git a/src/Controller/User/PostRegisterController.php b/src/Controller/User/PostRegisterController.php index 1218fbb4..2b1ea023 100644 --- a/src/Controller/User/PostRegisterController.php +++ b/src/Controller/User/PostRegisterController.php @@ -8,10 +8,10 @@ use App\Security\UserPasswordHasher; use App\Service\ElementManager; use App\Type\NodeElement; +use EmberNexusBundle\Service\EmberNexusConfiguration; use Laudis\Neo4j\Databags\Statement; use Ramsey\Uuid\Rfc4122\UuidV4; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -24,8 +24,8 @@ public function __construct( private ElementManager $elementManager, private CypherEntityManager $cypherEntityManager, private UrlGeneratorInterface $router, - private ParameterBagInterface $bag, - private UserPasswordHasher $userPasswordHasher + private UserPasswordHasher $userPasswordHasher, + private EmberNexusConfiguration $emberNexusConfiguration ) { } @@ -38,14 +38,7 @@ public function postRegister(Request $request): Response { $body = \Safe\json_decode($request->getContent(), true); - $registerConfig = $this->bag->get('register'); - if (null === $registerConfig) { - throw new \Exception("Unable to get unique identifier from config; key 'register' must exist."); - } - if (!is_array($registerConfig)) { - throw new \Exception("Configuration key 'register' must be an array."); - } - if (($registerConfig['enabled'] ?? false) === false) { + if (!$this->emberNexusConfiguration->isRegisterEnabled()) { throw new ClientForbiddenException(); } @@ -63,10 +56,7 @@ public function postRegister(Request $request): Response } $password = $body['password']; - $uniqueIdentifier = $registerConfig['uniqueIdentifier']; - if (null === $uniqueIdentifier) { - throw new \Exception("Unable to get unique identifier from config; key 'register.uniqueIdentifier' must exist."); - } + $uniqueIdentifier = $this->emberNexusConfiguration->getRegisterUniqueIdentifier(); if (!array_key_exists($uniqueIdentifier, $data)) { throw new ClientBadRequestException(detail: sprintf("Property '%s' must be set.", $uniqueIdentifier)); } diff --git a/src/EventListener/CreatedPropertyElementFragmentizeEventListener.php b/src/EventListener/CreatedPropertyElementFragmentizeEventListener.php index c81230bf..08a99faf 100755 --- a/src/EventListener/CreatedPropertyElementFragmentizeEventListener.php +++ b/src/EventListener/CreatedPropertyElementFragmentizeEventListener.php @@ -5,6 +5,8 @@ use App\Event\NodeElementFragmentizeEvent; use App\Event\RelationElementFragmentizeEvent; use App\Exception\ServerException; +use Laudis\Neo4j\Types\DateTimeZoneId; +use MongoDB\BSON\UTCDateTime; class CreatedPropertyElementFragmentizeEventListener { @@ -36,8 +38,14 @@ private function handleEvent(NodeElementFragmentizeEvent|RelationElementFragment throw new ServerException(detail: 'Server must set created property before persisting element'); } $created = $element->getProperty('created'); + if ($created instanceof DateTimeZoneId) { + $created = $created->toDateTime(); + } + if (!($created instanceof \DateTimeInterface)) { + throw new \Exception("Unable to get datetime info from created property of type '".get_class($created)."'."); + } $cypherFragment->addProperty('created', $created); - $mongoFragment->addProperty('created', $created); - $elasticFragment->addProperty('created', $created); + $mongoFragment->addProperty('created', new UTCDateTime($created)); + $elasticFragment->addProperty('created', $created->format('Uu')); } } diff --git a/src/EventListener/ElementToRawEventListener.php b/src/EventListener/ElementToRawEventListener.php index e11b38d4..12062110 100755 --- a/src/EventListener/ElementToRawEventListener.php +++ b/src/EventListener/ElementToRawEventListener.php @@ -5,6 +5,7 @@ use App\Contract\NodeElementInterface; use App\Contract\RelationElementInterface; use App\Event\ElementToRawEvent; +use Laudis\Neo4j\Types\DateTimeZoneId; class ElementToRawEventListener { @@ -28,6 +29,11 @@ public function onElementToRawEvent(ElementToRawEvent $event): void $rawData['end'] = $element->getEnd()?->toString(); } $properties = $element->getProperties(); + foreach ($properties as $key => $value) { + if ($value instanceof DateTimeZoneId) { + $properties[$key] = $value->toDateTime()->format(\DateTime::ATOM); + } + } ksort($properties); $rawData['data'] = $properties; $event->setRawData($rawData); diff --git a/src/EventListener/GenericPropertyElementFragmentizeEventListener.php b/src/EventListener/GenericPropertyElementFragmentizeEventListener.php index e2fe054a..6ee56c6c 100755 --- a/src/EventListener/GenericPropertyElementFragmentizeEventListener.php +++ b/src/EventListener/GenericPropertyElementFragmentizeEventListener.php @@ -4,6 +4,7 @@ use App\Event\NodeElementFragmentizeEvent; use App\Event\RelationElementFragmentizeEvent; +use Laudis\Neo4j\Types\DateTimeZoneId; class GenericPropertyElementFragmentizeEventListener { @@ -42,6 +43,11 @@ private function handleEvent(NodeElementFragmentizeEvent|RelationElementFragment $elasticFragment->addProperty($name, $value->format('Uu')); continue; } + if ($value instanceof DateTimeZoneId) { + $cypherFragment->addProperty($name, $value); + $elasticFragment->addProperty($name, $value->toDateTime()->format('Uu')); + continue; + } if (is_object($value)) { $mongoFragment->addProperty($name, $value); continue; diff --git a/src/EventListener/UpdatedPropertyElementFragmentizeEventListener.php b/src/EventListener/UpdatedPropertyElementFragmentizeEventListener.php index a8a17f73..d7f7dc2a 100644 --- a/src/EventListener/UpdatedPropertyElementFragmentizeEventListener.php +++ b/src/EventListener/UpdatedPropertyElementFragmentizeEventListener.php @@ -5,6 +5,8 @@ use App\Event\NodeElementFragmentizeEvent; use App\Event\RelationElementFragmentizeEvent; use App\Exception\ServerException; +use Laudis\Neo4j\Types\DateTimeZoneId; +use MongoDB\BSON\UTCDateTime; class UpdatedPropertyElementFragmentizeEventListener { @@ -36,8 +38,14 @@ private function handleEvent(NodeElementFragmentizeEvent|RelationElementFragment throw new ServerException(detail: 'Server must set updated property before persisting element'); } $updated = $element->getProperty('updated'); + if ($updated instanceof DateTimeZoneId) { + $updated = $updated->toDateTime(); + } + if (!($updated instanceof \DateTimeInterface)) { + throw new \Exception("Unable to get datetime info from updated property of type '".get_class($updated)."'."); + } $cypherFragment->addProperty('updated', $updated); - $mongoFragment->addProperty('updated', $updated); - $elasticFragment->addProperty('updated', $updated); + $mongoFragment->addProperty('updated', new UTCDateTime($updated)); + $elasticFragment->addProperty('updated', $updated->format('Uu')); } } diff --git a/src/EventListener/UserIdentifierPropertyElementFragmentizeEventListener.php b/src/EventListener/UserIdentifierPropertyElementFragmentizeEventListener.php index 3786fc87..aaf816f5 100644 --- a/src/EventListener/UserIdentifierPropertyElementFragmentizeEventListener.php +++ b/src/EventListener/UserIdentifierPropertyElementFragmentizeEventListener.php @@ -3,12 +3,12 @@ namespace App\EventListener; use App\Event\NodeElementFragmentizeEvent; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; +use EmberNexusBundle\Service\EmberNexusConfiguration; class UserIdentifierPropertyElementFragmentizeEventListener { public function __construct( - private ParameterBagInterface $bag + private EmberNexusConfiguration $emberNexusConfiguration ) { } @@ -19,21 +19,10 @@ public function onNodeElementFragmentizeEvent(NodeElementFragmentizeEvent $event return; } - $registerConfig = $this->bag->get('register'); - if (null === $registerConfig) { - throw new \Exception("Unable to get unique identifier from config; key 'register' must exist."); - } - if (!is_array($registerConfig)) { - throw new \Exception("Configuration key 'register' must be an array."); - } - $uniqueIdentifier = $registerConfig['uniqueIdentifier']; - if (null === $uniqueIdentifier) { - throw new \Exception("Unable to get unique identifier from config; key 'register.uniqueIdentifier' must exist."); - } - $cypherFragment = $event->getCypherFragment(); $mongoFragment = $event->getMongoFragment(); $elasticFragment = $event->getElasticFragment(); + $uniqueIdentifier = $this->emberNexusConfiguration->getRegisterUniqueIdentifier(); if ($element->hasProperty($uniqueIdentifier)) { $cypherFragment->addProperty($uniqueIdentifier, $element->getProperty($uniqueIdentifier)); $mongoFragment->addProperty($uniqueIdentifier, $element->getProperty($uniqueIdentifier)); diff --git a/src/Response/JsonResponse.php b/src/Response/JsonResponse.php index 500477af..200fd14e 100644 --- a/src/Response/JsonResponse.php +++ b/src/Response/JsonResponse.php @@ -12,6 +12,7 @@ class JsonResponse extends SymfonyJsonResponse public function __construct(mixed $data = null, int $status = 200, array $headers = [], bool $json = false) { $this->charset = 'UTF-8'; + $this->encodingOptions = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; parent::__construct( $data, $status, diff --git a/src/Security/TokenGenerator.php b/src/Security/TokenGenerator.php index 65aee492..07c84c58 100755 --- a/src/Security/TokenGenerator.php +++ b/src/Security/TokenGenerator.php @@ -47,14 +47,18 @@ public function createNewToken(UuidInterface $userUuid, string $name = null, int if (null === $lifetimeInSeconds) { $lifetimeInSeconds = $this->emberNexusConfiguration->getTokenDefaultLifetimeInSeconds(); } else { - if ($lifetimeInSeconds > $this->emberNexusConfiguration->getTokenMaxLifetimeInSeconds()) { - $lifetimeInSeconds = $this->emberNexusConfiguration->getTokenMaxLifetimeInSeconds(); + if (false !== $this->emberNexusConfiguration->getTokenMaxLifetimeInSeconds()) { + if ($lifetimeInSeconds > $this->emberNexusConfiguration->getTokenMaxLifetimeInSeconds()) { + $lifetimeInSeconds = $this->emberNexusConfiguration->getTokenMaxLifetimeInSeconds(); + } } if ($lifetimeInSeconds < $this->emberNexusConfiguration->getTokenMinLifetimeInSeconds()) { $lifetimeInSeconds = $this->emberNexusConfiguration->getTokenMinLifetimeInSeconds(); } } - + /** + * @var int $lifetimeInSeconds + */ $name ??= (new DateTime())->format('Y-m-d H:i:s'); $tokenUuid = Uuid::uuid4(); diff --git a/src/Service/CollectionService.php b/src/Service/CollectionService.php index 3c69d1ca..3c97100c 100755 --- a/src/Service/CollectionService.php +++ b/src/Service/CollectionService.php @@ -3,8 +3,8 @@ namespace App\Service; use App\Response\CollectionResponse; +use EmberNexusBundle\Service\EmberNexusConfiguration; use Ramsey\Uuid\UuidInterface; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\HttpFoundation\InputBag; use Symfony\Component\HttpFoundation\RequestStack; @@ -14,7 +14,7 @@ public function __construct( private RequestStack $requestStack, private ElementManager $elementManager, private ElementToRawService $elementToRawService, - private ParameterBagInterface $bag + private EmberNexusConfiguration $emberNexusConfiguration ) { } @@ -38,26 +38,19 @@ public function getCurrentPage(): int public function getPageSize(): int { - $pageSizeConfig = $this->bag->get('pageSize'); - if (!is_array($pageSizeConfig)) { - throw new \LogicException(); - } - $defaultPageSize = $pageSizeConfig['default'] ?? 25; - $minPageSize = $pageSizeConfig['min'] ?? 10; - $maxPageSize = $pageSizeConfig['max'] ?? 100; $query = $this->requestStack->getCurrentRequest()?->query; if (!($query instanceof InputBag)) { throw new \LogicException(); } if (!$query->has('pageSize')) { - return $defaultPageSize; + return $this->emberNexusConfiguration->getPageSizeDefault(); } $requestPageSize = (int) $query->get('pageSize'); - if ($requestPageSize < 1 || $requestPageSize < $minPageSize) { - return $minPageSize; + if ($requestPageSize < $this->emberNexusConfiguration->getPageSizeMin()) { + return $this->emberNexusConfiguration->getPageSizeMin(); } - if ($requestPageSize > $maxPageSize) { - return $maxPageSize; + if ($requestPageSize > $this->emberNexusConfiguration->getPageSizeMax()) { + return $this->emberNexusConfiguration->getPageSizeMax(); } return $requestPageSize; @@ -93,13 +86,8 @@ public function getPageLink(int $page = null): string } $pageSize = $this->getPageSize(); - if ($this->bag->has('pageSize')) { - $pageSizeConfig = $this->bag->get('pageSize'); - if (is_array($pageSizeConfig)) { - if ($pageSize !== $pageSizeConfig['default']) { - $params['pageSize'] = $pageSize; - } - } + if ($pageSize !== $this->emberNexusConfiguration->getPageSizeDefault()) { + $params['pageSize'] = $pageSize; } if ($currentRequest->query->has('sort')) { @@ -134,11 +122,6 @@ public function getPageLink(int $page = null): string ); } - public function buildEmptyCollection(): CollectionResponse - { - return $this->buildCollectionFromUuids([], [], 0); - } - /** * @param UuidInterface[] $nodeUuids * @param UuidInterface[] $relationUuids diff --git a/tests/FeatureTests/Endpoint/Scenario03PutElement/_E3_01_PutNodeTest.php b/tests/FeatureTests/Endpoint/Scenario03PutElement/_E3_01_PutNodeTest.php index 6a6e2d0b..5bab2b1c 100644 --- a/tests/FeatureTests/Endpoint/Scenario03PutElement/_E3_01_PutNodeTest.php +++ b/tests/FeatureTests/Endpoint/Scenario03PutElement/_E3_01_PutNodeTest.php @@ -28,6 +28,7 @@ public function testPutNode(): void 'test' => 'e3-01', ] ); + print_r((string) $response->getBody()); $this->assertNoContentResponse($response); $response = $this->runGetRequest(sprintf('/%s', self::DATA), self::TOKEN);