From a40a4d210faa84c97324a4fc8a4a36ce0b8ba4a1 Mon Sep 17 00:00:00 2001 From: Susanne Moog <look@susi.dev> Date: Thu, 6 Jul 2023 10:28:26 +0200 Subject: [PATCH] [BUGFIX] Check rootline for extendToSubpages when previewing The rootline may contain extendToSubpages settings for hidden or timed records which prevented previewing a page because the preview checks only considered the current page. The rootline is now taken into account. Resolves: #17599 Releases: main, 12.4 Change-Id: I0271caf8decd46fd9dedf31158d62a86e1e0028c Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/79856 Reviewed-by: Benni Mack <benni@typo3.org> Tested-by: core-ci <typo3@b13.com> Tested-by: Benni Mack <benni@typo3.org> --- .../Classes/Middleware/PreviewSimulator.php | 47 ++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/typo3/sysext/frontend/Classes/Middleware/PreviewSimulator.php b/typo3/sysext/frontend/Classes/Middleware/PreviewSimulator.php index 60300bb69bf4..88242448dbb2 100644 --- a/typo3/sysext/frontend/Classes/Middleware/PreviewSimulator.php +++ b/typo3/sysext/frontend/Classes/Middleware/PreviewSimulator.php @@ -21,6 +21,7 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; +use TYPO3\CMS\Core\Cache\CacheManager; use TYPO3\CMS\Core\Context\Context; use TYPO3\CMS\Core\Context\DateTimeAspect; use TYPO3\CMS\Core\Context\LanguageAspectFactory; @@ -28,6 +29,7 @@ use TYPO3\CMS\Core\Context\VisibilityAspect; use TYPO3\CMS\Core\Domain\Repository\PageRepository; use TYPO3\CMS\Core\Routing\PageArguments; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Core\Utility\RootlineUtility; use TYPO3\CMS\Frontend\Aspect\PreviewAspect; use TYPO3\CMS\Frontend\Controller\ErrorController; use TYPO3\CMS\Frontend\Page\PageAccessFailureReasons; @@ -66,11 +68,12 @@ class PreviewSimulator implements MiddlewareInterface } // The preview flag is set if the current page turns out to be hidden $showHiddenPages = $this->checkIfPageIsHidden($pageArguments->getPageId(), $request); + $rootlineRequiresPreviewFlag = $this->checkIfRootlineRequiresPreview($pageArguments->getPageId()); $simulatingDate = $this->simulateDate($request); $simulatingGroup = $this->simulateUserGroup($request); $showHiddenRecords = $visibilityAspect->includeHidden(); $isOfflineWorkspace = $this->context->getPropertyFromAspect('workspace', 'id', 0) > 0; - $isPreview = $simulatingDate || $simulatingGroup || $showHiddenRecords || $showHiddenPages || $isOfflineWorkspace; + $isPreview = $simulatingDate || $simulatingGroup || $showHiddenRecords || $showHiddenPages || $isOfflineWorkspace || $rootlineRequiresPreviewFlag; if ($this->context->hasAspect('frontend.preview')) { $previewAspect = $this->context->getAspect('frontend.preview'); $isPreview = $previewAspect->isPreview() || $isPreview; @@ -78,7 +81,7 @@ class PreviewSimulator implements MiddlewareInterface $previewAspect = GeneralUtility::makeInstance(PreviewAspect::class, $isPreview); $this->context->setAspect('frontend.preview', $previewAspect); - if ($showHiddenPages) { + if ($showHiddenPages || $rootlineRequiresPreviewFlag) { $newAspect = GeneralUtility::makeInstance(VisibilityAspect::class, true, $visibilityAspect->includeHiddenContent(), $visibilityAspect->includeDeletedRecords()); $this->context->setAspect('visibility', $newAspect); } @@ -87,6 +90,46 @@ class PreviewSimulator implements MiddlewareInterface return $handler->handle($request); } + protected function checkIfRootlineRequiresPreview(int $pageId): bool + { + $rootlineUtility = GeneralUtility::makeInstance(RootlineUtility::class, $pageId, '', $this->context); + $pageRepository = GeneralUtility::makeInstance(PageRepository::class, $this->context); + $groupRestricted = false; + $timeRestricted = false; + $hidden = false; + try { + $rootLine = $rootlineUtility->get(); + $pageInfo = $pageRepository->getPage_noCheck($pageId); + // Only check rootline if the current page has not set extendToSubpages itself + // @see \TYPO3\CMS\Backend\Routing\PreviewUriBuilder::class + if (!(bool)($pageInfo['extendToSubpages'] ?? false)) { + // remove the current page from the rootline + array_shift($rootLine); + foreach ($rootLine as $page) { + // Skip root node and pages which do not define extendToSubpages + if ((int)($page['uid'] ?? 0) === 0 || !(bool)($page['extendToSubpages'] ?? false)) { + continue; + } + $groupRestricted = (bool)(string)($page['fe_group'] ?? ''); + $timeRestricted = (int)($page['starttime'] ?? 0) || (int)($page['endtime'] ?? 0); + $hidden = (int)($page['hidden'] ?? 0); + // Stop as soon as a page in the rootline has extendToSubpages set + break; + } + } + + } catch (\Exception) { + // if the rootline cannot be resolved (404 because of delete placeholder in workspaces for example) + // we do not want to fail here but rather continue handling the request to trigger the TSFE 404 handling + } finally { + // clear the rootline cache to ensure it's cleanly built with the full context later on. + $cacheManager = GeneralUtility::makeInstance(CacheManager::class); + $cacheManager->getCache('runtime')->flushByTag(RootlineUtility::RUNTIME_CACHE_TAG); + $cacheManager->getCache('rootline')->flush(); + } + return $groupRestricted || $timeRestricted || $hidden; + } + /** * Checks if the page is hidden in the active workspace + language setup. */ -- GitLab