Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 69 additions & 16 deletions Neos.Media.Browser/Classes/Controller/UsageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
* source code.
*/

use Neos\ContentRepository\Core\ContentRepository;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter;
use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints;
use Neos\ContentRepository\Core\SharedModel\Exception\WorkspaceDoesNotExist;
use Neos\ContentRepository\Core\SharedModel\Workspace\Workspace;
use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry;
use Neos\Flow\Annotations as Flow;
Expand All @@ -25,8 +27,15 @@
use Neos\Media\Domain\Model\AssetInterface;
use Neos\Media\Domain\Service\AssetService;
use Neos\Neos\AssetUsage\Dto\AssetUsageReference;
use Neos\Neos\Domain\Model\User;
use Neos\Neos\Domain\Model\UserId;
use Neos\Neos\Domain\Model\WorkspaceClassification;
use Neos\Neos\Domain\Model\WorkspaceRole;
use Neos\Neos\Domain\Model\WorkspaceRoleSubjectType;
use Neos\Neos\Domain\Model\WorkspaceTitle;
use Neos\Neos\Domain\Repository\SiteRepository;
use Neos\Neos\Domain\Service\NodeTypeNameFactory;
use Neos\Neos\Domain\Service\UserService as DomainUserService;
use Neos\Neos\Domain\Service\WorkspaceService;
use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult;
use Neos\Neos\Security\Authorization\ContentRepositoryAuthorizationService;
Expand Down Expand Up @@ -87,6 +96,12 @@ class UsageController extends ActionController
*/
protected $privilegeManager;

/**
* @Flow\Inject
* @var DomainUserService
*/
protected $domainUserService;

Comment on lines +99 to +104
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/**
* @Flow\Inject
* @var DomainUserService
*/
protected $domainUserService;
#[Flow\Inject]
protected DomainUserService $domainUserService;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just taking the format from the other protected variables of the file to make it consistent.

Should I just apply this suggestion, rework the variables as well or leave it as it is? 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with both! Also with keeping it as it is. 😬

Using the attributes over annotation does not work for all cases. So you need to be careful rewriting all of them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Rewriting annotation to attributes work, but not the PHP type definition in all cases. But AFAIS this is an older issue.

