diff --git a/eZ/Publish/Core/MVC/Symfony/FieldType/RichText/Renderer.php b/eZ/Publish/Core/MVC/Symfony/FieldType/RichText/Renderer.php index 81d497895..1417030f6 100644 --- a/eZ/Publish/Core/MVC/Symfony/FieldType/RichText/Renderer.php +++ b/eZ/Publish/Core/MVC/Symfony/FieldType/RichText/Renderer.php @@ -9,6 +9,7 @@ namespace eZ\Publish\Core\MVC\Symfony\FieldType\RichText; use eZ\Publish\API\Repository\Repository; +use eZ\Publish\API\Repository\Values\Content\Content; use eZ\Publish\Core\FieldType\RichText\RendererInterface; use eZ\Publish\Core\MVC\ConfigResolverInterface; use Symfony\Component\Templating\EngineInterface; @@ -122,7 +123,24 @@ class Renderer implements RendererInterface $isDenied = false; try { - $this->checkContent($contentId); + /** @var \eZ\Publish\API\Repository\Values\Content\Content $content */ + $content = $this->repository->sudo( + function (Repository $repository) use ($contentId) { + return $repository->getContentService()->loadContent($contentId); + } + ); + + if (!$content->contentInfo->mainLocationId) { + if (isset($this->logger)) { + $this->logger->error( + "Could not render embedded resource: Content #{$contentId} is trashed." + ); + } + + return null; + } + + $this->checkContentPermissions($content); } catch (AccessDeniedException $e) { if (isset($this->logger)) { $this->logger->error( @@ -365,17 +383,30 @@ class Renderer implements RendererInterface * * @throws \Symfony\Component\Security\Core\Exception\AccessDeniedException * - * @param int|string $id + * @deprecated since 6.7 + * @param int $contentId */ - protected function checkContent($id) + protected function checkContent($contentId) { /** @var \eZ\Publish\API\Repository\Values\Content\Content $content */ $content = $this->repository->sudo( - function (Repository $repository) use ($id) { - return $repository->getContentService()->loadContent($id); + function (Repository $repository) use ($contentId) { + return $repository->getContentService()->loadContent($contentId); } ); + $this->checkContentPermissions($content); + } + + /** + * Check embed permissions for the given Content. + * + * @throws \Symfony\Component\Security\Core\Exception\AccessDeniedException + * + * @param \eZ\Publish\API\Repository\Values\Content\Content $content + */ + protected function checkContentPermissions(Content $content) + { // Check both 'content/read' and 'content/view_embed'. if ( !$this->authorizationChecker->isGranted( diff --git a/eZ/Publish/Core/MVC/Symfony/FieldType/Tests/RichText/RendererTest.php b/eZ/Publish/Core/MVC/Symfony/FieldType/Tests/RichText/RendererTest.php index 5d85fe999..b3b0a688d 100644 --- a/eZ/Publish/Core/MVC/Symfony/FieldType/Tests/RichText/RendererTest.php +++ b/eZ/Publish/Core/MVC/Symfony/FieldType/Tests/RichText/RendererTest.php @@ -8,6 +8,8 @@ */ namespace eZ\Publish\Core\MVC\Symfony\FieldType\Tests\RichText; +use eZ\Publish\API\Repository\Values\Content\Content; +use eZ\Publish\API\Repository\Values\Content\ContentInfo; use eZ\Publish\Core\MVC\Symfony\FieldType\RichText\Renderer; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use eZ\Publish\Core\Base\Exceptions\NotFoundException; @@ -306,7 +308,7 @@ class RendererTest extends TestCase public function testRenderContentEmbed() { - $renderer = $this->getMockedRenderer(array('render', 'checkContent', 'getEmbedTemplateName')); + $renderer = $this->getMockedRenderer(array('render', 'checkContentPermissions', 'getEmbedTemplateName')); $contentId = 42; $viewType = 'embedTest'; $templateName = 'templateName'; @@ -314,11 +316,20 @@ class RendererTest extends TestCase $isInline = true; $isDenied = false; $result = 'result'; + $mainLocationId = 2; + + $contentMock = $this->getContentMock($mainLocationId); + + $this->repositoryMock + ->expects($this->once()) + ->method('sudo') + ->willReturn($contentMock); $renderer ->expects($this->once()) - ->method('checkContent') - ->with($contentId); + ->method('checkContentPermissions') + ->with($contentMock) + ->willReturn($contentMock); $renderer ->expects($this->once()) @@ -350,18 +361,27 @@ class RendererTest extends TestCase public function testRenderContentEmbedNoTemplateConfigured() { - $renderer = $this->getMockedRenderer(array('render', 'checkContent', 'getEmbedTemplateName')); + $renderer = $this->getMockedRenderer(array('render', 'checkContentPermissions', 'getEmbedTemplateName')); $contentId = 42; $viewType = 'embedTest'; $templateName = null; $parameters = array('parameters'); $isInline = true; $isDenied = false; + $mainLocationId = 2; + + $contentMock = $this->getContentMock($mainLocationId); + + $this->repositoryMock + ->expects($this->once()) + ->method('sudo') + ->willReturn($contentMock); $renderer ->expects($this->once()) - ->method('checkContent') - ->with($contentId); + ->method('checkContentPermissions') + ->with($contentMock) + ->willReturn($contentMock); $renderer ->expects($this->never()) @@ -390,18 +410,26 @@ class RendererTest extends TestCase public function testRenderContentEmbedNoTemplateFound() { - $renderer = $this->getMockedRenderer(array('render', 'checkContent', 'getEmbedTemplateName')); + $renderer = $this->getMockedRenderer(array('render', 'checkContentPermissions', 'getEmbedTemplateName')); $contentId = 42; $viewType = 'embedTest'; $templateName = 'templateName'; $parameters = array('parameters'); $isInline = true; $isDenied = false; + $mainLocationId = 2; + + $contentMock = $this->getContentMock($mainLocationId); + + $this->repositoryMock + ->expects($this->once()) + ->method('sudo') + ->willReturn($contentMock); $renderer ->expects($this->once()) - ->method('checkContent') - ->with($contentId); + ->method('checkContentPermissions') + ->with($contentMock); $renderer ->expects($this->never()) @@ -432,7 +460,7 @@ class RendererTest extends TestCase public function testRenderContentEmbedAccessDenied() { - $renderer = $this->getMockedRenderer(array('render', 'checkContent', 'getEmbedTemplateName')); + $renderer = $this->getMockedRenderer(array('render', 'checkContentPermissions', 'getEmbedTemplateName')); $contentId = 42; $viewType = 'embedTest'; $templateName = 'templateName'; @@ -440,11 +468,19 @@ class RendererTest extends TestCase $isInline = true; $isDenied = true; $result = 'result'; + $mainLocationId = 2; + + $contentMock = $this->getContentMock($mainLocationId); + + $this->repositoryMock + ->expects($this->once()) + ->method('sudo') + ->willReturn($contentMock); $renderer ->expects($this->once()) - ->method('checkContent') - ->with($contentId) + ->method('checkContentPermissions') + ->with($contentMock) ->will($this->throwException(new AccessDeniedException())); $renderer @@ -476,6 +512,44 @@ class RendererTest extends TestCase ); } + public function testRenderContentEmbedTrashed() + { + $renderer = $this->getMockedRenderer(['checkContentPermissions']); + $contentId = 42; + $viewType = 'embedTest'; + $parameters = array('parameters'); + $isInline = true; + + $contentInfoMock = $this->getMock(ContentInfo::class); + $contentInfoMock + ->expects($this->once()) + ->method('__get') + ->with('mainLocationId') + ->willReturn(null); + + $contentMock = $this->getMock(Content::class); + $contentMock + ->expects($this->once()) + ->method('__get') + ->with('contentInfo') + ->willReturn($contentInfoMock); + + $this->repositoryMock + ->expects($this->once()) + ->method('sudo') + ->willReturn($contentMock); + + $this->loggerMock + ->expects($this->once()) + ->method('error') + ->with("Could not render embedded resource: Content #{$contentId} is trashed."); + + $this->assertEquals( + null, + $renderer->renderContentEmbed($contentId, $viewType, $parameters, $isInline) + ); + } + public function providerForTestRenderContentEmbedNotFound() { return array( @@ -489,17 +563,25 @@ class RendererTest extends TestCase */ public function testRenderContentEmbedNotFound(Exception $exception) { - $renderer = $this->getMockedRenderer(array('render', 'checkContent', 'getEmbedTemplateName')); + $renderer = $this->getMockedRenderer(array('render', 'checkContentPermissions', 'getEmbedTemplateName')); $contentId = 42; $viewType = 'embedTest'; $parameters = array('parameters'); $isInline = true; $result = null; + $mainLocationId = 2; + + $contentMock = $this->getContentMock($mainLocationId); + + $this->repositoryMock + ->expects($this->once()) + ->method('sudo') + ->willReturn($contentMock); $renderer ->expects($this->once()) - ->method('checkContent') - ->with($contentId) + ->method('checkContentPermissions') + ->with($contentMock) ->will($this->throwException($exception)); $renderer @@ -531,13 +613,21 @@ class RendererTest extends TestCase */ public function testRenderContentEmbedThrowsException() { - $renderer = $this->getMockedRenderer(array('checkContent')); + $renderer = $this->getMockedRenderer(array('checkContentPermissions')); $contentId = 42; + $mainLocationId = 2; + + $contentMock = $this->getContentMock($mainLocationId); + + $this->repositoryMock + ->expects($this->once()) + ->method('sudo') + ->willReturn($contentMock); $renderer ->expects($this->once()) - ->method('checkContent') - ->with($contentId) + ->method('checkContentPermissions') + ->with($contentMock) ->will($this->throwException(new Exception('Something threw up'))); $renderer->renderContentEmbed($contentId, 'embedTest', array('parameters'), true); @@ -675,22 +765,31 @@ class RendererTest extends TestCase $renderTemplate, $renderResult ) { - $renderer = $this->getMockedRenderer(array('render', 'checkContent')); + $renderer = $this->getMockedRenderer(array('render', 'checkContentPermissions')); $contentId = 42; $viewType = 'embedTest'; $parameters = array('parameters'); + $mainLocationId = 2; + + $contentMock = $this->getContentMock($mainLocationId); + + $this->repositoryMock + ->expects($this->once()) + ->method('sudo') + ->willReturn($contentMock); if (isset($deniedException)) { $renderer ->expects($this->once()) - ->method('checkContent') - ->with($contentId) + ->method('checkContentPermissions') + ->with($contentMock) ->will($this->throwException($deniedException)); } else { $renderer ->expects($this->once()) - ->method('checkContent') - ->with($contentId); + ->method('checkContentPermissions') + ->with($contentMock) + ->willReturn($contentMock); } if (!isset($renderTemplate)) { @@ -1322,9 +1421,10 @@ class RendererTest extends TestCase */ protected function getRepositoryMock() { - return $this->getMock( - 'eZ\\Publish\\API\\Repository\\Repository' - ); + return $this + ->getMockBuilder('eZ\\Publish\\Core\\Repository\\Repository') + ->disableOriginalConstructor() + ->getMock(); } /** @@ -1386,4 +1486,23 @@ class RendererTest extends TestCase 'Psr\\Log\\LoggerInterface' ); } + + protected function getContentMock($mainLocationId) + { + $contentInfoMock = $this->getMock(ContentInfo::class); + $contentInfoMock + ->expects($this->once()) + ->method('__get') + ->with('mainLocationId') + ->willReturn($mainLocationId); + + $contentMock = $this->getMock(Content::class); + $contentMock + ->expects($this->once()) + ->method('__get') + ->with('contentInfo') + ->willReturn($contentInfoMock); + + return $contentMock; + } }