Completed
Push — ezp-31079-follow-up ( 04d61c...0c606b )
by
unknown
11:57
created

UserServiceTest   F

Complexity

Total Complexity 136

Size/Duplication

Total Lines 3022
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 32

Importance

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

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\User\Type;
27
use eZ\Publish\Core\FieldType\ValidationError;
28
use eZ\Publish\Core\Repository\Values\Content\Content;
29
use eZ\Publish\Core\Repository\Values\Content\VersionInfo;
30
use eZ\Publish\Core\Repository\Values\User\UserGroup;
31
use Exception;
32
33
/**
34
 * Test case for operations in the UserService using in memory storage.
35
 *
36
 * @see eZ\Publish\API\Repository\UserService
37
 * @group integration
38
 * @group user
39
 */
40
class UserServiceTest extends BaseTest
41
{
42
    // Example password matching default rules
43
    private const EXAMPLE_PASSWORD = 'P@ssword123!';
44
45
    private const EXAMPLE_PASSWORD_TTL = 30;
46
    private const EXAMPLE_PASSWORD_TTL_WARNING = 14;
47
48
    /**
49
     * Test for the loadUserGroup() method.
50
     *
51
     * @see \eZ\Publish\API\Repository\UserService::loadUserGroup()
52
     */
53
    public function testLoadUserGroup()
54
    {
55
        $repository = $this->getRepository();
56
57
        $mainGroupId = $this->generateId('group', 4);
58
        /* BEGIN: Use Case */
59
        // $mainGroupId is the ID of the main "Users" group
60
61
        $userService = $repository->getUserService();
62
63
        $userGroup = $userService->loadUserGroup($mainGroupId);
64
        /* END: Use Case */
65
66
        $this->assertInstanceOf(UserGroup::class, $userGroup);
67
68
        // User group happens to also be a Content; isUserGroup() should be true and isUser() should be false
69
        $this->assertTrue($userService->isUserGroup($userGroup), 'isUserGroup() => false on a user group');
70
        $this->assertFalse($userService->isUser($userGroup), 'isUser() => true on a user group');
71
        $this->assertSame(0, $userGroup->parentId, 'parentId should be equal `0` because it is top level node');
72
    }
73
74
    /**
75
     * Test for the loadUserGroup() method to ensure that DomainUserGroupObject is created properly even if a user
76
     * has no access to parent of UserGroup.
77
     *
78
     * @see \eZ\Publish\API\Repository\UserService::loadUserGroup()
79
     */
80
    public function testLoadUserGroupWithNoAccessToParent()
81
    {
82
        $repository = $this->getRepository();
83
84
        $mainGroupId = $this->generateId('group', 4);
85
        /* BEGIN: Use Case */
86
        // $mainGroupId is the ID of the main "Users" group
87
88
        $userService = $repository->getUserService();
89
90
        $user = $this->createUserWithPolicies(
91
            'user',
92
            [
93
                ['module' => 'content', 'function' => 'read'],
94
            ],
95
            new SubtreeLimitation(['limitationValues' => ['/1/5']])
96
        );
97
        $repository->getPermissionResolver()->setCurrentUserReference($user);
98
99
        $userGroup = $userService->loadUserGroup($mainGroupId);
100
        /* END: Use Case */
101
102
        $this->assertInstanceOf(UserGroup::class, $userGroup);
103
104
        // User group happens to also be a Content; isUserGroup() should be true and isUser() should be false
105
        $this->assertTrue($userService->isUserGroup($userGroup), 'isUserGroup() => false on a user group');
106
        $this->assertFalse($userService->isUser($userGroup), 'isUser() => true on a user group');
107
        $this->assertSame(0, $userGroup->parentId, 'parentId should be equal `0` because it is top level node');
108
    }
109
110
    /**
111
     * Test for the loadUserGroup() method.
112
     *
113
     * @see \eZ\Publish\API\Repository\UserService::loadUserGroup()
114
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroup
115
     */
116
    public function testLoadUserGroupThrowsNotFoundException()
117
    {
118
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
119
120
        $repository = $this->getRepository();
121
122
        $nonExistingGroupId = $this->generateId('group', self::DB_INT_MAX);
123
        /* BEGIN: Use Case */
124
        $userService = $repository->getUserService();
125
126
        // This call will fail with a NotFoundException
127
        $userService->loadUserGroup($nonExistingGroupId);
128
        /* END: Use Case */
129
    }
130
131
    /**
132
     * Test for the loadSubUserGroups() method.
133
     *
134
     * @see \eZ\Publish\API\Repository\UserService::loadSubUserGroups()
135
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroup
136
     */
137
    public function testLoadSubUserGroups()
138
    {
139
        $repository = $this->getRepository();
140
141
        $mainGroupId = $this->generateId('group', 4);
142
        /* BEGIN: Use Case */
143
        // $mainGroupId is the ID of the main "Users" group
144
145
        $userService = $repository->getUserService();
146
147
        $userGroup = $userService->loadUserGroup($mainGroupId);
148
149
        $subUserGroups = $userService->loadSubUserGroups($userGroup);
150
        foreach ($subUserGroups as $subUserGroup) {
151
            // Do something with the $subUserGroup
152
            $this->assertInstanceOf(UserGroup::class, $subUserGroup);
153
        }
154
        /* END: Use Case */
155
    }
156
157
    /**
158
     * Test loading sub groups throwing NotFoundException.
159
     *
160
     * @covers \eZ\Publish\API\Repository\UserService::loadSubUserGroups
161
     */
162
    public function testLoadSubUserGroupsThrowsNotFoundException()
163
    {
164
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
165
166
        $repository = $this->getRepository();
167
        $userService = $repository->getUserService();
168
169
        $parentGroup = new UserGroup(
170
            [
171
                'content' => new Content(
172
                    [
173
                        'versionInfo' => new VersionInfo(
174
                            [
175
                                'contentInfo' => new ContentInfo(
176
                                    ['id' => 123456]
177
                                ),
178
                            ]
179
                        ),
180
                        'internalFields' => [],
181
                    ]
182
                ),
183
            ]
184
        );
185
        $userService->loadSubUserGroups($parentGroup);
186
    }
187
188
    /**
189
     * Test for the newUserGroupCreateStruct() method.
190
     *
191
     * @return \eZ\Publish\API\Repository\Values\User\UserGroupCreateStruct
192
     *
193
     * @see \eZ\Publish\API\Repository\UserService::newUserGroupCreateStruct()
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
     */
248
    public function testNewUserGroupCreateStructWithSecondParameter()
249
    {
250
        if ($this->isVersion4()) {
251
            $this->markTestSkipped('This test is only relevant for eZ Publish versions > 4');
252
        }
253
254
        $repository = $this->getRepository();
255
256
        /* BEGIN: Use Case */
257
        $contentTypeService = $repository->getContentTypeService();
258
        $userService = $repository->getUserService();
259
260
        // Load the default ContentType for user groups
261
        $groupType = $contentTypeService->loadContentTypeByIdentifier('user_group');
262
263
        // Instantiate a new group create struct
264
        $groupCreate = $userService->newUserGroupCreateStruct(
265
            'eng-US',
266
            $groupType
267
        );
268
        /* END: Use Case */
269
270
        $this->assertSame($groupType, $groupCreate->contentType);
271
    }
272
273
    /**
274
     * Test for the createUserGroup() method.
275
     *
276
     * @return \eZ\Publish\API\Repository\Values\User\UserGroup
277
     *
278
     * @see \eZ\Publish\API\Repository\UserService::createUserGroup()
279
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserGroupCreateStruct
280
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroup
281
     */
282
    public function testCreateUserGroup()
283
    {
284
        /* BEGIN: Use Case */
285
        $userGroup = $this->createUserGroupVersion1();
286
        /* END: Use Case */
287
288
        $this->assertInstanceOf(
289
            UserGroup::class,
290
            $userGroup
291
        );
292
293
        $versionInfo = $userGroup->getVersionInfo();
294
295
        $this->assertEquals(APIVersionInfo::STATUS_PUBLISHED, $versionInfo->status);
296
        $this->assertEquals(1, $versionInfo->versionNo);
297
298
        return $userGroup;
299
    }
300
301
    /**
302
     * Test for the createUserGroup() method.
303
     *
304
     * @param \eZ\Publish\API\Repository\Values\User\UserGroup $userGroup
305
     *
306
     * @see \eZ\Publish\API\Repository\UserService::createUserGroup()
307
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUserGroup
308
     */
309
    public function testCreateUserGroupSetsExpectedProperties($userGroup)
310
    {
311
        $this->assertEquals(
312
            [
313
                'parentId' => $this->generateId('group', 4),
314
            ],
315
            [
316
                'parentId' => $userGroup->parentId,
317
            ]
318
        );
319
    }
320
321
    /**
322
     * Test for the createUserGroup() method.
323
     *
324
     * @see \eZ\Publish\API\Repository\UserService::createUserGroup()
325
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUserGroup
326
     */
327
    public function testCreateUserGroupThrowsInvalidArgumentException()
328
    {
329
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
330
331
        $repository = $this->getRepository();
332
333
        $mainGroupId = $this->generateId('group', 4);
334
        /* BEGIN: Use Case */
335
        // $mainGroupId is the ID of the main "Users" group
336
337
        $userService = $repository->getUserService();
338
339
        // Load main group
340
        $parentUserGroup = $userService->loadUserGroup($mainGroupId);
341
342
        // Instantiate a new create struct
343
        $userGroupCreate = $userService->newUserGroupCreateStruct('eng-US');
344
        $userGroupCreate->setField('name', 'Example Group');
345
        $userGroupCreate->remoteId = '5f7f0bdb3381d6a461d8c29ff53d908f';
346
347
        // This call will fail with an "InvalidArgumentException", because the
348
        // specified remoteId is already used for the "Members" user group.
349
        $userService->createUserGroup(
350
            $userGroupCreate,
351
            $parentUserGroup
352
        );
353
        /* END: Use Case */
354
    }
355
356
    /**
357
     * Test for the createUserGroup() method.
358
     *
359
     * @see \eZ\Publish\API\Repository\UserService::createUserGroup()
360
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUserGroup
361
     */
362
    public function testCreateUserGroupThrowsInvalidArgumentExceptionFieldTypeNotAccept()
363
    {
364
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
365
366
        $repository = $this->getRepository();
367
368
        $mainGroupId = $this->generateId('group', 4);
369
        /* BEGIN: Use Case */
370
        // $mainGroupId is the ID of the main "Users" group
371
372
        $userService = $repository->getUserService();
373
374
        // Load main group
375
        $parentUserGroup = $userService->loadUserGroup($mainGroupId);
376
377
        // Instantiate a new create struct
378
        $userGroupCreate = $userService->newUserGroupCreateStruct('eng-US');
379
        $userGroupCreate->setField('name', new \stdClass());
380
381
        // This call will fail with an "InvalidArgumentException", because the
382
        // specified remoteId is already used for the "Members" user group.
383
        $userService->createUserGroup(
384
            $userGroupCreate,
385
            $parentUserGroup
386
        );
387
        /* END: Use Case */
388
    }
389
390
    /**
391
     * Test for the createUserGroup() method.
392
     *
393
     * @see \eZ\Publish\API\Repository\UserService::createUserGroup()
394
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUserGroup
395
     */
396
    public function testCreateUserGroupWhenMissingField()
397
    {
398
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
399
400
        $repository = $this->getRepository();
401
402
        $mainGroupId = $this->generateId('group', 4);
403
        /* BEGIN: Use Case */
404
        // $mainGroupId is the ID of the main "Users" group
405
406
        $userService = $repository->getUserService();
407
408
        // Load main group
409
        $parentUserGroup = $userService->loadUserGroup($mainGroupId);
410
411
        // Instantiate a new create struct
412
        $userGroupCreate = $userService->newUserGroupCreateStruct('eng-US');
413
414
        // This call will fail with a "ContentFieldValidationException", because the
415
        // only mandatory field "name" is not set.
416
        $userService->createUserGroup($userGroupCreate, $parentUserGroup);
417
        /* END: Use Case */
418
    }
419
420
    /**
421
     * Test for the createUserGroup() method.
422
     *
423
     * @return \eZ\Publish\API\Repository\Values\User\UserGroup
424
     *
425
     * @see \eZ\Publish\API\Repository\UserService::createUserGroup()
426
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserGroupCreateStruct
427
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroup
428
     */
429
    public function testCreateUserGroupInTransactionWithRollback()
430
    {
431
        $repository = $this->getRepository();
432
433
        $mainGroupId = $this->generateId('group', 4);
434
        /* BEGIN: Use Case */
435
        // $mainGroupId is the ID of the main "Users" group
436
437
        $userService = $repository->getUserService();
438
439
        $repository->beginTransaction();
440
441
        try {
442
            // Load main group
443
            $parentUserGroup = $userService->loadUserGroup($mainGroupId);
444
445
            // Instantiate a new create struct
446
            $userGroupCreate = $userService->newUserGroupCreateStruct('eng-US');
447
            $userGroupCreate->setField('name', 'Example Group');
448
449
            // Create the new user group
450
            $createdUserGroupId = $userService->createUserGroup(
451
                $userGroupCreate,
452
                $parentUserGroup
453
            )->id;
454
        } catch (Exception $e) {
455
            // Cleanup hanging transaction on error
456
            $repository->rollback();
457
            throw $e;
458
        }
459
460
        $repository->rollback();
461
462
        try {
463
            // Throws exception since creation of user group was rolled back
464
            $loadedGroup = $userService->loadUserGroup($createdUserGroupId);
465
        } catch (NotFoundException $e) {
466
            return;
467
        }
468
        /* END: Use Case */
469
470
        $this->fail('User group object still exists after rollback.');
471
    }
472
473
    /**
474
     * Test for the deleteUserGroup() method.
475
     *
476
     * @see \eZ\Publish\API\Repository\UserService::deleteUserGroup()
477
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUserGroup
478
     */
479
    public function testDeleteUserGroup()
480
    {
481
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
482
483
        $repository = $this->getRepository();
484
        $userService = $repository->getUserService();
485
486
        /* BEGIN: Use Case */
487
        $userGroup = $this->createUserGroupVersion1();
488
489
        // Delete the currently created user group again
490
        $userService->deleteUserGroup($userGroup);
491
        /* END: Use Case */
492
493
        // We use the NotFoundException here for verification
494
        $userService->loadUserGroup($userGroup->id);
495
    }
496
497
    /**
498
     * Test deleting user group throwing NotFoundException.
499
     *
500
     * @covers \eZ\Publish\API\Repository\UserService::deleteUserGroup
501
     */
502
    public function testDeleteUserGroupThrowsNotFoundException()
503
    {
504
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
505
506
        $repository = $this->getRepository();
507
        $userService = $repository->getUserService();
508
509
        $userGroup = new UserGroup(
510
            [
511
                'content' => new Content(
512
                    [
513
                        'versionInfo' => new VersionInfo(
514
                            ['contentInfo' => new ContentInfo(['id' => 123456])]
515
                        ),
516
                        'internalFields' => [],
517
                    ]
518
                ),
519
            ]
520
        );
521
        $userService->deleteUserGroup($userGroup);
522
    }
523
524
    /**
525
     * Test for the moveUserGroup() method.
526
     *
527
     * @see \eZ\Publish\API\Repository\UserService::moveUserGroup()
528
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUserGroup
529
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadSubUserGroups
530
     */
531
    public function testMoveUserGroup()
532
    {
533
        $repository = $this->getRepository();
534
        $userService = $repository->getUserService();
535
536
        $membersGroupId = $this->generateId('group', 13);
537
        /* BEGIN: Use Case */
538
        // $membersGroupId is the ID of the "Members" user group in an eZ
539
        // Publish demo installation
540
541
        $userGroup = $this->createUserGroupVersion1();
542
543
        // Load the new parent group
544
        $membersUserGroup = $userService->loadUserGroup($membersGroupId);
545
546
        // Move user group from "Users" to "Members"
547
        $userService->moveUserGroup($userGroup, $membersUserGroup);
548
549
        // Reload the user group to get an updated $parentId
550
        $userGroup = $userService->loadUserGroup($userGroup->id);
551
552
        $this->refreshSearch($repository);
553
554
        // The returned array will no contain $userGroup
555
        $subUserGroups = $userService->loadSubUserGroups(
556
            $membersUserGroup
557
        );
558
        /* END: Use Case */
559
560
        $subUserGroupIds = array_map(
561
            function ($content) {
562
                return $content->id;
563
            },
564
            $subUserGroups
565
        );
566
567
        $this->assertEquals($membersGroupId, $userGroup->parentId);
568
        $this->assertEquals([$userGroup->id], $subUserGroupIds);
569
    }
570
571
    /**
572
     * Test moving a user group below another group throws NotFoundException.
573
     *
574
     * @covers \eZ\Publish\API\Repository\UserService::moveUserGroup
575
     */
576
    public function testMoveUserGroupThrowsNotFoundException()
577
    {
578
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
579
580
        $repository = $this->getRepository();
581
        $userService = $repository->getUserService();
582
583
        $userGroupToMove = new UserGroup(
584
            [
585
                'content' => new Content(
586
                    [
587
                        'versionInfo' => new VersionInfo(
588
                            ['contentInfo' => new ContentInfo(['id' => 123456])]
589
                        ),
590
                        'internalFields' => [],
591
                    ]
592
                ),
593
            ]
594
        );
595
        $parentUserGroup = new UserGroup(
596
            [
597
                'content' => new Content(
598
                    [
599
                        'versionInfo' => new VersionInfo(
600
                            ['contentInfo' => new ContentInfo(['id' => 123455])]
601
                        ),
602
                        'internalFields' => [],
603
                    ]
604
                ),
605
            ]
606
        );
607
        $userService->moveUserGroup($userGroupToMove, $parentUserGroup);
608
    }
609
610
    /**
611
     * Test for the newUserGroupUpdateStruct() method.
612
     *
613
     * @covers \eZ\Publish\API\Repository\UserService::newUserGroupUpdateStruct
614
     */
615
    public function testNewUserGroupUpdateStruct()
616
    {
617
        $repository = $this->getRepository();
618
619
        /* BEGIN: Use Case */
620
        $userService = $repository->getUserService();
621
622
        $groupUpdate = $userService->newUserGroupUpdateStruct();
623
        /* END: Use Case */
624
625
        $this->assertInstanceOf(
626
            UserGroupUpdateStruct::class,
627
            $groupUpdate
628
        );
629
630
        $this->assertNull($groupUpdate->contentUpdateStruct);
631
        $this->assertNull($groupUpdate->contentMetadataUpdateStruct);
632
    }
633
634
    /**
635
     * Test for the updateUserGroup() method.
636
     *
637
     * @see \eZ\Publish\API\Repository\UserService::updateUserGroup()
638
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUserGroup
639
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserGroupUpdateStruct
640
     */
641
    public function testUpdateUserGroup()
642
    {
643
        $repository = $this->getRepository();
644
        $userService = $repository->getUserService();
645
646
        /* BEGIN: Use Case */
647
        $userGroup = $this->createUserGroupVersion1();
648
649
        // Create a group update struct and change nothing
650
        $groupUpdate = $userService->newUserGroupUpdateStruct();
651
652
        // This update will do nothing
653
        $userGroup = $userService->updateUserGroup(
654
            $userGroup,
655
            $groupUpdate
656
        );
657
        /* END: Use Case */
658
659
        $this->assertInstanceOf(
660
            UserGroup::class,
661
            $userGroup
662
        );
663
664
        $this->assertEquals(1, $userGroup->getVersionInfo()->versionNo);
665
    }
666
667
    /**
668
     * Test for the updateUserGroup() method.
669
     *
670
     * @see \eZ\Publish\API\Repository\UserService::updateUserGroup()
671
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUserGroup
672
     */
673
    public function testUpdateUserGroupWithSubContentUpdateStruct()
674
    {
675
        $repository = $this->getRepository();
676
        $userService = $repository->getUserService();
677
678
        /* BEGIN: Use Case */
679
        $userGroup = $this->createUserGroupVersion1();
680
681
        // Load the content service
682
        $contentService = $repository->getContentService();
683
684
        // Create a content update struct and update the group name
685
        $contentUpdate = $contentService->newContentUpdateStruct();
686
        $contentUpdate->setField('name', 'Sindelfingen', 'eng-US');
687
688
        // Create a group update struct and set content update struct
689
        $groupUpdate = $userService->newUserGroupUpdateStruct();
690
        $groupUpdate->contentUpdateStruct = $contentUpdate;
691
692
        // This will update the name and the increment the group version number
693
        $userGroup = $userService->updateUserGroup(
694
            $userGroup,
695
            $groupUpdate
696
        );
697
        /* END: Use Case */
698
699
        $this->assertEquals('Sindelfingen', $userGroup->getFieldValue('name', 'eng-US'));
700
701
        $versionInfo = $userGroup->getVersionInfo();
702
703
        $this->assertEquals(APIVersionInfo::STATUS_PUBLISHED, $versionInfo->status);
704
        $this->assertEquals(2, $versionInfo->versionNo);
705
    }
706
707
    /**
708
     * Test for the updateUserGroup() method.
709
     *
710
     * @see \eZ\Publish\API\Repository\UserService::updateUserGroup()
711
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUserGroup
712
     */
713
    public function testUpdateUserGroupWithSubContentMetadataUpdateStruct()
714
    {
715
        $repository = $this->getRepository();
716
        $userService = $repository->getUserService();
717
718
        /* BEGIN: Use Case */
719
        $userGroup = $this->createUserGroupVersion1();
720
721
        // Load the content service
722
        $contentService = $repository->getContentService();
723
724
        // Create a metadata update struct and change the remoteId
725
        $metadataUpdate = $contentService->newContentMetadataUpdateStruct();
726
        $metadataUpdate->remoteId = '3c61299780663bafa3af2101e52125da';
727
728
        // Create a group update struct and set content update struct
729
        $groupUpdate = $userService->newUserGroupUpdateStruct();
730
        $groupUpdate->contentMetadataUpdateStruct = $metadataUpdate;
731
732
        // This will update the name and the increment the group version number
733
        $userGroup = $userService->updateUserGroup(
734
            $userGroup,
735
            $groupUpdate
736
        );
737
        /* END: Use Case */
738
739
        $this->assertEquals(
740
            '3c61299780663bafa3af2101e52125da',
741
            $userGroup->contentInfo->remoteId
742
        );
743
744
        $versionInfo = $userGroup->getVersionInfo();
745
746
        $this->assertEquals(APIVersionInfo::STATUS_PUBLISHED, $versionInfo->status);
747
        $this->assertEquals(1, $versionInfo->versionNo);
748
    }
749
750
    /**
751
     * Test for the updateUserGroup() method.
752
     *
753
     * @see \eZ\Publish\API\Repository\UserService::updateUserGroup()
754
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUserGroup
755
     */
756
    public function testUpdateUserGroupThrowsInvalidArgumentExceptionOnFieldTypeNotAccept()
757
    {
758
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
759
760
        $repository = $this->getRepository();
761
        $userService = $repository->getUserService();
762
763
        /* BEGIN: Use Case */
764
        $userGroup = $this->createUserGroupVersion1();
765
766
        // Load the content service
767
        $contentService = $repository->getContentService();
768
769
        // Create a content update struct and update the group name
770
        $contentUpdate = $contentService->newContentUpdateStruct();
771
        // An object of stdClass is not accepted as a value by the field "name"
772
        $contentUpdate->setField('name', new \stdClass(), 'eng-US');
773
774
        // Create a group update struct and set content update struct
775
        $groupUpdate = $userService->newUserGroupUpdateStruct();
776
        $groupUpdate->contentUpdateStruct = $contentUpdate;
777
778
        // This call will fail with an InvalidArgumentException, because the
779
        // field "name" does not accept the given value
780
        $userService->updateUserGroup($userGroup, $groupUpdate);
781
        /* END: Use Case */
782
    }
783
784
    /**
785
     * Test for the newUserCreateStruct() method.
786
     *
787
     * @see \eZ\Publish\API\Repository\UserService::newUserCreateStruct()
788
     */
789
    public function testNewUserCreateStruct()
790
    {
791
        $repository = $this->getRepository();
792
793
        /* BEGIN: Use Case */
794
        $userService = $repository->getUserService();
795
796
        $userCreate = $userService->newUserCreateStruct(
797
            'user',
798
            '[email protected]',
799
            'secret',
800
            'eng-US'
801
        );
802
        /* END: Use Case */
803
804
        $this->assertInstanceOf(
805
            '\\eZ\\Publish\\API\\Repository\\Values\\User\\UserCreateStruct',
806
            $userCreate
807
        );
808
809
        return $userCreate;
810
    }
811
812
    /**
813
     * Test updating a user group throws ContentFieldValidationException.
814
     *
815
     * @covers \eZ\Publish\API\Repository\UserService::updateUserGroup
816
     */
817
    public function testUpdateUserGroupThrowsContentFieldValidationExceptionOnRequiredFieldEmpty()
818
    {
819
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
820
821
        $repository = $this->getRepository();
822
        $userService = $repository->getUserService();
823
        $contentService = $repository->getContentService();
824
825
        $userGroup = $userService->loadUserGroup(42);
826
        $userGroupUpdateStruct = $userService->newUserGroupUpdateStruct();
827
        $userGroupUpdateStruct->contentUpdateStruct = $contentService->newContentUpdateStruct();
828
        $userGroupUpdateStruct->contentUpdateStruct->setField('name', '', 'eng-US');
829
830
        $userService->updateUserGroup($userGroup, $userGroupUpdateStruct);
831
    }
832
833
    /**
834
     * Test for the newUserCreateStruct() method.
835
     *
836
     * @param \eZ\Publish\API\Repository\Values\User\UserCreateStruct $userCreate
837
     *
838
     * @see \eZ\Publish\API\Repository\UserService::newUserCreateStruct()
839
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserCreateStruct
840
     */
841
    public function testNewUserCreateStructSetsExpectedProperties($userCreate)
842
    {
843
        $this->assertEquals(
844
            [
845
                'login' => 'user',
846
                'email' => '[email protected]',
847
                'password' => 'secret',
848
                'mainLanguageCode' => 'eng-US',
849
            ],
850
            [
851
                'login' => $userCreate->login,
852
                'email' => $userCreate->email,
853
                'password' => $userCreate->password,
854
                'mainLanguageCode' => $userCreate->mainLanguageCode,
855
            ]
856
        );
857
    }
858
859
    /**
860
     * Test for the newUserCreateStruct() method.
861
     *
862
     * @see \eZ\Publish\API\Repository\UserService::newUserCreateStruct($login, $email, $password, $mainLanguageCode, $contentType)
863
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserCreateStruct
864
     */
865
    public function testNewUserCreateStructWithFifthParameter()
866
    {
867
        if ($this->isVersion4()) {
868
            $this->markTestSkipped('This test is only relevant for eZ Publish versions > 4');
869
        }
870
871
        $repository = $this->getRepository();
872
873
        /* BEGIN: Use Case */
874
        $contentTypeService = $repository->getContentTypeService();
875
        $userService = $repository->getUserService();
876
877
        $userType = $contentTypeService->loadContentTypeByIdentifier('user');
878
879
        $userCreate = $userService->newUserCreateStruct(
880
            'user',
881
            '[email protected]',
882
            'secret',
883
            'eng-US',
884
            $userType
885
        );
886
        /* END: Use Case */
887
888
        $this->assertSame($userType, $userCreate->contentType);
889
    }
890
891
    /**
892
     * Test for creating user with Active Directory login name.
893
     */
894
    public function testNewUserWithDomainName()
895
    {
896
        $repository = $this->getRepository();
897
        $userService = $repository->getUserService();
898
        $createdUser = $this->createUserVersion1(
899
            'ez-user-Domain\username-by-login',
900
            '[email protected]'
901
        );
902
        $loadedUser = $userService->loadUserByLogin('ez-user-Domain\username-by-login', Language::ALL);
903
904
        $this->assertEquals($createdUser, $loadedUser);
905
    }
906
907
    /**
908
     * Test for the createUser() method.
909
     *
910
     * @return \eZ\Publish\API\Repository\Values\User\User
911
     *
912
     * @see \eZ\Publish\API\Repository\UserService::createUser()
913
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroup
914
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserCreateStruct
915
     */
916
    public function testCreateUser()
917
    {
918
        /* BEGIN: Use Case */
919
        $user = $this->createUserVersion1();
920
        /* END: Use Case */
921
922
        $this->assertInstanceOf(
923
            '\\eZ\\Publish\\API\\Repository\\Values\\User\\User',
924
            $user
925
        );
926
927
        return $user;
928
    }
929
930
    /**
931
     * Test for the createUser() method.
932
     *
933
     * @param \eZ\Publish\API\Repository\Values\User\User $user
934
     *
935
     * @see \eZ\Publish\API\Repository\UserService::createUser()
936
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
937
     */
938
    public function testCreateUserSetsExpectedProperties(User $user)
939
    {
940
        $this->assertEquals(
941
            [
942
                'login' => 'user',
943
                'email' => '[email protected]',
944
                'mainLanguageCode' => 'eng-US',
945
            ],
946
            [
947
                'login' => $user->login,
948
                'email' => $user->email,
949
                'mainLanguageCode' => $user->contentInfo->mainLanguageCode,
950
            ]
951
        );
952
    }
953
954
    /**
955
     * Test for the createUser() method.
956
     *
957
     * @see \eZ\Publish\API\Repository\UserService::createUser()
958
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
959
     */
960
    public function testCreateUserWhenMissingField()
961
    {
962
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
963
964
        $repository = $this->getRepository();
965
966
        $editorsGroupId = $this->generateId('group', 13);
967
        /* BEGIN: Use Case */
968
        // $editorsGroupId is the ID of the "Editors" user group in an eZ
969
        // Publish demo installation
970
971
        $userService = $repository->getUserService();
972
973
        // Instantiate a create struct with mandatory properties
974
        $userCreate = $userService->newUserCreateStruct(
975
            'user',
976
            '[email protected]',
977
            'secret',
978
            'eng-US'
979
        );
980
981
        // Do not set the mandatory fields "first_name" and "last_name"
982
        //$userCreate->setField( 'first_name', 'Example' );
983
        //$userCreate->setField( 'last_name', 'User' );
984
985
        // Load parent group for the user
986
        $group = $userService->loadUserGroup($editorsGroupId);
987
988
        // This call will fail with a "ContentFieldValidationException", because the
989
        // mandatory fields "first_name" and "last_name" are not set.
990
        $userService->createUser($userCreate, [$group]);
991
        /* END: Use Case */
992
    }
993
994
    /**
995
     * Test for the createUser() method.
996
     *
997
     * @see \eZ\Publish\API\Repository\UserService::createUser()
998
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
999
     */
1000
    public function testCreateUserThrowsInvalidArgumentExceptionOnFieldTypeNotAccept()
1001
    {
1002
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
1003
1004
        $repository = $this->getRepository();
1005
1006
        $editorsGroupId = $this->generateId('group', 13);
1007
        /* BEGIN: Use Case */
1008
        // $editorsGroupId is the ID of the "Editors" user group in an eZ
1009
        // Publish demo installation
1010
1011
        $userService = $repository->getUserService();
1012
1013
        // Instantiate a create struct with mandatory properties
1014
        $userCreate = $userService->newUserCreateStruct(
1015
            'user',
1016
            '[email protected]',
1017
            'secret',
1018
            'eng-US'
1019
        );
1020
1021
        // An object of stdClass is not a valid value for the field first_name
1022
        $userCreate->setField('first_name', new \stdClass());
1023
        $userCreate->setField('last_name', 'User');
1024
1025
        // Load parent group for the user
1026
        $group = $userService->loadUserGroup($editorsGroupId);
1027
1028
        // This call will fail with an "InvalidArgumentException", because the
1029
        // value for the firled "first_name" is not accepted by the field type.
1030
        $userService->createUser($userCreate, [$group]);
1031
        /* END: Use Case */
1032
    }
1033
1034
    /**
1035
     * Test for the createUser() method.
1036
     *
1037
     * @covers \eZ\Publish\API\Repository\UserService::createUser
1038
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1039
     */
1040
    public function testCreateUserThrowsInvalidArgumentException()
1041
    {
1042
        $repository = $this->getRepository();
1043
1044
        $editorsGroupId = $this->generateId('group', 13);
1045
        /* BEGIN: Use Case */
1046
        // $editorsGroupId is the ID of the "Editors" user group in an eZ
1047
        // Publish demo installation
1048
1049
        $userService = $repository->getUserService();
1050
1051
        // Instantiate a create struct with mandatory properties
1052
        $userCreate = $userService->newUserCreateStruct(
1053
            // admin is an existing login
1054
            'admin',
1055
            '[email protected]',
1056
            'secret',
1057
            'eng-US'
1058
        );
1059
1060
        $userCreate->setField('first_name', 'Example');
1061
        $userCreate->setField('last_name', 'User');
1062
1063
        // Load parent group for the user
1064
        $group = $userService->loadUserGroup($editorsGroupId);
1065
1066
        try {
1067
            // This call will fail with a "InvalidArgumentException", because the
1068
            // user with "admin" login already exists.
1069
            $userService->createUser($userCreate, [$group]);
1070
            /* END: Use Case */
1071
        } catch (ContentFieldValidationException $e) {
1072
            // Exception is caught, as there is no other way to check exception properties.
1073
            $this->assertValidationErrorOccurs($e, 'The user login \'%login%\' is used by another user. You must enter a unique login.');
1074
1075
            /* END: Use Case */
1076
            return;
1077
        }
1078
1079
        $this->fail('Expected ValidationError messages did not occur.');
1080
    }
1081
1082
    /**
1083
     * Test for the createUser() method.
1084
     *
1085
     * @covers \eZ\Publish\API\Repository\UserService::createUser
1086
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1087
     */
1088
    public function testCreateUserWithEmailAlreadyTaken()
1089
    {
1090
        $repository = $this->getRepository();
1091
1092
        $userContentType = $this->createUserContentTypeWithAccountSettings('user_email_unique', [
1093
            Type::REQUIRE_UNIQUE_EMAIL => true,
1094
        ]);
1095
1096
        $existingUser = $this->createUserVersion1(
1097
            'existing_user',
1098
            '[email protected]',
1099
            $userContentType,
1100
        );
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected ')'
Loading history...
1101
1102
        $editorsGroupId = $this->generateId('group', 13);
1103
        /* BEGIN: Use Case */
1104
        // $editorsGroupId is the ID of the "Editors" user group in an eZ
1105
        // Publish demo installation
1106
1107
        $userService = $repository->getUserService();
1108
1109
        // Instantiate a create struct with mandatory properties
1110
        $userCreate = $userService->newUserCreateStruct(
1111
        // admin is an existing login
1112
            'another_user',
1113
            '[email protected]',
1114
            '[email protected]',
1115
            'eng-US',
1116
            $userContentType
1117
        );
1118
1119
        $userCreate->setField('first_name', 'Example');
1120
        $userCreate->setField('last_name', 'User');
1121
1122
        // Load parent group for the user
1123
        $group = $userService->loadUserGroup($editorsGroupId);
1124
1125
        try {
1126
            // This call will fail with a "InvalidArgumentException", because the
1127
            // user with "admin" login already exists.
1128
            $userService->createUser($userCreate, [$group]);
1129
            /* END: Use Case */
1130
        } catch (ContentFieldValidationException $e) {
1131
            // Exception is caught, as there is no other way to check exception properties.
1132
            $this->assertValidationErrorOccurs($e, 'Email \'%email%\' is used by another user. You must enter a unique email.');
1133
1134
            /* END: Use Case */
1135
            return;
1136
        }
1137
1138
        $this->fail('Expected ValidationError messages did not occur.');
1139
    }
1140
1141
    /**
1142
     * Test for the createUser() method.
1143
     *
1144
     * @covers \eZ\Publish\API\Repository\UserService::createUser
1145
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1146
     */
1147
    public function testCreateInvalidFormatUsername()
1148
    {
1149
        $repository = $this->getRepository();
1150
1151
        $userContentType = $this->createUserContentTypeWithAccountSettings('username_format', [
1152
            Type::USERNAME_PATTERN => '^[^@]$',
1153
        ]);
1154
1155
        $editorsGroupId = $this->generateId('group', 13);
1156
        /* BEGIN: Use Case */
1157
        // $editorsGroupId is the ID of the "Editors" user group in an eZ
1158
        // Publish demo installation
1159
1160
        $userService = $repository->getUserService();
1161
1162
        // Instantiate a create struct with mandatory properties
1163
        $userCreate = $userService->newUserCreateStruct(
1164
        // admin is an existing login
1165
            'invalid@user',
1166
            '[email protected]',
1167
            '[email protected]',
1168
            'eng-US',
1169
            $userContentType
1170
        );
1171
1172
        $userCreate->setField('first_name', 'Example');
1173
        $userCreate->setField('last_name', 'User');
1174
1175
        // Load parent group for the user
1176
        $group = $userService->loadUserGroup($editorsGroupId);
1177
1178
        try {
1179
            // This call will fail with a "InvalidArgumentException", because the
1180
            // user with "admin" login already exists.
1181
            $userService->createUser($userCreate, [$group]);
1182
            /* END: Use Case */
1183
        } catch (ContentFieldValidationException $e) {
1184
            // Exception is caught, as there is no other way to check exception properties.
1185
            $this->assertValidationErrorOccurs($e, 'Invalid login format');
1186
1187
            /* END: Use Case */
1188
            return;
1189
        }
1190
1191
        $this->fail('Expected ValidationError messages did not occur.');
1192
    }
1193
1194
    /**
1195
     * Test for the createUser() method.
1196
     *
1197
     * @return \eZ\Publish\API\Repository\Values\User\User
1198
     *
1199
     * @see \eZ\Publish\API\Repository\UserService::createUser()
1200
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroup
1201
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserCreateStruct
1202
     */
1203
    public function testCreateUserInTransactionWithRollback()
1204
    {
1205
        $repository = $this->getRepository();
1206
        $userService = $repository->getUserService();
1207
1208
        /* BEGIN: Use Case */
1209
        $repository->beginTransaction();
1210
1211
        try {
1212
            $user = $this->createUserVersion1();
1213
        } catch (Exception $e) {
1214
            // Cleanup hanging transaction on error
1215
            $repository->rollback();
1216
            throw $e;
1217
        }
1218
1219
        $repository->rollback();
1220
1221
        try {
1222
            // Throws exception since creation of user was rolled back
1223
            $loadedUser = $userService->loadUser($user->id);
1224
        } catch (NotFoundException $e) {
1225
            return;
1226
        }
1227
        /* END: Use Case */
1228
1229
        $this->fail('User object still exists after rollback.');
1230
    }
1231
1232
    /**
1233
     * Test creating a user throwing NotFoundException.
1234
     *
1235
     * @covers \eZ\Publish\API\Repository\UserService::createUser
1236
     */
1237
    public function testCreateUserThrowsNotFoundException()
1238
    {
1239
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
1240
1241
        $repository = $this->getRepository();
1242
        $userService = $repository->getUserService();
1243
1244
        $userCreateStruct = $userService->newUserCreateStruct('new_user', '[email protected]', 'password', 'eng-GB');
1245
        $userCreateStruct->setField('first_name', 'New');
1246
        $userCreateStruct->setField('last_name', 'User');
1247
1248
        $parentGroup = new UserGroup(
1249
            [
1250
                'content' => new Content(
1251
                    [
1252
                        'versionInfo' => new VersionInfo(
1253
                            [
1254
                                'contentInfo' => new ContentInfo(['id' => 123456]),
1255
                            ]
1256
                        ),
1257
                        'internalFields' => [],
1258
                    ]
1259
                ),
1260
            ]
1261
        );
1262
        $userService->createUser($userCreateStruct, [$parentGroup]);
1263
    }
1264
1265
    /**
1266
     * Test creating a user throwing UserPasswordValidationException when password doesn't follow specific rules.
1267
     *
1268
     * @covers \eZ\Publish\API\Repository\UserService::createUser
1269
     */
1270
    public function testCreateUserWithWeakPasswordThrowsUserPasswordValidationException()
1271
    {
1272
        $userContentType = $this->createUserContentTypeWithStrongPassword();
1273
1274
        try {
1275
            // This call will fail with a "UserPasswordValidationException" because the
1276
            // the password does not follow specified rules.
1277
            $this->createTestUserWithPassword('pass', $userContentType);
1278
        } catch (ContentFieldValidationException $e) {
1279
            // Exception is caught, as there is no other way to check exception properties.
1280
            $this->assertAllValidationErrorsOccur(
1281
                $e,
1282
                [
1283
                    'User password must include at least one special character',
1284
                    'User password must be at least %length% characters long',
1285
                    'User password must include at least one upper case letter',
1286
                    'User password must include at least one number',
1287
                ]
1288
            );
1289
1290
            return;
1291
        }
1292
1293
        $this->fail('Expected ValidationError messages did not occur.');
1294
    }
1295
1296
    /**
1297
     * Opposite test case for testCreateUserWithWeakPasswordThrowsUserPasswordValidationException.
1298
     *
1299
     * @covers \eZ\Publish\API\Repository\UserService::createUser
1300
     */
1301
    public function testCreateUserWithStrongPassword()
1302
    {
1303
        $userContentType = $this->createUserContentTypeWithStrongPassword();
1304
1305
        /* BEGIN: Use Case */
1306
        $user = $this->createTestUserWithPassword('H@xxi0r!', $userContentType);
1307
        /* END: Use Case */
1308
1309
        $this->assertInstanceOf(User::class, $user);
1310
    }
1311
1312
    /**
1313
     * Test for the loadUser() method.
1314
     *
1315
     * @see \eZ\Publish\API\Repository\UserService::loadUser()
1316
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1317
     */
1318
    public function testLoadUser()
1319
    {
1320
        $repository = $this->getRepository();
1321
1322
        $userService = $repository->getUserService();
1323
1324
        /* BEGIN: Use Case */
1325
        $user = $this->createUserVersion1();
1326
1327
        // Load the newly created user
1328
        $userReloaded = $userService->loadUser($user->id, Language::ALL);
1329
        /* END: Use Case */
1330
1331
        $this->assertEquals($user, $userReloaded);
1332
1333
        // User happens to also be a Content; isUser() should be true and isUserGroup() should be false
1334
        $this->assertTrue($userService->isUser($user), 'isUser() => false on a user');
1335
        $this->assertFalse($userService->isUserGroup($user), 'isUserGroup() => true on a user group');
1336
    }
1337
1338
    /**
1339
     * Test for the loadUser() method.
1340
     *
1341
     * @see \eZ\Publish\API\Repository\UserService::loadUser()
1342
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUser
1343
     */
1344
    public function testLoadUserThrowsNotFoundException()
1345
    {
1346
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
1347
1348
        $repository = $this->getRepository();
1349
1350
        $nonExistingUserId = $this->generateId('user', self::DB_INT_MAX);
1351
        /* BEGIN: Use Case */
1352
        $userService = $repository->getUserService();
1353
1354
        // This call will fail with a "NotFoundException", because no user with
1355
        // an id equal to self::DB_INT_MAX should exist.
1356
        $userService->loadUser($nonExistingUserId);
1357
        /* END: Use Case */
1358
    }
1359
1360
    /**
1361
     * @see \eZ\Publish\API\Repository\UserService::checkUserCredentials()
1362
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1363
     */
1364
    public function testCheckUserCredentialsValid(): void
1365
    {
1366
        $repository = $this->getRepository();
1367
1368
        $userService = $repository->getUserService();
1369
1370
        /* BEGIN: Use Case */
1371
        $user = $this->createUserVersion1();
1372
1373
        // Load the newly created user credentials
1374
        $credentialsValid = $userService->checkUserCredentials($user, '[email protected]');
1375
        /* END: Use Case */
1376
1377
        $this->assertTrue($credentialsValid);
1378
    }
1379
1380
    /**
1381
     * @see \eZ\Publish\API\Repository\UserService::checkUserCredentials()
1382
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1383
     */
1384
    public function testCheckUserCredentialsInvalid(): void
1385
    {
1386
        $repository = $this->getRepository();
1387
1388
        $userService = $repository->getUserService();
1389
1390
        /* BEGIN: Use Case */
1391
        $user = $this->createUserVersion1();
1392
1393
        // Load the newly created user credentials
1394
        $credentialsValid = $userService->checkUserCredentials($user, 'NotSoSecretPassword');
1395
        /* END: Use Case */
1396
1397
        $this->assertFalse($credentialsValid);
1398
    }
1399
1400
    /**
1401
     * Test for the loadUserByLogin() method.
1402
     *
1403
     * @see \eZ\Publish\API\Repository\UserService::loadUserByLogin()
1404
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1405
     */
1406
    public function testLoadUserByLogin()
1407
    {
1408
        $repository = $this->getRepository();
1409
1410
        $userService = $repository->getUserService();
1411
1412
        /* BEGIN: Use Case */
1413
        $user = $this->createUserVersion1('User');
1414
1415
        // Load the newly created user
1416
        $userReloaded = $userService->loadUserByLogin('User');
1417
        /* END: Use Case */
1418
1419
        $this->assertPropertiesCorrect(
1420
            [
1421
                'login' => $user->login,
1422
                'email' => $user->email,
1423
                'passwordHash' => $user->passwordHash,
1424
                'hashAlgorithm' => $user->hashAlgorithm,
1425
                'enabled' => $user->enabled,
1426
                'maxLogin' => $user->maxLogin,
1427
                'id' => $user->id,
1428
                'contentInfo' => $user->contentInfo,
1429
                'versionInfo' => $user->versionInfo,
1430
                'fields' => $user->fields,
1431
            ],
1432
            $userReloaded
1433
        );
1434
    }
1435
1436
    /**
1437
     * Test for the loadUserByLogin() method.
1438
     *
1439
     * @see \eZ\Publish\API\Repository\UserService::loadUserByLogin()
1440
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserByLogin
1441
     */
1442
    public function testLoadUserByLoginThrowsNotFoundExceptionForUnknownLogin()
1443
    {
1444
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
1445
1446
        $repository = $this->getRepository();
1447
1448
        $userService = $repository->getUserService();
1449
1450
        /* BEGIN: Use Case */
1451
        $this->createUserVersion1();
1452
1453
        // This call will fail with a "NotFoundException", because the given
1454
        // login/password combination does not exist.
1455
        $userService->loadUserByLogin('user42');
1456
        /* END: Use Case */
1457
    }
1458
1459
    /**
1460
     * Test for the loadUserByLogin() method.
1461
     *
1462
     * @see \eZ\Publish\API\Repository\UserService::loadUserByLogin()
1463
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserByLogin
1464
     */
1465
    public function testLoadUserByLoginWorksForLoginWithWrongCase()
1466
    {
1467
        $repository = $this->getRepository();
1468
1469
        $userService = $repository->getUserService();
1470
1471
        /* BEGIN: Use Case */
1472
        $user = $this->createUserVersion1();
1473
1474
        // Lookup by user login should ignore casing
1475
        $userReloaded = $userService->loadUserByLogin('USER');
1476
        /* END: Use Case */
1477
1478
        $this->assertPropertiesCorrect(
1479
            [
1480
                'login' => $user->login,
1481
                'email' => $user->email,
1482
                'passwordHash' => $user->passwordHash,
1483
                'hashAlgorithm' => $user->hashAlgorithm,
1484
                'enabled' => $user->enabled,
1485
                'maxLogin' => $user->maxLogin,
1486
                'id' => $user->id,
1487
                'contentInfo' => $user->contentInfo,
1488
                'versionInfo' => $user->versionInfo,
1489
                'fields' => $user->fields,
1490
            ],
1491
            $userReloaded
1492
        );
1493
    }
1494
1495
    /**
1496
     * Test for the loadUserByLogin() method.
1497
     *
1498
     * In some cases people use email as login name, make sure system works as exepcted when asking for user by email.
1499
     *
1500
     * @see \eZ\Publish\API\Repository\UserService::loadUserByLogin()
1501
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserByLogin
1502
     */
1503
    public function testLoadUserByLoginThrowsNotFoundExceptionForUnknownLoginByEmail()
1504
    {
1505
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
1506
1507
        $repository = $this->getRepository();
1508
1509
        $userService = $repository->getUserService();
1510
1511
        /* BEGIN: Use Case */
1512
        $user = $this->createUserVersion1();
1513
1514
        // Lookup by user login by email should behave as normal
1515
        $userService->loadUserByLogin('[email protected]');
1516
        /* END: Use Case */
1517
    }
1518
1519
    /**
1520
     * Test for the loadUsersByEmail() method.
1521
     *
1522
     * @see \eZ\Publish\API\Repository\UserService::loadUsersByEmail()
1523
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1524
     */
1525
    public function testLoadUserByEmail()
1526
    {
1527
        $repository = $this->getRepository();
1528
1529
        $userService = $repository->getUserService();
1530
1531
        /* BEGIN: Use Case */
1532
        $user = $this->createUserVersion1();
1533
1534
        // Load the newly created user
1535
        $usersReloaded = $userService->loadUsersByEmail('[email protected]', Language::ALL);
1536
        /* END: Use Case */
1537
1538
        $this->assertEquals([$user], $usersReloaded);
1539
    }
1540
1541
    /**
1542
     * Test for the loadUsersByEmail() method.
1543
     *
1544
     * @see \eZ\Publish\API\Repository\UserService::loadUsersByEmail()
1545
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserByEmail
1546
     */
1547
    public function testLoadUserByEmailReturnsEmptyInUnknownEmail()
1548
    {
1549
        $repository = $this->getRepository();
1550
1551
        $userService = $repository->getUserService();
1552
1553
        /* BEGIN: Use Case */
1554
        $this->createUserVersion1();
1555
1556
        // This call will return empty array, because the given
1557
        // login/password combination does not exist.
1558
        $emptyUserList = $userService->loadUsersByEmail('[email protected]');
1559
        /* END: Use Case */
1560
1561
        $this->assertEquals([], $emptyUserList);
1562
    }
1563
1564
    /**
1565
     * Test for the deleteUser() method.
1566
     *
1567
     * @see \eZ\Publish\API\Repository\UserService::deleteUser()
1568
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1569
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUser
1570
     */
1571
    public function testDeleteUser()
1572
    {
1573
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
1574
1575
        $repository = $this->getRepository();
1576
1577
        $userService = $repository->getUserService();
1578
1579
        /* BEGIN: Use Case */
1580
        $user = $this->createUserVersion1();
1581
1582
        // Delete the currently created user
1583
        $userService->deleteUser($user);
1584
        /* END: Use Case */
1585
1586
        // We use the NotFoundException here to verify that the user not exists
1587
        $userService->loadUser($user->id);
1588
    }
1589
1590
    /**
1591
     * Test for the deleteUser() method.
1592
     *
1593
     * @covers \eZ\Publish\API\Repository\UserService::deleteUser()
1594
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1595
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUser
1596
     */
1597
    public function testDeleteUserDeletesRelatedBookmarks()
1598
    {
1599
        $repository = $this->getRepository();
1600
1601
        $userService = $repository->getUserService();
1602
        $locationService = $repository->getLocationService();
1603
        $bookmarkService = $repository->getBookmarkService();
1604
        /* BEGIN: Use Case */
1605
        $admin = $repository->getPermissionResolver()->getCurrentUserReference();
1606
1607
        $user = $this->createUserVersion1();
1608
1609
        $repository->getPermissionResolver()->setCurrentUserReference($user);
1610
1611
        $bookmarkService->createBookmark(
1612
            $locationService->loadLocation($this->generateId('location', 43))
1613
        );
1614
1615
        $repository->getPermissionResolver()->setCurrentUserReference($admin);
1616
        // Delete the currently created user
1617
        $userService->deleteUser($user);
1618
1619
        $repository->getPermissionResolver()->setCurrentUserReference($user);
1620
        /* END: Use Case */
1621
1622
        $this->assertEquals(0, $bookmarkService->loadBookmarks(0, 9999)->totalCount);
1623
    }
1624
1625
    /**
1626
     * Test for the newUserUpdateStruct() method.
1627
     *
1628
     * @see \eZ\Publish\API\Repository\UserService::newUserUpdateStruct()
1629
     */
1630
    public function testNewUserUpdateStruct()
1631
    {
1632
        $repository = $this->getRepository();
1633
1634
        /* BEGIN: Use Case */
1635
        $userService = $repository->getUserService();
1636
1637
        // Create a new update struct instance
1638
        $userUpdate = $userService->newUserUpdateStruct();
1639
        /* END: Use Case */
1640
1641
        $this->assertInstanceOf(
1642
            UserUpdateStruct::class,
1643
            $userUpdate
1644
        );
1645
1646
        $this->assertNull($userUpdate->contentUpdateStruct);
1647
        $this->assertNull($userUpdate->contentMetadataUpdateStruct);
1648
1649
        $this->assertPropertiesCorrect(
1650
            [
1651
                'email' => null,
1652
                'password' => null,
1653
                'enabled' => null,
1654
                'maxLogin' => null,
1655
            ],
1656
            $userUpdate
1657
        );
1658
    }
1659
1660
    /**
1661
     * Test for the updateUser() method.
1662
     *
1663
     * @return \eZ\Publish\API\Repository\Values\User\User
1664
     *
1665
     * @see \eZ\Publish\API\Repository\UserService::updateUser()
1666
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1667
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserUpdateStruct
1668
     */
1669
    public function testUpdateUser()
1670
    {
1671
        $repository = $this->getRepository();
1672
1673
        $userService = $repository->getUserService();
1674
1675
        /* BEGIN: Use Case */
1676
        $user = $this->createUserVersion1();
1677
1678
        // Create a new update struct instance
1679
        $userUpdate = $userService->newUserUpdateStruct();
1680
1681
        // Set new values for password and maxLogin
1682
        $userUpdate->password = 'my-new-password';
1683
        $userUpdate->maxLogin = 42;
1684
        $userUpdate->enabled = false;
1685
1686
        // Updated the user record.
1687
        $userVersion2 = $userService->updateUser($user, $userUpdate);
1688
        /* END: Use Case */
1689
1690
        $this->assertInstanceOf(User::class, $userVersion2);
1691
1692
        return $userVersion2;
1693
    }
1694
1695
    /**
1696
     * Test for the updateUser() and loadUsersByEmail() method on change to email.
1697
     */
1698
    public function testUpdateUserEmail(): void
1699
    {
1700
        $repository = $this->getRepository();
1701
        $userService = $repository->getUserService();
1702
1703
        // Create a user
1704
        $user = $this->createUserVersion1();
1705
1706
        // Check we get what we expect (and implicit warmup any kind of cache)
1707
        $users = $userService->loadUsersByEmail('[email protected]');
1708
        $this->assertCount(0, $users);
1709
1710
        // Update user with the given email address
1711
        $userUpdate = $userService->newUserUpdateStruct();
1712
        $userUpdate->email = '[email protected]';
1713
        $updatedUser = $userService->updateUser($user, $userUpdate);
1714
        $this->assertInstanceOf(User::class, $updatedUser);
1715
1716
        // Check that we can load user by email
1717
        $users = $userService->loadUsersByEmail('[email protected]');
1718
        $this->assertCount(1, $users);
1719
        $this->assertInstanceOf(User::class, $users[0]);
1720
    }
1721
1722
    /**
1723
     * Test for the updateUser() method.
1724
     *
1725
     * @return \eZ\Publish\API\Repository\Values\User\User
1726
     *
1727
     * @see \eZ\Publish\API\Repository\UserService::updateUser()
1728
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
1729
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testNewUserUpdateStruct
1730
     */
1731
    public function testUpdateUserNoPassword()
1732
    {
1733
        $repository = $this->getRepository();
1734
        $userService = $repository->getUserService();
1735
1736
        /* BEGIN: Use Case */
1737
        $user = $this->createUserVersion1();
1738
1739
        // Create a new update struct instance
1740
        $userUpdate = $userService->newUserUpdateStruct();
1741
1742
        // Set new values for maxLogin, don't change password
1743
        $userUpdate->maxLogin = 43;
1744
        $userUpdate->enabled = false;
1745
1746
        // Updated the user record.
1747
        $userVersion2 = $userService->updateUser($user, $userUpdate);
1748
        /* END: Use Case */
1749
1750
        $this->assertInstanceOf(User::class, $user);
1751
1752
        $this->assertEquals(
1753
            [
1754
                'login' => $user->login,
1755
                'email' => $user->email,
1756
                'passwordHash' => $user->passwordHash,
1757
                'hashAlgorithm' => $user->hashAlgorithm,
1758
                'maxLogin' => 43,
1759
                'enabled' => false,
1760
            ],
1761
            [
1762
                'login' => $userVersion2->login,
1763
                'email' => $userVersion2->email,
1764
                'passwordHash' => $userVersion2->passwordHash,
1765
                'hashAlgorithm' => $userVersion2->hashAlgorithm,
1766
                'maxLogin' => $userVersion2->maxLogin,
1767
                'enabled' => $userVersion2->enabled,
1768
            ]
1769
        );
1770
    }
1771
1772
    /**
1773
     * Test for the updateUser() method.
1774
     *
1775
     * @param \eZ\Publish\API\Repository\Values\User\User $user
1776
     *
1777
     * @see \eZ\Publish\API\Repository\UserService::updateUser()
1778
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUser
1779
     */
1780
    public function testUpdateUserUpdatesExpectedProperties(User $user)
1781
    {
1782
        $this->assertEquals(
1783
            [
1784
                'login' => 'user',
1785
                'email' => '[email protected]',
1786
                'maxLogin' => 42,
1787
                'enabled' => false,
1788
            ],
1789
            [
1790
                'login' => $user->login,
1791
                'email' => $user->email,
1792
                'maxLogin' => $user->maxLogin,
1793
                'enabled' => $user->enabled,
1794
            ]
1795
        );
1796
    }
1797
1798
    /**
1799
     * Test for the updateUser() method.
1800
     *
1801
     * @param \eZ\Publish\API\Repository\Values\User\User $user
1802
     *
1803
     * @see \eZ\Publish\API\Repository\UserService::updateUser()
1804
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUser
1805
     */
1806
    public function testUpdateUserReturnsPublishedVersion(User $user)
1807
    {
1808
        $this->assertEquals(
1809
            APIVersionInfo::STATUS_PUBLISHED,
1810
            $user->getVersionInfo()->status
1811
        );
1812
    }
1813
1814
    /**
1815
     * Test for the updateUser() method.
1816
     *
1817
     * @see \eZ\Publish\API\Repository\UserService::updateUser()
1818
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUser
1819
     */
1820
    public function testUpdateUserWithContentMetadataUpdateStruct()
1821
    {
1822
        $repository = $this->getRepository();
1823
1824
        $userService = $repository->getUserService();
1825
1826
        /* BEGIN: Use Case */
1827
        $user = $this->createUserVersion1();
1828
1829
        // Get the ContentService implementation
1830
        $contentService = $repository->getContentService();
1831
1832
        // Create a metadata update struct and change the remote id.
1833
        $metadataUpdate = $contentService->newContentMetadataUpdateStruct();
1834
        $metadataUpdate->remoteId = '85e10037d1ac0a00aa75443ced483e08';
1835
1836
        // Create a new update struct instance
1837
        $userUpdate = $userService->newUserUpdateStruct();
1838
1839
        // Set the metadata update struct.
1840
        $userUpdate->contentMetadataUpdateStruct = $metadataUpdate;
1841
1842
        // Updated the user record.
1843
        $userVersion2 = $userService->updateUser($user, $userUpdate);
1844
1845
        // The contentInfo->remoteId will be changed now.
1846
        $remoteId = $userVersion2->contentInfo->remoteId;
1847
        /* END: Use Case */
1848
1849
        $this->assertEquals('85e10037d1ac0a00aa75443ced483e08', $remoteId);
1850
    }
1851
1852
    /**
1853
     * Test for the updateUser() method.
1854
     *
1855
     * @see \eZ\Publish\API\Repository\UserService::updateUser()
1856
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUser
1857
     */
1858
    public function testUpdateUserWithContentUpdateStruct()
1859
    {
1860
        $repository = $this->getRepository();
1861
1862
        $userService = $repository->getUserService();
1863
1864
        /* BEGIN: Use Case */
1865
        $user = $this->createUserVersion1();
1866
1867
        // Get the ContentService implementation
1868
        $contentService = $repository->getContentService();
1869
1870
        // Create a content update struct and change the remote id.
1871
        $contentUpdate = $contentService->newContentUpdateStruct();
1872
        $contentUpdate->setField('first_name', 'Hello', 'eng-US');
1873
        $contentUpdate->setField('last_name', 'World', 'eng-US');
1874
1875
        // Create a new update struct instance
1876
        $userUpdate = $userService->newUserUpdateStruct();
1877
1878
        // Set the content update struct.
1879
        $userUpdate->contentUpdateStruct = $contentUpdate;
1880
1881
        // Updated the user record.
1882
        $userVersion2 = $userService->updateUser($user, $userUpdate);
1883
1884
        $name = sprintf(
1885
            '%s %s',
1886
            $userVersion2->getFieldValue('first_name'),
1887
            $userVersion2->getFieldValue('last_name')
1888
        );
1889
        /* END: Use Case */
1890
1891
        $this->assertEquals('Hello World', $name);
1892
    }
1893
1894
    /**
1895
     * Test for the updateUser() method.
1896
     *
1897
     * @see \eZ\Publish\API\Repository\UserService::updateUser()
1898
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUser
1899
     */
1900
    public function testUpdateUserWhenMissingField()
1901
    {
1902
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException::class);
1903
1904
        $repository = $this->getRepository();
1905
1906
        $userService = $repository->getUserService();
1907
1908
        /* BEGIN: Use Case */
1909
        $user = $this->createUserVersion1();
1910
1911
        // Get the ContentService implementation
1912
        $contentService = $repository->getContentService();
1913
1914
        // Create a content update struct and change the remote id.
1915
        $contentUpdate = $contentService->newContentUpdateStruct();
1916
        $contentUpdate->setField('first_name', null, 'eng-US');
1917
1918
        // Create a new update struct instance
1919
        $userUpdate = $userService->newUserUpdateStruct();
1920
1921
        // Set the content update struct.
1922
        $userUpdate->contentUpdateStruct = $contentUpdate;
1923
1924
        // This call will fail with a "ContentFieldValidationException" because the
1925
        // mandatory field "first_name" is set to an empty value.
1926
        $userService->updateUser($user, $userUpdate);
1927
1928
        /* END: Use Case */
1929
    }