/**
* Get Related Nodes for an asset
*
Expand Down Expand Up @@ -120,22 +135,31 @@ public function relatedNodesAction(AssetInterface $asset)

$contentRepository = $this->contentRepositoryRegistry->get($usage->getContentRepositoryId());

$nodeAggregate = $contentRepository->getContentGraph($usage->getWorkspaceName())->findNodeAggregateById(
$usage->getNodeAggregateId()
$nodeAggregate = $this->securityContext->withoutAuthorizationChecks(
function () use ($contentRepository, $usage) {
try {
return $contentRepository->getContentGraph($usage->getWorkspaceName())->findNodeAggregateById(
$usage->getNodeAggregateId()
);
} catch (WorkspaceDoesNotExist $e) {
return null;
}
}
);
$nodeType = $nodeAggregate ? $contentRepository->getNodeTypeManager()->getNodeType($nodeAggregate->nodeTypeName) : null;

$workspacePermissions = $this->contentRepositoryAuthorizationService->getWorkspacePermissions($currentContentRepositoryId, $usage->getWorkspaceName(), $this->securityContext->getRoles(), $this->userService->getBackendUser()?->getId());
$workspace = $contentRepository->findWorkspaceByName($usage->getWorkspaceName());

$inaccessibleRelation['label'] = $workspace && $this->getLabelForInaccessibleWorkspace($workspace);
$inaccessibleRelation['nodeIdentifier'] = $usage->getNodeAggregateId()->value;
$inaccessibleRelation['workspaceName'] = $usage->getWorkspaceName()->value;
$inaccessibleRelation['workspace'] = $workspace;
$inaccessibleRelation['relevantWorkspaceMetadata'] = $this->getRelevantMetadataFromInaccessibleWorkspace($workspace, $contentRepository);
$inaccessibleRelation['nodeType'] = $nodeType;
$inaccessibleRelation['accessible'] = $workspacePermissions->read;

if (!$workspacePermissions->read) {
// the workspace from `usage` might not be found, but we expect a given workspace in further function
// and user should have access to it, if not we have an inaccessible relation
if ($workspace === null || !$workspacePermissions->read) {
$inaccessibleRelations[] = $inaccessibleRelation;
continue;
}
Expand Down Expand Up @@ -181,6 +205,7 @@ public function relatedNodesAction(AssetInterface $asset)
$relatedNodes[$site->getNodeName()->value]['nodes'][] = [
'node' => $node,
'workspace' => $workspace,
'workspaceMetadata' => $this->workspaceService->getWorkspaceMetadata($contentRepository->id, $workspace->workspaceName),
'documentNode' => $documentNode
];
}
Expand All @@ -196,24 +221,52 @@ public function relatedNodesAction(AssetInterface $asset)
]);
}

private function getLabelForInaccessibleWorkspace(Workspace $workspace): string
/**
* @return array{title: WorkspaceTitle|null, relatedUserName: string|null, personalWorkspace: bool, privateWorkspace: bool}
*/
private function getRelevantMetadataFromInaccessibleWorkspace(?Workspace $workspace, ?ContentRepository $contentRepository): array
{
/*
TODO: Needs to get re-implemented for Neos 9.
See: https://github.com/neos/neos-development-collection/pull/5182
$structuredReturn = [
'title' => null,
'relatedUserName' => '',
'personalWorkspace' => false,
'privateWorkspace' => false,
];

if ($workspace === null) {
return $structuredReturn;
}

$currentAccount = $this->securityContext->getAccount();

if ($currentAccount != null && $this->privilegeManager->isPrivilegeTargetGranted('Neos.Media.Browser:WorkspaceName')) {
if ($workspace->isPrivateWorkspace()) {
$owner = $workspace->getOwner();
return '(' . $owner->getLabel() . ')';
if ($currentAccount != null && $contentRepository != null && $this->privilegeManager->isPrivilegeTargetGranted('Neos.Media.Browser:WorkspaceName')) {
$workspaceMetadata = $this->workspaceService->getWorkspaceMetadata($contentRepository->id, $workspace->workspaceName);
$workspaceOwner = $workspaceMetadata->ownerUserId
? $this->domainUserService->findUserById($workspaceMetadata->ownerUserId)
: null;

$roleAssignments = $this->workspaceService->getWorkspaceRoleAssignments(
$contentRepository->id,
$workspace->workspaceName
);
$relatedUser = null;
foreach ($roleAssignments as $roleAssignment) {
if (($roleAssignment->role->value !== WorkspaceRole::VIEWER->value) && ($roleAssignment->subject->type->value === WorkspaceRoleSubjectType::USER->value)) {
$relatedUser = $this->domainUserService->findUserById(UserId::fromString($roleAssignment->subject->value));
break;
}
}

if ($workspaceMetadata->classification->value === WorkspaceClassification::PERSONAL->value) {
$structuredReturn['relatedUserName'] = $workspaceOwner?->getLabel();
$structuredReturn['personalWorkspace'] = true;
} else {
return '(' . $workspace->getTitle() . ')';
$structuredReturn['title'] = $workspaceMetadata->title;
$structuredReturn['relatedUserName'] = $relatedUser?->getLabel();
$structuredReturn['privateWorkspace'] = true;
}
}
*/

return '';
return $structuredReturn;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,34 @@
</td>
<td>
<f:switch expression="{true}">
<f:case value="{inaccessibleRelation.workspace.personalWorkspace}">
<f:case value="{inaccessibleRelation.relevantWorkspaceMetadata.personalWorkspace}">
<i class="fas fa-user"
title="{neos:backend.translate(id: 'workspaces.personalWorkspace', source: 'Main', package: 'Neos.Workspace.Ui')}"
data-neos-toggle="tooltip"></i>
{neos:backend.translate(id: 'workspaces.personalWorkspace', source: 'Main', package: 'Neos.Workspace.Ui')}
{inaccessibleRelation.label}
<f:if condition="{inaccessibleRelation.relevantWorkspaceMetadata.relatedUserName}">
<f:then>
(@{inaccessibleRelation.relevantWorkspaceMetadata.relatedUserName})
</f:then>
</f:if>
</f:case>
<f:case value="{inaccessibleRelation.workspace.privateWorkspace}">
<f:case value="{inaccessibleRelation.relevantWorkspaceMetadata.privateWorkspace}">
<i class="fas fa-shield"
title="{neos:backend.translate(id: 'workspaces.privateWorkspace', source: 'Main', package: 'Neos.Workspace.Ui')}"
data-neos-toggle="tooltip"></i>
{neos:backend.translate(id: 'workspaces.privateWorkspace', source: 'Main', package: 'Neos.Workspace.Ui')}
{inaccessibleRelation.label}
</f:case>
<f:case value="{inaccessibleRelation.workspace.internalWorkspace}">
<i class="fas fa-group"
title="{neos:backend.translate(id: 'workspaces.internalWorkspace', source: 'Main', package: 'Neos.Workspace.Ui')}"
data-neos-toggle="tooltip"></i>
{neos:backend.translate(id: 'workspaces.internalWorkspace', source: 'Main', package: 'Neos.Workspace.Ui')}
{inaccessibleRelation.label}
<f:if condition="{inaccessibleRelation.relevantWorkspaceMetadata.title} && {inaccessibleRelation.relevantWorkspaceMetadata.relatedUserName}">
<f:then>
({inaccessibleRelation.relevantWorkspaceMetadata.title.value} | @{inaccessibleRelation.relevantWorkspaceMetadata.relatedUserName})
</f:then>
<f:else>
<f:if condition="{inaccessibleRelation.relevantWorkspaceMetadata.title} && !{inaccessibleRelation.relevantWorkspaceMetadata.relatedUserName}">
<f:then>
({inaccessibleRelation.relevantWorkspaceMetadata.title.value} | ---)
</f:then>
</f:if>
</f:else>
</f:if>
</f:case>
<f:defaultCase>
---
Expand Down Expand Up @@ -143,7 +151,7 @@
</f:if>
</f:else>
</f:if>
<span title="{nodeInformation.workspace.name.value}" data-neos-toggle="tooltip">{nodeInformation.workspace.name.value -> f:format.crop(maxCharacters: 25, append: '…')}</span>
<span title="{nodeInformation.workspaceMetadata.title.value}" data-neos-toggle="tooltip">{nodeInformation.workspaceMetadata.title.value -> f:format.crop(maxCharacters: 25, append: '…')}</span>
</td>
<td class="neos-aRight">
<f:if condition="{nodeInformation.node.timestamps.lastModified}">
Expand Down