Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EZP-30997: Fixed permission checks when copying translations during publishing #2858

Merged
merged 11 commits into from
Dec 5, 2019
111 changes: 111 additions & 0 deletions eZ/Publish/API/Repository/Tests/Limitation/LanguageLimitationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php
/**
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
namespace eZ\Publish\API\Repository\Tests\Limitation;

use eZ\Publish\API\Repository\Exceptions\UnauthorizedException;
use eZ\Publish\API\Repository\Tests\BaseTest;
use eZ\Publish\API\Repository\Values\User\Limitation\LanguageLimitation;

class LanguageLimitationTest extends BaseTest
mikadamczyk marked this conversation as resolved.
Show resolved Hide resolved
{
/** @var string */
private const ENG_US = 'eng-US';

/** @var string */
private const GER_DE = 'ger-DE';

public function testPublishVersionTranslation(): void
{
$repository = $this->getRepository(false);
$contentService = $repository->getContentService();
$permissionResolver = $repository->getPermissionResolver();

$publishedContent = $this->createFolder(
[
self::ENG_US => 'Published US',
self::GER_DE => 'Published DE',
],
$this->generateId('location', 2)
);

$draft = $contentService->createContentDraft($publishedContent->contentInfo);

$contentUpdateStruct = $contentService->newContentUpdateStruct();
$contentUpdateStruct->initialLanguageCode = self::GER_DE;

$contentUpdateStruct->setField('name', 'Draft 1 DE', self::GER_DE);

$contentService->updateContent($draft->versionInfo, $contentUpdateStruct);

$user = $this->createUserWithPolicies(
'user',
[
[
'module' => 'content',
'function' => 'publish',
'limitations' => [new LanguageLimitation(['limitationValues' => [self::GER_DE]])],
],
]
);

$admin = $permissionResolver->getCurrentUserReference();
$permissionResolver->setCurrentUserReference($user);

$contentService->publishVersion($draft->versionInfo, [self::GER_DE]);

$permissionResolver->setCurrentUserReference($admin);
$content = $contentService->loadContent($draft->contentInfo->id);
$this->assertEquals(
[
self::ENG_US => 'Published US',
self::GER_DE => 'Draft 1 DE',
],
$content->fields['name']
);
}

