Skip to content

Commit 40698b3

Browse files
committed
Merge branch '4.6' into main
2 parents ace51ec + bdab9ea commit 40698b3

File tree

4 files changed

+196
-7
lines changed

4 files changed

+196
-7
lines changed

src/lib/Repository/ContentService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1423,7 +1423,7 @@ protected function internalUpdateContent(
14231423
)->id,
14241424
]
14251425
);
1426-
$existingRelations = $this->internalLoadRelations($versionInfo);
1426+
$existingRelations = $this->repository->sudo(fn (): array => $this->internalLoadRelations($versionInfo));
14271427

14281428
$this->repository->beginTransaction();
14291429
try {
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\Tests\Integration\Core\Repository\ContentService;
10+
11+
use Ibexa\Contracts\Core\Repository\Values\Content\Content;
12+
use Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo;
13+
use Ibexa\Contracts\Core\Repository\Values\Content\Section;
14+
use Ibexa\Contracts\Core\Repository\Values\User\Limitation\SectionLimitation;
15+
use Ibexa\Contracts\Core\Repository\Values\User\User;
16+
use Ibexa\Tests\Integration\Core\RepositoryTestCase;
17+
18+
/**
19+
* @covers \Ibexa\Contracts\Core\Repository\ContentService
20+
*/
21+
final class UpdateContentTest extends RepositoryTestCase
22+
{
23+
/**
24+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\Exception
25+
*/
26+
public function testUpdateContentHavingPrivateRelation(): void
27+
{
28+
$sectionService = self::getSectionService();
29+
$contentService = self::getContentService();
30+
$permissionResolver = self::getPermissionResolver();
31+
32+
$this->addRelationFieldToFolderContentType();
33+
34+
$privateSection = $this->createPrivateSection();
35+
36+
$folderPrivate = $this->createFolder(['eng-GB' => 'Private Folder'], 2);
37+
$sectionService->assignSection($folderPrivate->getContentInfo(), $privateSection);
38+
39+
// Create folder with relation to 'Private Folder'
40+
$folder = $this->createFolderWithRelations([$folderPrivate->getId()]);
41+
42+
$userWithRoleLimitation = $this->createUserWithNoAccessToPrivateSection();
43+
44+
// Create & publish new $folder version as $editor
45+
$permissionResolver->setCurrentUserReference($userWithRoleLimitation);
46+
$folder = $this->publishVersionWithoutChanges($folder->getContentInfo());
47+
48+
// Read relations & check if count($relations) is unchanged
49+
self::setAdministratorUser();
50+
$relations = $contentService->loadRelations($folder->getVersionInfo());
51+
if ($relations instanceof \Traversable) {
52+
$relations = iterator_to_array($relations);
53+
}
54+
self::assertCount(1, $relations);
55+
}
56+
57+
/**
58+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\Exception
59+
*/
60+
private function addRelationFieldToFolderContentType(): void
61+
{
62+
$contentTypeService = self::getContentTypeService();
63+
$folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
64+
$folderTypeDraft = $contentTypeService->createContentTypeDraft($folderType);
65+
66+
$relationsFieldCreateStruct = $contentTypeService->newFieldDefinitionCreateStruct(
67+
'relations',
68+
'ezobjectrelationlist'
69+
);
70+
$relationsFieldCreateStruct->names = ['eng-GB' => 'Relations'];
71+
$contentTypeService->addFieldDefinition($folderTypeDraft, $relationsFieldCreateStruct);
72+
$contentTypeService->publishContentTypeDraft($folderTypeDraft);
73+
}
74+
75+
/**
76+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
77+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
78+
*/
79+
private function createPrivateSection(): Section
80+
{
81+
$sectionService = self::getSectionService();
82+
83+
$sectionCreateStruct = $sectionService->newSectionCreateStruct();
84+
$sectionCreateStruct->identifier = 'private';
85+
$sectionCreateStruct->name = 'Private Section';
86+
87+
return $sectionService->createSection($sectionCreateStruct);
88+
}
89+
90+
/**
91+
* @param int[] $relationListTarget
92+
*
93+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\Exception
94+
*/
95+
private function createFolderWithRelations(array $relationListTarget): Content
96+
{
97+
$contentService = self::getContentService();
98+
99+
$folder = $this->createFolder(['eng-GB' => 'Folder with private relation'], 2);
100+
$folderDraft = $contentService->createContentDraft($folder->getContentInfo());
101+
$folderUpdateStruct = $contentService->newContentUpdateStruct();
102+
$folderUpdateStruct->setField('relations', $relationListTarget);
103+
104+
$folder = $contentService->updateContent($folderDraft->getVersionInfo(), $folderUpdateStruct);
105+
106+
return $contentService->publishVersion($folder->getVersionInfo());
107+
}
108+
109+
/**
110+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
111+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
112+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
113+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\LimitationValidationException
114+
*/
115+
private function assignToUserRoleWithStandardSectionLimitation(User $user): void
116+
{
117+
$sectionService = self::getSectionService();
118+
$roleService = self::getRoleService();
119+
120+
$roleCreateStruct = $roleService->newRoleCreateStruct('limited_access');
121+
$roleCreateStruct->addPolicy($roleService->newPolicyCreateStruct('*', '*'));
122+
$role = $roleService->createRole($roleCreateStruct);
123+
$roleService->publishRoleDraft($role);
124+
125+
// limit access to standard section only on the role assignment level
126+
$standardSection = $sectionService->loadSectionByIdentifier('standard');
127+
$roleService->assignRoleToUser(
128+
$role,
129+
$user,
130+
new SectionLimitation(['limitationValues' => [$standardSection->id]])
131+
);
132+
}
133+
134+
/**
135+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\Exception
136+
*/
137+
private function createUserWithNoAccessToPrivateSection(): User
138+
{
139+
$user = $this->createUser('test.editor', 'Editor', 'Test');
140+
$this->assignToUserRoleWithStandardSectionLimitation($user);
141+
142+
return $user;
143+
}
144+
145+
/**
146+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\Exception
147+
*/
148+
private function publishVersionWithoutChanges(ContentInfo $contentInfo): Content
149+
{
150+
$contentService = self::getContentService();
151+
152+
$folderDraft = $contentService->createContentDraft($contentInfo);
153+
$folderUpdateStruct = $contentService->newContentUpdateStruct();
154+
$folder = $contentService->updateContent($folderDraft->getVersionInfo(), $folderUpdateStruct);
155+
156+
return $contentService->publishVersion($folder->getVersionInfo());
157+
}
158+
}

tests/integration/Core/RepositoryTestCase.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
namespace Ibexa\Tests\Integration\Core;
1010

1111
use Ibexa\Contracts\Core\Repository\Values\Content\Content;
12+
use Ibexa\Contracts\Core\Repository\Values\User\User;
13+
use Ibexa\Contracts\Core\Repository\Values\User\UserGroup;
1214
use Ibexa\Contracts\Core\Test\IbexaKernelTestCase;
1315
use InvalidArgumentException;
1416

@@ -17,6 +19,7 @@ abstract class RepositoryTestCase extends IbexaKernelTestCase
1719
public const CONTENT_TREE_ROOT_ID = 2;
1820

1921
private const CONTENT_TYPE_FOLDER_IDENTIFIER = 'folder';
22+
private const MAIN_USER_GROUP_REMOTE_ID = 'f5c88a2209584891056f987fd965b0ba';
2023

2124
protected function setUp(): void
2225
{
@@ -41,6 +44,37 @@ public function createFolder(array $names, int $parentLocationId = self::CONTENT
4144
return $contentService->publishVersion($draft->getVersionInfo());
4245
}
4346

47+
/**
48+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
49+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentValidationException
50+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
51+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\ContentFieldValidationException
52+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
53+
*/
54+
final protected function createUser(string $login, string $firstName, string $lastName, UserGroup $userGroup = null): User
55+
{
56+
$userService = self::getUserService();
57+
58+
if (null === $userGroup) {
59+
$userGroup = $userService->loadUserGroupByRemoteId(self::MAIN_USER_GROUP_REMOTE_ID);
60+
}
61+
62+
$userCreateStruct = $userService->newUserCreateStruct(
63+
$login,
64+
"$login@mail.invalid",
65+
'secret',
66+
'eng-US'
67+
);
68+
$userCreateStruct->enabled = true;
69+
70+
// Set some fields required by the user ContentType
71+
$userCreateStruct->setField('first_name', $firstName);
72+
$userCreateStruct->setField('last_name', $lastName);
73+
74+
// Create a new user instance.
75+
return $userService->createUser($userCreateStruct, [$userGroup]);
76+
}
77+
4478
/**
4579
* @param array<string, string> $names
4680
*

tests/lib/Repository/Service/Mock/ContentTest.php

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3331,7 +3331,7 @@ protected function assertForTestUpdateContentNonRedundantFieldSet(
33313331
->expects(self::once())
33323332
->method('getCurrentUserReference')
33333333
->willReturn(new UserReference(169));
3334-
$mockedService = $this->getPartlyMockedContentService(['internalLoadContentById', 'internalLoadRelations'], $permissionResolverMock);
3334+
$mockedService = $this->getPartlyMockedContentService(['internalLoadContentById'], $permissionResolverMock);
33353335
$permissionResolverMock = $this->getPermissionResolverMock();
33363336
/** @var \PHPUnit\Framework\MockObject\MockObject $contentHandlerMock */
33373337
$contentHandlerMock = $this->getPersistenceMock()->contentHandler();
@@ -3484,11 +3484,8 @@ static function (SPIValue $value) use ($emptyValue) {
34843484
)->will(self::returnValue([]));
34853485

34863486
$existingRelations = ['RELATIONS!!!'];
3487-
$mockedService
3488-
->method('internalLoadRelations')
3489-
->with($content->versionInfo)
3490-
->will(self::returnValue($existingRelations));
3491-
$relationProcessorMock->expects(self::any())
3487+
$repositoryMock->method('sudo')->willReturn($existingRelations);
3488+
$relationProcessorMock->expects($this->any())
34923489
->method('processFieldRelations')
34933490
->with(
34943491
self::isType('array'),

0 commit comments

Comments
 (0)