1930
1931
    /**
1932
     * Test for the updateUser() method.
1933
     *
1934
     * @see \eZ\Publish\API\Repository\UserService::updateUser()
1935
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUpdateUser
1936
     */
1937
    public function testUpdateUserThrowsInvalidArgumentExceptionOnFieldTypeNotAccept()
1938
    {
1939
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
1940
1941
        $repository = $this->getRepository();
1942
1943
        $userService = $repository->getUserService();
1944
1945
        /* BEGIN: Use Case */
1946
        $user = $this->createUserVersion1();
1947
1948
        // Get the ContentService implementation
1949
        $contentService = $repository->getContentService();
1950
1951
        $contentUpdate = $contentService->newContentUpdateStruct();
1952
        // An object of stdClass is not valid for the field first_name
1953
        $contentUpdate->setField('first_name', new \stdClass(), 'eng-US');
1954
1955
        // Create a new update struct instance
1956
        $userUpdate = $userService->newUserUpdateStruct();
1957
1958
        // Set the content update struct.
1959
        $userUpdate->contentUpdateStruct = $contentUpdate;
1960
1961
        // This call will fail with a "InvalidArgumentException" because the
1962
        // the field "first_name" does not accept the given value.
1963
        $userService->updateUser($user, $userUpdate);
1964
1965
        /* END: Use Case */
1966
    }
