Skip to content

Commit

Permalink
Merge pull request #2654 from bwaidelich/bugfix/2653-node-preview-route
Browse files Browse the repository at this point in the history
FEATURE: Custom Route for node preview
  • Loading branch information
bwaidelich authored Dec 2, 2019
2 parents d9d4b62 + 0743604 commit eccf0d3
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 17 deletions.
52 changes: 36 additions & 16 deletions Neos.Neos/Classes/Controller/Frontend/NodeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Http\Component\SetHeaderComponent;
use Neos\Flow\Mvc\Controller\ActionController;
use Neos\Flow\Mvc\Exception\NoSuchArgumentException;
use Neos\Flow\Property\PropertyMapper;
use Neos\Flow\Security\Authorization\PrivilegeManagerInterface;
use Neos\Flow\Session\Exception\SessionNotStartedException;
use Neos\Flow\Session\SessionInterface;
use Neos\Neos\Controller\Exception\NodeNotFoundException;
use Neos\Neos\Controller\Exception\UnresolvableShortcutException;
use Neos\Neos\Domain\Service\NodeShortcutResolver;
use Neos\Neos\Exception as NeosException;
use Neos\Neos\TypeConverter\NodeConverter;
use Neos\Neos\View\FusionView;
use Neos\ContentRepository\Domain\Model\NodeInterface;
Expand Down Expand Up @@ -73,32 +76,50 @@ class NodeController extends ActionController
protected $propertyMapper;

/**
* Allow invisible nodes to be redirected to
* Shows the specified node and takes visibility and access restrictions into
* account.
*
* @param NodeInterface $node
* @return string View output for the specified node
* @throws NodeNotFoundException | UnresolvableShortcutException | NeosException
* @Flow\SkipCsrfProtection We need to skip CSRF protection here because this action could be called with unsafe requests from widgets or plugins that are rendered on the node - For those the CSRF token is validated on the sub-request, so it is safe to be skipped here
* @Flow\IgnoreValidation("node")
*/
public function showAction(NodeInterface $node = null)
{
if ($node === null || !$node->getContext()->isLive()) {
throw new NodeNotFoundException('The requested node does not exist or isn\'t accessible to the current user', 1430218623);
}

if ($node->getNodeType()->isOfType('Neos.Neos:Shortcut')) {
$this->handleShortcutNode($node);
}

$this->view->assign('value', $node);
}

