Skip to content

Commit

Permalink
EZP-30394: Implemented External Storage for User Field Type (#2621)
Browse files Browse the repository at this point in the history
  • Loading branch information
ViniTou authored and lserwatka committed Sep 27, 2019
1 parent f81af13 commit 7901c99
Show file tree
Hide file tree
Showing 39 changed files with 1,172 additions and 1,159 deletions.
2 changes: 2 additions & 0 deletions doc/bc/changes-8.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ Changes affecting version compatibility with former or future versions.
* the namespace `eZ\Publish\Core\FieldType\RichText` has been dropped (all classes are available
in the mentioned package).

* Deprecated hash types constants have been dropped from `\eZ\Publish\API\Repository\Values\User\User`.

* Deprecated `eZ\Publish\SPI\FieldType\EventListener` interface, `eZ\Publish\SPI\FieldType\Event` class and
`eZ\Publish\SPI\FieldType\Events` namespace have been dropped.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

use eZ\Publish\Core\FieldType\FieldTypeRegistry;
use eZ\Publish\Core\MVC\ConfigResolverInterface;
use eZ\Publish\Core\Repository\User\PasswordHashGeneratorInterface;
use eZ\Publish\Core\Repository\Helper\RelationProcessor;
use eZ\Publish\Core\Search\Common\BackgroundIndexer;
use eZ\Publish\SPI\Persistence\Handler as PersistenceHandler;
Expand Down Expand Up @@ -70,6 +71,7 @@ public function __construct(
* @param \eZ\Publish\Core\Search\Common\BackgroundIndexer $backgroundIndexer
* @param \eZ\Publish\Core\Repository\Helper\RelationProcessor $relationProcessor
* @param \eZ\Publish\Core\FieldType\FieldTypeRegistry $fieldTypeRegistry
* @param \eZ\Publish\Core\Repository\User\PasswordHashGeneratorInterface $passwordHashGenerator
*
* @return \eZ\Publish\API\Repository\Repository
*/
Expand All @@ -78,7 +80,8 @@ public function buildRepository(
SearchHandler $searchHandler,
BackgroundIndexer $backgroundIndexer,
RelationProcessor $relationProcessor,
FieldTypeRegistry $fieldTypeRegistry
FieldTypeRegistry $fieldTypeRegistry,
PasswordHashGeneratorInterface $passwordHashGenerator
) {
$config = $this->container->get('ezpublish.api.repository_configuration_provider')->getRepositoryConfig();

Expand All @@ -88,6 +91,7 @@ public function buildRepository(
$backgroundIndexer,
$relationProcessor,
$fieldTypeRegistry,
$passwordHashGenerator,
[
'role' => [
'limitationTypes' => $this->roleLimitations,
Expand Down
32 changes: 24 additions & 8 deletions eZ/Publish/API/Repository/Tests/BaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
use eZ\Publish\API\Repository\Exceptions\ForbiddenException;
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
use eZ\Publish\API\Repository\Exceptions\UnauthorizedException;
use eZ\Publish\API\Repository\Tests\PHPUnitConstraint\AllValidationErrorsOccur as PHPUnitConstraintAllValidationErrorsOccur;
use eZ\Publish\API\Repository\Tests\PHPUnitConstraint\ValidationErrorOccurs as PHPUnitConstraintValidationErrorOccurs;
use eZ\Publish\API\Repository\Tests\SetupFactory\Legacy;
use eZ\Publish\API\Repository\Values\Content\Content;
use eZ\Publish\API\Repository\Values\Content\Language;
use eZ\Publish\API\Repository\Values\User\User;
use EzSystems\EzPlatformSolrSearchEngine\Tests\SetupFactory\LegacySetupFactory as LegacySolrSetupFactory;
use PHPUnit\Framework\TestCase;
use eZ\Publish\API\Repository\Repository;
Expand Down Expand Up @@ -295,12 +297,8 @@ private function assertPropertiesEqual($propertyName, $expectedValue, $actualVal

/**
* Create a user in editor user group.
*
* @param string $login
*
* @return \eZ\Publish\API\Repository\Values\User\User
*/
protected function createUserVersion1($login = 'user')
protected function createUserVersion1(string $login = 'user', ?string $email = null): User
{
$repository = $this->getRepository();

Expand All @@ -311,9 +309,10 @@ protected function createUserVersion1($login = 'user')
$userService = $repository->getUserService();

// Instantiate a create struct with mandatory properties
$email = $email ?? "{$login}@example.com";
$userCreate = $userService->newUserCreateStruct(
$login,
"{$login}@example.com",
$email,
'secret',
'eng-US'
);
Expand Down Expand Up @@ -669,13 +668,30 @@ public function performRawDatabaseOperation(callable $callback)
*/
protected function assertValidationErrorOccurs(
ContentFieldValidationException $exception,
$expectedValidationErrorMessage
) {
string $expectedValidationErrorMessage
): void {
$constraint = new PHPUnitConstraintValidationErrorOccurs($expectedValidationErrorMessage);

self::assertThat($exception, $constraint);
}

/**
* Traverse all errors for all fields in all Translations to find if all expected ones occurred.
*
* @param \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException $exception
* @param string[] $expectedValidationErrorMessages
*/
protected function assertAllValidationErrorsOccur(
ContentFieldValidationException $exception,
array $expectedValidationErrorMessages
): void {
$constraint = new PHPUnitConstraintAllValidationErrorsOccur(
$expectedValidationErrorMessages
);

self::assertThat($exception, $constraint);
}

/**
* Create 'folder' Content.
*
Expand Down
109 changes: 77 additions & 32 deletions eZ/Publish/API/Repository/Tests/FieldType/UserIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
*/
namespace eZ\Publish\API\Repository\Tests\FieldType;

use Doctrine\DBAL\Exception\NotNullConstraintViolationException;
use eZ\Publish\API\Repository\Exceptions\BadStateException;
use eZ\Publish\API\Repository\Exceptions\ForbiddenException;
use eZ\Publish\API\Repository\Values\ContentType\ContentType;
use eZ\Publish\API\Repository\Values\ContentType\FieldDefinition;
use eZ\Publish\Core\FieldType\User\Type;
Expand All @@ -23,6 +26,8 @@
*/
class UserIntegrationTest extends BaseIntegrationTest
{
private const TEST_LOGIN = 'hans';

/**
* Get name of tested field type.
*
Expand Down Expand Up @@ -143,11 +148,16 @@ public function getInvalidValidatorConfiguration()
/**
* Get initial field externals data.
*
* @return array
* @return \eZ\Publish\Core\FieldType\User\Value
*/
public function getValidCreationFieldData()
public function getValidCreationFieldData(): UserValue
{
return new UserValue(['login' => 'hans']);
return new UserValue([
'login' => self::TEST_LOGIN,
'email' => sprintf('%s@example.com', self::TEST_LOGIN),
'enabled' => true,
'plainPassword' => 'PassWord42',
]);
}

/**
Expand All @@ -157,7 +167,7 @@ public function getValidCreationFieldData()
*/
public function getFieldName()
{
return 'hans';
return self::TEST_LOGIN;
}

/**
Expand All @@ -171,13 +181,13 @@ public function getFieldName()
public function assertFieldDataLoadedCorrect(Field $field)
{
$this->assertInstanceOf(
'eZ\\Publish\\Core\\FieldType\\User\\Value',
UserValue::class,
$field->value
);

$expectedData = [
'hasStoredLogin' => true,
'login' => 'hans',
'login' => self::TEST_LOGIN,
'email' => 'hans@example.com',
'passwordHashType' => User::PASSWORD_HASH_PHP_DEFAULT,
'enabled' => true,
Expand Down Expand Up @@ -225,17 +235,18 @@ public function testCreateContentFails($failingValue = null, $expectedException
/**
* Get update field externals data.
*
* @return array
* @return \eZ\Publish\Core\FieldType\User\Value
*/
public function getValidUpdateFieldData()
{
return new UserValue(
[
'login' => 'change', // Change is intended to not get through
'email' => 'change', // Change is intended to not get through
'passwordHash' => 'change', // Change is intended to not get through
'passwordHashType' => 'change', // Change is intended to not get through
'enabled' => 'change', // Change is intended to not get through
'hasStoredLogin' => true,
'login' => 'changeLogin',
'email' => 'changeEmail@ez.no',
'passwordHash' => '*2',
'passwordHashType' => 1,
'enabled' => false,
]
);
}
Expand All @@ -249,8 +260,25 @@ public function getValidUpdateFieldData()
*/
public function assertUpdatedFieldDataLoadedCorrect(Field $field)
{
// No update possible through field type
$this->assertFieldDataLoadedCorrect($field);
$this->assertInstanceOf(
UserValue::class,
$field->value
);

$expectedData = [
'hasStoredLogin' => true,
'login' => 'changeLogin',
'email' => 'changeEmail@ez.no',
'passwordHashType' => 1,
'enabled' => false,
];

$this->assertPropertiesCorrect(
$expectedData,
$field->value
);

$this->assertNotNull($field->value->contentId);
}

/**
Expand Down Expand Up @@ -279,7 +307,7 @@ public function provideInvalidUpdateFieldData()
return [
[
null,
'eZ\\Publish\\Core\\Base\\Exceptions\\ContentValidationException',
NotNullConstraintViolationException::class,
],
// @todo: Define more failure cases ...
];
Expand All @@ -296,7 +324,7 @@ public function provideInvalidUpdateFieldData()
public function assertCopiedFieldDataLoadedCorrectly(Field $field)
{
$this->assertInstanceOf(
'eZ\\Publish\\Core\\FieldType\\User\\Value',
UserValue::class,
$field->value
);

Expand Down Expand Up @@ -341,16 +369,17 @@ public function provideToHashData()
{
return [
[
new UserValue(['login' => 'hans']),
new UserValue(['login' => self::TEST_LOGIN]),
[
'login' => 'hans',
'login' => self::TEST_LOGIN,
'hasStoredLogin' => null,
'contentId' => null,
'email' => null,
'passwordHash' => null,
'passwordHashType' => null,
'enabled' => null,
'maxLogin' => null,
'plainPassword' => null,
'passwordUpdatedAt' => null,
],
],
Expand Down Expand Up @@ -381,8 +410,8 @@ public function provideFromHashData()
{
return [
[
['login' => 'hans'],
new UserValue(['login' => 'hans']),
['login' => self::TEST_LOGIN],
new UserValue(['login' => self::TEST_LOGIN]),
],
];
}
Expand All @@ -403,7 +432,7 @@ protected function createContent($fieldData, $contentType = null)

// Instantiate a create struct with mandatory properties
$userCreate = $userService->newUserCreateStruct(
'hans',
self::TEST_LOGIN,
'hans@example.com',
'PassWord42',
'eng-US',
Expand Down Expand Up @@ -472,22 +501,38 @@ public function testRemoveFieldDefinition()

public function testAddFieldDefinition()
{
$this->markTestIncomplete(
'Currently cannot be tested since user can be properly created only through UserService'
);
// Field cannot be added to ContentType with existing content.
$this->expectException(BadStateException::class);

return parent::testAddFieldDefinition();
}

/**
* @param mixed $failingValue
* @param string $expectedException
*
* @dataProvider provideInvalidUpdateFieldData
* @depends testCreateContent
*/
public function testUpdateContentFails($failingValue, $expectedException)
public function testCopyField($content)
{
$this->markTestIncomplete(
'Currently cannot be tested since user can be properly created only through UserService'
);
// Users cannot be copied.
$this->expectException(ForbiddenException::class);
$this->expectExceptionMessage(sprintf('User "%s" already exists', self::TEST_LOGIN));

return parent::testCopyField($content);
}

/**
* @depends testCopyField
*/
public function testCopiedFieldType($content)
{
$this->markTestSkipped('Users cannot be copied, content is not passed to test.');
}

/**
* @depends testCopiedFieldType
*/
public function testCopiedExternalData(Field $field)
{
$this->markTestSkipped('Users cannot be copied, field is not passed to test.');
}

/**
Expand Down
Loading

0 comments on commit 7901c99

Please sign in to comment.