1967
1968
    /**
1969
     * Test updating a user throwing UserPasswordValidationException when password doesn't follow specified rules.
1970
     *
1971
     * @covers \eZ\Publish\API\Repository\UserService::updateUser
1972
     */
1973
    public function testUpdateUserWithWeakPasswordThrowsUserPasswordValidationException()
1974
    {
1975
        $userService = $this->getRepository()->getUserService();
1976
1977
        $user = $this->createTestUserWithPassword('H@xxxiR!_1', $this->createUserContentTypeWithStrongPassword());
1978
1979
        /* BEGIN: Use Case */
1980
        // Create a new update struct instance
1981
        $userUpdate = $userService->newUserUpdateStruct();
1982
        $userUpdate->password = 'pass';
1983
1984
        try {
1985
            // This call will fail with a "UserPasswordValidationException" because the
1986
            // the password does not follow specified rules
1987
            $userService->updateUser($user, $userUpdate);
1988
            /* END: Use Case */
1989
        } catch (ContentFieldValidationException $e) {
1990
            // Exception is caught, as there is no other way to check exception properties.
1991
            $this->assertValidationErrorOccurs($e, 'User password must include at least one special character');
1992
            $this->assertValidationErrorOccurs($e, 'User password must be at least %length% characters long');
1993
            $this->assertValidationErrorOccurs($e, 'User password must include at least one upper case letter');
1994
            $this->assertValidationErrorOccurs($e, 'User password must include at least one number');
1995
1996
            /* END: Use Case */
1997
            return;
1998
        }
1999
2000
        $this->fail('Expected ValidationError messages did not occur.');
2001
    }
