diff --git a/eZ/Publish/API/Repository/Tests/BaseTest.php b/eZ/Publish/API/Repository/Tests/BaseTest.php index a22596020b..7b0c52a514 100644 --- a/eZ/Publish/API/Repository/Tests/BaseTest.php +++ b/eZ/Publish/API/Repository/Tests/BaseTest.php @@ -299,7 +299,7 @@ private function assertPropertiesEqual($propertyName, $expectedValue, $actualVal /** * Create a user in editor user group. */ - protected function createUserVersion1(string $login = 'user', ?string $email = null): User + protected function createUserVersion1(string $login = 'user', ?string $email = null, ContentType $contentType = null): User { $repository = $this->getRepository(); @@ -314,7 +314,7 @@ protected function createUserVersion1(string $login = 'user', ?string $email = n $userCreate = $userService->newUserCreateStruct( $login, $email, - 'secret', + 'VerySecret@Password.1234', 'eng-US' ); $userCreate->enabled = true; @@ -323,6 +323,10 @@ protected function createUserVersion1(string $login = 'user', ?string $email = n $userCreate->setField('first_name', 'Example'); $userCreate->setField('last_name', 'User'); + if (!empty($contentType)) { + $userCreate->contentType = $contentType; + } + // Load parent group for the user $group = $userService->loadUserGroup($editorsGroupId); diff --git a/eZ/Publish/API/Repository/Tests/FieldType/UserIntegrationTest.php b/eZ/Publish/API/Repository/Tests/FieldType/UserIntegrationTest.php index 60a8497ad8..396ffd3d0f 100644 --- a/eZ/Publish/API/Repository/Tests/FieldType/UserIntegrationTest.php +++ b/eZ/Publish/API/Repository/Tests/FieldType/UserIntegrationTest.php @@ -54,6 +54,14 @@ public function getSettingsSchema() 'type' => 'int', 'default' => null, ], + 'RequireUniqueEmail' => [ + 'type' => 'bool', + 'default' => true, + ], + 'UsernamePattern' => [ + 'type' => 'string', + 'default' => '^[^@]+$', + ], ]; } @@ -67,6 +75,8 @@ public function getValidFieldSettings() return [ 'PasswordTTL' => null, 'PasswordTTLWarning' => null, + 'RequireUniqueEmail' => false, + 'UsernamePattern' => '.*', ]; } @@ -553,6 +563,8 @@ public function testUpdateFieldDefinitionWithIncompleteSettingsSchema() $userFieldDefinitionUpdateStruct = $contentTypeService->newFieldDefinitionUpdateStruct(); $userFieldDefinitionUpdateStruct->fieldSettings = [ Type::PASSWORD_TTL_WARNING_SETTING => null, + Type::REQUIRE_UNIQUE_EMAIL => false, + Type::USERNAME_PATTERN => '.*', ]; $contentTypeService->updateFieldDefinition($contentTypeDraft, $userFieldDefinition, $userFieldDefinitionUpdateStruct); diff --git a/eZ/Publish/API/Repository/Tests/UserServiceTest.php b/eZ/Publish/API/Repository/Tests/UserServiceTest.php index 76909c64ce..9ea8711b7a 100644 --- a/eZ/Publish/API/Repository/Tests/UserServiceTest.php +++ b/eZ/Publish/API/Repository/Tests/UserServiceTest.php @@ -23,6 +23,7 @@ use eZ\Publish\API\Repository\Values\User\UserTokenUpdateStruct; use eZ\Publish\API\Repository\Values\User\UserUpdateStruct; use eZ\Publish\API\Repository\Values\User\User; +use eZ\Publish\Core\FieldType\User\Type; use eZ\Publish\Core\FieldType\ValidationError; use eZ\Publish\Core\Repository\Values\Content\Content; use eZ\Publish\Core\Repository\Values\Content\VersionInfo; @@ -190,7 +191,6 @@ public function testLoadSubUserGroupsThrowsNotFoundException() * @return \eZ\Publish\API\Repository\Values\User\UserGroupCreateStruct * * @see \eZ\Publish\API\Repository\UserService::newUserGroupCreateStruct() - * @depends eZ\Publish\API\Repository\Tests\ContentTypeServiceTest::testLoadContentTypeByIdentifier */ public function testNewUserGroupCreateStruct() { @@ -244,7 +244,6 @@ public function testNewUserGroupCreateStructSetsContentType($groupCreate) * * @see \eZ\Publish\API\Repository\UserService::newUserGroupCreateStruct($mainLanguageCode, $contentType) * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserGroupCreateStruct - * @depends eZ\Publish\API\Repository\Tests\ContentTypeServiceTest::testLoadContentTypeByIdentifier */ public function testNewUserGroupCreateStructWithSecondParameter() { @@ -279,7 +278,6 @@ public function testNewUserGroupCreateStructWithSecondParameter() * @see \eZ\Publish\API\Repository\UserService::createUserGroup() * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserGroupCreateStruct * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroup - * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent */ public function testCreateUserGroup() { @@ -427,7 +425,6 @@ public function testCreateUserGroupWhenMissingField() * @see \eZ\Publish\API\Repository\UserService::createUserGroup() * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserGroupCreateStruct * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroup - * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent */ public function testCreateUserGroupInTransactionWithRollback() { @@ -864,7 +861,6 @@ public function testNewUserCreateStructSetsExpectedProperties($userCreate) * * @see \eZ\Publish\API\Repository\UserService::newUserCreateStruct($login, $email, $password, $mainLanguageCode, $contentType) * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserCreateStruct - * @depends eZ\Publish\API\Repository\Tests\ContentTypeServiceTest::testLoadContentTypeByIdentifier */ public function testNewUserCreateStructWithFifthParameter() { @@ -916,7 +912,6 @@ public function testNewUserWithDomainName() * @see \eZ\Publish\API\Repository\UserService::createUser() * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroup * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserCreateStruct - * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent */ public function testCreateUser() { @@ -1084,6 +1079,114 @@ public function testCreateUserThrowsInvalidArgumentException() $this->fail('Expected ValidationError messages did not occur.'); } + /** + * Test for the createUser() method. + * + * @covers \eZ\Publish\API\Repository\UserService::createUser + * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser + */ + public function testCreateUserWithEmailAlreadyTaken(): void + { + $repository = $this->getRepository(); + + $userContentType = $this->createUserContentTypeWithAccountSettings('user_email_unique', [ + Type::REQUIRE_UNIQUE_EMAIL => true, + ]); + + $existingUser = $this->createUserVersion1( + 'existing_user', + 'unique@email.com', + $userContentType, + ); + + $editorsGroupId = $this->generateId('group', 13); + /* BEGIN: Use Case */ + // $editorsGroupId is the ID of the "Editors" user group in an eZ + // Publish demo installation + + $userService = $repository->getUserService(); + + // Instantiate a create struct with mandatory properties + $userCreate = $userService->newUserCreateStruct( + 'another_user', + // email is already taken + 'unique@email.com', + 'VerySecure@Password.1234', + 'eng-US', + $userContentType + ); + + $userCreate->setField('first_name', 'Example'); + $userCreate->setField('last_name', 'User'); + + // Load parent group for the user + $group = $userService->loadUserGroup($editorsGroupId); + + try { + // This call will fail with a "ContentFieldValidationException", because the + // user with "unique@email.com" email already exists in database. + $userService->createUser($userCreate, [$group]); + } catch (ContentFieldValidationException $e) { + // Exception is caught, as there is no other way to check exception properties. + $this->assertValidationErrorOccurs($e, 'Email \'%email%\' is used by another user. You must enter a unique email.'); + + return; + } + + $this->fail('Expected ValidationError messages did not occur.'); + } + + /** + * Test for the createUser() method. + * + * @covers \eZ\Publish\API\Repository\UserService::createUser + * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser + */ + public function testCreateInvalidFormatUsername(): void + { + $repository = $this->getRepository(); + + $userContentType = $this->createUserContentTypeWithAccountSettings('username_format', [ + Type::USERNAME_PATTERN => '^[^@]$', + ]); + + $editorsGroupId = $this->generateId('group', 13); + /* BEGIN: Use Case */ + // $editorsGroupId is the ID of the "Editors" user group in an eZ + // Publish demo installation + + $userService = $repository->getUserService(); + + // Instantiate a create struct with mandatory properties + $userCreate = $userService->newUserCreateStruct( + // login contains @ + 'invalid@user', + 'unique@email.com', + 'VerySecure@Password.1234', + 'eng-US', + $userContentType + ); + + $userCreate->setField('first_name', 'Example'); + $userCreate->setField('last_name', 'User'); + + // Load parent group for the user + $group = $userService->loadUserGroup($editorsGroupId); + + try { + // This call will fail with a "ContentFieldValidationException", because the + // user with "invalid@user" login does not match "^[^@]$" pattern. + $userService->createUser($userCreate, [$group]); + } catch (ContentFieldValidationException $e) { + // Exception is caught, as there is no other way to check exception properties. + $this->assertValidationErrorOccurs($e, 'Invalid login format'); + + return; + } + + $this->fail('Expected ValidationError messages did not occur.'); + } + /** * Test for the createUser() method. * @@ -1092,7 +1195,6 @@ public function testCreateUserThrowsInvalidArgumentException() * @see \eZ\Publish\API\Repository\UserService::createUser() * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroup * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserCreateStruct - * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent */ public function testCreateUserInTransactionWithRollback() { @@ -1253,7 +1355,7 @@ public function testLoadUserThrowsNotFoundException() /** * @see \eZ\Publish\API\Repository\UserService::checkUserCredentials() - * @depends \eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser + * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser */ public function testCheckUserCredentialsValid(): void { @@ -1265,7 +1367,7 @@ public function testCheckUserCredentialsValid(): void $user = $this->createUserVersion1(); // Load the newly created user credentials - $credentialsValid = $userService->loadUserByCredentials($user, 'secret'); + $credentialsValid = $userService->checkUserCredentials($user, 'VerySecret@Password.1234'); /* END: Use Case */ $this->assertTrue($credentialsValid); @@ -1273,7 +1375,7 @@ public function testCheckUserCredentialsValid(): void /** * @see \eZ\Publish\API\Repository\UserService::checkUserCredentials() - * @depends \eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser + * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser */ public function testCheckUserCredentialsInvalid(): void { @@ -1285,7 +1387,7 @@ public function testCheckUserCredentialsInvalid(): void $user = $this->createUserVersion1(); // Load the newly created user credentials - $credentialsValid = $userService->loadUserByCredentials($user, '1234'); + $credentialsValid = $userService->checkUserCredentials($user, 'NotSoSecretPassword'); /* END: Use Case */ $this->assertFalse($credentialsValid); @@ -1559,8 +1661,6 @@ public function testNewUserUpdateStruct() * @see \eZ\Publish\API\Repository\UserService::updateUser() * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserUpdateStruct - * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent - * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata */ public function testUpdateUser() { @@ -1623,8 +1723,6 @@ public function testUpdateUserEmail(): void * @see \eZ\Publish\API\Repository\UserService::updateUser() * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserUpdateStruct - * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent - * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata */ public function testUpdateUserNoPassword() { @@ -3031,7 +3129,7 @@ private function createUserContentTypeWithAccountSettings( $typeCreate->addFieldDefinition($lastNameFieldCreate); - $accountFieldCreateStruct = $contentTypeService->newFieldDefinitionCreateStruct('account', 'ezuser'); + $accountFieldCreateStruct = $contentTypeService->newFieldDefinitionCreateStruct('user_account', 'ezuser'); $accountFieldCreateStruct->names = [ 'eng-GB' => 'User account', ]; diff --git a/eZ/Publish/Core/FieldType/Tests/UserTest.php b/eZ/Publish/Core/FieldType/Tests/UserTest.php index 480b94119c..c4418b36d6 100644 --- a/eZ/Publish/Core/FieldType/Tests/UserTest.php +++ b/eZ/Publish/Core/FieldType/Tests/UserTest.php @@ -18,6 +18,8 @@ use eZ\Publish\Core\Persistence\Cache\UserHandler; use eZ\Publish\Core\Repository\User\PasswordHashServiceInterface; use eZ\Publish\Core\Repository\User\PasswordValidatorInterface; +use eZ\Publish\Core\Repository\Values\ContentType\FieldDefinition as CoreFieldDefinition; +use eZ\Publish\SPI\Persistence\User; use PHPUnit\Framework\MockObject\Builder\InvocationMocker; /** @@ -102,6 +104,14 @@ protected function getSettingsSchemaExpectation() 'type' => 'int', 'default' => null, ], + UserType::REQUIRE_UNIQUE_EMAIL => [ + 'type' => 'bool', + 'default' => true, + ], + UserType::USERNAME_PATTERN => [ + 'type' => 'string', + 'default' => '^[^@]+$', + ], ]; } @@ -415,6 +425,200 @@ public function testValidate( self::assertEquals($expectedValidationErrors, $validationErrors); } + public function testInvalidLoginFormat(): void + { + $validateUserValue = new UserValue([ + 'hasStoredLogin' => false, + 'contentId' => 46, + 'login' => 'validate@user', + 'email' => 'example@test.ez', + 'passwordHash' => '1234567890abcdef', + 'passwordHashType' => 'md5', + 'enabled' => true, + 'maxLogin' => 1000, + 'plainPassword' => 'testPassword', + ]); + + $userHandlerMock = $this->createMock(UserHandler::class); + + $userHandlerMock + ->expects($this->once()) + ->method('loadByLogin') + ->with($validateUserValue->login) + ->willThrowException(new NotFoundException('', '')); + + $userType = new UserType( + $userHandlerMock, + $this->createMock(PasswordHashServiceInterface::class), + $this->createMock(PasswordValidatorInterface::class) + ); + + $fieldSettings = [ + UserType::REQUIRE_UNIQUE_EMAIL => false, + UserType::USERNAME_PATTERN => '^[^@]+$', + ]; + + $fieldDefinition = new CoreFieldDefinition(['fieldSettings' => $fieldSettings]); + + $validationErrors = $userType->validate($fieldDefinition, $validateUserValue); + + self::assertEquals([ + new ValidationError( + 'Invalid login format', + null, + [], + 'username' + ), + ], $validationErrors); + } + + public function testValidLoginFormat(): void + { + $validateUserValue = new UserValue([ + 'hasStoredLogin' => false, + 'contentId' => 46, + 'login' => 'validate_user', + 'email' => 'example@test.ez', + 'passwordHash' => '1234567890abcdef', + 'passwordHashType' => 'md5', + 'enabled' => true, + 'maxLogin' => 1000, + 'plainPassword' => 'testPassword', + ]); + + $userHandlerMock = $this->createMock(UserHandler::class); + + $userHandlerMock + ->expects($this->once()) + ->method('loadByLogin') + ->with($validateUserValue->login) + ->willThrowException(new NotFoundException('', '')); + + $userType = new UserType( + $userHandlerMock, + $this->createMock(PasswordHashServiceInterface::class), + $this->createMock(PasswordValidatorInterface::class) + ); + + $fieldSettings = [ + UserType::REQUIRE_UNIQUE_EMAIL => false, + UserType::USERNAME_PATTERN => '^[^@]+$', + ]; + + $fieldDefinition = new CoreFieldDefinition(['fieldSettings' => $fieldSettings]); + + $validationErrors = $userType->validate($fieldDefinition, $validateUserValue); + + self::assertEquals([], $validationErrors); + } + + public function testEmailAlreadyTaken(): void + { + $existingUser = new User([ + 'id' => 23, + 'login' => 'existing_user', + 'email' => 'test@test.ez', + ]); + + $validateUserValue = new UserValue([ + 'hasStoredLogin' => false, + 'contentId' => 46, + 'login' => 'validate_user', + 'email' => 'test@test.ez', + 'passwordHash' => '1234567890abcdef', + 'passwordHashType' => 'md5', + 'enabled' => true, + 'maxLogin' => 1000, + 'plainPassword' => 'testPassword', + ]); + + $userHandlerMock = $this->createMock(UserHandler::class); + + $userHandlerMock + ->expects($this->once()) + ->method('loadByLogin') + ->with($validateUserValue->login) + ->willThrowException(new NotFoundException('', '')); + + $userHandlerMock + ->expects($this->once()) + ->method('loadByEmail') + ->with($validateUserValue->email) + ->willReturn($existingUser); + + $userType = new UserType( + $userHandlerMock, + $this->createMock(PasswordHashServiceInterface::class), + $this->createMock(PasswordValidatorInterface::class) + ); + + $fieldSettings = [ + UserType::REQUIRE_UNIQUE_EMAIL => true, + UserType::USERNAME_PATTERN => '^[^@]+$', + ]; + + $fieldDefinition = new CoreFieldDefinition(['fieldSettings' => $fieldSettings]); + + $validationErrors = $userType->validate($fieldDefinition, $validateUserValue); + + self::assertEquals([ + new ValidationError( + "Email '%email%' is used by another user. You must enter a unique email.", + null, + [ + '%email%' => $validateUserValue->email, + ], + 'email' + ), + ], $validationErrors); + } + + public function testEmailFreeToUse(): void + { + $validateUserValue = new UserValue([ + 'hasStoredLogin' => false, + 'contentId' => 46, + 'login' => 'validate_user', + 'email' => 'test@test.ez', + 'passwordHash' => '1234567890abcdef', + 'passwordHashType' => 'md5', + 'enabled' => true, + 'maxLogin' => 1000, + 'plainPassword' => 'testPassword', + ]); + + $userHandlerMock = $this->createMock(UserHandler::class); + + $userHandlerMock + ->expects($this->once()) + ->method('loadByLogin') + ->with($validateUserValue->login) + ->willThrowException(new NotFoundException('', '')); + + $userHandlerMock + ->expects($this->once()) + ->method('loadByEmail') + ->with($validateUserValue->email) + ->willThrowException(new NotFoundException('', '')); + + $userType = new UserType( + $userHandlerMock, + $this->createMock(PasswordHashServiceInterface::class), + $this->createMock(PasswordValidatorInterface::class) + ); + + $fieldSettings = [ + UserType::REQUIRE_UNIQUE_EMAIL => true, + UserType::USERNAME_PATTERN => '^[^@]+$', + ]; + + $fieldDefinition = new CoreFieldDefinition(['fieldSettings' => $fieldSettings]); + + $validationErrors = $userType->validate($fieldDefinition, $validateUserValue); + + self::assertEquals([], $validationErrors); + } + /** * Data provider for testValidate test. * @@ -543,6 +747,8 @@ public function provideValidFieldSettings(): array [ UserType::PASSWORD_TTL_SETTING => 30, UserType::PASSWORD_TTL_WARNING_SETTING => 14, + UserType::REQUIRE_UNIQUE_EMAIL => true, + UserType::USERNAME_PATTERN => '^[^!]+$', ], ], ]; diff --git a/eZ/Publish/Core/FieldType/User/Type.php b/eZ/Publish/Core/FieldType/User/Type.php index 1ea22b37e2..c7b5fcfe29 100644 --- a/eZ/Publish/Core/FieldType/User/Type.php +++ b/eZ/Publish/Core/FieldType/User/Type.php @@ -20,6 +20,7 @@ use eZ\Publish\Core\FieldType\Value as BaseValue; use eZ\Publish\API\Repository\Values\ContentType\FieldDefinition; use eZ\Publish\API\Repository\Exceptions\NotFoundException; +use LogicException; /** * The User field type. @@ -30,6 +31,8 @@ class Type extends FieldType { public const PASSWORD_TTL_SETTING = 'PasswordTTL'; public const PASSWORD_TTL_WARNING_SETTING = 'PasswordTTLWarning'; + public const REQUIRE_UNIQUE_EMAIL = 'RequireUniqueEmail'; + public const USERNAME_PATTERN = 'UsernamePattern'; /** @var array */ protected $settingsSchema = [ @@ -41,6 +44,14 @@ class Type extends FieldType 'type' => 'int', 'default' => null, ], + self::REQUIRE_UNIQUE_EMAIL => [ + 'type' => 'bool', + 'default' => true, + ], + self::USERNAME_PATTERN => [ + 'type' => 'string', + 'default' => '^[^@]+$', + ], ]; /** @var array */ @@ -300,6 +311,17 @@ public function validate(FieldDefinition $fieldDefinition, SPIValue $fieldValue) ); } + $pattern = sprintf('/%s/', $fieldDefinition->fieldSettings[self::USERNAME_PATTERN]); + $loginFormatValid = preg_match($pattern, $fieldValue->login); + if (!$fieldValue->hasStoredLogin && !$loginFormatValid) { + $errors[] = new ValidationError( + 'Invalid login format', + null, + [], + 'username' + ); + } + if (!is_string($fieldValue->email) || empty($fieldValue->email)) { $errors[] = new ValidationError( 'Email required', @@ -339,7 +361,7 @@ public function validate(FieldDefinition $fieldDefinition, SPIValue $fieldValue) $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 + // If you want to change this ValidationError message, please remember to change it also in Content 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, @@ -353,6 +375,32 @@ public function validate(FieldDefinition $fieldDefinition, SPIValue $fieldValue) } } + if ($fieldDefinition->fieldSettings[self::REQUIRE_UNIQUE_EMAIL]) { + try { + $email = $fieldValue->email; + try { + $user = $this->userHandler->loadByEmail($email); + } catch (LogicException $exception) { + // There are multiple users with the same email + } + + // Don't prevent email update + if (empty($user) || $user->id != $fieldValue->contentId) { + // If you want to change this ValidationError message, please remember to change it also in Content Forms in lib/Validator/Constraints/FieldValueValidatorMessages class + $errors[] = new ValidationError( + "Email '%email%' is used by another user. You must enter a unique email.", + null, + [ + '%email%' => $email, + ], + 'email' + ); + } + } catch (NotFoundException $e) { + // Do nothing + } + } + if (!empty($fieldValue->plainPassword)) { $passwordValidationErrors = $this->passwordValidator->validatePassword( $fieldValue->plainPassword, diff --git a/eZ/Publish/Core/Persistence/Legacy/Content/FieldValue/Converter/UserConverter.php b/eZ/Publish/Core/Persistence/Legacy/Content/FieldValue/Converter/UserConverter.php index 96d69ff527..9eb0d0a816 100644 --- a/eZ/Publish/Core/Persistence/Legacy/Content/FieldValue/Converter/UserConverter.php +++ b/eZ/Publish/Core/Persistence/Legacy/Content/FieldValue/Converter/UserConverter.php @@ -25,6 +25,7 @@ class UserConverter implements Converter private const REQUIRE_AT_LEAST_ONE_NUMERIC_CHAR = 4; private const REQUIRE_AT_LEAST_ONE_NON_ALPHANUMERIC_CHAR = 8; private const REQUIRE_NEW_PASSWORD = 16; + private const REQUIRE_UNIQUE_EMAIL = 32; /** * {@inheritdoc} @@ -60,6 +61,8 @@ public function toStorageFieldDefinition(FieldDefinition $fieldDef, StorageField 'requireNewPassword' => self::REQUIRE_NEW_PASSWORD, ]; + $fieldSettings = $fieldDef->fieldTypeConstraints->fieldSettings; + $storageDef->dataInt1 = 0; foreach ($rules as $rule => $flag) { if (isset($validatorParameters[$rule]) && $validatorParameters[$rule]) { @@ -67,15 +70,19 @@ public function toStorageFieldDefinition(FieldDefinition $fieldDef, StorageField } } + $storageDef->dataInt1 |= $fieldSettings[UserType::REQUIRE_UNIQUE_EMAIL] + ? self::REQUIRE_UNIQUE_EMAIL + : 0; + $storageDef->dataInt2 = null; if (isset($validatorParameters['minLength'])) { $storageDef->dataInt2 = $validatorParameters['minLength']; } - $fieldSettings = $fieldDef->fieldTypeConstraints->fieldSettings; - $storageDef->dataInt3 = $fieldSettings[UserType::PASSWORD_TTL_SETTING] ?? null; $storageDef->dataInt4 = $fieldSettings[UserType::PASSWORD_TTL_WARNING_SETTING] ?? null; + + $storageDef->dataText2 = $fieldSettings[UserType::USERNAME_PATTERN]; } /** @@ -103,6 +110,8 @@ public function toFieldDefinition(StorageFieldDefinition $storageDef, FieldDefin $fieldDef->fieldTypeConstraints->fieldSettings = new FieldSettings([ UserType::PASSWORD_TTL_SETTING => $storageDef->dataInt3, UserType::PASSWORD_TTL_WARNING_SETTING => $storageDef->dataInt4, + UserType::REQUIRE_UNIQUE_EMAIL => (bool)($storageDef->dataInt1 & self::REQUIRE_UNIQUE_EMAIL), + UserType::USERNAME_PATTERN => $storageDef->dataText2, ]); }