public function testthrowUnauthorizedExceptionWhilePublishVersionTranslation(): void
{
$this->expectException(UnauthorizedException::class);

$repository = $this->getRepository(false);
$contentService = $repository->getContentService();
$permissionResolver = $repository->getPermissionResolver();

$publishedContent = $this->createFolder(
[
self::ENG_US => 'Published US',
self::GER_DE => 'Published DE',
],
$this->generateId('location', 2)
);

$draft = $contentService->createContentDraft($publishedContent->contentInfo);

$contentUpdateStruct = $contentService->newContentUpdateStruct();
$contentUpdateStruct->initialLanguageCode = self::ENG_US;

$contentUpdateStruct->setField('name', 'Draft 1 EN', self::ENG_US);

$contentService->updateContent($draft->versionInfo, $contentUpdateStruct);

$user = $this->createUserWithPolicies(
'editor',
[
[
'module' => 'content',
'function' => 'publish',
'limitations' => [new LanguageLimitation(['limitationValues' => [self::GER_DE]])],
],
]
);

$admin = $permissionResolver->getCurrentUserReference();
$permissionResolver->setCurrentUserReference($user);

$contentService->publishVersion($draft->versionInfo, [self::ENG_US]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/
declare(strict_types=1);

namespace eZ\Publish\API\Repository\Tests\Limitation;
namespace eZ\Publish\API\Repository\Tests\Values\User\Limitation;

use eZ\Publish\API\Repository\Exceptions\UnauthorizedException;
use eZ\Publish\API\Repository\Tests\BaseTest;
Expand Down
59 changes: 48 additions & 11 deletions eZ/Publish/Core/Repository/ContentService.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use eZ\Publish\API\Repository\Values\Content\RelationList\Item\RelationListItem;
use eZ\Publish\API\Repository\Values\Content\RelationList\Item\UnauthorizedRelationListItem;
use eZ\Publish\API\Repository\Values\User\UserReference;
use eZ\Publish\Core\Repository\Values\Content\Content;
use eZ\Publish\Core\Repository\Values\Content\Location;
use eZ\Publish\API\Repository\Values\Content\Language;
use eZ\Publish\SPI\Persistence\Handler;
Expand Down Expand Up @@ -1267,20 +1268,12 @@ public function loadContentDraftList(?User $user = null, int $offset = 0, int $l
*/
public function updateContent(APIVersionInfo $versionInfo, APIContentUpdateStruct $contentUpdateStruct)
{
$contentUpdateStruct = clone $contentUpdateStruct;

/** @var $content \eZ\Publish\Core\Repository\Values\Content\Content */
$content = $this->loadContent(
$versionInfo->getContentInfo()->id,
null,
$versionInfo->versionNo
);
if (!$content->versionInfo->isDraft()) {
throw new BadStateException(
'$versionInfo',
'Version is not a draft and can not be updated'
);
}

if (!$this->repository->getPermissionResolver()->canUser(
'content',
Expand All @@ -1298,6 +1291,39 @@ public function updateContent(APIVersionInfo $versionInfo, APIContentUpdateStruc
throw new UnauthorizedException('content', 'edit', ['contentId' => $content->id]);
}

return $this->internalUpdateContent($versionInfo, $contentUpdateStruct);
}

/**
* Updates the fields of a draft without checking the permissions.
*
* @throws \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException if a field in the $contentCreateStruct is not valid,
* or if a required field is missing / set to an empty value.
* @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException If field definition does not exist in the ContentType,
* or value is set for non-translatable field in language
* other than main.
*
* @throws \eZ\Publish\API\Repository\Exceptions\BadStateException if the version is not a draft
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if a property on the struct is invalid.
* @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
*/
protected function internalUpdateContent(APIVersionInfo $versionInfo, APIContentUpdateStruct $contentUpdateStruct): Content
{
$contentUpdateStruct = clone $contentUpdateStruct;

/** @var $content \eZ\Publish\Core\Repository\Values\Content\Content */
$content = $this->internalLoadContent(
$versionInfo->getContentInfo()->id,
null,
$versionInfo->versionNo
);
if (!$content->versionInfo->isDraft()) {
throw new BadStateException(
'$versionInfo',
'Version is not a draft and can not be updated'
);
}

$mainLanguageCode = $content->contentInfo->mainLanguageCode;
if ($contentUpdateStruct->initialLanguageCode === null) {
$contentUpdateStruct->initialLanguageCode = $mainLanguageCode;
Expand Down Expand Up @@ -1425,7 +1451,7 @@ public function updateContent(APIVersionInfo $versionInfo, APIContentUpdateStruc
)->id,
]
);
$existingRelations = $this->loadRelations($versionInfo);
$existingRelations = $this->internalLoadRelations($versionInfo);

$this->repository->beginTransaction();
try {
Expand Down Expand Up @@ -1621,7 +1647,6 @@ public function publishVersion(APIVersionInfo $versionInfo, array $translations
* @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
* @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
*/
protected function copyTranslationsFromPublishedVersion(APIVersionInfo $versionInfo, array $translations = []): void
{
Expand Down Expand Up @@ -1670,7 +1695,7 @@ protected function copyTranslationsFromPublishedVersion(APIVersionInfo $versionI
}
}

$this->updateContent($versionInfo, $updateStruct);
$this->internalUpdateContent($versionInfo, $updateStruct);
pawbuj marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down Expand Up @@ -1929,6 +1954,18 @@ public function loadRelations(APIVersionInfo $versionInfo)
throw new UnauthorizedException('content', $function);
}

return $this->internalLoadRelations($versionInfo);
}

/**
* Loads all outgoing relations for the given version without checking the permissions.
*
* @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
*
* @return \eZ\Publish\API\Repository\Values\Content\Relation[]
*/
protected function internalLoadRelations(APIVersionInfo $versionInfo): array
{
$contentInfo = $versionInfo->getContentInfo();
$spiRelations = $this->persistenceHandler->contentHandler()->loadRelations(
$contentInfo->id,
Expand Down
Loading