2002
2003
    /**
2004
     * Opposite test case for testUpdateUserWithWeakPasswordThrowsUserPasswordValidationException.
2005
     *
2006
     * @covers \eZ\Publish\API\Repository\UserService::updateUser
2007
     */
2008
    public function testUpdateUserWithStrongPassword()
2009
    {
2010
        $userService = $this->getRepository()->getUserService();
2011
2012
        $user = $this->createTestUserWithPassword('H@xxxiR!_1', $this->createUserContentTypeWithStrongPassword());
2013
2014
        /* BEGIN: Use Case */
2015
        // Create a new update struct instance
2016
        $userUpdate = $userService->newUserUpdateStruct();
2017
        $userUpdate->password = 'H@xxxiR!_2';
2018
2019
        $user = $userService->updateUser($user, $userUpdate);
2020
        /* END: Use Case */
2021
2022
        $this->assertInstanceOf(User::class, $user);
2023
    }
2024
2025
    /**
2026
     * Test for the loadUserGroupsOfUser() method.
2027
     *
2028
     * @covers \eZ\Publish\API\Repository\UserService::loadUserGroupsOfUser
2029
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
2030
     */
2031
    public function testLoadUserGroupsOfUser()
2032
    {
2033
        $repository = $this->getRepository();
2034
2035
        $userService = $repository->getUserService();
2036
2037
        /* BEGIN: Use Case */
2038
        $user = $this->createUserVersion1();
2039
2040
        // This array will contain the "Editors" user group name
2041
        $userGroupNames = [];
2042
        foreach ($userService->loadUserGroupsOfUser($user) as $userGroup) {
2043
            $this->assertInstanceOf(UserGroup::class, $userGroup);
2044
            $userGroupNames[] = $userGroup->getFieldValue('name');
2045
        }
2046
        /* END: Use Case */
2047
2048
        $this->assertEquals(['Editors'], $userGroupNames);
2049
    }
