Completed
Push — ezp-31420-merge-up ( ec14fb...141a64 )
by
unknown
40:13 queued 27:42
created

UserServiceTest   F

Complexity

Total Complexity 136

Size/Duplication

Total Lines 3032
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 32

Importance

Changes 0
Metric Value
dl 0
loc 3032
rs 0.8
c 0
b 0
f 0
wmc 136
lcom 1
cbo 32

99 Methods

Rating   Name   Duplication   Size   Complexity  
A testLoadSubUserGroups() 0 19 2
A testLoadUserGroup() 0 20 1
A testLoadUserGroupWithNoAccessToParent() 0 29 1
A testLoadUserGroupThrowsNotFoundException() 0 14 1
A testLoadSubUserGroupsThrowsNotFoundException() 0 25 1
A testNewUserGroupCreateStruct() 0 17 1
A testNewUserGroupCreateStructSetsMainLanguageCode() 0 4 1
A testNewUserGroupCreateStructSetsContentType() 0 7 1
A testNewUserGroupCreateStructWithSecondParameter() 0 24 2
A testCreateUserGroup() 0 18 1
A testCreateUserGroupSetsExpectedProperties() 0 11 1
A testCreateUserGroupThrowsInvalidArgumentException() 0 28 1
A testCreateUserGroupThrowsInvalidArgumentExceptionFieldTypeNotAccept() 0 27 1
A testCreateUserGroupWhenMissingField() 0 23 1
A testCreateUserGroupInTransactionWithRollback() 0 43 3
A testDeleteUserGroup() 0 17 1
A testDeleteUserGroupThrowsNotFoundException() 0 21 1
A testMoveUserGroup() 0 39 1
A testMoveUserGroupThrowsNotFoundException() 0 33 1
A testNewUserGroupUpdateStruct() 0 18 1
A testUpdateUserGroup() 0 25 1
A testUpdateUserGroupWithSubContentUpdateStruct() 0 33 1
A testUpdateUserGroupWithSubContentMetadataUpdateStruct() 0 36 1
A testUpdateUserGroupThrowsInvalidArgumentExceptionOnFieldTypeNotAccept() 0 27 1
A testNewUserCreateStruct() 0 22 1
A testUpdateUserGroupThrowsContentFieldValidationExceptionOnRequiredFieldEmpty() 0 15 1
A testNewUserCreateStructSetsExpectedProperties() 0 17 1
A testNewUserCreateStructWithFifthParameter() 0 25 2
A testNewUserWithDomainName() 0 12 1
A testCreateUser() 0 13 1
A testCreateUserSetsExpectedProperties() 0 15 1
A testCreateUserWhenMissingField() 0 33 1
A testCreateUserThrowsInvalidArgumentExceptionOnFieldTypeNotAccept() 0 33 1
A testCreateUserThrowsInvalidArgumentException() 0 41 2
A testCreateUserInTransactionWithRollback() 0 28 3
A testCreateUserThrowsNotFoundException() 0 27 1
A testCreateUserWithWeakPasswordThrowsUserPasswordValidationException() 0 25 2
A testCreateUserWithStrongPassword() 0 10 1
A testLoadUser() 0 19 1
A testLoadUserThrowsNotFoundException() 0 15 1
A testCheckUserCredentialsValid() 0 15 1
A testCheckUserCredentialsInvalid() 0 15 1
A testLoadUserByLogin() 0 29 1
A testLoadUserByLoginThrowsNotFoundExceptionForUnknownLogin() 0 16 1
A testLoadUserByLoginWorksForLoginWithWrongCase() 0 29 1
A testLoadUserByLoginThrowsNotFoundExceptionForUnknownLoginByEmail() 0 15 1
A testLoadUserByEmail() 0 15 1
A testLoadUserByEmailReturnsEmptyInUnknownEmail() 0 16 1
A testDeleteUser() 0 18 1
A testDeleteUserDeletesRelatedBookmarks() 0 27 1
A testNewUserUpdateStruct() 0 29 1
A testUpdateUser() 0 25 1
A testUpdateUserEmail() 0 23 1
A testUpdateUserNoPassword() 0 40 1
A testUpdateUserUpdatesExpectedProperties() 0 17 1
A testUpdateUserReturnsPublishedVersion() 0 7 1
A testUpdateUserWithContentMetadataUpdateStruct() 0 31 1
A testUpdateUserWithContentUpdateStruct() 0 35 1
A testUpdateUserWhenMissingField() 0 30 1
A testUpdateUserThrowsInvalidArgumentExceptionOnFieldTypeNotAccept() 0 30 1
A testUpdateUserWithWeakPasswordThrowsUserPasswordValidationException() 0 29 2
A testUpdateUserWithStrongPassword() 0 16 1
A testLoadUserGroupsOfUser() 0 19 2
A testLoadUsersOfUserGroup() 0 21 2
A testAssignUserToUserGroup() 0 35 2
A testAssignUserToUserGroupThrowsInvalidArgumentException() 0 22 1
A testUnAssignUserFromUserGroup() 0 35 2
A testUnAssignUserFromUserGroupThrowsInvalidArgumentException() 0 21 1
A testUnAssignUserFromUserGroupThrowsBadStateArgumentException() 0 20 1
A testLoadUserGroupWithPrioritizedLanguagesList() 0 23 2
A testLoadUserGroupWithPrioritizedLanguagesListAfterMainLanguageUpdate() 0 30 2
A testLoadSubUserGroupsWithPrioritizedLanguagesList() 0 31 3
A testLoadUserWithPrioritizedLanguagesList() 0 26 3
A testLoadUserWithPrioritizedLanguagesListAfterMainLanguageUpdate() 0 34 3
A testLoadUserByLoginWithPrioritizedLanguagesList() 0 26 3
A testLoadUsersByEmailWithPrioritizedLanguagesList() 0 28 4
A testLoadUserGroupsOfUserWithPrioritizedLanguagesList() 0 21 2
A testLoadUsersOfUserGroupWithPrioritizedLanguagesList() 0 32 4
A getPrioritizedLanguageList() 0 13 1
A createMultiLanguageUserGroup() 0 18 1
A createUserGroupVersion1() 0 26 1
A createMultiLanguageUser() 0 29 2
A testCreateUserInvalidPasswordHashTypeThrowsException() 0 43 4
A testLoadUserByToken() 0 18 1
A testLoadUserByTokenThrowsNotFoundException() 0 17 1
A testUpdateUserToken() 0 16 1
A testExpireUserToken() 0 15 1
A testValidatePasswordWithDefaultContext() 0 10 1
A testValidatePassword() 0 15 1
A testValidatePasswordReturnsErrorWhenOldPasswordIsReused() 0 22 1
A dataProviderForValidatePassword() 0 20 1
A testGetPasswordInfo() 0 32 2
A testGetPasswordInfoIfExpirationIsDisabled() 0 13 1
A testGetPasswordInfoIfExpirationWarningIsDisabled() 0 22 2
A createTestUser() 0 4 1
A createTestUserWithPassword() 0 22 1
A createUserContentTypeWithStrongPassword() 0 13 1
A createUserContentTypeWithPasswordExpirationDate() 0 9 1
B createUserContentTypeWithAccountSettings() 0 97 1

How to fix   Complexity   

Complex Class

Complex classes like UserServiceTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use UserServiceTest, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
5
 * @license For full copyright and license information view LICENSE file distributed with this source code.
6
 */
7
namespace eZ\Publish\API\Repository\Tests;
8
9
use DateInterval;
10
use DateTime;
11
use DateTimeImmutable;
12
use eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException;
13
use eZ\Publish\API\Repository\Exceptions\InvalidArgumentException;
14
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
15
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
16
use eZ\Publish\API\Repository\Values\Content\Language;
17
use eZ\Publish\API\Repository\Values\Content\VersionInfo as APIVersionInfo;
18
use eZ\Publish\API\Repository\Values\ContentType\ContentType;
19
use eZ\Publish\API\Repository\Values\User\Limitation\SubtreeLimitation;
20
use eZ\Publish\API\Repository\Values\User\PasswordInfo;
21
use eZ\Publish\API\Repository\Values\User\PasswordValidationContext;
22
use eZ\Publish\API\Repository\Values\User\UserGroupUpdateStruct;
23
use eZ\Publish\API\Repository\Values\User\UserTokenUpdateStruct;
24
use eZ\Publish\API\Repository\Values\User\UserUpdateStruct;
25
use eZ\Publish\API\Repository\Values\User\User;
26
use eZ\Publish\Core\FieldType\ValidationError;
27
use eZ\Publish\Core\Repository\Values\Content\Content;
28
use eZ\Publish\Core\Repository\Values\Content\VersionInfo;
29
use eZ\Publish\Core\Repository\Values\User\UserGroup;
30
use Exception;
31
32
/**
33
 * Test case for operations in the UserService using in memory storage.
34
 *
35
 * @see eZ\Publish\API\Repository\UserService
36
 * @group integration
37
 * @group user
38
 */