/**
* Allow invisible nodes to be previewed
*
* @return void
* @throws NoSuchArgumentException
*/
protected function initializeShowAction()
protected function initializePreviewAction(): void
{
if ($this->arguments->hasArgument('node')
&& $this->request->hasArgument('showInvisible')
&& (bool)$this->request->getArgument('showInvisible')
&& $this->privilegeManager->isPrivilegeTargetGranted('Neos.Neos:Backend.GeneralAccess')
) {
if ($this->arguments->hasArgument('node') && $this->privilegeManager->isPrivilegeTargetGranted('Neos.Neos:Backend.GeneralAccess')) {
$this->arguments->getArgument('node')->getPropertyMappingConfiguration()->setTypeConverterOption(NodeConverter::class, NodeConverter::INVISIBLE_CONTENT_SHOWN, true);
}
}

/**
* Shows the specified node and takes visibility and access restrictions into
* account.
* Previews a node that is not live (i.e. for the Backend Preview & Edit Mode)
*
* @param NodeInterface $node
* @return string View output for the specified node
* @Flow\SkipCsrfProtection We need to skip CSRF protection here because this action could be called with unsafe requests from widgets or plugins that are rendered on the node - For those the CSRF token is validated on the sub-request, so it is safe to be skipped here
* @throws NeosException | NodeNotFoundException | SessionNotStartedException | UnresolvableShortcutException
* @Flow\IgnoreValidation("node")
* @throws NodeNotFoundException
*/
public function showAction(NodeInterface $node = null)
public function previewAction(NodeInterface $node = null)
{
if ($node === null) {
throw new NodeNotFoundException('The requested node does not exist or isn\'t accessible to the current user', 1430218623);
Expand All @@ -118,10 +139,9 @@ public function showAction(NodeInterface $node = null)
if (!$this->view->canRenderWithNodeAndPath()) {
$this->view->setFusionPath('rawContent');
}
}

if ($this->session->isStarted() && $inBackend) {
$this->session->putData('lastVisitedNode', $node->getContextPath());
if ($this->session->isStarted()) {
$this->session->putData('lastVisitedNode', $node->getContextPath());
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion Neos.Neos/Classes/Service/LinkingService.php
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ public function convertUriToObject($uri, NodeInterface $contextNode = null)
* @throws \Neos\Flow\Property\Exception
* @throws \Neos\Flow\Security\Exception
* @throws HttpException
* @throws \Neos\Flow\Persistence\Exception\IllegalObjectTypeException
*/
public function createNodeUri(ControllerContext $controllerContext, $node = null, NodeInterface $baseNode = null, $format = null, $absolute = false, array $arguments = [], $section = '', $addQueryString = false, array $argumentsToBeExcludedFromQueryString = [], $resolveShortcuts = true): string
{
Expand Down Expand Up @@ -301,14 +302,15 @@ public function createNodeUri(ControllerContext $controllerContext, $node = null

$uriBuilder = clone $controllerContext->getUriBuilder();
$uriBuilder->setRequest($request);
$action = $resolvedNode->getContext()->getWorkspace()->isPublicWorkspace() && !$resolvedNode->isHidden() ? 'show' : 'preview';
$uri = $uriBuilder
->reset()
->setSection($section)
->setArguments($arguments)
->setAddQueryString($addQueryString)
->setArgumentsToBeExcludedFromQueryString($argumentsToBeExcludedFromQueryString)
->setFormat($format ?: $request->getFormat())
->uriFor('show', ['node' => $resolvedNode], 'Frontend\Node', 'Neos.Neos');
->uriFor($action, ['node' => $resolvedNode], 'Frontend\Node', 'Neos.Neos');

$siteNode = $resolvedNode->getContext()->getCurrentSiteNode();
if ($siteNode instanceof NodeInterface && NodePaths::isSubPathOf($siteNode->getPath(), $resolvedNode->getPath())) {
Expand Down
7 changes: 7 additions & 0 deletions Neos.Neos/Configuration/Policy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ privilegeTargets:
'Neos.Neos:PublicFrontendAccess':
matcher: 'method(Neos\Neos\Controller\Frontend\NodeController->showAction())'

'Neos.Neos:ContentPreview':
matcher: 'method(Neos\Neos\Controller\Frontend\NodeController->previewAction())'

'Neos.Neos:BackendLogin':
matcher: 'method(Neos\Neos\Controller\LoginController->(index|tokenLogin|authenticate)Action()) || method(Neos\Flow\Security\Authentication\Controller\AbstractAuthenticationController->authenticateAction())'

Expand Down Expand Up @@ -171,6 +174,10 @@ roles:
privilegeTarget: 'Neos.Neos:Backend.GeneralAccess'
permission: GRANT

-
privilegeTarget: 'Neos.Neos:ContentPreview'
permission: GRANT

-
privilegeTarget: 'Neos.Neos:Backend.Module.Content'
permission: GRANT
Expand Down
7 changes: 7 additions & 0 deletions Neos.Neos/Configuration/Routes.Frontend.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
# "Frontend" subroutes configuration for the Neos.Neos package #
# #

-
name: 'Preview'
uriPattern: 'neos/preview'
defaults:
'@action': 'preview'
appendExceedingArguments: true

-
name: 'Homepage'
uriPattern: '{node}'
Expand Down

0 comments on commit eccf0d3

Please sign in to comment.