2050
2051
    /**
2052
     * Test for the loadUsersOfUserGroup() method.
2053
     *
2054
     * @covers \eZ\Publish\API\Repository\UserService::loadUsersOfUserGroup
2055
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testCreateUser
2056
     */
2057
    public function testLoadUsersOfUserGroup()
2058
    {
2059
        $repository = $this->getRepository();
2060
        $userService = $repository->getUserService();
2061
2062
        $group = $userService->loadUserGroup($this->generateId('group', 13));
2063
2064
        /* BEGIN: Use Case */
2065
        $this->createUserVersion1();
2066
2067
        $this->refreshSearch($repository);
2068
2069
        // This array will contain the email of the newly created "Editor" user
2070
        $email = [];
2071
        foreach ($userService->loadUsersOfUserGroup($group) as $user) {
2072
            $this->assertInstanceOf(User::class, $user);
2073
            $email[] = $user->email;
2074
        }
2075
        /* END: Use Case */
2076
        $this->assertEquals(['[email protected]'], $email);
2077
    }
2078
2079
    /**
2080
     * Test for the assignUserToUserGroup() method.
2081
     *
2082
     * @see \eZ\Publish\API\Repository\UserService::assignUserToUserGroup()
2083
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroupsOfUser
2084
     */
2085
    public function testAssignUserToUserGroup()
2086
    {
2087
        $repository = $this->getRepository();
2088
        $userService = $repository->getUserService();
2089
2090
        $administratorGroupId = $this->generateId('group', 12);
2091
        /* BEGIN: Use Case */
2092
        // $administratorGroupId is the ID of the "Administrator" group in an
2093
        // eZ Publish demo installation
2094
2095
        $user = $this->createUserVersion1();
2096
2097
        // Assign group to newly created user
2098
        $userService->assignUserToUserGroup(
2099
            $user,
2100
            $userService->loadUserGroup($administratorGroupId)
2101
        );
2102
2103
        // This array will contain "Editors" and "Administrator users"
2104
        $userGroupNames = [];
2105
        foreach ($userService->loadUserGroupsOfUser($user) as $userGroup) {
2106
            $userGroupNames[] = $userGroup->getFieldValue('name');
2107
        }
2108
        /* END: Use Case */
2109
2110
        sort($userGroupNames, SORT_STRING);
2111
2112
        $this->assertEquals(
2113
            [
2114
                'Administrator users',
2115
                'Editors',
2116
            ],
2117
            $userGroupNames
2118
        );
2119
    }
2120
2121
    /**
2122
     * Test for the assignUserToUserGroup() method.
2123
     *
2124
     * @covers \eZ\Publish\API\Repository\UserService::assignUserToUserGroup
2125
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testAssignUserToUserGroup
2126
     */
2127
    public function testAssignUserToUserGroupThrowsInvalidArgumentException()
2128
    {
2129
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
2130
        $this->expectExceptionMessage('Argument \'user\' is invalid: User is already in the given User Group');
2131
2132
        $repository = $this->getRepository();
2133
        $userService = $repository->getUserService();
2134
2135
        $editorsGroupId = $this->generateId('group', 13);
2136
        /* BEGIN: Use Case */
2137
        $user = $this->createUserVersion1();
2138
        // $editorsGroupId is the ID of the "Editors" group in an
2139
        // eZ Publish demo installation
2140
2141
        // This call will fail with an "InvalidArgumentException", because the
2142
        // user is already assigned to the "Editors" group
2143
        $userService->assignUserToUserGroup(
2144
            $user,
2145
            $userService->loadUserGroup($editorsGroupId)
2146
        );
2147
        /* END: Use Case */
2148
    }
