From d987eea8efb47893805adbead5c0e7730b02ba49 Mon Sep 17 00:00:00 2001 From: Mikolaj Adamczyk Date: Mon, 19 Mar 2018 17:17:42 +0100 Subject: [PATCH] EZP-28902: Creating a user with existing username results in Internal Server Error. (#2279) --- eZ/Publish/Core/FieldType/Tests/UserTest.php | 66 ++++++++++++++++++- eZ/Publish/Core/FieldType/User/Type.php | 55 ++++++++++++++++ eZ/Publish/Core/settings/fieldtypes.yml | 1 + .../Tests/FieldType/UserIntegrationTest.php | 4 +- 4 files changed, 124 insertions(+), 2 deletions(-) diff --git a/eZ/Publish/Core/FieldType/Tests/UserTest.php b/eZ/Publish/Core/FieldType/Tests/UserTest.php index 65ce415f297..fc6cd13e079 100644 --- a/eZ/Publish/Core/FieldType/Tests/UserTest.php +++ b/eZ/Publish/Core/FieldType/Tests/UserTest.php @@ -8,9 +8,11 @@ */ namespace eZ\Publish\Core\FieldType\Tests; +use eZ\Publish\Core\Persistence\Cache\UserHandler; use eZ\Publish\Core\FieldType\User\Type as UserType; use eZ\Publish\Core\FieldType\User\Value as UserValue; use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException; +use eZ\Publish\Core\FieldType\ValidationError; /** * @group fieldType @@ -31,7 +33,8 @@ class UserTest extends FieldTypeTest */ protected function createFieldTypeUnderTest() { - $fieldType = new UserType(); + $userHandler = $this->createMock(UserHandler::class); + $fieldType = new UserType($userHandler); $fieldType->setTransformationProcessor($this->getTransformationProcessorMock()); return $fieldType; @@ -295,6 +298,67 @@ public function provideInputForFromHash() ); } + /** + * Provides data sets with validator configuration and/or field settings and + * field value which are considered valid by the {@link validate()} method. + * + * @return array + */ + public function provideValidDataForValidate() + { + return [ + [ + [], + new UserValue([ + 'hasStoredLogin' => true, + 'contentId' => 23, + 'login' => 'sindelfingen', + 'email' => 'sindelfingen@example.com', + 'passwordHash' => '1234567890abcdef', + 'passwordHashType' => 'md5', + 'enabled' => true, + 'maxLogin' => 1000, + ]), + ], + ]; + } + + /** + * Provides data sets with validator configuration and/or field settings, + * field value and corresponding validation errors returned by + * the {@link validate()} method. + * + * @return array + */ + public function provideInvalidDataForValidate() + { + return [ + [ + [], + new UserValue([ + 'hasStoredLogin' => false, + 'contentId' => 23, + 'login' => 'sindelfingen', + 'email' => 'sindelfingen@example.com', + 'passwordHash' => '1234567890abcdef', + 'passwordHashType' => 'md5', + 'enabled' => true, + 'maxLogin' => 1000, + ]), + [ + new ValidationError( + "The user login '%login%' is used by another user. You must enter a unique login.", + null, + [ + '%login%' => 'sindelfingen', + ], + 'username' + ), + ], + ], + ]; + } + protected function provideFieldTypeIdentifier() { return 'ezuser'; diff --git a/eZ/Publish/Core/FieldType/User/Type.php b/eZ/Publish/Core/FieldType/User/Type.php index 5fe35b7417f..68e4a7c8446 100644 --- a/eZ/Publish/Core/FieldType/User/Type.php +++ b/eZ/Publish/Core/FieldType/User/Type.php @@ -9,9 +9,13 @@ namespace eZ\Publish\Core\FieldType\User; use eZ\Publish\Core\FieldType\FieldType; +use eZ\Publish\Core\FieldType\ValidationError; use eZ\Publish\SPI\FieldType\Value as SPIValue; use eZ\Publish\SPI\Persistence\Content\FieldValue; use eZ\Publish\Core\FieldType\Value as BaseValue; +use eZ\Publish\API\Repository\Values\ContentType\FieldDefinition; +use eZ\Publish\Core\Persistence\Cache\UserHandler; +use eZ\Publish\API\Repository\Exceptions\NotFoundException; /** * The User field type. @@ -20,6 +24,17 @@ */ class Type extends FieldType { + /** @var \eZ\Publish\Core\Persistence\Cache\UserHandler */ + protected $userHandler; + + /** + * @param \eZ\Publish\Core\Persistence\Cache\UserHandler $userHandler + */ + public function __construct(UserHandler $userHandler) + { + $this->userHandler = $userHandler; + } + /** * Returns the field type identifier for this field type. * @@ -190,4 +205,44 @@ public function fromPersistenceValue(FieldValue $fieldValue) { return $this->acceptValue($fieldValue->externalData); } + + /** + * Validates a field based on the validators in the field definition. + * + * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException + * + * @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition $fieldDefinition The field definition of the field + * @param \eZ\Publish\Core\FieldType\User\Value $fieldValue The field value for which an action is performed + * + * @return \eZ\Publish\SPI\FieldType\ValidationError[] + */ + public function validate(FieldDefinition $fieldDefinition, SPIValue $fieldValue) + { + $errors = []; + + if ($this->isEmptyValue($fieldValue)) { + return $errors; + } + + if (!$fieldValue->hasStoredLogin) { + try { + $login = $fieldValue->login; + $this->userHandler->loadByLogin($login); + + // If you want to change this ValidationError message, please remember to change it also in Repository Forms in lib/Validator/Constraints/FieldValueValidatorMessages class + $errors[] = new ValidationError( + "The user login '%login%' is used by another user. You must enter a unique login.", + null, + [ + '%login%' => $login, + ], + 'username' + ); + } catch (NotFoundException $e) { + // Do nothing + } + } + + return $errors; + } } diff --git a/eZ/Publish/Core/settings/fieldtypes.yml b/eZ/Publish/Core/settings/fieldtypes.yml index 61a4f1bd72a..b8a6f7729c9 100644 --- a/eZ/Publish/Core/settings/fieldtypes.yml +++ b/eZ/Publish/Core/settings/fieldtypes.yml @@ -439,6 +439,7 @@ services: ezpublish.fieldType.ezuser: class: "%ezpublish.fieldType.ezuser.class%" parent: ezpublish.fieldType + arguments: ["@ezpublish.spi.persistence.cache.userHandler"] tags: - {name: ezpublish.fieldType, alias: ezuser} diff --git a/eZ/Publish/SPI/Tests/FieldType/UserIntegrationTest.php b/eZ/Publish/SPI/Tests/FieldType/UserIntegrationTest.php index d13274bdf17..66881de75c9 100644 --- a/eZ/Publish/SPI/Tests/FieldType/UserIntegrationTest.php +++ b/eZ/Publish/SPI/Tests/FieldType/UserIntegrationTest.php @@ -14,6 +14,7 @@ use eZ\Publish\SPI\Persistence\Content\Field; use eZ\Publish\SPI\Persistence\Content\FieldTypeConstraints; use eZ\Publish\SPI\Persistence\User; +use eZ\Publish\Core\Persistence\Cache\UserHandler; /** * Integration test for legacy storage field types. @@ -54,7 +55,8 @@ public function getTypeName() */ public function getCustomHandler() { - $fieldType = new FieldType\User\Type(); + $userHandler = $this->createMock(UserHandler::class); + $fieldType = new FieldType\User\Type($userHandler); $fieldType->setTransformationProcessor($this->getTransformationProcessor()); return $this->getHandler(