39
class UserServiceTest extends BaseTest
40
{
41
    // Example password matching default rules
42
    private const EXAMPLE_PASSWORD = 'P@ssword123!';
43
44
    private const EXAMPLE_PASSWORD_TTL = 30;
45
    private const EXAMPLE_PASSWORD_TTL_WARNING = 14;
46
47
    /**
48
     * Test for the loadUserGroup() method.
49
     *
50
     * @see \eZ\Publish\API\Repository\UserService::loadUserGroup()
51
     */
52
    public function testLoadUserGroup()
53
    {
54
        $repository = $this->getRepository();
55
56
        $mainGroupId = $this->generateId('group', 4);
57
        /* BEGIN: Use Case */
58
        // $mainGroupId is the ID of the main "Users" group
59
60
        $userService = $repository->getUserService();
61
62
        $userGroup = $userService->loadUserGroup($mainGroupId);
63
        /* END: Use Case */
64
65
        $this->assertInstanceOf(UserGroup::class, $userGroup);
66
67
        // User group happens to also be a Content; isUserGroup() should be true and isUser() should be false
68
        $this->assertTrue($userService->isUserGroup($userGroup), 'isUserGroup() => false on a user group');
69
        $this->assertFalse($userService->isUser($userGroup), 'isUser() => true on a user group');
70
        $this->assertSame(0, $userGroup->parentId, 'parentId should be equal `0` because it is top level node');
71
    }
72
73
    /**
74
     * Test for the loadUserGroup() method to ensure that DomainUserGroupObject is created properly even if a user
75
     * has no access to parent of UserGroup.
76
     *
77
     * @see \eZ\Publish\API\Repository\UserService::loadUserGroup()
78
     */
79
    public function testLoadUserGroupWithNoAccessToParent()
80
    {
81
        $repository = $this->getRepository();
82
83
        $mainGroupId = $this->generateId('group', 4);
84
        /* BEGIN: Use Case */
85
        // $mainGroupId is the ID of the main "Users" group
86
87
        $userService = $repository->getUserService();
88
89
        $user = $this->createUserWithPolicies(
90
            'user',
91
            [
92
                ['module' => 'content', 'function' => 'read'],
93
            ],
94
            new SubtreeLimitation(['limitationValues' => ['/1/5']])
95
        );
96
        $repository->getPermissionResolver()->setCurrentUserReference($user);
97
98
        $userGroup = $userService->loadUserGroup($mainGroupId);
99
        /* END: Use Case */
100
101
        $this->assertInstanceOf(UserGroup::class, $userGroup);
102
103
        // User group happens to also be a Content; isUserGroup() should be true and isUser() should be false
104
        $this->assertTrue($userService->isUserGroup($userGroup), 'isUserGroup() => false on a user group');
105
        $this->assertFalse($userService->isUser($userGroup), 'isUser() => true on a user group');
106
        $this->assertSame(0, $userGroup->parentId, 'parentId should be equal `0` because it is top level node');
107
    }
108
109
    /**
110
     * Test for the loadUserGroup() method.
111
     *
112
     * @see \eZ\Publish\API\Repository\UserService::loadUserGroup()
113
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroup
114
     */
115
    public function testLoadUserGroupThrowsNotFoundException()
116
    {
117
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
118
119
        $repository = $this->getRepository();
120
121
        $nonExistingGroupId = $this->generateId('group', self::DB_INT_MAX);
122
        /* BEGIN: Use Case */
123
        $userService = $repository->getUserService();
124
125
        // This call will fail with a NotFoundException
126
        $userService->loadUserGroup($nonExistingGroupId);
127
        /* END: Use Case */
128
    }
129
130
    /**
131
     * Test for the loadSubUserGroups() method.
132
     *
133
     * @see \eZ\Publish\API\Repository\UserService::loadSubUserGroups()
134
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroup
135
     */
136
    public function testLoadSubUserGroups()
137
    {
138
        $repository = $this->getRepository();
139
140
        $mainGroupId = $this->generateId('group', 4);
141
        /* BEGIN: Use Case */
142
        // $mainGroupId is the ID of the main "Users" group
143
144
        $userService = $repository->getUserService();
145
146
        $userGroup = $userService->loadUserGroup($mainGroupId);
147
148
        $subUserGroups = $userService->loadSubUserGroups($userGroup);
149
        foreach ($subUserGroups as $subUserGroup) {
150
            // Do something with the $subUserGroup
151
            $this->assertInstanceOf(UserGroup::class, $subUserGroup);
152
        }
153
        /* END: Use Case */
154
    }
155
156
    /**
157
     * Test loading sub groups throwing NotFoundException.
158
     *
159
     * @covers \eZ\Publish\API\Repository\UserService::loadSubUserGroups
160
     */
161
    public function testLoadSubUserGroupsThrowsNotFoundException()
162
    {
163
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
164
165
        $repository = $this->getRepository();
166
        $userService = $repository->getUserService();
167
168
        $parentGroup = new UserGroup(
169
            [
170
                'content' => new Content(
171
                    [
172
                        'versionInfo' => new VersionInfo(
173
                            [
174
                                'contentInfo' => new ContentInfo(
175
                                    ['id' => 123456]
176
                                ),
177
                            ]
178
                        ),
179
                        'internalFields' => [],
180
                    ]
181
                ),
182
            ]
183
        );
184
        $userService->loadSubUserGroups($parentGroup);
185
    }
186
187
    /**
188
     * Test for the newUserGroupCreateStruct() method.
189
     *
190
     * @return \eZ\Publish\API\Repository\Values\User\UserGroupCreateStruct
191
     *
192
     * @see \eZ\Publish\API\Repository\UserService::newUserGroupCreateStruct()
193
     * @depends eZ\Publish\API\Repository\Tests\ContentTypeServiceTest::testLoadContentTypeByIdentifier
194
     */
195
    public function testNewUserGroupCreateStruct()
196
    {
197
        $repository = $this->getRepository();
198
199
        /* BEGIN: Use Case */
200
        $userService = $repository->getUserService();
201
202
        $groupCreate = $userService->newUserGroupCreateStruct('eng-US');
203
        /* END: Use Case */
204
205
        $this->assertInstanceOf(
206
            '\\eZ\\Publish\\API\\Repository\\Values\\User\\UserGroupCreateStruct',
207
            $groupCreate
208
        );
209
210
        return $groupCreate;
211
    }
212
213
    /**
214
     * Test for the newUserGroupCreateStruct() method.
215
     *
216
     * @param \eZ\Publish\API\Repository\Values\User\UserGroupCreateStruct $groupCreate
217
     *
218
     * @see \eZ\Publish\API\Repository\UserService::newUserGroupCreateStruct()
219
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserGroupCreateStruct
220
     */
221
    public function testNewUserGroupCreateStructSetsMainLanguageCode($groupCreate)
222
    {
223
        $this->assertEquals('eng-US', $groupCreate->mainLanguageCode);
224
    }
225
226
    /**
227
     * Test for the newUserGroupCreateStruct() method.
228
     *
229
     * @param \eZ\Publish\API\Repository\Values\User\UserGroupCreateStruct $groupCreate
230
     *
231
     * @see \eZ\Publish\API\Repository\UserService::newUserGroupCreateStruct()
232
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserGroupCreateStruct
233
     */
234
    public function testNewUserGroupCreateStructSetsContentType($groupCreate)
235
    {
236
        $this->assertInstanceOf(
237
            '\\eZ\\Publish\\API\\Repository\\Values\\ContentType\\ContentType',
238
            $groupCreate->contentType
239
        );
240
    }
241
242
    /**
243
     * Test for the newUserGroupCreateStruct() method.
244
     *
245
     * @see \eZ\Publish\API\Repository\UserService::newUserGroupCreateStruct($mainLanguageCode, $contentType)
246
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserGroupCreateStruct
247
     * @depends eZ\Publish\API\Repository\Tests\ContentTypeServiceTest::testLoadContentTypeByIdentifier
248
     */
249
    public function testNewUserGroupCreateStructWithSecondParameter()
250
    {
251
        if ($this->isVersion4()) {
252
            $this->markTestSkipped('This test is only relevant for eZ Publish versions > 4');
253
        }
254
255
        $repository = $this->getRepository();
256
257
        /* BEGIN: Use Case */
258
        $contentTypeService = $repository->getContentTypeService();
259
        $userService = $repository->getUserService();
260
261
        // Load the default ContentType for user groups
262
        $groupType = $contentTypeService->loadContentTypeByIdentifier('user_group');
263
264
        // Instantiate a new group create struct
265
        $groupCreate = $userService->newUserGroupCreateStruct(
266
            'eng-US',
267
            $groupType
268
        );
269
        /* END: Use Case */
270
271
        $this->assertSame($groupType, $groupCreate->contentType);
272
    }
273
274
    /**
275
     * Test for the createUserGroup() method.
276
     *
277
     * @return \eZ\Publish\API\Repository\Values\User\UserGroup
278
     *
279
     * @see \eZ\Publish\API\Repository\UserService::createUserGroup()
280
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserGroupCreateStruct
281
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroup
282
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
283
     */
284
    public function testCreateUserGroup()
285
    {
286
        /* BEGIN: Use Case */
287
        $userGroup = $this->createUserGroupVersion1();
288
        /* END: Use Case */
289
290
        $this->assertInstanceOf(
291
            UserGroup::class,
292
            $userGroup
293
        );
294
295
        $versionInfo = $userGroup->getVersionInfo();
296
297
        $this->assertEquals(APIVersionInfo::STATUS_PUBLISHED, $versionInfo->status);
298
        $this->assertEquals(1, $versionInfo->versionNo);
299
300
        return $userGroup;
301
    }
302
303
    /**
304
     * Test for the createUserGroup() method.
305
     *
306
     * @param \eZ\Publish\API\Repository\Values\User\UserGroup $userGroup
307
     *
308
     * @see \eZ\Publish\API\Repository\UserService::createUserGroup()
309
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUserGroup
310
     */
311
    public function testCreateUserGroupSetsExpectedProperties($userGroup)
312
    {
313
        $this->assertEquals(
314
            [
315
                'parentId' => $this->generateId('group', 4),
316
            ],
317
            [
318
                'parentId' => $userGroup->parentId,
319
            ]
320
        );
321
    }
322
323
    /**
324
     * Test for the createUserGroup() method.
325
     *
326
     * @see \eZ\Publish\API\Repository\UserService::createUserGroup()
327
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUserGroup
328
     */
329
    public function testCreateUserGroupThrowsInvalidArgumentException()
330
    {
331
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
332
333
        $repository = $this->getRepository();
334
335
        $mainGroupId = $this->generateId('group', 4);
336
        /* BEGIN: Use Case */
337
        // $mainGroupId is the ID of the main "Users" group
338
339
        $userService = $repository->getUserService();
340
341
        // Load main group
342
        $parentUserGroup = $userService->loadUserGroup($mainGroupId);
343
344
        // Instantiate a new create struct
345
        $userGroupCreate = $userService->newUserGroupCreateStruct('eng-US');
346
        $userGroupCreate->setField('name', 'Example Group');
347
        $userGroupCreate->remoteId = '5f7f0bdb3381d6a461d8c29ff53d908f';
348
349
        // This call will fail with an "InvalidArgumentException", because the
350
        // specified remoteId is already used for the "Members" user group.
351
        $userService->createUserGroup(
352
            $userGroupCreate,
353
            $parentUserGroup
354
        );
355
        /* END: Use Case */
356
    }
357
358
    /**
359
     * Test for the createUserGroup() method.
360
     *
361
     * @see \eZ\Publish\API\Repository\UserService::createUserGroup()
362
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUserGroup
363
     */
364
    public function testCreateUserGroupThrowsInvalidArgumentExceptionFieldTypeNotAccept()
365
    {
366
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
367
368
        $repository = $this->getRepository();
369
370
        $mainGroupId = $this->generateId('group', 4);
371
        /* BEGIN: Use Case */
372
        // $mainGroupId is the ID of the main "Users" group
373
374
        $userService = $repository->getUserService();
375
376
        // Load main group
377
        $parentUserGroup = $userService->loadUserGroup($mainGroupId);
378
379
        // Instantiate a new create struct
380
        $userGroupCreate = $userService->newUserGroupCreateStruct('eng-US');
381
        $userGroupCreate->setField('name', new \stdClass());
382
383
        // This call will fail with an "InvalidArgumentException", because the
384
        // specified remoteId is already used for the "Members" user group.
385
        $userService->createUserGroup(
386
            $userGroupCreate,
387
            $parentUserGroup
388
        );
389
        /* END: Use Case */
390
    }
391
392
    /**
393
     * Test for the createUserGroup() method.
394
     *
395
     * @see \eZ\Publish\API\Repository\UserService::createUserGroup()
396
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUserGroup
397
     */
398
    public function testCreateUserGroupWhenMissingField()
399
    {
400
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
401
402
        $repository = $this->getRepository();
403
404
        $mainGroupId = $this->generateId('group', 4);
405
        /* BEGIN: Use Case */
406
        // $mainGroupId is the ID of the main "Users" group
407
408
        $userService = $repository->getUserService();
409
410
        // Load main group
411
        $parentUserGroup = $userService->loadUserGroup($mainGroupId);
412
413
        // Instantiate a new create struct
414
        $userGroupCreate = $userService->newUserGroupCreateStruct('eng-US');
415
416
        // This call will fail with a "ContentFieldValidationException", because the
417
        // only mandatory field "name" is not set.
418
        $userService->createUserGroup($userGroupCreate, $parentUserGroup);
419
        /* END: Use Case */
420
    }
421
422
    /**
423
     * Test for the createUserGroup() method.
424
     *
425
     * @return \eZ\Publish\API\Repository\Values\User\UserGroup
426
     *
427
     * @see \eZ\Publish\API\Repository\UserService::createUserGroup()
428
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserGroupCreateStruct
429
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroup
430
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
431
     */
432
    public function testCreateUserGroupInTransactionWithRollback()
433
    {
434
        $repository = $this->getRepository();
435
436
        $mainGroupId = $this->generateId('group', 4);
437
        /* BEGIN: Use Case */
438
        // $mainGroupId is the ID of the main "Users" group
439
440
        $userService = $repository->getUserService();
441
442
        $repository->beginTransaction();
443
444
        try {
445
            // Load main group
446
            $parentUserGroup = $userService->loadUserGroup($mainGroupId);
447
448
            // Instantiate a new create struct
449
            $userGroupCreate = $userService->newUserGroupCreateStruct('eng-US');
450
            $userGroupCreate->setField('name', 'Example Group');
451
452
            // Create the new user group
453
            $createdUserGroupId = $userService->createUserGroup(
454
                $userGroupCreate,
455
                $parentUserGroup
456
            )->id;
457
        } catch (Exception $e) {
458
            // Cleanup hanging transaction on error
459
            $repository->rollback();
460
            throw $e;
461
        }
462
463
        $repository->rollback();
464
465
        try {
466
            // Throws exception since creation of user group was rolled back
467
            $loadedGroup = $userService->loadUserGroup($createdUserGroupId);
0 ignored issues
show
Unused Code introduced by
$loadedGroup is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
468
        } catch (NotFoundException $e) {
469
            return;
470
        }
471
        /* END: Use Case */
472
473
        $this->fail('User group object still exists after rollback.');
474
    }
475
476
    /**
477
     * Test for the deleteUserGroup() method.
478
     *
479
     * @see \eZ\Publish\API\Repository\UserService::deleteUserGroup()
480
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUserGroup
481
     */
482
    public function testDeleteUserGroup()
483
    {
484
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
485
486
        $repository = $this->getRepository();
487
        $userService = $repository->getUserService();
488
489
        /* BEGIN: Use Case */
490
        $userGroup = $this->createUserGroupVersion1();
491
492
        // Delete the currently created user group again
493
        $userService->deleteUserGroup($userGroup);
494
        /* END: Use Case */
495
496
        // We use the NotFoundException here for verification
497
        $userService->loadUserGroup($userGroup->id);
498
    }
499
500
    /**
501
     * Test deleting user group throwing NotFoundException.
502
     *
503
     * @covers \eZ\Publish\API\Repository\UserService::deleteUserGroup
504
     */
505
    public function testDeleteUserGroupThrowsNotFoundException()
506
    {
507
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
508
509
        $repository = $this->getRepository();
510
        $userService = $repository->getUserService();
511
512
        $userGroup = new UserGroup(
513
            [
514
                'content' => new Content(
515
                    [
516
                        'versionInfo' => new VersionInfo(
517
                            ['contentInfo' => new ContentInfo(['id' => 123456])]
518
                        ),
519
                        'internalFields' => [],
520
                    ]
521
                ),
522
            ]
523
        );
524
        $userService->deleteUserGroup($userGroup);
525
    }
526
527
    /**
528
     * Test for the moveUserGroup() method.
529
     *
530
     * @see \eZ\Publish\API\Repository\UserService::moveUserGroup()
531
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUserGroup
532
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadSubUserGroups
533
     */
534
    public function testMoveUserGroup()
535
    {
536
        $repository = $this->getRepository();
537
        $userService = $repository->getUserService();
538
539
        $membersGroupId = $this->generateId('group', 13);
540
        /* BEGIN: Use Case */
541
        // $membersGroupId is the ID of the "Members" user group in an eZ
542
        // Publish demo installation
543
544
        $userGroup = $this->createUserGroupVersion1();
545
546
        // Load the new parent group
547
        $membersUserGroup = $userService->loadUserGroup($membersGroupId);
548
549
        // Move user group from "Users" to "Members"
550
        $userService->moveUserGroup($userGroup, $membersUserGroup);
551
552
        // Reload the user group to get an updated $parentId
553
        $userGroup = $userService->loadUserGroup($userGroup->id);
554
555
        $this->refreshSearch($repository);
556
557
        // The returned array will no contain $userGroup
558
        $subUserGroups = $userService->loadSubUserGroups(
559
            $membersUserGroup
560
        );
561
        /* END: Use Case */
562
563
        $subUserGroupIds = array_map(
564
            function ($content) {
565
                return $content->id;
566
            },
567
            $subUserGroups
568
        );
569
570
        $this->assertEquals($membersGroupId, $userGroup->parentId);
571
        $this->assertEquals([$userGroup->id], $subUserGroupIds);
572
    }
573
574
    /**
575
     * Test moving a user group below another group throws NotFoundException.
576
     *
577
     * @covers \eZ\Publish\API\Repository\UserService::moveUserGroup
578
     */
579
    public function testMoveUserGroupThrowsNotFoundException()
580
    {
581
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
582
583
        $repository = $this->getRepository();
584
        $userService = $repository->getUserService();
585
586
        $userGroupToMove = new UserGroup(
587
            [
588
                'content' => new Content(
589
                    [
590
                        'versionInfo' => new VersionInfo(
591
                            ['contentInfo' => new ContentInfo(['id' => 123456])]
592
                        ),
593
                        'internalFields' => [],
594
                    ]
595
                ),
596
            ]
597
        );
598
        $parentUserGroup = new UserGroup(
599
            [
600
                'content' => new Content(
601
                    [
602
                        'versionInfo' => new VersionInfo(
603
                            ['contentInfo' => new ContentInfo(['id' => 123455])]
604
                        ),
605
                        'internalFields' => [],
606
                    ]
607
                ),
608
            ]
609
        );
610
        $userService->moveUserGroup($userGroupToMove, $parentUserGroup);
611
    }
612
613
    /**
614
     * Test for the newUserGroupUpdateStruct() method.
615
     *
616
     * @covers \eZ\Publish\API\Repository\UserService::newUserGroupUpdateStruct
617
     */
618
    public function testNewUserGroupUpdateStruct()
619
    {
620
        $repository = $this->getRepository();
621
622
        /* BEGIN: Use Case */
623
        $userService = $repository->getUserService();
624
625
        $groupUpdate = $userService->newUserGroupUpdateStruct();
626
        /* END: Use Case */
627
628
        $this->assertInstanceOf(
629
            UserGroupUpdateStruct::class,
630
            $groupUpdate
631
        );
632
633
        $this->assertNull($groupUpdate->contentUpdateStruct);
634
        $this->assertNull($groupUpdate->contentMetadataUpdateStruct);
635
    }
636
637
    /**
638
     * Test for the updateUserGroup() method.
639
     *
640
     * @see \eZ\Publish\API\Repository\UserService::updateUserGroup()
641
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUserGroup
642
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserGroupUpdateStruct
643
     */
644
    public function testUpdateUserGroup()
645
    {
646
        $repository = $this->getRepository();
647
        $userService = $repository->getUserService();
648
649
        /* BEGIN: Use Case */
650
        $userGroup = $this->createUserGroupVersion1();
651
652
        // Create a group update struct and change nothing
653
        $groupUpdate = $userService->newUserGroupUpdateStruct();
654
655
        // This update will do nothing
656
        $userGroup = $userService->updateUserGroup(
657
            $userGroup,
658
            $groupUpdate
659
        );
660
        /* END: Use Case */
661
662
        $this->assertInstanceOf(
663
            UserGroup::class,
664
            $userGroup
665
        );
666
667
        $this->assertEquals(1, $userGroup->getVersionInfo()->versionNo);
668
    }
669
670
    /**
671
     * Test for the updateUserGroup() method.
672
     *
673
     * @see \eZ\Publish\API\Repository\UserService::updateUserGroup()
674
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUserGroup
675
     */
676
    public function testUpdateUserGroupWithSubContentUpdateStruct()
677
    {
678
        $repository = $this->getRepository();
679
        $userService = $repository->getUserService();
680
681
        /* BEGIN: Use Case */
682
        $userGroup = $this->createUserGroupVersion1();
683
684
        // Load the content service
685
        $contentService = $repository->getContentService();
686
687
        // Create a content update struct and update the group name
688
        $contentUpdate = $contentService->newContentUpdateStruct();
689
        $contentUpdate->setField('name', 'Sindelfingen', 'eng-US');
690
691
        // Create a group update struct and set content update struct
692
        $groupUpdate = $userService->newUserGroupUpdateStruct();
693
        $groupUpdate->contentUpdateStruct = $contentUpdate;
694
695
        // This will update the name and the increment the group version number
696
        $userGroup = $userService->updateUserGroup(
697
            $userGroup,
698
            $groupUpdate
699
        );
700
        /* END: Use Case */
701
702
        $this->assertEquals('Sindelfingen', $userGroup->getFieldValue('name', 'eng-US'));
703
704
        $versionInfo = $userGroup->getVersionInfo();
705
706
        $this->assertEquals(APIVersionInfo::STATUS_PUBLISHED, $versionInfo->status);
707
        $this->assertEquals(2, $versionInfo->versionNo);
708
    }
709
710
    /**
711
     * Test for the updateUserGroup() method.
712
     *
713
     * @see \eZ\Publish\API\Repository\UserService::updateUserGroup()
714
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUserGroup
715
     */
716
    public function testUpdateUserGroupWithSubContentMetadataUpdateStruct()
717
    {
718
        $repository = $this->getRepository();
719
        $userService = $repository->getUserService();
720
721
        /* BEGIN: Use Case */
722
        $userGroup = $this->createUserGroupVersion1();
723
724
        // Load the content service
725
        $contentService = $repository->getContentService();
726
727
        // Create a metadata update struct and change the remoteId
728
        $metadataUpdate = $contentService->newContentMetadataUpdateStruct();
729
        $metadataUpdate->remoteId = '3c61299780663bafa3af2101e52125da';
730
731
        // Create a group update struct and set content update struct
732
        $groupUpdate = $userService->newUserGroupUpdateStruct();
733
        $groupUpdate->contentMetadataUpdateStruct = $metadataUpdate;
734
735
        // This will update the name and the increment the group version number
736
        $userGroup = $userService->updateUserGroup(
737
            $userGroup,
738
            $groupUpdate
739
        );
740
        /* END: Use Case */
741
742
        $this->assertEquals(
743
            '3c61299780663bafa3af2101e52125da',
744
            $userGroup->contentInfo->remoteId
745
        );
746
747
        $versionInfo = $userGroup->getVersionInfo();
748
749
        $this->assertEquals(APIVersionInfo::STATUS_PUBLISHED, $versionInfo->status);
750
        $this->assertEquals(1, $versionInfo->versionNo);
751
    }
752
753
    /**
754
     * Test for the updateUserGroup() method.
755
     *
756
     * @see \eZ\Publish\API\Repository\UserService::updateUserGroup()
757
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUserGroup
758
     */
759
    public function testUpdateUserGroupThrowsInvalidArgumentExceptionOnFieldTypeNotAccept()
760
    {
761
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
762
763
        $repository = $this->getRepository();
764
        $userService = $repository->getUserService();
765
766
        /* BEGIN: Use Case */
767
        $userGroup = $this->createUserGroupVersion1();
768
769
        // Load the content service
770
        $contentService = $repository->getContentService();
771
772
        // Create a content update struct and update the group name
773
        $contentUpdate = $contentService->newContentUpdateStruct();
774
        // An object of stdClass is not accepted as a value by the field "name"
775
        $contentUpdate->setField('name', new \stdClass(), 'eng-US');
776
777
        // Create a group update struct and set content update struct
778
        $groupUpdate = $userService->newUserGroupUpdateStruct();
779
        $groupUpdate->contentUpdateStruct = $contentUpdate;
780
781
        // This call will fail with an InvalidArgumentException, because the
782
        // field "name" does not accept the given value
783
        $userService->updateUserGroup($userGroup, $groupUpdate);
784
        /* END: Use Case */
785
    }
786
787
    /**
788
     * Test for the newUserCreateStruct() method.
789
     *
790
     * @see \eZ\Publish\API\Repository\UserService::newUserCreateStruct()
791
     */
792
    public function testNewUserCreateStruct()
793
    {
794
        $repository = $this->getRepository();
795
796
        /* BEGIN: Use Case */
797
        $userService = $repository->getUserService();
798
799
        $userCreate = $userService->newUserCreateStruct(
800
            'user',
801
            '[email protected]',
802
            'secret',
803
            'eng-US'
804
        );
805
        /* END: Use Case */
806
807
        $this->assertInstanceOf(
808
            '\\eZ\\Publish\\API\\Repository\\Values\\User\\UserCreateStruct',
809
            $userCreate
810
        );
811
812
        return $userCreate;
813
    }
814
815
    /**
816
     * Test updating a user group throws ContentFieldValidationException.
817
     *
818
     * @covers \eZ\Publish\API\Repository\UserService::updateUserGroup
819
     */
820
    public function testUpdateUserGroupThrowsContentFieldValidationExceptionOnRequiredFieldEmpty()
821
    {
822
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
823
824
        $repository = $this->getRepository();
825
        $userService = $repository->getUserService();
826
        $contentService = $repository->getContentService();
827
828
        $userGroup = $userService->loadUserGroup(42);
829
        $userGroupUpdateStruct = $userService->newUserGroupUpdateStruct();
830
        $userGroupUpdateStruct->contentUpdateStruct = $contentService->newContentUpdateStruct();
831
        $userGroupUpdateStruct->contentUpdateStruct->setField('name', '', 'eng-US');
832
833
        $userService->updateUserGroup($userGroup, $userGroupUpdateStruct);
834
    }
835
836
    /**
837
     * Test for the newUserCreateStruct() method.
838
     *
839
     * @param \eZ\Publish\API\Repository\Values\User\UserCreateStruct $userCreate
840
     *
841
     * @see \eZ\Publish\API\Repository\UserService::newUserCreateStruct()
842
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserCreateStruct
843
     */
844
    public function testNewUserCreateStructSetsExpectedProperties($userCreate)
845
    {
846
        $this->assertEquals(
847
            [
848
                'login' => 'user',
849
                'email' => '[email protected]',
850
                'password' => 'secret',
851
                'mainLanguageCode' => 'eng-US',
852
            ],
853
            [
854
                'login' => $userCreate->login,
855
                'email' => $userCreate->email,
856
                'password' => $userCreate->password,
857
                'mainLanguageCode' => $userCreate->mainLanguageCode,
858
            ]
859
        );
860
    }
861
862
    /**
863
     * Test for the newUserCreateStruct() method.
864
     *
865
     * @see \eZ\Publish\API\Repository\UserService::newUserCreateStruct($login, $email, $password, $mainLanguageCode, $contentType)
866
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserCreateStruct
867
     * @depends eZ\Publish\API\Repository\Tests\ContentTypeServiceTest::testLoadContentTypeByIdentifier
868
     */
869
    public function testNewUserCreateStructWithFifthParameter()
870
    {
871
        if ($this->isVersion4()) {
872
            $this->markTestSkipped('This test is only relevant for eZ Publish versions > 4');
873
        }
874
875
        $repository = $this->getRepository();
876
877
        /* BEGIN: Use Case */
878
        $contentTypeService = $repository->getContentTypeService();
879
        $userService = $repository->getUserService();
880
881
        $userType = $contentTypeService->loadContentTypeByIdentifier('user');
882
883
        $userCreate = $userService->newUserCreateStruct(
884
            'user',
885
            '[email protected]',
886
            'secret',
887
            'eng-US',
888
            $userType
889
        );
890
        /* END: Use Case */
891
892
        $this->assertSame($userType, $userCreate->contentType);
893
    }
894
895
    /**
896
     * Test for creating user with Active Directory login name.
897
     */
898
    public function testNewUserWithDomainName()
899
    {
900
        $repository = $this->getRepository();
901
        $userService = $repository->getUserService();
902
        $createdUser = $this->createUserVersion1(
903
            'ez-user-Domain\username-by-login',
904
            '[email protected]'
905
        );
906
        $loadedUser = $userService->loadUserByLogin('ez-user-Domain\username-by-login', Language::ALL);
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...vice::loadUserByLogin() has been deprecated with message: since eZ Platform 2.5, will be dropped in the next major version as authentication may depend on various user providers. Use UserService::checkUserCredentials() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
907
908
        $this->assertEquals($createdUser, $loadedUser);
909
    }
910
911
    /**
912
     * Test for the createUser() method.
913
     *
914
     * @return \eZ\Publish\API\Repository\Values\User\User
915
     *
916
     * @see \eZ\Publish\API\Repository\UserService::createUser()
917
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroup
918
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserCreateStruct
919
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
920
     */
921
    public function testCreateUser()
922
    {
923
        /* BEGIN: Use Case */
924
        $user = $this->createUserVersion1();
925
        /* END: Use Case */
926
927
        $this->assertInstanceOf(
928
            '\\eZ\\Publish\\API\\Repository\\Values\\User\\User',
929
            $user
930
        );
931
932
        return $user;
933
    }
934
935
    /**
936
     * Test for the createUser() method.
937
     *
938
     * @param \eZ\Publish\API\Repository\Values\User\User $user
939
     *
940
     * @see \eZ\Publish\API\Repository\UserService::createUser()
941
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
942
     */
943
    public function testCreateUserSetsExpectedProperties(User $user)
944
    {
945
        $this->assertEquals(
946
            [
947
                'login' => 'user',
948
                'email' => '[email protected]',
949
                'mainLanguageCode' => 'eng-US',
950
            ],
951
            [
952
                'login' => $user->login,
953
                'email' => $user->email,
954
                'mainLanguageCode' => $user->contentInfo->mainLanguageCode,
955
            ]
956
        );
957
    }
958
959
    /**
960
     * Test for the createUser() method.
961
     *
962
     * @see \eZ\Publish\API\Repository\UserService::createUser()
963
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
964
     */
965
    public function testCreateUserWhenMissingField()
966
    {
967
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
968
969
        $repository = $this->getRepository();
970
971
        $editorsGroupId = $this->generateId('group', 13);
972
        /* BEGIN: Use Case */
973
        // $editorsGroupId is the ID of the "Editors" user group in an eZ
974
        // Publish demo installation
975
976
        $userService = $repository->getUserService();
977
978
        // Instantiate a create struct with mandatory properties
979
        $userCreate = $userService->newUserCreateStruct(
980
            'user',
981
            '[email protected]',
982
            'secret',
983
            'eng-US'
984
        );
985
986
        // Do not set the mandatory fields "first_name" and "last_name"
987
        //$userCreate->setField( 'first_name', 'Example' );
988
        //$userCreate->setField( 'last_name', 'User' );
989
990
        // Load parent group for the user
991
        $group = $userService->loadUserGroup($editorsGroupId);
992
993
        // This call will fail with a "ContentFieldValidationException", because the
994
        // mandatory fields "first_name" and "last_name" are not set.
995
        $userService->createUser($userCreate, [$group]);
996
        /* END: Use Case */
997
    }
998
999
    /**
1000
     * Test for the createUser() method.
1001
     *
1002
     * @see \eZ\Publish\API\Repository\UserService::createUser()
1003
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1004
     */
1005
    public function testCreateUserThrowsInvalidArgumentExceptionOnFieldTypeNotAccept()
1006
    {
1007
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
1008
1009
        $repository = $this->getRepository();
1010
1011
        $editorsGroupId = $this->generateId('group', 13);
1012
        /* BEGIN: Use Case */
1013
        // $editorsGroupId is the ID of the "Editors" user group in an eZ
1014
        // Publish demo installation
1015
1016
        $userService = $repository->getUserService();
1017
1018
        // Instantiate a create struct with mandatory properties
1019
        $userCreate = $userService->newUserCreateStruct(
1020
            'user',
1021
            '[email protected]',
1022
            'secret',
1023
            'eng-US'
1024
        );
1025
1026
        // An object of stdClass is not a valid value for the field first_name
1027
        $userCreate->setField('first_name', new \stdClass());
1028
        $userCreate->setField('last_name', 'User');
1029
1030
        // Load parent group for the user
1031
        $group = $userService->loadUserGroup($editorsGroupId);
1032
1033
        // This call will fail with an "InvalidArgumentException", because the
1034
        // value for the firled "first_name" is not accepted by the field type.
1035
        $userService->createUser($userCreate, [$group]);
1036
        /* END: Use Case */
1037
    }
1038
1039
    /**
1040
     * Test for the createUser() method.
1041
     *
1042
     * @covers \eZ\Publish\API\Repository\UserService::createUser
1043
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1044
     */
1045
    public function testCreateUserThrowsInvalidArgumentException()
1046
    {
1047
        $repository = $this->getRepository();
1048
1049
        $editorsGroupId = $this->generateId('group', 13);
1050
        /* BEGIN: Use Case */
1051
        // $editorsGroupId is the ID of the "Editors" user group in an eZ
1052
        // Publish demo installation
1053
1054
        $userService = $repository->getUserService();
1055
1056
        // Instantiate a create struct with mandatory properties
1057
        $userCreate = $userService->newUserCreateStruct(
1058
            // admin is an existing login
1059
            'admin',
1060
            '[email protected]',
1061
            'secret',
1062
            'eng-US'
1063
        );
1064
1065
        $userCreate->setField('first_name', 'Example');
1066
        $userCreate->setField('last_name', 'User');
1067
1068
        // Load parent group for the user
1069
        $group = $userService->loadUserGroup($editorsGroupId);
1070
1071
        try {
1072
            // This call will fail with a "InvalidArgumentException", because the
1073
            // user with "admin" login already exists.
1074
            $userService->createUser($userCreate, [$group]);
1075
            /* END: Use Case */
1076
        } catch (ContentFieldValidationException $e) {
1077
            // Exception is caught, as there is no other way to check exception properties.
1078
            $this->assertValidationErrorOccurs($e, 'The user login \'%login%\' is used by another user. You must enter a unique login.');
1079
1080
            /* END: Use Case */
1081
            return;
1082
        }
1083
1084
        $this->fail('Expected ValidationError messages did not occur.');
1085
    }
1086
1087
    /**
1088
     * Test for the createUser() method.
1089
     *
1090
     * @return \eZ\Publish\API\Repository\Values\User\User
1091
     *
1092
     * @see \eZ\Publish\API\Repository\UserService::createUser()
1093
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroup
1094
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserCreateStruct
1095
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testCreateContent
1096
     */
1097
    public function testCreateUserInTransactionWithRollback()
1098
    {
1099
        $repository = $this->getRepository();
1100
        $userService = $repository->getUserService();
1101
1102
        /* BEGIN: Use Case */
1103
        $repository->beginTransaction();
1104
1105
        try {
1106
            $user = $this->createUserVersion1();
1107
        } catch (Exception $e) {
1108
            // Cleanup hanging transaction on error
1109
            $repository->rollback();
1110
            throw $e;
1111
        }
1112
1113
        $repository->rollback();
1114
1115
        try {
1116
            // Throws exception since creation of user was rolled back
1117
            $loadedUser = $userService->loadUser($user->id);
0 ignored issues
show
Unused Code introduced by
$loadedUser is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1118
        } catch (NotFoundException $e) {
1119
            return;
1120
        }
1121
        /* END: Use Case */
1122
1123
        $this->fail('User object still exists after rollback.');
1124
    }
1125
1126
    /**
1127
     * Test creating a user throwing NotFoundException.
1128
     *
1129
     * @covers \eZ\Publish\API\Repository\UserService::createUser
1130
     */
1131
    public function testCreateUserThrowsNotFoundException()
1132
    {
1133
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
1134
1135
        $repository = $this->getRepository();
1136
        $userService = $repository->getUserService();
1137
1138
        $userCreateStruct = $userService->newUserCreateStruct('new_user', '[email protected]', 'password', 'eng-GB');
1139
        $userCreateStruct->setField('first_name', 'New');
1140
        $userCreateStruct->setField('last_name', 'User');
1141
1142
        $parentGroup = new UserGroup(
1143
            [
1144
                'content' => new Content(
1145
                    [
1146
                        'versionInfo' => new VersionInfo(
1147
                            [
1148
                                'contentInfo' => new ContentInfo(['id' => 123456]),
1149
                            ]
1150
                        ),
1151
                        'internalFields' => [],
1152
                    ]
1153
                ),
1154
            ]
1155
        );
1156
        $userService->createUser($userCreateStruct, [$parentGroup]);
1157
    }
1158
1159
    /**
1160
     * Test creating a user throwing UserPasswordValidationException when password doesn't follow specific rules.
1161
     *
1162
     * @covers \eZ\Publish\API\Repository\UserService::createUser
1163
     */
1164
    public function testCreateUserWithWeakPasswordThrowsUserPasswordValidationException()
1165
    {
1166
        $userContentType = $this->createUserContentTypeWithStrongPassword();
1167
1168
        try {
1169
            // This call will fail with a "UserPasswordValidationException" because the
1170
            // the password does not follow specified rules.
1171
            $this->createTestUserWithPassword('pass', $userContentType);
1172
        } catch (ContentFieldValidationException $e) {
1173
            // Exception is caught, as there is no other way to check exception properties.
1174
            $this->assertAllValidationErrorsOccur(
1175
                $e,
1176
                [
1177
                    'User password must include at least one special character',
1178
                    'User password must be at least %length% characters long',
1179
                    'User password must include at least one upper case letter',
1180
                    'User password must include at least one number',
1181
                ]
1182
            );
1183
1184
            return;
1185
        }
1186
1187
        $this->fail('Expected ValidationError messages did not occur.');
1188
    }
1189
1190
    /**
1191
     * Opposite test case for testCreateUserWithWeakPasswordThrowsUserPasswordValidationException.
1192
     *
1193
     * @covers \eZ\Publish\API\Repository\UserService::createUser
1194
     */
1195
    public function testCreateUserWithStrongPassword()
1196
    {
1197
        $userContentType = $this->createUserContentTypeWithStrongPassword();
1198
1199
        /* BEGIN: Use Case */
1200
        $user = $this->createTestUserWithPassword('H@xxi0r!', $userContentType);
1201
        /* END: Use Case */
1202
1203
        $this->assertInstanceOf(User::class, $user);
1204
    }
1205
1206
    /**
1207
     * Test for the loadUser() method.
1208
     *
1209
     * @see \eZ\Publish\API\Repository\UserService::loadUser()
1210
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1211
     */
1212
    public function testLoadUser()
1213
    {
1214
        $repository = $this->getRepository();
1215
1216
        $userService = $repository->getUserService();
1217
1218
        /* BEGIN: Use Case */
1219
        $user = $this->createUserVersion1();
1220
1221
        // Load the newly created user
1222
        $userReloaded = $userService->loadUser($user->id, Language::ALL);
1223
        /* END: Use Case */
1224
1225
        $this->assertEquals($user, $userReloaded);
1226
1227
        // User happens to also be a Content; isUser() should be true and isUserGroup() should be false
1228
        $this->assertTrue($userService->isUser($user), 'isUser() => false on a user');
1229
        $this->assertFalse($userService->isUserGroup($user), 'isUserGroup() => true on a user group');
1230
    }
1231
1232
    /**
1233
     * Test for the loadUser() method.
1234
     *
1235
     * @see \eZ\Publish\API\Repository\UserService::loadUser()
1236
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUser
1237
     */
1238
    public function testLoadUserThrowsNotFoundException()
1239
    {
1240
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
1241
1242
        $repository = $this->getRepository();
1243
1244
        $nonExistingUserId = $this->generateId('user', self::DB_INT_MAX);
1245
        /* BEGIN: Use Case */
1246
        $userService = $repository->getUserService();
1247
1248
        // This call will fail with a "NotFoundException", because no user with
1249
        // an id equal to self::DB_INT_MAX should exist.
1250
        $userService->loadUser($nonExistingUserId);
1251
        /* END: Use Case */
1252
    }
1253
1254
    /**
1255
     * @see \eZ\Publish\API\Repository\UserService::checkUserCredentials()
1256
     * @depends \eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1257
     */
1258
    public function testCheckUserCredentialsValid(): void
1259
    {
1260
        $repository = $this->getRepository();
1261
1262
        $userService = $repository->getUserService();
1263
1264
        /* BEGIN: Use Case */
1265
        $user = $this->createUserVersion1();
1266
1267
        // Load the newly created user credentials
1268
        $credentialsValid = $userService->loadUserByCredentials($user, 'secret');
0 ignored issues
show
Bug introduced by
The method loadUserByCredentials() does not exist on eZ\Publish\API\Repository\UserService. Did you maybe mean loadUser()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1269
        /* END: Use Case */
1270
1271
        $this->assertTrue($credentialsValid);
1272
    }
1273
1274
    /**
1275
     * @see \eZ\Publish\API\Repository\UserService::checkUserCredentials()
1276
     * @depends \eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1277
     */
1278
    public function testCheckUserCredentialsInvalid(): void
1279
    {
1280
        $repository = $this->getRepository();
1281
1282
        $userService = $repository->getUserService();
1283
1284
        /* BEGIN: Use Case */
1285
        $user = $this->createUserVersion1();
1286
1287
        // Load the newly created user credentials
1288
        $credentialsValid = $userService->loadUserByCredentials($user, '1234');
0 ignored issues
show
Bug introduced by
The method loadUserByCredentials() does not exist on eZ\Publish\API\Repository\UserService. Did you maybe mean loadUser()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1289
        /* END: Use Case */
1290
1291
        $this->assertFalse($credentialsValid);
1292
    }
1293
1294
    /**
1295
     * Test for the loadUserByLogin() method.
1296
     *
1297
     * @see \eZ\Publish\API\Repository\UserService::loadUserByLogin()
1298
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1299
     */
1300
    public function testLoadUserByLogin()
1301
    {
1302
        $repository = $this->getRepository();
1303
1304
        $userService = $repository->getUserService();
1305
1306
        /* BEGIN: Use Case */
1307
        $user = $this->createUserVersion1('User');
1308
1309
        // Load the newly created user
1310
        $userReloaded = $userService->loadUserByLogin('User');
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...vice::loadUserByLogin() has been deprecated with message: since eZ Platform 2.5, will be dropped in the next major version as authentication may depend on various user providers. Use UserService::checkUserCredentials() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1311
        /* END: Use Case */
1312
1313
        $this->assertPropertiesCorrect(
1314
            [
1315
                'login' => $user->login,
1316
                'email' => $user->email,
1317
                'passwordHash' => $user->passwordHash,
1318
                'hashAlgorithm' => $user->hashAlgorithm,
1319
                'enabled' => $user->enabled,
1320
                'maxLogin' => $user->maxLogin,
1321
                'id' => $user->id,
1322
                'contentInfo' => $user->contentInfo,
1323
                'versionInfo' => $user->versionInfo,
1324
                'fields' => $user->fields,
1325
            ],
1326
            $userReloaded
1327
        );
1328
    }
1329
1330
    /**
1331
     * Test for the loadUserByLogin() method.
1332
     *
1333
     * @see \eZ\Publish\API\Repository\UserService::loadUserByLogin()
1334
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserByLogin
1335
     */
1336
    public function testLoadUserByLoginThrowsNotFoundExceptionForUnknownLogin()
1337
    {
1338
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
1339
1340
        $repository = $this->getRepository();
1341
1342
        $userService = $repository->getUserService();
1343
1344
        /* BEGIN: Use Case */
1345
        $this->createUserVersion1();
1346
1347
        // This call will fail with a "NotFoundException", because the given
1348
        // login/password combination does not exist.
1349
        $userService->loadUserByLogin('user42');
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...vice::loadUserByLogin() has been deprecated with message: since eZ Platform 2.5, will be dropped in the next major version as authentication may depend on various user providers. Use UserService::checkUserCredentials() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1350
        /* END: Use Case */
1351
    }
1352
1353
    /**
1354
     * Test for the loadUserByLogin() method.
1355
     *
1356
     * @see \eZ\Publish\API\Repository\UserService::loadUserByLogin()
1357
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserByLogin
1358
     */
1359
    public function testLoadUserByLoginWorksForLoginWithWrongCase()
1360
    {
1361
        $repository = $this->getRepository();
1362
1363
        $userService = $repository->getUserService();
1364
1365
        /* BEGIN: Use Case */
1366
        $user = $this->createUserVersion1();
1367
1368
        // Lookup by user login should ignore casing
1369
        $userReloaded = $userService->loadUserByLogin('USER');
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...vice::loadUserByLogin() has been deprecated with message: since eZ Platform 2.5, will be dropped in the next major version as authentication may depend on various user providers. Use UserService::checkUserCredentials() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1370
        /* END: Use Case */
1371
1372
        $this->assertPropertiesCorrect(
1373
            [
1374
                'login' => $user->login,
1375
                'email' => $user->email,
1376
                'passwordHash' => $user->passwordHash,
1377
                'hashAlgorithm' => $user->hashAlgorithm,
1378
                'enabled' => $user->enabled,
1379
                'maxLogin' => $user->maxLogin,
1380
                'id' => $user->id,
1381
                'contentInfo' => $user->contentInfo,
1382
                'versionInfo' => $user->versionInfo,
1383
                'fields' => $user->fields,
1384
            ],
1385
            $userReloaded
1386
        );
1387
    }
1388
1389
    /**
1390
     * Test for the loadUserByLogin() method.
1391
     *
1392
     * In some cases people use email as login name, make sure system works as exepcted when asking for user by email.
1393
     *
1394
     * @see \eZ\Publish\API\Repository\UserService::loadUserByLogin()
1395
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserByLogin
1396
     */
1397
    public function testLoadUserByLoginThrowsNotFoundExceptionForUnknownLoginByEmail()
1398
    {
1399
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
1400
1401
        $repository = $this->getRepository();
1402
1403
        $userService = $repository->getUserService();
1404
1405
        /* BEGIN: Use Case */
1406
        $user = $this->createUserVersion1();
0 ignored issues
show
Unused Code introduced by
$user is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1407
1408
        // Lookup by user login by email should behave as normal
1409
        $userService->loadUserByLogin('[email protected]');
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...vice::loadUserByLogin() has been deprecated with message: since eZ Platform 2.5, will be dropped in the next major version as authentication may depend on various user providers. Use UserService::checkUserCredentials() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1410
        /* END: Use Case */
1411
    }
1412
1413
    /**
1414
     * Test for the loadUsersByEmail() method.
1415
     *
1416
     * @see \eZ\Publish\API\Repository\UserService::loadUsersByEmail()
1417
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1418
     */
1419
    public function testLoadUserByEmail()
1420
    {
1421
        $repository = $this->getRepository();
1422
1423
        $userService = $repository->getUserService();
1424
1425
        /* BEGIN: Use Case */
1426
        $user = $this->createUserVersion1();
1427
1428
        // Load the newly created user
1429
        $usersReloaded = $userService->loadUsersByEmail('[email protected]', Language::ALL);
1430
        /* END: Use Case */
1431
1432
        $this->assertEquals([$user], $usersReloaded);
1433
    }
1434
1435
    /**
1436
     * Test for the loadUsersByEmail() method.
1437
     *
1438
     * @see \eZ\Publish\API\Repository\UserService::loadUsersByEmail()
1439
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserByEmail
1440
     */
1441
    public function testLoadUserByEmailReturnsEmptyInUnknownEmail()
1442
    {
1443
        $repository = $this->getRepository();
1444
1445
        $userService = $repository->getUserService();
1446
1447
        /* BEGIN: Use Case */
1448
        $this->createUserVersion1();
1449
1450
        // This call will return empty array, because the given
1451
        // login/password combination does not exist.
1452
        $emptyUserList = $userService->loadUsersByEmail('[email protected]');
1453
        /* END: Use Case */
1454
1455
        $this->assertEquals([], $emptyUserList);
1456
    }
1457
1458
    /**
1459
     * Test for the deleteUser() method.
1460
     *
1461
     * @see \eZ\Publish\API\Repository\UserService::deleteUser()
1462
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1463
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUser
1464
     */
1465
    public function testDeleteUser()
1466
    {
1467
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
1468
1469
        $repository = $this->getRepository();
1470
1471
        $userService = $repository->getUserService();
1472
1473
        /* BEGIN: Use Case */
1474
        $user = $this->createUserVersion1();
1475
1476
        // Delete the currently created user
1477
        $userService->deleteUser($user);
1478
        /* END: Use Case */
1479
1480
        // We use the NotFoundException here to verify that the user not exists
1481
        $userService->loadUser($user->id);
1482
    }
1483
1484
    /**
1485
     * Test for the deleteUser() method.
1486
     *
1487
     * @covers \eZ\Publish\API\Repository\UserService::deleteUser()
1488
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1489
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUser
1490
     */
1491
    public function testDeleteUserDeletesRelatedBookmarks()
1492
    {
1493
        $repository = $this->getRepository();
1494
1495
        $userService = $repository->getUserService();
1496
        $locationService = $repository->getLocationService();
1497
        $bookmarkService = $repository->getBookmarkService();
1498
        /* BEGIN: Use Case */
1499
        $admin = $repository->getPermissionResolver()->getCurrentUserReference();
1500
1501
        $user = $this->createUserVersion1();
1502
1503
        $repository->getPermissionResolver()->setCurrentUserReference($user);
1504
1505
        $bookmarkService->createBookmark(
1506
            $locationService->loadLocation($this->generateId('location', 43))
1507
        );
1508
1509
        $repository->getPermissionResolver()->setCurrentUserReference($admin);
1510
        // Delete the currently created user
1511
        $userService->deleteUser($user);
1512
1513
        $repository->getPermissionResolver()->setCurrentUserReference($user);
1514
        /* END: Use Case */
1515
1516
        $this->assertEquals(0, $bookmarkService->loadBookmarks(0, 9999)->totalCount);
1517
    }
1518
1519
    /**
1520
     * Test for the newUserUpdateStruct() method.
1521
     *
1522
     * @see \eZ\Publish\API\Repository\UserService::newUserUpdateStruct()
1523
     */
1524
    public function testNewUserUpdateStruct()
1525
    {
1526
        $repository = $this->getRepository();
1527
1528
        /* BEGIN: Use Case */
1529
        $userService = $repository->getUserService();
1530
1531
        // Create a new update struct instance
1532
        $userUpdate = $userService->newUserUpdateStruct();
1533
        /* END: Use Case */
1534
1535
        $this->assertInstanceOf(
1536
            UserUpdateStruct::class,
1537
            $userUpdate
1538
        );
1539
1540
        $this->assertNull($userUpdate->contentUpdateStruct);
1541
        $this->assertNull($userUpdate->contentMetadataUpdateStruct);
1542
1543
        $this->assertPropertiesCorrect(
1544
            [
1545
                'email' => null,
1546
                'password' => null,
1547
                'enabled' => null,
1548
                'maxLogin' => null,
1549
            ],
1550
            $userUpdate
1551
        );
1552
    }
1553
1554
    /**
1555
     * Test for the updateUser() method.
1556
     *
1557
     * @return \eZ\Publish\API\Repository\Values\User\User
1558
     *
1559
     * @see \eZ\Publish\API\Repository\UserService::updateUser()
1560
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1561
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserUpdateStruct
1562
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1563
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
1564
     */
1565
    public function testUpdateUser()
1566
    {
1567
        $repository = $this->getRepository();
1568
1569
        $userService = $repository->getUserService();
1570
1571
        /* BEGIN: Use Case */
1572
        $user = $this->createUserVersion1();
1573
1574
        // Create a new update struct instance
1575
        $userUpdate = $userService->newUserUpdateStruct();
1576
1577
        // Set new values for password and maxLogin
1578
        $userUpdate->password = 'my-new-password';
1579
        $userUpdate->maxLogin = 42;
1580
        $userUpdate->enabled = false;
1581
1582
        // Updated the user record.
1583
        $userVersion2 = $userService->updateUser($user, $userUpdate);
1584
        /* END: Use Case */
1585
1586
        $this->assertInstanceOf(User::class, $userVersion2);
1587
1588
        return $userVersion2;
1589
    }
1590
1591
    /**
1592
     * Test for the updateUser() and loadUsersByEmail() method on change to email.
1593
     */
1594
    public function testUpdateUserEmail(): void
1595
    {
1596
        $repository = $this->getRepository();
1597
        $userService = $repository->getUserService();
1598
1599
        // Create a user
1600
        $user = $this->createUserVersion1();
1601
1602
        // Check we get what we expect (and implicit warmup any kind of cache)
1603
        $users = $userService->loadUsersByEmail('[email protected]');
1604
        $this->assertCount(0, $users);
1605
1606
        // Update user with the given email address
1607
        $userUpdate = $userService->newUserUpdateStruct();
1608
        $userUpdate->email = '[email protected]';
1609
        $updatedUser = $userService->updateUser($user, $userUpdate);
1610
        $this->assertInstanceOf(User::class, $updatedUser);
1611
1612
        // Check that we can load user by email
1613
        $users = $userService->loadUsersByEmail('[email protected]');
1614
        $this->assertCount(1, $users);
1615
        $this->assertInstanceOf(User::class, $users[0]);
1616
    }
1617
1618
    /**
1619
     * Test for the updateUser() method.
1620
     *
1621
     * @return \eZ\Publish\API\Repository\Values\User\User
1622
     *
1623
     * @see \eZ\Publish\API\Repository\UserService::updateUser()
1624
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1625
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserUpdateStruct
1626
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContent
1627
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testUpdateContentMetadata
1628
     */
1629
    public function testUpdateUserNoPassword()
1630
    {
1631
        $repository = $this->getRepository();
1632
        $userService = $repository->getUserService();
1633
1634
        /* BEGIN: Use Case */
1635
        $user = $this->createUserVersion1();
1636
1637
        // Create a new update struct instance
1638
        $userUpdate = $userService->newUserUpdateStruct();
1639
1640
        // Set new values for maxLogin, don't change password
1641
        $userUpdate->maxLogin = 43;
1642
        $userUpdate->enabled = false;
1643
1644
        // Updated the user record.
1645
        $userVersion2 = $userService->updateUser($user, $userUpdate);
1646
        /* END: Use Case */
1647
1648
        $this->assertInstanceOf(User::class, $user);
1649
1650
        $this->assertEquals(
1651
            [
1652
                'login' => $user->login,
1653
                'email' => $user->email,
1654
                'passwordHash' => $user->passwordHash,
1655
                'hashAlgorithm' => $user->hashAlgorithm,
1656
                'maxLogin' => 43,
1657
                'enabled' => false,
1658
            ],
1659
            [
1660
                'login' => $userVersion2->login,
1661
                'email' => $userVersion2->email,
1662
                'passwordHash' => $userVersion2->passwordHash,
1663
                'hashAlgorithm' => $userVersion2->hashAlgorithm,
1664
                'maxLogin' => $userVersion2->maxLogin,
1665
                'enabled' => $userVersion2->enabled,
1666
            ]
1667
        );
1668
    }
1669
1670
    /**
1671
     * Test for the updateUser() method.
1672
     *
1673
     * @param \eZ\Publish\API\Repository\Values\User\User $user
1674
     *
1675
     * @see \eZ\Publish\API\Repository\UserService::updateUser()
1676
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUser
1677
     */
1678
    public function testUpdateUserUpdatesExpectedProperties(User $user)
1679
    {
1680
        $this->assertEquals(
1681
            [
1682
                'login' => 'user',
1683
                'email' => '[email protected]',
1684
                'maxLogin' => 42,
1685
                'enabled' => false,
1686
            ],
1687
            [
1688
                'login' => $user->login,
1689
                'email' => $user->email,
1690
                'maxLogin' => $user->maxLogin,
1691
                'enabled' => $user->enabled,
1692
            ]
1693
        );
1694
    }
1695
1696
    /**
1697
     * Test for the updateUser() method.
1698
     *
1699
     * @param \eZ\Publish\API\Repository\Values\User\User $user
1700
     *
1701
     * @see \eZ\Publish\API\Repository\UserService::updateUser()
1702
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUser
1703
     */
1704
    public function testUpdateUserReturnsPublishedVersion(User $user)
1705
    {
1706
        $this->assertEquals(
1707
            APIVersionInfo::STATUS_PUBLISHED,
1708
            $user->getVersionInfo()->status
1709
        );
1710
    }
1711
1712
    /**
1713
     * Test for the updateUser() method.
1714
     *
1715
     * @see \eZ\Publish\API\Repository\UserService::updateUser()
1716
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUser
1717
     */
1718
    public function testUpdateUserWithContentMetadataUpdateStruct()
1719
    {
1720
        $repository = $this->getRepository();
1721
1722
        $userService = $repository->getUserService();
1723
1724
        /* BEGIN: Use Case */
1725
        $user = $this->createUserVersion1();
1726
1727
        // Get the ContentService implementation
1728
        $contentService = $repository->getContentService();
1729
1730
        // Create a metadata update struct and change the remote id.
1731
        $metadataUpdate = $contentService->newContentMetadataUpdateStruct();
1732
        $metadataUpdate->remoteId = '85e10037d1ac0a00aa75443ced483e08';
1733
1734
        // Create a new update struct instance
1735
        $userUpdate = $userService->newUserUpdateStruct();
1736
1737
        // Set the metadata update struct.
1738
        $userUpdate->contentMetadataUpdateStruct = $metadataUpdate;
1739
1740
        // Updated the user record.
1741
        $userVersion2 = $userService->updateUser($user, $userUpdate);
1742
1743
        // The contentInfo->remoteId will be changed now.
1744
        $remoteId = $userVersion2->contentInfo->remoteId;
1745
        /* END: Use Case */
1746
1747
        $this->assertEquals('85e10037d1ac0a00aa75443ced483e08', $remoteId);
1748
    }
1749
1750
    /**
1751
     * Test for the updateUser() method.
1752
     *
1753
     * @see \eZ\Publish\API\Repository\UserService::updateUser()
1754
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUser
1755
     */
1756
    public function testUpdateUserWithContentUpdateStruct()
1757
    {
1758
        $repository = $this->getRepository();
1759
1760
        $userService = $repository->getUserService();
1761
1762
        /* BEGIN: Use Case */
1763
        $user = $this->createUserVersion1();
1764
1765
        // Get the ContentService implementation
1766
        $contentService = $repository->getContentService();
1767
1768
        // Create a content update struct and change the remote id.
1769
        $contentUpdate = $contentService->newContentUpdateStruct();
1770
        $contentUpdate->setField('first_name', 'Hello', 'eng-US');
1771
        $contentUpdate->setField('last_name', 'World', 'eng-US');
1772
1773
        // Create a new update struct instance
1774
        $userUpdate = $userService->newUserUpdateStruct();
1775
1776
        // Set the content update struct.
1777
        $userUpdate->contentUpdateStruct = $contentUpdate;
1778
1779
        // Updated the user record.
1780
        $userVersion2 = $userService->updateUser($user, $userUpdate);
1781
1782
        $name = sprintf(
1783
            '%s %s',
1784
            $userVersion2->getFieldValue('first_name'),
1785
            $userVersion2->getFieldValue('last_name')
1786
        );
1787
        /* END: Use Case */
1788
1789
        $this->assertEquals('Hello World', $name);
1790
    }
1791
1792
    /**
1793
     * Test for the updateUser() method.
1794
     *
1795
     * @see \eZ\Publish\API\Repository\UserService::updateUser()
1796
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUser
1797
     */
1798
    public function testUpdateUserWhenMissingField()
1799
    {
1800
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
1801
1802
        $repository = $this->getRepository();
1803
1804
        $userService = $repository->getUserService();
1805
1806
        /* BEGIN: Use Case */
1807
        $user = $this->createUserVersion1();
1808
1809
        // Get the ContentService implementation
1810
        $contentService = $repository->getContentService();
1811
1812
        // Create a content update struct and change the remote id.
1813
        $contentUpdate = $contentService->newContentUpdateStruct();
1814
        $contentUpdate->setField('first_name', null, 'eng-US');
1815
1816
        // Create a new update struct instance
1817
        $userUpdate = $userService->newUserUpdateStruct();
1818
1819
        // Set the content update struct.
1820
        $userUpdate->contentUpdateStruct = $contentUpdate;
1821
1822
        // This call will fail with a "ContentFieldValidationException" because the
1823
        // mandatory field "first_name" is set to an empty value.
1824
        $userService->updateUser($user, $userUpdate);
1825
1826
        /* END: Use Case */
1827
    }
1828
1829
    /**
1830
     * Test for the updateUser() method.
1831
     *
1832
     * @see \eZ\Publish\API\Repository\UserService::updateUser()
1833
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUser
1834
     */
1835
    public function testUpdateUserThrowsInvalidArgumentExceptionOnFieldTypeNotAccept()
1836
    {
1837
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
1838
1839
        $repository = $this->getRepository();
1840
1841
        $userService = $repository->getUserService();
1842
1843
        /* BEGIN: Use Case */
1844
        $user = $this->createUserVersion1();
1845
1846
        // Get the ContentService implementation
1847
        $contentService = $repository->getContentService();
1848
1849
        $contentUpdate = $contentService->newContentUpdateStruct();
1850
        // An object of stdClass is not valid for the field first_name
1851
        $contentUpdate->setField('first_name', new \stdClass(), 'eng-US');
1852
1853
        // Create a new update struct instance
1854
        $userUpdate = $userService->newUserUpdateStruct();
1855
1856
        // Set the content update struct.
1857
        $userUpdate->contentUpdateStruct = $contentUpdate;
1858
1859
        // This call will fail with a "InvalidArgumentException" because the
1860
        // the field "first_name" does not accept the given value.
1861
        $userService->updateUser($user, $userUpdate);
1862
1863
        /* END: Use Case */
1864
    }
1865
1866
    /**
1867
     * Test updating a user throwing UserPasswordValidationException when password doesn't follow specified rules.
1868
     *
1869
     * @covers \eZ\Publish\API\Repository\UserService::updateUser
1870
     */
1871
    public function testUpdateUserWithWeakPasswordThrowsUserPasswordValidationException()
1872
    {
1873
        $userService = $this->getRepository()->getUserService();
1874
1875
        $user = $this->createTestUserWithPassword('H@xxxiR!_1', $this->createUserContentTypeWithStrongPassword());
1876
1877
        /* BEGIN: Use Case */
1878
        // Create a new update struct instance
1879
        $userUpdate = $userService->newUserUpdateStruct();
1880
        $userUpdate->password = 'pass';
1881
1882
        try {
1883
            // This call will fail with a "UserPasswordValidationException" because the
1884
            // the password does not follow specified rules
1885
            $userService->updateUser($user, $userUpdate);
1886
            /* END: Use Case */
1887
        } catch (ContentFieldValidationException $e) {
1888
            // Exception is caught, as there is no other way to check exception properties.
1889
            $this->assertValidationErrorOccurs($e, 'User password must include at least one special character');
1890
            $this->assertValidationErrorOccurs($e, 'User password must be at least %length% characters long');
1891
            $this->assertValidationErrorOccurs($e, 'User password must include at least one upper case letter');
1892
            $this->assertValidationErrorOccurs($e, 'User password must include at least one number');
1893
1894
            /* END: Use Case */
1895
            return;
1896
        }
1897
1898
        $this->fail('Expected ValidationError messages did not occur.');
1899
    }
1900
1901
    /**
1902
     * Opposite test case for testUpdateUserWithWeakPasswordThrowsUserPasswordValidationException.
1903
     *
1904
     * @covers \eZ\Publish\API\Repository\UserService::updateUser
1905
     */
1906
    public function testUpdateUserWithStrongPassword()
1907
    {
1908
        $userService = $this->getRepository()->getUserService();
1909
1910
        $user = $this->createTestUserWithPassword('H@xxxiR!_1', $this->createUserContentTypeWithStrongPassword());
1911
1912
        /* BEGIN: Use Case */
1913
        // Create a new update struct instance
1914
        $userUpdate = $userService->newUserUpdateStruct();
1915
        $userUpdate->password = 'H@xxxiR!_2';
1916
1917
        $user = $userService->updateUser($user, $userUpdate);
1918
        /* END: Use Case */
1919
1920
        $this->assertInstanceOf(User::class, $user);
1921
    }
1922
1923
    /**
1924
     * Test for the loadUserGroupsOfUser() method.
1925
     *
1926
     * @covers \eZ\Publish\API\Repository\UserService::loadUserGroupsOfUser
1927
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1928
     */
1929
    public function testLoadUserGroupsOfUser()
1930
    {
1931
        $repository = $this->getRepository();
1932
1933
        $userService = $repository->getUserService();
1934
1935
        /* BEGIN: Use Case */
1936
        $user = $this->createUserVersion1();
1937
1938
        // This array will contain the "Editors" user group name
1939
        $userGroupNames = [];
1940
        foreach ($userService->loadUserGroupsOfUser($user) as $userGroup) {
1941
            $this->assertInstanceOf(UserGroup::class, $userGroup);
1942
            $userGroupNames[] = $userGroup->getFieldValue('name');
1943
        }
1944
        /* END: Use Case */
1945
1946
        $this->assertEquals(['Editors'], $userGroupNames);
1947
    }
1948
1949
    /**
1950
     * Test for the loadUsersOfUserGroup() method.
1951
     *
1952
     * @covers \eZ\Publish\API\Repository\UserService::loadUsersOfUserGroup
1953
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1954
     */
1955
    public function testLoadUsersOfUserGroup()
1956
    {
1957
        $repository = $this->getRepository();
1958
        $userService = $repository->getUserService();
1959
1960
        $group = $userService->loadUserGroup($this->generateId('group', 13));
1961
1962
        /* BEGIN: Use Case */
1963
        $this->createUserVersion1();
1964
1965
        $this->refreshSearch($repository);
1966
1967
        // This array will contain the email of the newly created "Editor" user
1968
        $email = [];
1969
        foreach ($userService->loadUsersOfUserGroup($group) as $user) {
1970
            $this->assertInstanceOf(User::class, $user);
1971
            $email[] = $user->email;
1972
        }
1973
        /* END: Use Case */
1974
        $this->assertEquals(['[email protected]'], $email);
1975
    }
1976
1977
    /**
1978
     * Test for the assignUserToUserGroup() method.
1979
     *
1980
     * @see \eZ\Publish\API\Repository\UserService::assignUserToUserGroup()
1981
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroupsOfUser
1982
     */
1983
    public function testAssignUserToUserGroup()
1984
    {
1985
        $repository = $this->getRepository();
1986
        $userService = $repository->getUserService();
1987
1988
        $administratorGroupId = $this->generateId('group', 12);
1989
        /* BEGIN: Use Case */
1990
        // $administratorGroupId is the ID of the "Administrator" group in an
1991
        // eZ Publish demo installation
1992
1993
        $user = $this->createUserVersion1();
1994
1995
        // Assign group to newly created user
1996
        $userService->assignUserToUserGroup(
1997
            $user,
1998
            $userService->loadUserGroup($administratorGroupId)
1999
        );
2000
2001
        // This array will contain "Editors" and "Administrator users"
2002
        $userGroupNames = [];
2003
        foreach ($userService->loadUserGroupsOfUser($user) as $userGroup) {
2004
            $userGroupNames[] = $userGroup->getFieldValue('name');
2005
        }
2006
        /* END: Use Case */
2007
2008
        sort($userGroupNames, SORT_STRING);
2009
2010
        $this->assertEquals(
2011
            [
2012
                'Administrator users',
2013
                'Editors',
2014
            ],
2015
            $userGroupNames
2016
        );
2017
    }
2018
2019
    /**
2020
     * Test for the assignUserToUserGroup() method.
2021
     *
2022
     * @covers \eZ\Publish\API\Repository\UserService::assignUserToUserGroup
2023
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testAssignUserToUserGroup
2024
     */
2025
    public function testAssignUserToUserGroupThrowsInvalidArgumentException()
2026
    {
2027
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
2028
        $this->expectExceptionMessage('Argument \'user\' is invalid: User is already in the given User Group');
2029
2030
        $repository = $this->getRepository();
2031
        $userService = $repository->getUserService();
2032
2033
        $editorsGroupId = $this->generateId('group', 13);
2034
        /* BEGIN: Use Case */
2035
        $user = $this->createUserVersion1();
2036
        // $editorsGroupId is the ID of the "Editors" group in an
2037
        // eZ Publish demo installation
2038
2039
        // This call will fail with an "InvalidArgumentException", because the
2040
        // user is already assigned to the "Editors" group
2041
        $userService->assignUserToUserGroup(
2042
            $user,
2043
            $userService->loadUserGroup($editorsGroupId)
2044
        );
2045
        /* END: Use Case */
2046
    }
2047
2048
    /**
2049
     * Test for the unAssignUssrFromUserGroup() method.
2050
     *
2051
     * @see \eZ\Publish\API\Repository\UserService::unAssignUssrFromUserGroup()
2052
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroupsOfUser
2053
     */
2054
    public function testUnAssignUserFromUserGroup()
2055
    {
2056
        $repository = $this->getRepository();
2057
        $userService = $repository->getUserService();
2058
2059
        $editorsGroupId = $this->generateId('group', 13);
2060
        $anonymousGroupId = $this->generateId('group', 42);
2061
2062
        /* BEGIN: Use Case */
2063
        // $anonymousGroupId is the ID of the "Anonymous Users" group in an eZ
2064
        // Publish demo installation
2065
2066
        $user = $this->createUserVersion1();
2067
2068
        // Assign group to newly created user
2069
        $userService->assignUserToUserGroup(
2070
            $user,
2071
            $userService->loadUserGroup($anonymousGroupId)
2072
        );
2073
2074
        // Unassign user from "Editors" group
2075
        $userService->unAssignUserFromUserGroup(
2076
            $user,
2077
            $userService->loadUserGroup($editorsGroupId)
2078
        );
2079
2080
        // This array will contain "Anonymous Users"
2081
        $userGroupNames = [];
2082
        foreach ($userService->loadUserGroupsOfUser($user) as $userGroup) {
2083
            $userGroupNames[] = $userGroup->getFieldValue('name');
2084
        }
2085
        /* END: Use Case */
2086
2087
        $this->assertEquals(['Anonymous Users'], $userGroupNames);
2088
    }
2089
2090
    /**
2091
     * Test for the unAssignUserFromUserGroup() method.
2092
     *
2093
     * @see \eZ\Publish\API\Repository\UserService::unAssignUserFromUserGroup()
2094
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUnAssignUserFromUserGroup
2095
     */
2096
    public function testUnAssignUserFromUserGroupThrowsInvalidArgumentException()
2097
    {
2098
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
2099
2100
        $repository = $this->getRepository();
2101
        $userService = $repository->getUserService();
2102
2103
        $administratorGroupId = $this->generateId('group', 12);
2104
        /* BEGIN: Use Case */
2105
        $user = $this->createUserVersion1();
2106
        // $administratorGroupId is the ID of the "Administrator" group in an
2107
        // eZ Publish demo installation
2108
2109
        // This call will fail with an "InvalidArgumentException", because the
2110
        // user is not assigned to the "Administrator" group
2111
        $userService->unAssignUserFromUserGroup(
2112
            $user,
2113
            $userService->loadUserGroup($administratorGroupId)
2114
        );
2115
        /* END: Use Case */
2116
    }
2117
2118
    /**
2119
     * Test for the unAssignUserFromUserGroup() method removing user from the last group.
2120
     *
2121
     * @covers \eZ\Publish\API\Repository\UserService::unAssignUserFromUserGroup
2122
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUnAssignUserFromUserGroup
2123
     */
2124
    public function testUnAssignUserFromUserGroupThrowsBadStateArgumentException()
2125
    {
2126
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
2127
        $this->expectExceptionMessage('Argument \'user\' has a bad state: User only has one User Group, cannot unassign from last group');
2128
2129
        $repository = $this->getRepository();
2130
        $userService = $repository->getUserService();
2131
2132
        $editorsGroupId = $this->generateId('group', 13);
2133
        /* BEGIN: Use Case */
2134
        $user = $this->createUserVersion1();
2135
2136
        // This call will fail with an "BadStateException", because the
2137
        // user has to be assigned to at least one group
2138
        $userService->unAssignUserFromUserGroup(
2139
            $user,
2140
            $userService->loadUserGroup($editorsGroupId)
2141
        );
2142
        /* END: Use Case */
2143
    }
2144
2145
    /**
2146
     * Test that multi-language logic for the loadUserGroup method respects prioritized language list.
2147
     *
2148
     * @covers \eZ\Publish\API\Repository\UserService::loadUserGroup
2149
     * @dataProvider getPrioritizedLanguageList
2150
     *
2151
     * @param string[] $prioritizedLanguages
2152
     * @param string|null $expectedLanguageCode language code of expected translation
2153
     */
2154
    public function testLoadUserGroupWithPrioritizedLanguagesList(
2155
        array $prioritizedLanguages,
2156
        $expectedLanguageCode
2157
    ) {
2158
        $repository = $this->getRepository();
2159
        $userService = $repository->getUserService();
2160
2161
        $userGroup = $this->createMultiLanguageUserGroup();
2162
        if ($expectedLanguageCode === null) {
2163
            $expectedLanguageCode = $userGroup->contentInfo->mainLanguageCode;
2164
        }
2165
2166
        $loadedUserGroup = $userService->loadUserGroup($userGroup->id, $prioritizedLanguages);
2167
2168
        self::assertEquals(
2169
            $loadedUserGroup->getName($expectedLanguageCode),
2170
            $loadedUserGroup->getName()
2171
        );
2172
        self::assertEquals(
2173
            $loadedUserGroup->getFieldValue('description', $expectedLanguageCode),
2174
            $loadedUserGroup->getFieldValue('description')
2175
        );
2176
    }
2177
2178
    /**
2179
     * Test that multi-language logic works correctly after updating user group main language.
2180
     *
2181
     * @covers \eZ\Publish\API\Repository\UserService::loadUserGroup
2182
     * @dataProvider getPrioritizedLanguageList
2183
     *
2184
     * @param string[] $prioritizedLanguages
2185
     * @param string|null $expectedLanguageCode language code of expected translation
2186
     */
2187
    public function testLoadUserGroupWithPrioritizedLanguagesListAfterMainLanguageUpdate(
2188
        array $prioritizedLanguages,
2189
        $expectedLanguageCode
2190
    ) {
2191
        $repository = $this->getRepository();
2192
        $userService = $repository->getUserService();
2193
        $contentService = $repository->getContentService();
2194
2195
        $userGroup = $this->createMultiLanguageUserGroup();
2196
2197
        $userGroupUpdateStruct = $userService->newUserGroupUpdateStruct();
2198
        $userGroupUpdateStruct->contentMetadataUpdateStruct = $contentService->newContentMetadataUpdateStruct();
2199
        $userGroupUpdateStruct->contentMetadataUpdateStruct->mainLanguageCode = 'eng-GB';
2200
        $userService->updateUserGroup($userGroup, $userGroupUpdateStruct);
2201
2202
        if ($expectedLanguageCode === null) {
2203
            $expectedLanguageCode = 'eng-GB';
2204
        }
2205
2206
        $loadedUserGroup = $userService->loadUserGroup($userGroup->id, $prioritizedLanguages);
2207
2208
        self::assertEquals(
2209
            $loadedUserGroup->getName($expectedLanguageCode),
2210
            $loadedUserGroup->getName()
2211
        );
2212
        self::assertEquals(
2213
            $loadedUserGroup->getFieldValue('description', $expectedLanguageCode),
2214
            $loadedUserGroup->getFieldValue('description')
2215
        );
2216
    }
2217
2218
    /**
2219
     * Test that multi-language logic for the loadSubUserGroups method respects prioritized language list.
2220
     *
2221
     * @covers \eZ\Publish\API\Repository\UserService::loadSubUserGroups
2222
     * @dataProvider getPrioritizedLanguageList
2223
     *
2224
     * @param string[] $prioritizedLanguages
2225
     * @param string|null $expectedLanguageCode language code of expected translation
2226
     */
2227
    public function testLoadSubUserGroupsWithPrioritizedLanguagesList(
2228
        array $prioritizedLanguages,
2229
        $expectedLanguageCode
2230
    ) {
2231
        $repository = $this->getRepository();
2232
        $userService = $repository->getUserService();
2233
2234
        // create main group for subgroups
2235
        $userGroup = $this->createMultiLanguageUserGroup(4);
2236
        if ($expectedLanguageCode === null) {
2237
            $expectedLanguageCode = $userGroup->contentInfo->mainLanguageCode;
2238
        }
2239
2240
        // create subgroups
2241
        $this->createMultiLanguageUserGroup($userGroup->id);
2242
        $this->createMultiLanguageUserGroup($userGroup->id);
2243
2244
        $userGroup = $userService->loadUserGroup($userGroup->id, $prioritizedLanguages);
2245
2246
        $subUserGroups = $userService->loadSubUserGroups($userGroup, 0, 2, $prioritizedLanguages);
2247
        foreach ($subUserGroups as $subUserGroup) {
2248
            self::assertEquals(
2249
                $subUserGroup->getName($expectedLanguageCode),
2250
                $subUserGroup->getName()
2251
            );
2252
            self::assertEquals(
2253
                $subUserGroup->getFieldValue('description', $expectedLanguageCode),
2254
                $subUserGroup->getFieldValue('description')
2255
            );
2256
        }
2257
    }
2258
2259
    /**
2260
     * Test that multi-language logic for the loadUser method respects prioritized language list.
2261
     *
2262
     * @covers \eZ\Publish\API\Repository\UserService::loadUser
2263
     * @dataProvider getPrioritizedLanguageList
2264
     *
2265
     * @param string[] $prioritizedLanguages
2266
     * @param string|null $expectedLanguageCode language code of expected translation
2267
     */
2268
    public function testLoadUserWithPrioritizedLanguagesList(
2269
        array $prioritizedLanguages,
2270
        $expectedLanguageCode
2271
    ) {
2272
        $repository = $this->getRepository();
2273
        $userService = $repository->getUserService();
2274
2275
        $user = $this->createMultiLanguageUser();
2276
        if ($expectedLanguageCode === null) {
2277
            $expectedLanguageCode = $user->contentInfo->mainLanguageCode;
2278
        }
2279
2280
        $loadedUser = $userService->loadUser($user->id, $prioritizedLanguages);
2281
2282
        self::assertEquals(
2283
            $loadedUser->getName($expectedLanguageCode),
2284
            $loadedUser->getName()
2285
        );
2286
2287
        foreach (['fist_name', 'last_name', 'signature'] as $fieldIdentifier) {
2288
            self::assertEquals(
2289
                $loadedUser->getFieldValue($fieldIdentifier, $expectedLanguageCode),
2290
                $loadedUser->getFieldValue($fieldIdentifier)
2291
            );
2292
        }
2293
    }
2294
2295
    /**
2296
     * Test that multi-language logic for the loadUser method works correctly after updating
2297
     * user content main language.
2298
     *
2299
     * @covers \eZ\Publish\API\Repository\UserService::loadUserGroup
2300
     * @dataProvider getPrioritizedLanguageList
2301
     *
2302
     * @param string[] $prioritizedLanguages
2303
     * @param string|null $expectedLanguageCode language code of expected translation
2304
     */
2305
    public function testLoadUserWithPrioritizedLanguagesListAfterMainLanguageUpdate(
2306
        array $prioritizedLanguages,
2307
        $expectedLanguageCode
2308
    ) {
2309
        $repository = $this->getRepository();
2310
        $userService = $repository->getUserService();
2311
        $contentService = $repository->getContentService();
2312
2313
        $user = $this->createMultiLanguageUser();
2314
        // sanity check
2315
        self::assertEquals($user->contentInfo->mainLanguageCode, 'eng-US');
2316
2317
        $userUpdateStruct = $userService->newUserUpdateStruct();
2318
        $userUpdateStruct->contentMetadataUpdateStruct = $contentService->newContentMetadataUpdateStruct();
2319
        $userUpdateStruct->contentMetadataUpdateStruct->mainLanguageCode = 'eng-GB';
2320
        $userService->updateUser($user, $userUpdateStruct);
2321
        if ($expectedLanguageCode === null) {
2322
            $expectedLanguageCode = 'eng-GB';
2323
        }
2324
2325
        $loadedUser = $userService->loadUser($user->id, $prioritizedLanguages);
2326
2327
        self::assertEquals(
2328
            $loadedUser->getName($expectedLanguageCode),
2329
            $loadedUser->getName()
2330
        );
2331
2332
        foreach (['fist_name', 'last_name', 'signature'] as $fieldIdentifier) {
2333
            self::assertEquals(
2334
                $loadedUser->getFieldValue($fieldIdentifier, $expectedLanguageCode),
2335
                $loadedUser->getFieldValue($fieldIdentifier)
2336
            );
2337
        }
2338
    }
2339
2340
    /**
2341
     * Test that multi-language logic for the loadUserByLogin method respects prioritized language list.
2342
     *
2343
     * @covers \eZ\Publish\API\Repository\UserService::loadUserByLogin
2344
     * @dataProvider getPrioritizedLanguageList
2345
     *
2346
     * @param string[] $prioritizedLanguages
2347
     * @param string|null $expectedLanguageCode language code of expected translation
2348
     */
2349
    public function testLoadUserByLoginWithPrioritizedLanguagesList(
2350
        array $prioritizedLanguages,
2351
        $expectedLanguageCode
2352
    ) {
2353
        $repository = $this->getRepository();
2354
        $userService = $repository->getUserService();
2355
        $user = $this->createMultiLanguageUser();
2356
2357
        // load, with prioritized languages, the newly created user
2358
        $loadedUser = $userService->loadUserByLogin($user->login, $prioritizedLanguages);
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...vice::loadUserByLogin() has been deprecated with message: since eZ Platform 2.5, will be dropped in the next major version as authentication may depend on various user providers. Use UserService::checkUserCredentials() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
2359
        if ($expectedLanguageCode === null) {
2360
            $expectedLanguageCode = $loadedUser->contentInfo->mainLanguageCode;
2361
        }
2362
2363
        self::assertEquals(
2364
            $loadedUser->getName($expectedLanguageCode),
2365
            $loadedUser->getName()
2366
        );
2367
2368
        foreach (['first_name', 'last_name', 'signature'] as $fieldIdentifier) {
2369
            self::assertEquals(
2370
                $loadedUser->getFieldValue($fieldIdentifier, $expectedLanguageCode),
2371
                $loadedUser->getFieldValue($fieldIdentifier)
2372
            );
2373
        }
2374
    }
2375
2376
    /**
2377
     * Test that multi-language logic for the loadUsersByEmail method respects
2378
     * prioritized language list.
2379
     *
2380
     * @covers \eZ\Publish\API\Repository\UserService::loadUsersByEmail
2381
     * @dataProvider getPrioritizedLanguageList
2382
     *
2383
     * @param string[] $prioritizedLanguages
2384
     * @param string|null $expectedLanguageCode language code of expected translation
2385
     */
2386
    public function testLoadUsersByEmailWithPrioritizedLanguagesList(
2387
        array $prioritizedLanguages,
2388
        $expectedLanguageCode
2389
    ) {
2390
        $repository = $this->getRepository();
2391
        $userService = $repository->getUserService();
2392
        $user = $this->createMultiLanguageUser();
2393
2394
        // load, with prioritized languages, users by email
2395
        $loadedUsers = $userService->loadUsersByEmail($user->email, $prioritizedLanguages);
2396
2397
        foreach ($loadedUsers as $loadedUser) {
2398
            if ($expectedLanguageCode === null) {
2399
                $expectedLanguageCode = $loadedUser->contentInfo->mainLanguageCode;
2400
            }
2401
            self::assertEquals(
2402
                $loadedUser->getName($expectedLanguageCode),
2403
                $loadedUser->getName()
2404
            );
2405
2406
            foreach (['first_name', 'last_name', 'signature'] as $fieldIdentifier) {
2407
                self::assertEquals(
2408
                    $loadedUser->getFieldValue($fieldIdentifier, $expectedLanguageCode),
2409
                    $loadedUser->getFieldValue($fieldIdentifier)
2410
                );
2411
            }
2412
        }
2413
    }
2414
2415
    /**
2416
     * Test that multi-language logic for the loadUserGroupsOfUser method respects
2417
     * prioritized language list.
2418
     *
2419
     * @covers \eZ\Publish\API\Repository\UserService::loadUserGroupsOfUser
2420
     * @dataProvider getPrioritizedLanguageList
2421
     *
2422
     * @param string[] $prioritizedLanguages
2423
     * @param string|null $expectedLanguageCode language code of expected translation
2424
     */
2425
    public function testLoadUserGroupsOfUserWithPrioritizedLanguagesList(
2426
        array $prioritizedLanguages,
2427
        $expectedLanguageCode
2428
    ) {
2429
        $repository = $this->getRepository();
2430
        $userService = $repository->getUserService();
2431
        $userGroup = $this->createMultiLanguageUserGroup();
2432
        $user = $this->createMultiLanguageUser($userGroup->id);
2433
2434
        $userGroups = $userService->loadUserGroupsOfUser($user, 0, 25, $prioritizedLanguages);
2435
        foreach ($userGroups as $userGroup) {
2436
            self::assertEquals(
2437
                $userGroup->getName($expectedLanguageCode),
2438
                $userGroup->getName()
2439
            );
2440
            self::assertEquals(
2441
                $userGroup->getFieldValue('description', $expectedLanguageCode),
2442
                $userGroup->getFieldValue('description')
2443
            );
2444
        }
2445
    }
2446
2447
    /**
2448
     * Test that multi-language logic for the loadUsersOfUserGroup method respects
2449
     * prioritized language list.
2450
     *
2451
     * @covers \eZ\Publish\API\Repository\UserService::loadUsersOfUserGroup
2452
     * @dataProvider getPrioritizedLanguageList
2453
     *
2454
     * @param string[] $prioritizedLanguages
2455
     * @param string|null $expectedLanguageCode language code of expected translation
2456
     */
2457
    public function testLoadUsersOfUserGroupWithPrioritizedLanguagesList(
2458
        array $prioritizedLanguages,
2459
        $expectedLanguageCode
2460
    ) {
2461
        $repository = $this->getRepository();
2462
        $userService = $repository->getUserService();
2463
2464
        // create parent user group
2465
        $userGroup = $this->createMultiLanguageUserGroup();
2466
        // add two users to the created parent user group
2467
        $this->createMultiLanguageUser($userGroup->id);
2468
        $this->createMultiLanguageUser($userGroup->id);
2469
2470
        // test loading of users via user group with prioritized languages list
2471
        $users = $userService->loadUsersOfUserGroup($userGroup, 0, 25, $prioritizedLanguages);
2472
        foreach ($users as $user) {
2473
            if ($expectedLanguageCode === null) {
2474
                $expectedLanguageCode = $user->contentInfo->mainLanguageCode;
2475
            }
2476
            self::assertEquals(
2477
                $user->getName($expectedLanguageCode),
2478
                $user->getName()
2479
            );
2480
2481
            foreach (['first_name', 'last_name', 'signature'] as $fieldIdentifier) {
2482
                self::assertEquals(
2483
                    $user->getFieldValue($fieldIdentifier, $expectedLanguageCode),
2484
                    $user->getFieldValue($fieldIdentifier)
2485
                );
2486
            }
2487
        }
2488
    }
2489
2490
    /**
2491
     * Get prioritized languages list data.
2492
     *
2493
     * Test cases using this data provider should expect the following arguments:
2494
     * <code>
2495
     *   array $prioritizedLanguagesList
2496
     *   string $expectedLanguage (if null - use main language)
2497
     * </code>
2498
     *
2499
     * @return array
2500
     */
2501
    public function getPrioritizedLanguageList()
2502
    {
2503
        return [
2504
            [[], null],
2505
            [['eng-US'], 'eng-US'],
2506
            [['eng-GB'], 'eng-GB'],
2507
            [['eng-US', 'eng-GB'], 'eng-US'],
2508
            [['eng-GB', 'eng-US'], 'eng-GB'],
2509
            // use non-existent group as the first one
2510
            [['ger-DE'], null],
2511
            [['ger-DE', 'eng-GB'], 'eng-GB'],
2512
        ];
2513
    }
2514
2515
    /**
2516
     * @param int $parentGroupId
2517
     *
2518
     * @return \eZ\Publish\API\Repository\Values\User\UserGroup
2519
     */
2520
    private function createMultiLanguageUserGroup($parentGroupId = 4)
2521
    {
2522
        $repository = $this->getRepository();
2523
        $userService = $repository->getUserService();
2524
2525
        // create user group with multiple translations
2526
        $parentGroupId = $this->generateId('group', $parentGroupId);
2527
        $parentGroup = $userService->loadUserGroup($parentGroupId);
2528
2529
        $userGroupCreateStruct = $userService->newUserGroupCreateStruct('eng-US');
2530
        $userGroupCreateStruct->setField('name', 'US user group', 'eng-US');
2531
        $userGroupCreateStruct->setField('name', 'GB user group', 'eng-GB');
2532
        $userGroupCreateStruct->setField('description', 'US user group description', 'eng-US');
2533
        $userGroupCreateStruct->setField('description', 'GB user group description', 'eng-GB');
2534
        $userGroupCreateStruct->alwaysAvailable = true;
2535
2536
        return $userService->createUserGroup($userGroupCreateStruct, $parentGroup);
2537
    }
2538
2539
    /**
2540
     * Create a user group fixture in a variable named <b>$userGroup</b>,.
2541
     *
2542
     * @return \eZ\Publish\API\Repository\Values\User\UserGroup
2543
     */
2544
    private function createUserGroupVersion1()
2545
    {
2546
        $repository = $this->getRepository();
2547
2548
        $mainGroupId = $this->generateId('group', 4);
2549
        /* BEGIN: Inline */
2550
        // $mainGroupId is the ID of the main "Users" group
2551
2552
        $userService = $repository->getUserService();
2553
2554
        // Load main group
2555
        $parentUserGroup = $userService->loadUserGroup($mainGroupId);
2556
2557
        // Instantiate a new create struct
2558
        $userGroupCreate = $userService->newUserGroupCreateStruct('eng-US');
2559
        $userGroupCreate->setField('name', 'Example Group');
2560
2561
        // Create the new user group
2562
        $userGroup = $userService->createUserGroup(
2563
            $userGroupCreate,
2564
            $parentUserGroup
2565
        );
2566
        /* END: Inline */
2567
2568
        return $userGroup;
2569
    }
2570
2571
    /**
2572
     * Create user with multiple translations of User Content fields.
2573
     *
2574
     * @param int $userGroupId User group ID (default 13 - Editors)
2575
     *
2576
     * @return \eZ\Publish\API\Repository\Values\User\User
2577
     */
2578
    private function createMultiLanguageUser($userGroupId = 13)
2579
    {
2580
        $repository = $this->getRepository();
2581
        $userService = $repository->getUserService();
2582
2583
        // Instantiate a create struct with mandatory properties
2584
        $randomLogin = md5(mt_rand() . time());
2585
        $userCreateStruct = $userService->newUserCreateStruct(
2586
            $randomLogin,
2587
            "{$randomLogin}@example.com",
2588
            'secret',
2589
            'eng-US'
2590
        );
2591
        $userCreateStruct->enabled = true;
2592
        $userCreateStruct->alwaysAvailable = true;
2593
2594
        // set field for each language
2595
        foreach (['eng-US', 'eng-GB'] as $languageCode) {
2596
            $userCreateStruct->setField('first_name', "{$languageCode} Example", $languageCode);
2597
            $userCreateStruct->setField('last_name', "{$languageCode} User", $languageCode);
2598
            $userCreateStruct->setField('signature', "{$languageCode} signature", $languageCode);
2599
        }
2600
2601
        // Load parent group for the user
2602
        $group = $userService->loadUserGroup($userGroupId);
2603
2604
        // Create a new user
2605
        return $userService->createUser($userCreateStruct, [$group]);
2606
    }
2607
2608
    /**
2609
     * Test for the createUser() method.
2610
     *
2611
     * @see \eZ\Publish\API\Repository\UserService::createUser()
2612
     */
2613
    public function testCreateUserInvalidPasswordHashTypeThrowsException()
2614
    {
2615
        $repository = $this->getRepository();
2616
        $eventUserService = $repository->getUserService();
2617
2618
        // Instantiate a create struct with mandatory properties.
2619
        $createStruct = $eventUserService->newUserCreateStruct(
2620
            'user',
2621
            '[email protected]',
2622
            'secret',
2623
            'eng-US'
2624
        );
2625
2626
        // Set some fields required by the user ContentType.
2627
        $createStruct->setField('first_name', 'Example');
2628
        $createStruct->setField('last_name', 'User');
2629
2630
        // Get User fieldType.
2631
        $userFieldDef = null;
2632
        foreach ($createStruct->fields as $field) {
2633
            if ($field->fieldTypeIdentifier === 'ezuser') {
2634
                $userFieldDef = $field;
2635
                break;
2636
            }
2637
        }
2638
2639
        if (!$userFieldDef) {
2640
            $this->fail('User FieldType not found in userCreateStruct!');
2641
        }
2642
2643
        /** @var \eZ\Publish\Core\FieldType\User\Value $userValue */
2644
        $userValue = $userFieldDef->value;
2645
2646
        // Set not supported hash type.
2647
        $userValue->passwordHashType = 42424242;
2648
2649
        $this->expectException(InvalidArgumentException::class);
2650
        $this->expectExceptionMessage("Argument 'hashType' is invalid: Password hash type '42424242' is not recognized");
2651
2652
        // Create a new user instance.
2653
        // 13 is ID of the "Editors" user group in an eZ Publish demo installation.
2654
        $eventUserService->createUser($createStruct, [$eventUserService->loadUserGroup(13)]);
2655
    }
2656
2657
    /**
2658
     * Test loading User by Token.
2659
     *
2660
     * @covers \eZ\Publish\API\Repository\UserService::loadUserByToken
2661
     */
2662
    public function testLoadUserByToken()
2663
    {
2664
        $repository = $this->getRepository();
2665
        $userService = $repository->getUserService();
2666
2667
        $user = $this->createUserVersion1();
2668
2669
        $userTokenUpdateStruct = new UserTokenUpdateStruct();
2670
        $userTokenUpdateStruct->hashKey = md5('hash');
2671
        $userTokenUpdateStruct->time = (new DateTime())->add(new DateInterval('PT10S'));
2672
2673
        $userService->updateUserToken($user, $userTokenUpdateStruct);
2674
2675
        $loadedUser = $userService->loadUserByToken($userTokenUpdateStruct->hashKey, Language::ALL);
2676
        self::assertEquals($user, $loadedUser);
2677
2678
        return $userTokenUpdateStruct->hashKey;
2679
    }
2680
2681
    /**
2682
     * Test trying to load User by invalid Token.
2683
     *
2684
     * @covers \eZ\Publish\API\Repository\UserService::loadUserByToken
2685
     */
2686
    public function testLoadUserByTokenThrowsNotFoundException()
2687
    {
2688
        $this->expectException(NotFoundException::class);
2689
2690
        $repository = $this->getRepository();
2691
        $userService = $repository->getUserService();
2692
2693
        $user = $this->createUserVersion1();
2694
2695
        $userTokenUpdateStruct = new UserTokenUpdateStruct();
2696
        $userTokenUpdateStruct->hashKey = md5('hash');
2697
        $userTokenUpdateStruct->time = new DateTime();
2698
2699
        $userService->updateUserToken($user, $userTokenUpdateStruct);
2700
2701
        $userService->loadUserByToken('not_existing_token');
2702
    }
2703
2704
    /**
2705
     * Test updating User Token.
2706
     *
2707
     * @covers \eZ\Publish\API\Repository\UserService::updateUserToken()
2708
     *
2709
     * @depends testLoadUserByToken
2710
     *
2711
     * @param string $originalUserToken
2712
     */
2713
    public function testUpdateUserToken($originalUserToken)
2714
    {
2715
        $repository = $this->getRepository(false);
2716
        $userService = $repository->getUserService();
2717
2718
        $user = $userService->loadUserByToken($originalUserToken);
2719
2720
        $userTokenUpdateStruct = new UserTokenUpdateStruct();
2721
        $userTokenUpdateStruct->hashKey = md5('my_updated_hash');
2722
        $userTokenUpdateStruct->time = (new DateTime())->add(new DateInterval('PT10S'));
2723
2724
        $userService->updateUserToken($user, $userTokenUpdateStruct);
2725
2726
        $loadedUser = $userService->loadUserByToken($userTokenUpdateStruct->hashKey);
2727
        self::assertEquals($user, $loadedUser);
2728
    }
2729
2730
    /**
2731
     * Test invalidating (expiring) User Token.
2732
     *
2733
     * @covers \eZ\Publish\API\Repository\UserService::expireUserToken()
2734
     *
2735
     * @depends testLoadUserByToken
2736
     *
2737
     * @param string $userToken
2738
     */
2739
    public function testExpireUserToken($userToken)
2740
    {
2741
        $this->expectException(NotFoundException::class);
2742
2743
        $repository = $this->getRepository(false);
2744
        $userService = $repository->getUserService();
2745
2746
        // sanity check
2747
        $userService->loadUserByToken($userToken);
2748
2749
        $userService->expireUserToken($userToken);
2750
2751
        // should throw NotFoundException now
2752
        $userService->loadUserByToken($userToken);
2753
    }
2754
2755
    /**
2756
     * @covers \eZ\Publish\API\Repository\UserService::validatePassword()
2757
     */
2758
    public function testValidatePasswordWithDefaultContext()
2759
    {
2760
        $userService = $this->getRepository()->getUserService();
2761
2762
        /* BEGIN: Use Case */
2763
        $errors = $userService->validatePassword('pass');
2764
        /* END: Use Case */
2765
2766
        $this->assertEmpty($errors);
2767
    }
2768
2769
    /**
2770
     * @covers \eZ\Publish\API\Repository\UserService::validatePassword()
2771
     * @dataProvider dataProviderForValidatePassword
2772
     */
2773
    public function testValidatePassword(string $password, array $expectedErrors)
2774
    {
2775
        $userService = $this->getRepository()->getUserService();
2776
        $contentType = $this->createUserContentTypeWithStrongPassword();
2777
2778
        /* BEGIN: Use Case */
2779
        $context = new PasswordValidationContext([
2780
            'contentType' => $contentType,
2781
        ]);
2782
2783
        $actualErrors = $userService->validatePassword($password, $context);
2784
        /* END: Use Case */
2785
2786
        $this->assertEquals($expectedErrors, $actualErrors);
2787
    }
2788
2789
    public function testValidatePasswordReturnsErrorWhenOldPasswordIsReused(): void
2790
    {
2791
        $password = 'P@blish123!';
2792
2793
        $userService = $this->getRepository()->getUserService();
2794
        // Password expiration needs to be enabled
2795
        $contentType = $this->createUserContentTypeWithPasswordExpirationDate();
2796
2797
        $user = $this->createTestUserWithPassword($password, $contentType);
2798
2799
        $context = new PasswordValidationContext([
2800
            'contentType' => $contentType,
2801
            'user' => $user,
2802
        ]);
2803
2804
        $actualErrors = $userService->validatePassword($password, $context);
2805
2806
        $this->assertEquals(
2807
            [new ValidationError('New password cannot be the same as old password', null, [], 'password')],
2808
            $actualErrors
2809
        );
2810
    }
2811
2812
    /**
2813
     * Data provider for testValidatePassword.
2814
     *
2815
     * @return array
2816
     */
2817
    public function dataProviderForValidatePassword(): array
2818
    {
2819
        return [
2820
            [
2821
                'pass',
2822
                [
2823
                    new ValidationError('User password must be at least %length% characters long', null, [
2824
                        '%length%' => 8,
2825
                    ], 'password'),
2826
                    new ValidationError('User password must include at least one upper case letter', null, [], 'password'),
2827
                    new ValidationError('User password must include at least one number', null, [], 'password'),
2828
                    new ValidationError('User password must include at least one special character', null, [], 'password'),
2829
                ],
2830
            ],
2831
            [
2832
                'H@xxxi0R!!!',
2833
                [],
2834
            ],
2835
        ];
2836
    }
2837
2838
    public function testGetPasswordInfo(): void
2839
    {
2840
        $userService = $this->getRepository()->getUserService();
2841
        $contentType = $this->createUserContentTypeWithPasswordExpirationDate(
2842
            self::EXAMPLE_PASSWORD_TTL,
2843
            self::EXAMPLE_PASSWORD_TTL_WARNING
2844
        );
2845
2846
        $user = $this->createTestUser($contentType);
2847
2848
        /* BEGIN: Use Case */
2849
        $passwordInfo = $userService->getPasswordInfo($user);
2850
        /* END: Use Case */
2851
2852
        $passwordUpdatedAt = $user->passwordUpdatedAt;
2853
        if ($passwordUpdatedAt instanceof DateTime) {
2854
            $passwordUpdatedAt = DateTimeImmutable::createFromFormat(DateTime::ATOM, $passwordUpdatedAt->format(DateTime::ATOM));
2855
        }
2856
2857
        $expectedPasswordExpirationDate = $passwordUpdatedAt->add(
2858
            new DateInterval(sprintf('P%dD', self::EXAMPLE_PASSWORD_TTL))
2859
        );
2860
2861
        $expectedPasswordExpirationWarningDate = $passwordUpdatedAt->add(
2862
            new DateInterval(sprintf('P%dD', self::EXAMPLE_PASSWORD_TTL - self::EXAMPLE_PASSWORD_TTL_WARNING))
2863
        );
2864
2865
        $this->assertEquals(new PasswordInfo(
2866
            $expectedPasswordExpirationDate,
2867
            $expectedPasswordExpirationWarningDate
2868
        ), $passwordInfo);
2869
    }
2870
2871
    public function testGetPasswordInfoIfExpirationIsDisabled(): void
2872
    {
2873
        $userService = $this->getRepository()->getUserService();
2874
        $contentType = $this->createUserContentTypeWithPasswordExpirationDate(null, null);
2875
2876
        $user = $this->createTestUser($contentType);
2877
2878
        /* BEGIN: Use Case */
2879
        $passwordInfo = $userService->getPasswordInfo($user);
2880
        /* END: Use Case */
2881
2882
        $this->assertEquals(new PasswordInfo(), $passwordInfo);
2883
    }
2884
2885
    public function testGetPasswordInfoIfExpirationWarningIsDisabled(): void
2886
    {
2887
        $userService = $this->getRepository()->getUserService();
2888
        $contentType = $this->createUserContentTypeWithPasswordExpirationDate(self::EXAMPLE_PASSWORD_TTL, null);
2889
2890
        $user = $this->createTestUser($contentType);
2891
2892
        /* BEGIN: Use Case */
2893
        $passwordInfo = $userService->getPasswordInfo($user);
2894
        /* END: Use Case */
2895
2896
        $passwordUpdatedAt = $user->passwordUpdatedAt;
2897
        if ($passwordUpdatedAt instanceof DateTime) {
2898
            $passwordUpdatedAt = DateTimeImmutable::createFromFormat(DateTime::ATOM, $passwordUpdatedAt->format(DateTime::ATOM));
2899
        }
2900
2901
        $expectedPasswordExpirationDate = $passwordUpdatedAt->add(
2902
            new DateInterval(sprintf('P%dD', self::EXAMPLE_PASSWORD_TTL))
2903
        );
2904
2905
        $this->assertEquals(new PasswordInfo($expectedPasswordExpirationDate, null), $passwordInfo);
2906
    }
2907
2908
    public function createTestUser(ContentType $contentType): User
2909
    {
2910
        return $this->createTestUserWithPassword(self::EXAMPLE_PASSWORD, $contentType);
2911
    }
2912
2913
    /**
2914
     * Creates a user with given password.
2915
     *
2916
     * @param string $password
2917
     * @param \eZ\Publish\API\Repository\Values\ContentType\ContentType $contentType
2918
     *
2919
     * @return \eZ\Publish\API\Repository\Values\User\User
2920
     */
2921
    private function createTestUserWithPassword(string $password, ContentType $contentType): User
2922
    {
2923
        $userService = $this->getRepository()->getUserService();
2924
        // ID of the "Editors" user group in an eZ Publish demo installation
2925
        $editorsGroupId = 13;
2926
2927
        // Instantiate a create struct with mandatory properties
2928
        $userCreate = $userService->newUserCreateStruct(
2929
            'johndoe',
2930
            '[email protected]',
2931
            $password,
2932
            'eng-US',
2933
            $contentType
2934
        );
2935
        $userCreate->enabled = true;
2936
        $userCreate->setField('first_name', 'John');
2937
        $userCreate->setField('last_name', 'Doe');
2938
2939
        return $userService->createUser($userCreate, [
2940
            $userService->loadUserGroup($editorsGroupId),
2941
        ]);
2942
    }
2943
2944
    /**
2945
     * Creates the User Content Type with password constraints.
2946
     *
2947
     * @return \eZ\Publish\API\Repository\Values\ContentType\ContentType
2948
     */
2949
    private function createUserContentTypeWithStrongPassword(): ContentType
2950
    {
2951
        return $this->createUserContentTypeWithAccountSettings('user-with-strong-password', null, [
2952
            'PasswordValueValidator' => [
2953
                'requireAtLeastOneUpperCaseCharacter' => 1,
2954
                'requireAtLeastOneLowerCaseCharacter' => 1,
2955
                'requireAtLeastOneNumericCharacter' => 1,
2956
                'requireAtLeastOneNonAlphanumericCharacter' => 1,
2957
                'requireNewPassword' => 1,
2958
                'minLength' => 8,
2959
            ],
2960
        ]);
2961
    }
2962
2963
    private function createUserContentTypeWithPasswordExpirationDate(
2964
        ?int $passwordTTL = self::EXAMPLE_PASSWORD_TTL,
2965
        ?int $passwordTTLWarning = self::EXAMPLE_PASSWORD_TTL_WARNING
2966
    ): ContentType {
2967
        return $this->createUserContentTypeWithAccountSettings('password-expiration', [
2968
            'PasswordTTL' => $passwordTTL,
2969
            'PasswordTTLWarning' => $passwordTTLWarning,
2970
        ]);
2971
    }
2972
2973
    private function createUserContentTypeWithAccountSettings(
2974
        string $identifier,
2975
        ?array $fieldSetting = null,
2976
        ?array $validatorConfiguration = null
2977
    ): ContentType {
2978
        $repository = $this->getRepository();
2979
2980
        $contentTypeService = $repository->getContentTypeService();
2981
        $permissionResolver = $repository->getPermissionResolver();
2982
2983
        $typeCreate = $contentTypeService->newContentTypeCreateStruct($identifier);
2984
        $typeCreate->mainLanguageCode = 'eng-GB';
2985
        $typeCreate->urlAliasSchema = 'url|scheme';
2986
        $typeCreate->nameSchema = 'name|scheme';
2987
        $typeCreate->names = [
2988
            'eng-GB' => 'User: ' . $identifier,
2989
        ];
2990
        $typeCreate->descriptions = [
2991
            'eng-GB' => '',
2992
        ];
2993
        $typeCreate->creatorId = $this->generateId('user', $permissionResolver->getCurrentUserReference()->getUserId());
2994
        $typeCreate->creationDate = $this->createDateTime();
2995
2996
        $firstNameFieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('first_name', 'ezstring');
2997
        $firstNameFieldCreate->names = [
2998
            'eng-GB' => 'First name',
2999
        ];
3000
        $firstNameFieldCreate->descriptions = [
3001
            'eng-GB' => '',
3002
        ];
3003
        $firstNameFieldCreate->fieldGroup = 'default';
3004
        $firstNameFieldCreate->position = 1;
3005
        $firstNameFieldCreate->isTranslatable = false;
3006
        $firstNameFieldCreate->isRequired = true;
3007
        $firstNameFieldCreate->isInfoCollector = false;
3008
        $firstNameFieldCreate->validatorConfiguration = [
3009
            'StringLengthValidator' => [
3010
                'minStringLength' => 0,
3011
                'maxStringLength' => 0,
3012
            ],
3013
        ];
3014
        $firstNameFieldCreate->fieldSettings = [];
3015
        $firstNameFieldCreate->isSearchable = true;
3016
        $firstNameFieldCreate->defaultValue = '';
3017
3018
        $typeCreate->addFieldDefinition($firstNameFieldCreate);
3019
3020
        $lastNameFieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('last_name', 'ezstring');
3021
        $lastNameFieldCreate->names = [
3022
            'eng-GB' => 'Last name',
3023
        ];
3024
        $lastNameFieldCreate->descriptions = [
3025
            'eng-GB' => '',
3026
        ];
3027
        $lastNameFieldCreate->fieldGroup = 'default';
3028
        $lastNameFieldCreate->position = 2;
3029
        $lastNameFieldCreate->isTranslatable = false;
3030
        $lastNameFieldCreate->isRequired = true;
3031
        $lastNameFieldCreate->isInfoCollector = false;
3032
        $lastNameFieldCreate->validatorConfiguration = [
3033
            'StringLengthValidator' => [
3034
                'minStringLength' => 0,
3035
                'maxStringLength' => 0,
3036
            ],
3037
        ];
3038
        $lastNameFieldCreate->fieldSettings = [];
3039
        $lastNameFieldCreate->isSearchable = true;
3040
        $lastNameFieldCreate->defaultValue = '';
3041
3042
        $typeCreate->addFieldDefinition($lastNameFieldCreate);
3043
3044
        $accountFieldCreateStruct = $contentTypeService->newFieldDefinitionCreateStruct('account', 'ezuser');
3045
        $accountFieldCreateStruct->names = [
3046
            'eng-GB' => 'User account',
3047
        ];
3048
        $accountFieldCreateStruct->descriptions = [
3049
            'eng-GB' => '',
3050
        ];
3051
        $accountFieldCreateStruct->fieldGroup = 'default';
3052
        $accountFieldCreateStruct->position = 3;
3053
        $accountFieldCreateStruct->isTranslatable = false;
3054
        $accountFieldCreateStruct->isRequired = true;
3055
        $accountFieldCreateStruct->isInfoCollector = false;
3056
        $accountFieldCreateStruct->validatorConfiguration = $validatorConfiguration;
3057
        $accountFieldCreateStruct->fieldSettings = $fieldSetting;
3058
        $accountFieldCreateStruct->isSearchable = false;
3059
        $accountFieldCreateStruct->defaultValue = null;
3060
3061
        $typeCreate->addFieldDefinition($accountFieldCreateStruct);
3062
3063
        $contentTypeDraft = $contentTypeService->createContentType($typeCreate, [
3064
            $contentTypeService->loadContentTypeGroupByIdentifier('Users'),
3065
        ]);
3066
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
3067
3068
        return $contentTypeService->loadContentTypeByIdentifier($identifier);
3069
    }
3070
}
3071