2149
2150
    /**
2151
     * Test for the unAssignUssrFromUserGroup() method.
2152
     *
2153
     * @see \eZ\Publish\API\Repository\UserService::unAssignUssrFromUserGroup()
2154
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testLoadUserGroupsOfUser
2155
     */
2156
    public function testUnAssignUserFromUserGroup()
2157
    {
2158
        $repository = $this->getRepository();
2159
        $userService = $repository->getUserService();
2160
2161
        $editorsGroupId = $this->generateId('group', 13);
2162
        $anonymousGroupId = $this->generateId('group', 42);
2163
2164
        /* BEGIN: Use Case */
2165
        // $anonymousGroupId is the ID of the "Anonymous Users" group in an eZ
2166
        // Publish demo installation
2167
2168
        $user = $this->createUserVersion1();
2169
2170
        // Assign group to newly created user
2171
        $userService->assignUserToUserGroup(
2172
            $user,
2173
            $userService->loadUserGroup($anonymousGroupId)
2174
        );
2175
2176
        // Unassign user from "Editors" group
2177
        $userService->unAssignUserFromUserGroup(
2178
            $user,
2179
            $userService->loadUserGroup($editorsGroupId)
2180
        );
2181
2182
        // This array will contain "Anonymous Users"
2183
        $userGroupNames = [];
2184
        foreach ($userService->loadUserGroupsOfUser($user) as $userGroup) {
2185
            $userGroupNames[] = $userGroup->getFieldValue('name');
2186
        }
2187
        /* END: Use Case */
2188
2189
        $this->assertEquals(['Anonymous Users'], $userGroupNames);
2190
    }
2191
2192
    /**
2193
     * Test for the unAssignUserFromUserGroup() method.
2194
     *
2195
     * @see \eZ\Publish\API\Repository\UserService::unAssignUserFromUserGroup()
2196
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUnAssignUserFromUserGroup
2197
     */
2198
    public function testUnAssignUserFromUserGroupThrowsInvalidArgumentException()
2199
    {
2200
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
2201
2202
        $repository = $this->getRepository();
2203
        $userService = $repository->getUserService();
2204
2205
        $administratorGroupId = $this->generateId('group', 12);
2206
        /* BEGIN: Use Case */
2207
        $user = $this->createUserVersion1();
2208
        // $administratorGroupId is the ID of the "Administrator" group in an
2209
        // eZ Publish demo installation
2210
2211
        // This call will fail with an "InvalidArgumentException", because the
2212
        // user is not assigned to the "Administrator" group
2213
        $userService->unAssignUserFromUserGroup(
2214
            $user,
2215
            $userService->loadUserGroup($administratorGroupId)
2216
        );
2217
        /* END: Use Case */
2218
    }
2219
2220
    /**
2221
     * Test for the unAssignUserFromUserGroup() method removing user from the last group.
2222
     *
2223
     * @covers \eZ\Publish\API\Repository\UserService::unAssignUserFromUserGroup
2224
     * @depends eZ\Publish\API\Repository\Tests\UserServiceTest::testUnAssignUserFromUserGroup
2225
     */
2226
    public function testUnAssignUserFromUserGroupThrowsBadStateArgumentException()
2227
    {
2228
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
2229
        $this->expectExceptionMessage('Argument \'user\' has a bad state: User only has one User Group, cannot unassign from last group');
2230
2231
        $repository = $this->getRepository();
2232
        $userService = $repository->getUserService();
2233
2234
        $editorsGroupId = $this->generateId('group', 13);
2235
        /* BEGIN: Use Case */
2236
        $user = $this->createUserVersion1();
2237
2238
        // This call will fail with an "BadStateException", because the
2239
        // user has to be assigned to at least one group
2240
        $userService->unAssignUserFromUserGroup(
2241
            $user,
2242
            $userService->loadUserGroup($editorsGroupId)
2243
        );
2244
        /* END: Use Case */
2245
    }
2246
2247
    /**
2248
     * Test that multi-language logic for the loadUserGroup method respects prioritized language list.
2249
     *
2250
     * @covers \eZ\Publish\API\Repository\UserService::loadUserGroup
2251
     * @dataProvider getPrioritizedLanguageList
2252
     * @param string[] $prioritizedLanguages
2253
     * @param string|null $expectedLanguageCode language code of expected translation
2254
     */
2255
    public function testLoadUserGroupWithPrioritizedLanguagesList(
2256
        array $prioritizedLanguages,
2257
        $expectedLanguageCode
2258
    ) {
2259
        $repository = $this->getRepository();
2260
        $userService = $repository->getUserService();
2261
2262
        $userGroup = $this->createMultiLanguageUserGroup();
2263
        if ($expectedLanguageCode === null) {
2264
            $expectedLanguageCode = $userGroup->contentInfo->mainLanguageCode;
2265
        }
2266
2267
        $loadedUserGroup = $userService->loadUserGroup($userGroup->id, $prioritizedLanguages);
2268
2269
        self::assertEquals(
2270
            $loadedUserGroup->getName($expectedLanguageCode),
2271
            $loadedUserGroup->getName()
2272
        );
2273
        self::assertEquals(
2274
            $loadedUserGroup->getFieldValue('description', $expectedLanguageCode),
2275
            $loadedUserGroup->getFieldValue('description')
2276
        );
2277
    }
2278
2279
    /**
2280
     * Test that multi-language logic works correctly after updating user group main language.
2281
     *
2282
     * @covers \eZ\Publish\API\Repository\UserService::loadUserGroup
2283
     * @dataProvider getPrioritizedLanguageList
2284
     * @param string[] $prioritizedLanguages
2285
     * @param string|null $expectedLanguageCode language code of expected translation
2286
     */
2287
    public function testLoadUserGroupWithPrioritizedLanguagesListAfterMainLanguageUpdate(
2288
        array $prioritizedLanguages,
2289
        $expectedLanguageCode
2290
    ) {
2291
        $repository = $this->getRepository();
2292
        $userService = $repository->getUserService();
2293
        $contentService = $repository->getContentService();
2294
2295
        $userGroup = $this->createMultiLanguageUserGroup();
2296
2297
        $userGroupUpdateStruct = $userService->newUserGroupUpdateStruct();
2298
        $userGroupUpdateStruct->contentMetadataUpdateStruct = $contentService->newContentMetadataUpdateStruct();
2299
        $userGroupUpdateStruct->contentMetadataUpdateStruct->mainLanguageCode = 'eng-GB';
2300
        $userService->updateUserGroup($userGroup, $userGroupUpdateStruct);
2301
2302
        if ($expectedLanguageCode === null) {
2303
            $expectedLanguageCode = 'eng-GB';
2304
        }
2305
2306
        $loadedUserGroup = $userService->loadUserGroup($userGroup->id, $prioritizedLanguages);
2307
2308
        self::assertEquals(
2309
            $loadedUserGroup->getName($expectedLanguageCode),
2310
            $loadedUserGroup->getName()
2311
        );
2312
        self::assertEquals(
2313
            $loadedUserGroup->getFieldValue('description', $expectedLanguageCode),
2314
            $loadedUserGroup->getFieldValue('description')
2315
        );
2316
    }
2317
2318
    /**
2319
     * Test that multi-language logic for the loadSubUserGroups method respects prioritized language list.
2320
     *
2321
     * @covers \eZ\Publish\API\Repository\UserService::loadSubUserGroups
2322
     * @dataProvider getPrioritizedLanguageList
2323
     * @param string[] $prioritizedLanguages
2324
     * @param string|null $expectedLanguageCode language code of expected translation
2325
     */
2326
    public function testLoadSubUserGroupsWithPrioritizedLanguagesList(
2327
        array $prioritizedLanguages,
2328
        $expectedLanguageCode
2329
    ) {
2330
        $repository = $this->getRepository();
2331
        $userService = $repository->getUserService();
2332
2333
        // create main group for subgroups
2334
        $userGroup = $this->createMultiLanguageUserGroup(4);
2335
        if ($expectedLanguageCode === null) {
2336
            $expectedLanguageCode = $userGroup->contentInfo->mainLanguageCode;
2337
        }
2338
2339
        // create subgroups
2340
        $this->createMultiLanguageUserGroup($userGroup->id);
2341
        $this->createMultiLanguageUserGroup($userGroup->id);
2342
2343
        $userGroup = $userService->loadUserGroup($userGroup->id, $prioritizedLanguages);
2344
2345
        $subUserGroups = $userService->loadSubUserGroups($userGroup, 0, 2, $prioritizedLanguages);
2346
        foreach ($subUserGroups as $subUserGroup) {
2347
            self::assertEquals(
2348
                $subUserGroup->getName($expectedLanguageCode),
2349
                $subUserGroup->getName()
2350
            );
2351
            self::assertEquals(
2352
                $subUserGroup->getFieldValue('description', $expectedLanguageCode),
2353
                $subUserGroup->getFieldValue('description')
2354
            );
2355
        }
2356
    }
2357
2358
    /**
2359
     * Test that multi-language logic for the loadUser method respects prioritized language list.
2360
     *
2361
     * @covers \eZ\Publish\API\Repository\UserService::loadUser
2362
     * @dataProvider getPrioritizedLanguageList
2363
     * @param string[] $prioritizedLanguages
2364
     * @param string|null $expectedLanguageCode language code of expected translation
2365
     */
2366
    public function testLoadUserWithPrioritizedLanguagesList(
2367
        array $prioritizedLanguages,
2368
        $expectedLanguageCode
2369
    ) {
2370
        $repository = $this->getRepository();
2371
        $userService = $repository->getUserService();
2372
2373
        $user = $this->createMultiLanguageUser();
2374
        if ($expectedLanguageCode === null) {
2375
            $expectedLanguageCode = $user->contentInfo->mainLanguageCode;
2376
        }
2377
2378
        $loadedUser = $userService->loadUser($user->id, $prioritizedLanguages);
2379
2380
        self::assertEquals(
2381
            $loadedUser->getName($expectedLanguageCode),
2382
            $loadedUser->getName()
2383
        );
2384
2385
        foreach (['fist_name', 'last_name', 'signature'] as $fieldIdentifier) {
2386
            self::assertEquals(
2387
                $loadedUser->getFieldValue($fieldIdentifier, $expectedLanguageCode),
2388
                $loadedUser->getFieldValue($fieldIdentifier)
2389
            );
2390
        }
2391
    }
2392
2393
    /**
2394
     * Test that multi-language logic for the loadUser method works correctly after updating
2395
     * user content main language.
2396
     *
2397
     * @covers \eZ\Publish\API\Repository\UserService::loadUserGroup
2398
     * @dataProvider getPrioritizedLanguageList
2399
     * @param string[] $prioritizedLanguages
2400
     * @param string|null $expectedLanguageCode language code of expected translation
2401
     */
2402
    public function testLoadUserWithPrioritizedLanguagesListAfterMainLanguageUpdate(
2403
        array $prioritizedLanguages,
2404
        $expectedLanguageCode
2405
    ) {
2406
        $repository = $this->getRepository();
2407
        $userService = $repository->getUserService();
2408
        $contentService = $repository->getContentService();
2409
2410
        $user = $this->createMultiLanguageUser();
2411
        // sanity check
2412
        self::assertEquals($user->contentInfo->mainLanguageCode, 'eng-US');
2413
2414
        $userUpdateStruct = $userService->newUserUpdateStruct();
2415
        $userUpdateStruct->contentMetadataUpdateStruct = $contentService->newContentMetadataUpdateStruct();
2416
        $userUpdateStruct->contentMetadataUpdateStruct->mainLanguageCode = 'eng-GB';
2417
        $userService->updateUser($user, $userUpdateStruct);
2418
        if ($expectedLanguageCode === null) {
2419
            $expectedLanguageCode = 'eng-GB';
2420
        }
2421
2422
        $loadedUser = $userService->loadUser($user->id, $prioritizedLanguages);
2423
2424
        self::assertEquals(
2425
            $loadedUser->getName($expectedLanguageCode),
2426
            $loadedUser->getName()
2427
        );
2428
2429
        foreach (['fist_name', 'last_name', 'signature'] as $fieldIdentifier) {
2430
            self::assertEquals(
2431
                $loadedUser->getFieldValue($fieldIdentifier, $expectedLanguageCode),
2432
                $loadedUser->getFieldValue($fieldIdentifier)
2433
            );
2434
        }
2435
    }
2436
2437
    /**
2438
     * Test that multi-language logic for the loadUserByLogin method respects prioritized language list.
2439
     *
2440
     * @covers \eZ\Publish\API\Repository\UserService::loadUserByLogin
2441
     * @dataProvider getPrioritizedLanguageList
2442
     * @param string[] $prioritizedLanguages
2443
     * @param string|null $expectedLanguageCode language code of expected translation
2444
     */
2445
    public function testLoadUserByLoginWithPrioritizedLanguagesList(
2446
        array $prioritizedLanguages,
2447
        $expectedLanguageCode
2448
    ) {
2449
        $repository = $this->getRepository();
2450
        $userService = $repository->getUserService();
2451
        $user = $this->createMultiLanguageUser();
2452
2453
        // load, with prioritized languages, the newly created user
2454
        $loadedUser = $userService->loadUserByLogin($user->login, $prioritizedLanguages);
2455
        if ($expectedLanguageCode === null) {
2456
            $expectedLanguageCode = $loadedUser->contentInfo->mainLanguageCode;
2457
        }
2458
2459
        self::assertEquals(
2460
            $loadedUser->getName($expectedLanguageCode),
2461
            $loadedUser->getName()
2462
        );
2463
2464
        foreach (['first_name', 'last_name', 'signature'] as $fieldIdentifier) {
2465
            self::assertEquals(
2466
                $loadedUser->getFieldValue($fieldIdentifier, $expectedLanguageCode),
2467
                $loadedUser->getFieldValue($fieldIdentifier)
2468
            );
2469
        }
2470
    }
2471
2472
    /**
2473
     * Test that multi-language logic for the loadUsersByEmail method respects
2474
     * prioritized language list.
2475
     *
2476
     * @covers \eZ\Publish\API\Repository\UserService::loadUsersByEmail
2477
     * @dataProvider getPrioritizedLanguageList
2478
     * @param string[] $prioritizedLanguages
2479
     * @param string|null $expectedLanguageCode language code of expected translation
2480
     */
2481
    public function testLoadUsersByEmailWithPrioritizedLanguagesList(
2482
        array $prioritizedLanguages,
2483
        $expectedLanguageCode
2484
    ) {
2485
        $repository = $this->getRepository();
2486
        $userService = $repository->getUserService();
2487
        $user = $this->createMultiLanguageUser();
2488
2489
        // load, with prioritized languages, users by email
2490
        $loadedUsers = $userService->loadUsersByEmail($user->email, $prioritizedLanguages);
2491
2492
        foreach ($loadedUsers as $loadedUser) {
2493
            if ($expectedLanguageCode === null) {
2494
                $expectedLanguageCode = $loadedUser->contentInfo->mainLanguageCode;
2495
            }
2496
            self::assertEquals(
2497
                $loadedUser->getName($expectedLanguageCode),
2498
                $loadedUser->getName()
2499
            );
2500
2501
            foreach (['first_name', 'last_name', 'signature'] as $fieldIdentifier) {
2502
                self::assertEquals(
2503
                    $loadedUser->getFieldValue($fieldIdentifier, $expectedLanguageCode),
2504
                    $loadedUser->getFieldValue($fieldIdentifier)
2505
                );
2506
            }
2507
        }
2508
    }
2509
2510
    /**
2511
     * Test that multi-language logic for the loadUserGroupsOfUser method respects
2512
     * prioritized language list.
2513
     *
2514
     * @covers \eZ\Publish\API\Repository\UserService::loadUserGroupsOfUser
2515
     * @dataProvider getPrioritizedLanguageList
2516
     * @param string[] $prioritizedLanguages
2517
     * @param string|null $expectedLanguageCode language code of expected translation
2518
     */
2519
    public function testLoadUserGroupsOfUserWithPrioritizedLanguagesList(
2520
        array $prioritizedLanguages,
2521
        $expectedLanguageCode
2522
    ) {
2523
        $repository = $this->getRepository();
2524
        $userService = $repository->getUserService();
2525
        $userGroup = $this->createMultiLanguageUserGroup();
2526
        $user = $this->createMultiLanguageUser($userGroup->id);
2527
2528
        $userGroups = $userService->loadUserGroupsOfUser($user, 0, 25, $prioritizedLanguages);
2529
        foreach ($userGroups as $userGroup) {
2530
            self::assertEquals(
2531
                $userGroup->getName($expectedLanguageCode),
2532
                $userGroup->getName()
2533
            );
2534
            self::assertEquals(
2535
                $userGroup->getFieldValue('description', $expectedLanguageCode),
2536
                $userGroup->getFieldValue('description')
2537
            );
2538
        }
2539
    }
2540
2541
    /**
2542
     * Test that multi-language logic for the loadUsersOfUserGroup method respects
2543
     * prioritized language list.
2544
     *
2545
     * @covers \eZ\Publish\API\Repository\UserService::loadUsersOfUserGroup
2546
     * @dataProvider getPrioritizedLanguageList
2547
     * @param string[] $prioritizedLanguages
2548
     * @param string|null $expectedLanguageCode language code of expected translation
2549
     */
2550
    public function testLoadUsersOfUserGroupWithPrioritizedLanguagesList(
2551
        array $prioritizedLanguages,
2552
        $expectedLanguageCode
2553
    ) {
2554
        $repository = $this->getRepository();
2555
        $userService = $repository->getUserService();
2556
2557
        // create parent user group
2558
        $userGroup = $this->createMultiLanguageUserGroup();
2559
        // add two users to the created parent user group
2560
        $this->createMultiLanguageUser($userGroup->id);
2561
        $this->createMultiLanguageUser($userGroup->id);
2562
2563
        // test loading of users via user group with prioritized languages list
2564
        $users = $userService->loadUsersOfUserGroup($userGroup, 0, 25, $prioritizedLanguages);
2565
        foreach ($users as $user) {
2566
            if ($expectedLanguageCode === null) {
2567
                $expectedLanguageCode = $user->contentInfo->mainLanguageCode;
2568
            }
2569
            self::assertEquals(
2570
                $user->getName($expectedLanguageCode),
2571
                $user->getName()
2572
            );
2573
2574
            foreach (['first_name', 'last_name', 'signature'] as $fieldIdentifier) {
2575
                self::assertEquals(
2576
                    $user->getFieldValue($fieldIdentifier, $expectedLanguageCode),
2577
                    $user->getFieldValue($fieldIdentifier)
2578
                );
2579
            }
2580
        }
2581
    }
2582
2583
    /**
2584
     * Get prioritized languages list data.
2585
     *
2586
     * Test cases using this data provider should expect the following arguments:
2587
     * <code>
2588
     *   array $prioritizedLanguagesList
2589
     *   string $expectedLanguage (if null - use main language)
2590
     * </code>
2591
     *
2592
     * @return array
2593
     */
2594
    public function getPrioritizedLanguageList()
2595
    {
2596
        return [
2597
            [[], null],
2598
            [['eng-US'], 'eng-US'],
2599
            [['eng-GB'], 'eng-GB'],
2600
            [['eng-US', 'eng-GB'], 'eng-US'],
2601
            [['eng-GB', 'eng-US'], 'eng-GB'],
2602
            // use non-existent group as the first one
2603
            [['ger-DE'], null],
2604
            [['ger-DE', 'eng-GB'], 'eng-GB'],
2605
        ];
2606
    }
2607
2608
    /**
2609
     * @param int $parentGroupId
2610
     * @return \eZ\Publish\API\Repository\Values\User\UserGroup
2611
     */
2612
    private function createMultiLanguageUserGroup($parentGroupId = 4)
2613
    {
2614
        $repository = $this->getRepository();
2615
        $userService = $repository->getUserService();
2616
2617
        // create user group with multiple translations
2618
        $parentGroupId = $this->generateId('group', $parentGroupId);
2619
        $parentGroup = $userService->loadUserGroup($parentGroupId);
2620
2621
        $userGroupCreateStruct = $userService->newUserGroupCreateStruct('eng-US');
2622
        $userGroupCreateStruct->setField('name', 'US user group', 'eng-US');
2623
        $userGroupCreateStruct->setField('name', 'GB user group', 'eng-GB');
2624
        $userGroupCreateStruct->setField('description', 'US user group description', 'eng-US');
2625
        $userGroupCreateStruct->setField('description', 'GB user group description', 'eng-GB');
2626
        $userGroupCreateStruct->alwaysAvailable = true;
2627
2628
        return $userService->createUserGroup($userGroupCreateStruct, $parentGroup);
2629
    }
2630
2631
    /**
2632
     * Create a user group fixture in a variable named <b>$userGroup</b>,.
2633
     *
2634
     * @return \eZ\Publish\API\Repository\Values\User\UserGroup
2635
     */
2636
    private function createUserGroupVersion1()
2637
    {
2638
        $repository = $this->getRepository();
2639
2640
        $mainGroupId = $this->generateId('group', 4);
2641
        /* BEGIN: Inline */
2642
        // $mainGroupId is the ID of the main "Users" group
2643
2644
        $userService = $repository->getUserService();
2645
2646
        // Load main group
2647
        $parentUserGroup = $userService->loadUserGroup($mainGroupId);
2648
2649
        // Instantiate a new create struct
2650
        $userGroupCreate = $userService->newUserGroupCreateStruct('eng-US');
2651
        $userGroupCreate->setField('name', 'Example Group');
2652
2653
        // Create the new user group
2654
        $userGroup = $userService->createUserGroup(
2655
            $userGroupCreate,
2656
            $parentUserGroup
2657
        );
2658
        /* END: Inline */
2659
2660
        return $userGroup;
2661
    }
2662
2663
    /**
2664
     * Create user with multiple translations of User Content fields.
2665
     *
2666
     * @param int $userGroupId User group ID (default 13 - Editors)
2667
     *
2668
     * @return \eZ\Publish\API\Repository\Values\User\User
2669
     */
2670
    private function createMultiLanguageUser($userGroupId = 13)
2671
    {
2672
        $repository = $this->getRepository();
2673
        $userService = $repository->getUserService();
2674
2675
        // Instantiate a create struct with mandatory properties
2676
        $randomLogin = md5(mt_rand() . time());
2677
        $userCreateStruct = $userService->newUserCreateStruct(
2678
            $randomLogin,
2679
            "{$randomLogin}@example.com",
2680
            'secret',
2681
            'eng-US'
2682
        );
2683
        $userCreateStruct->enabled = true;
2684
        $userCreateStruct->alwaysAvailable = true;
2685
2686
        // set field for each language
2687
        foreach (['eng-US', 'eng-GB'] as $languageCode) {
2688
            $userCreateStruct->setField('first_name', "{$languageCode} Example", $languageCode);
2689
            $userCreateStruct->setField('last_name', "{$languageCode} User", $languageCode);
2690
            $userCreateStruct->setField('signature', "{$languageCode} signature", $languageCode);
2691
        }
2692
2693
        // Load parent group for the user
2694
        $group = $userService->loadUserGroup($userGroupId);
2695
2696
        // Create a new user
2697
        return $userService->createUser($userCreateStruct, [$group]);
2698
    }
2699
2700
    /**
2701
     * Test for the createUser() method.
2702
     *
2703
     * @see \eZ\Publish\API\Repository\UserService::createUser()
2704
     */
2705
    public function testCreateUserInvalidPasswordHashTypeThrowsException()
2706
    {
2707
        $repository = $this->getRepository();
2708
        $eventUserService = $repository->getUserService();
2709
2710
        // Instantiate a create struct with mandatory properties.
2711
        $createStruct = $eventUserService->newUserCreateStruct(
2712
            'user',
2713
            '[email protected]',
2714
            'secret',
2715
            'eng-US'
2716
        );
2717
2718
        // Set some fields required by the user ContentType.
2719
        $createStruct->setField('first_name', 'Example');
2720
        $createStruct->setField('last_name', 'User');
2721
2722
        // Get User fieldType.
2723
        $userFieldDef = null;
2724
        foreach ($createStruct->fields as $field) {
2725
            if ($field->fieldTypeIdentifier === 'ezuser') {
2726
                $userFieldDef = $field;
2727
                break;
2728
            }
2729
        }
2730
2731
        if (!$userFieldDef) {
2732
            $this->fail('User FieldType not found in userCreateStruct!');
2733
        }
2734
2735
        /** @var \eZ\Publish\Core\FieldType\User\Value $userValue */
2736
        $userValue = $userFieldDef->value;
2737
2738
        // Set not supported hash type.
2739
        $userValue->passwordHashType = 42424242;
2740
2741
        $this->expectException(InvalidArgumentException::class);
2742
        $this->expectExceptionMessage("Argument 'hashType' is invalid: Password hash type '42424242' is not recognized");
2743
2744
        // Create a new user instance.
2745
        // 13 is ID of the "Editors" user group in an eZ Publish demo installation.
2746
        $eventUserService->createUser($createStruct, [$eventUserService->loadUserGroup(13)]);
2747
    }
2748
2749
    /**
2750
     * Test loading User by Token.
2751
     *
2752
     * @covers \eZ\Publish\API\Repository\UserService::loadUserByToken
2753
     */
2754
    public function testLoadUserByToken()
2755
    {
2756
        $repository = $this->getRepository();
2757
        $userService = $repository->getUserService();
2758
2759
        $user = $this->createUserVersion1();
2760
2761
        $userTokenUpdateStruct = new UserTokenUpdateStruct();
2762
        $userTokenUpdateStruct->hashKey = md5('hash');
2763
        $userTokenUpdateStruct->time = (new DateTime())->add(new DateInterval('PT10S'));
2764
2765
        $userService->updateUserToken($user, $userTokenUpdateStruct);
2766
2767
        $loadedUser = $userService->loadUserByToken($userTokenUpdateStruct->hashKey, Language::ALL);
2768
        self::assertEquals($user, $loadedUser);
2769
2770
        return $userTokenUpdateStruct->hashKey;
2771
    }
2772
2773
    /**
2774
     * Test trying to load User by invalid Token.
2775
     *
2776
     * @covers \eZ\Publish\API\Repository\UserService::loadUserByToken
2777
     */
2778
    public function testLoadUserByTokenThrowsNotFoundException()
2779
    {
2780
        $this->expectException(NotFoundException::class);
2781
2782
        $repository = $this->getRepository();
2783
        $userService = $repository->getUserService();
2784
2785
        $user = $this->createUserVersion1();
2786
2787
        $userTokenUpdateStruct = new UserTokenUpdateStruct();
2788
        $userTokenUpdateStruct->hashKey = md5('hash');
2789
        $userTokenUpdateStruct->time = new DateTime();
2790
2791
        $userService->updateUserToken($user, $userTokenUpdateStruct);
2792
2793
        $userService->loadUserByToken('not_existing_token');
2794
    }
2795
2796
    /**
2797
     * Test updating User Token.
2798
     *
2799
     * @covers \eZ\Publish\API\Repository\UserService::updateUserToken()
2800
     *
2801
     * @depends testLoadUserByToken
2802
     *
2803
     * @param string $originalUserToken
2804
     */
2805
    public function testUpdateUserToken($originalUserToken)
2806
    {
2807
        $repository = $this->getRepository(false);
2808
        $userService = $repository->getUserService();
2809
2810
        $user = $userService->loadUserByToken($originalUserToken);
2811
2812
        $userTokenUpdateStruct = new UserTokenUpdateStruct();
2813
        $userTokenUpdateStruct->hashKey = md5('my_updated_hash');
2814
        $userTokenUpdateStruct->time = (new DateTime())->add(new DateInterval('PT10S'));
2815
2816
        $userService->updateUserToken($user, $userTokenUpdateStruct);
2817
2818
        $loadedUser = $userService->loadUserByToken($userTokenUpdateStruct->hashKey);
2819
        self::assertEquals($user, $loadedUser);
2820
    }
2821
2822
    /**
2823
     * Test invalidating (expiring) User Token.
2824
     *
2825
     * @covers \eZ\Publish\API\Repository\UserService::expireUserToken()
2826
     *
2827
     * @depends testLoadUserByToken
2828
     *
2829
     * @param string $userToken
2830
     */
2831
    public function testExpireUserToken($userToken)
2832
    {
2833
        $this->expectException(NotFoundException::class);
2834
2835
        $repository = $this->getRepository(false);
2836
        $userService = $repository->getUserService();
2837
2838
        // sanity check
2839
        $userService->loadUserByToken($userToken);
2840
2841
        $userService->expireUserToken($userToken);
2842
2843
        // should throw NotFoundException now
2844
        $userService->loadUserByToken($userToken);
2845
    }
2846
2847
    /**
2848
     * @covers \eZ\Publish\API\Repository\UserService::validatePassword()
2849
     */
2850
    public function testValidatePasswordWithDefaultContext()
2851
    {
2852
        $userService = $this->getRepository()->getUserService();
2853
2854
        /* BEGIN: Use Case */
2855
        $errors = $userService->validatePassword('pass');
2856
        /* END: Use Case */
2857
2858
        $this->assertEmpty($errors);
2859
    }
2860
2861
    /**
2862
     * @covers \eZ\Publish\API\Repository\UserService::validatePassword()
2863
     * @dataProvider dataProviderForValidatePassword
2864
     */
2865
    public function testValidatePassword(string $password, array $expectedErrors)
2866
    {
2867
        $userService = $this->getRepository()->getUserService();
2868
        $contentType = $this->createUserContentTypeWithStrongPassword();
2869
2870
        /* BEGIN: Use Case */
2871
        $context = new PasswordValidationContext([
2872
            'contentType' => $contentType,
2873
        ]);
2874
2875
        $actualErrors = $userService->validatePassword($password, $context);
2876
        /* END: Use Case */
2877
2878
        $this->assertEquals($expectedErrors, $actualErrors);
2879
    }
2880
2881
    public function testValidatePasswordReturnsErrorWhenOldPasswordIsReused(): void
2882
    {
2883
        $password = 'P@blish123!';
2884
2885
        $userService = $this->getRepository()->getUserService();
2886
        // Password expiration needs to be enabled
2887
        $contentType = $this->createUserContentTypeWithPasswordExpirationDate();
2888
2889
        $user = $this->createTestUserWithPassword($password, $contentType);
2890
2891
        $context = new PasswordValidationContext([
2892
            'contentType' => $contentType,
2893
            'user' => $user,
2894
        ]);
2895
2896
        $actualErrors = $userService->validatePassword($password, $context);
2897
2898
        $this->assertEquals(
2899
            [new ValidationError('New password cannot be the same as old password', null, [], 'password')],
2900
            $actualErrors
2901
        );
2902
    }
2903
2904
    /**
2905
     * Data provider for testValidatePassword.
2906
     *
2907
     * @return array
2908
     */
2909
    public function dataProviderForValidatePassword(): array
2910
    {
2911
        return [
2912
            [
2913
                'pass',
2914
                [
2915
                    new ValidationError('User password must be at least %length% characters long', null, [
2916
                        '%length%' => 8,
2917
                    ], 'password'),
2918
                    new ValidationError('User password must include at least one upper case letter', null, [], 'password'),
2919
                    new ValidationError('User password must include at least one number', null, [], 'password'),
2920
                    new ValidationError('User password must include at least one special character', null, [], 'password'),
2921
                ],
2922
            ],
2923
            [
2924
                'H@xxxi0R!!!',
2925
                [],
2926
            ],
2927
        ];
2928
    }
2929
2930
    public function testGetPasswordInfo(): void
2931
    {
2932
        $userService = $this->getRepository()->getUserService();
2933
        $contentType = $this->createUserContentTypeWithPasswordExpirationDate(
2934
            self::EXAMPLE_PASSWORD_TTL,
2935
            self::EXAMPLE_PASSWORD_TTL_WARNING
2936
        );
2937
2938
        $user = $this->createTestUser($contentType);
2939
2940
        /* BEGIN: Use Case */
2941
        $passwordInfo = $userService->getPasswordInfo($user);
2942
        /* END: Use Case */
2943
2944
        $passwordUpdatedAt = $user->passwordUpdatedAt;
2945
        if ($passwordUpdatedAt instanceof DateTime) {
2946
            $passwordUpdatedAt = DateTimeImmutable::createFromFormat(DateTime::ATOM, $passwordUpdatedAt->format(DateTime::ATOM));
2947
        }
2948
2949
        $expectedPasswordExpirationDate = $passwordUpdatedAt->add(
2950
            new DateInterval(sprintf('P%dD', self::EXAMPLE_PASSWORD_TTL))
2951
        );
2952
2953
        $expectedPasswordExpirationWarningDate = $passwordUpdatedAt->add(
2954
            new DateInterval(sprintf('P%dD', self::EXAMPLE_PASSWORD_TTL - self::EXAMPLE_PASSWORD_TTL_WARNING))
2955
        );
2956
2957
        $this->assertEquals(new PasswordInfo(
2958
            $expectedPasswordExpirationDate,
2959
            $expectedPasswordExpirationWarningDate
2960
        ), $passwordInfo);
2961
    }
2962
2963
    public function testGetPasswordInfoIfExpirationIsDisabled(): void
2964
    {
2965
        $userService = $this->getRepository()->getUserService();
2966
        $contentType = $this->createUserContentTypeWithPasswordExpirationDate(null, null);
2967
2968
        $user = $this->createTestUser($contentType);
2969
2970
        /* BEGIN: Use Case */
2971
        $passwordInfo = $userService->getPasswordInfo($user);
2972
        /* END: Use Case */
2973
2974
        $this->assertEquals(new PasswordInfo(), $passwordInfo);
2975
    }
2976
2977
    public function testGetPasswordInfoIfExpirationWarningIsDisabled(): void
2978
    {
2979
        $userService = $this->getRepository()->getUserService();
2980
        $contentType = $this->createUserContentTypeWithPasswordExpirationDate(self::EXAMPLE_PASSWORD_TTL, null);
2981
2982
        $user = $this->createTestUser($contentType);
2983
2984
        /* BEGIN: Use Case */
2985
        $passwordInfo = $userService->getPasswordInfo($user);
2986
        /* END: Use Case */
2987
2988
        $passwordUpdatedAt = $user->passwordUpdatedAt;
2989
        if ($passwordUpdatedAt instanceof DateTime) {
2990
            $passwordUpdatedAt = DateTimeImmutable::createFromFormat(DateTime::ATOM, $passwordUpdatedAt->format(DateTime::ATOM));
2991
        }
2992
2993
        $expectedPasswordExpirationDate = $passwordUpdatedAt->add(
2994
            new DateInterval(sprintf('P%dD', self::EXAMPLE_PASSWORD_TTL))
2995
        );
2996
2997
        $this->assertEquals(new PasswordInfo($expectedPasswordExpirationDate, null), $passwordInfo);
2998
    }
2999
3000
    public function createTestUser(ContentType $contentType): User
3001
    {
3002
        return $this->createTestUserWithPassword(self::EXAMPLE_PASSWORD, $contentType);
3003
    }
3004
3005
    /**
3006
     * Creates a user with given password.
3007
     *
3008
     * @param string $password
3009
     * @param \eZ\Publish\API\Repository\Values\ContentType\ContentType $contentType
3010
     *
3011
     * @return \eZ\Publish\API\Repository\Values\User\User
3012
     */
3013
    private function createTestUserWithPassword(string $password, ContentType $contentType): User
3014
    {
3015
        $userService = $this->getRepository()->getUserService();
3016
        // ID of the "Editors" user group in an eZ Publish demo installation
3017
        $editorsGroupId = 13;
3018
3019
        // Instantiate a create struct with mandatory properties
3020
        $userCreate = $userService->newUserCreateStruct(
3021
            'johndoe',
3022
            '[email protected]',
3023
            $password,
3024
            'eng-US',
3025
            $contentType
3026
        );
3027
        $userCreate->enabled = true;
3028
        $userCreate->setField('first_name', 'John');
3029
        $userCreate->setField('last_name', 'Doe');
3030
3031
        return $userService->createUser($userCreate, [
3032
            $userService->loadUserGroup($editorsGroupId),
3033
        ]);
3034
    }
3035
3036
    /**
3037
     * Creates the User Content Type with password constraints.
3038
     *
3039
     * @return \eZ\Publish\API\Repository\Values\ContentType\ContentType
3040
     */
3041
    private function createUserContentTypeWithStrongPassword(): ContentType
3042
    {
3043
        return $this->createUserContentTypeWithAccountSettings('user-with-strong-password', null, [
3044
            'PasswordValueValidator' => [
3045
                'requireAtLeastOneUpperCaseCharacter' => 1,
3046
                'requireAtLeastOneLowerCaseCharacter' => 1,
3047
                'requireAtLeastOneNumericCharacter' => 1,
3048
                'requireAtLeastOneNonAlphanumericCharacter' => 1,
3049
                'requireNewPassword' => 1,
3050
                'minLength' => 8,
3051
            ],
3052
        ]);
3053
    }
3054
3055
    private function createUserContentTypeWithPasswordExpirationDate(
3056
        ?int $passwordTTL = self::EXAMPLE_PASSWORD_TTL,
3057
        ?int $passwordTTLWarning = self::EXAMPLE_PASSWORD_TTL_WARNING
3058
    ): ContentType {
3059
        return $this->createUserContentTypeWithAccountSettings('password-expiration', [
3060
            'PasswordTTL' => $passwordTTL,
3061
            'PasswordTTLWarning' => $passwordTTLWarning,
3062
        ]);
3063
    }
3064
3065
    private function createUserContentTypeWithAccountSettings(
3066
        string $identifier,
3067
        ?array $fieldSetting = null,
3068
        ?array $validatorConfiguration = null
3069
    ): ContentType {
3070
        $repository = $this->getRepository();
3071
3072
        $contentTypeService = $repository->getContentTypeService();
3073
        $permissionResolver = $repository->getPermissionResolver();
3074
3075
        $typeCreate = $contentTypeService->newContentTypeCreateStruct($identifier);
3076
        $typeCreate->mainLanguageCode = 'eng-GB';
3077
        $typeCreate->urlAliasSchema = 'url|scheme';
3078
        $typeCreate->nameSchema = 'name|scheme';
3079
        $typeCreate->names = [
3080
            'eng-GB' => 'User: ' . $identifier,
3081
        ];
3082
        $typeCreate->descriptions = [
3083
            'eng-GB' => '',
3084
        ];
3085
        $typeCreate->creatorId = $this->generateId('user', $permissionResolver->getCurrentUserReference()->getUserId());
3086
        $typeCreate->creationDate = $this->createDateTime();
3087
3088
        $firstNameFieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('first_name', 'ezstring');
3089
        $firstNameFieldCreate->names = [
3090
            'eng-GB' => 'First name',
3091
        ];
3092
        $firstNameFieldCreate->descriptions = [
3093
            'eng-GB' => '',
3094
        ];
3095
        $firstNameFieldCreate->fieldGroup = 'default';
3096
        $firstNameFieldCreate->position = 1;
3097
        $firstNameFieldCreate->isTranslatable = false;
3098
        $firstNameFieldCreate->isRequired = true;
3099
        $firstNameFieldCreate->isInfoCollector = false;
3100
        $firstNameFieldCreate->validatorConfiguration = [
3101
            'StringLengthValidator' => [
3102
                'minStringLength' => 0,
3103
                'maxStringLength' => 0,
3104
            ],
3105
        ];
3106
        $firstNameFieldCreate->fieldSettings = [];
3107
        $firstNameFieldCreate->isSearchable = true;
3108
        $firstNameFieldCreate->defaultValue = '';
3109
3110
        $typeCreate->addFieldDefinition($firstNameFieldCreate);
3111
3112
        $lastNameFieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('last_name', 'ezstring');
3113
        $lastNameFieldCreate->names = [
3114
            'eng-GB' => 'Last name',
3115
        ];
3116
        $lastNameFieldCreate->descriptions = [
3117
            'eng-GB' => '',
3118
        ];
3119
        $lastNameFieldCreate->fieldGroup = 'default';
3120
        $lastNameFieldCreate->position = 2;
3121
        $lastNameFieldCreate->isTranslatable = false;
3122
        $lastNameFieldCreate->isRequired = true;
3123
        $lastNameFieldCreate->isInfoCollector = false;
3124
        $lastNameFieldCreate->validatorConfiguration = [
3125
            'StringLengthValidator' => [
3126
                'minStringLength' => 0,
3127
                'maxStringLength' => 0,
3128
            ],
3129
        ];
3130
        $lastNameFieldCreate->fieldSettings = [];
3131
        $lastNameFieldCreate->isSearchable = true;
3132
        $lastNameFieldCreate->defaultValue = '';
3133
3134
        $typeCreate->addFieldDefinition($lastNameFieldCreate);
3135
3136
        $accountFieldCreateStruct = $contentTypeService->newFieldDefinitionCreateStruct('user_account', 'ezuser');
3137
        $accountFieldCreateStruct->names = [
3138
            'eng-GB' => 'User account',
3139
        ];
3140
        $accountFieldCreateStruct->descriptions = [
3141
            'eng-GB' => '',
3142
        ];
3143
        $accountFieldCreateStruct->fieldGroup = 'default';
3144
        $accountFieldCreateStruct->position = 3;
3145
        $accountFieldCreateStruct->isTranslatable = false;
3146
        $accountFieldCreateStruct->isRequired = true;
3147
        $accountFieldCreateStruct->isInfoCollector = false;
3148
        $accountFieldCreateStruct->validatorConfiguration = $validatorConfiguration;
3149
        $accountFieldCreateStruct->fieldSettings = $fieldSetting;
3150
        $accountFieldCreateStruct->isSearchable = false;
3151
        $accountFieldCreateStruct->defaultValue = null;
3152
3153
        $typeCreate->addFieldDefinition($accountFieldCreateStruct);
3154
3155
        $contentTypeDraft = $contentTypeService->createContentType($typeCreate, [
3156
            $contentTypeService->loadContentTypeGroupByIdentifier('Users'),
3157
        ]);
3158
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
3159
3160
        return $contentTypeService->loadContentTypeByIdentifier($identifier);
3161
    }
3162
}
3163