Skip to content

Commit

Permalink
FEATURE: Extract workspace metadata and user-assignment to Neos (#3838)
Browse files Browse the repository at this point in the history
* Draft: FEATURE: Extract workspace metadata and user-assignment to Neos

Counter-part to neos/neos-development-collection#5146

* wip

* WIP REVERT ME, PATCH E2E

* Remove Neos UI `WorkspaceService`

* Re-add UI WorkspaceService for now

* Remove `WorkspaceNameBuilder` usages

* TASK: Reintroduce usage of neos ui command value objects

* Remove obsolete namespace import

* WIP: Try to adjust e2e to work with new Neos workspace metadata

* TASK: Remove `migrateWorkspaceMetadataToWorkspaceService` hack from e2e tests and use `assignrole`

* Revert "WIP REVERT ME, PATCH E2E"

This reverts commit 3aefeb2.

---------

Co-authored-by: mhsdesign <[email protected]>
  • Loading branch information
bwaidelich and mhsdesign authored Oct 9, 2024
1 parent a06fc70 commit 0daa55c
Show file tree
Hide file tree
Showing 13 changed files with 180 additions and 220 deletions.
4 changes: 0 additions & 4 deletions Classes/Application/ReloadNodes/ReloadNodesQueryHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Mvc\ActionRequest;
use Neos\Neos\Domain\Service\NodeTypeNameFactory;
use Neos\Neos\Domain\Workspace\WorkspaceProvider;
use Neos\Neos\FrontendRouting\NodeAddressFactory;
use Neos\Neos\Ui\Fusion\Helper\NodeInfoHelper;

Expand All @@ -36,9 +35,6 @@
#[Flow\Scope("singleton")]
final class ReloadNodesQueryHandler
{
#[Flow\Inject]
protected WorkspaceProvider $workspaceProvider;

#[Flow\Inject]
protected ContentRepositoryRegistry $contentRepositoryRegistry;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry;
use Neos\Flow\Annotations as Flow;
use Neos\Neos\Domain\NodeLabel\NodeLabelGeneratorInterface;
use Neos\Neos\Domain\Workspace\WorkspaceProvider;
use Neos\Neos\Domain\Service\WorkspacePublishingService;

/**
* The application layer level command handler to for rebasing the workspace
Expand All @@ -32,20 +32,19 @@ final class SyncWorkspaceCommandHandler
protected ContentRepositoryRegistry $contentRepositoryRegistry;

#[Flow\Inject]
protected WorkspaceProvider $workspaceProvider;
protected WorkspacePublishingService $workspacePublishingService;

#[Flow\Inject]
protected NodeLabelGeneratorInterface $nodeLabelGenerator;

public function handle(SyncWorkspaceCommand $command): void
{
try {
$workspace = $this->workspaceProvider->provideForWorkspaceName(
$this->workspacePublishingService->rebaseWorkspace(
$command->contentRepositoryId,
$command->workspaceName
$command->workspaceName,
$command->rebaseErrorHandlingStrategy
);

$workspace->rebase($command->rebaseErrorHandlingStrategy);
} catch (WorkspaceRebaseFailed $e) {
$conflictsBuilder = Conflicts::builder(
contentRepository: $this->contentRepositoryRegistry
Expand Down
74 changes: 9 additions & 65 deletions Classes/ContentRepository/Service/WorkspaceService.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,18 @@
* source code.
*/

use Neos\ContentRepository\Core\ContentRepository;
use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\Neos\Domain\Service\NodeTypeNameFactory;
use Neos\Neos\FrontendRouting\NodeAddress;
use Neos\Neos\FrontendRouting\NodeAddressFactory;
use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints;
use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry;
use Neos\Flow\Annotations as Flow;
use Neos\Neos\Domain\Service\UserService as DomainUserService;
use Neos\Neos\Domain\Service\NodeTypeNameFactory;
use Neos\Neos\Domain\Service\WorkspacePublishingService;
use Neos\Neos\FrontendRouting\NodeAddress;
use Neos\Neos\FrontendRouting\NodeAddressFactory;
use Neos\Neos\PendingChangesProjection\Change;
use Neos\Neos\PendingChangesProjection\ChangeFinder;
use Neos\Neos\Service\UserService;
use Neos\Neos\Utility\NodeTypeWithFallbackProvider;

/**
Expand All @@ -44,17 +41,8 @@ class WorkspaceService
#[Flow\Inject]
protected ContentRepositoryRegistry $contentRepositoryRegistry;

/**
* @Flow\Inject
* @var UserService
*/
protected $userService;

/**
* @Flow\Inject
* @var DomainUserService
*/
protected $domainUserService;
#[Flow\Inject]
protected WorkspacePublishingService $workspacePublishingService;

/**
* Get all publishable node context paths for a workspace
Expand All @@ -64,15 +52,10 @@ class WorkspaceService
public function getPublishableNodeInfo(WorkspaceName $workspaceName, ContentRepositoryId $contentRepositoryId): array
{
$contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId);
$workspace = $contentRepository->getWorkspaceFinder()->findOneByName($workspaceName);
if (is_null($workspace) || $workspace->baseWorkspaceName === null) {
return [];
}
$changeFinder = $contentRepository->projectionState(ChangeFinder::class);
$changes = $changeFinder->findByContentStreamId($workspace->currentContentStreamId);
$pendingChanges = $this->workspacePublishingService->pendingWorkspaceChanges($contentRepositoryId, $workspaceName);
/** @var array{contextPath:string,documentContextPath:string,typeOfChange:int}[] $unpublishedNodes */
$unpublishedNodes = [];
foreach ($changes as $change) {
foreach ($pendingChanges as $change) {
if ($change->removalAttachmentPoint) {
$nodeAddress = new NodeAddress(
$change->contentStreamId,
Expand Down Expand Up @@ -106,7 +89,6 @@ public function getPublishableNodeInfo(WorkspaceName $workspaceName, ContentRepo
if ($node instanceof Node) {
$documentNode = $subgraph->findClosestNode($node->aggregateId, FindClosestNodeFilter::create(nodeTypes: NodeTypeNameFactory::NAME_DOCUMENT));
if ($documentNode instanceof Node) {
$contentRepository = $this->contentRepositoryRegistry->get($documentNode->contentRepositoryId);
$nodeAddressFactory = NodeAddressFactory::create($contentRepository);
$unpublishedNodes[] = [
'contextPath' => $nodeAddressFactory->createFromNode($node)->serializeForUri(),
Expand All @@ -124,44 +106,6 @@ public function getPublishableNodeInfo(WorkspaceName $workspaceName, ContentRepo
}));
}

/**
* Get allowed target workspaces for current user
*
* @return array<string,array<string,mixed>>
*/
public function getAllowedTargetWorkspaces(ContentRepository $contentRepository): array
{
$user = $this->domainUserService->getCurrentUser();

$workspacesArray = [];
foreach ($contentRepository->getWorkspaceFinder()->findAll() as $workspace) {
// FIXME: This check should be implemented through a specialized Workspace Privilege or something similar
// Skip workspace not owned by current user
if ($workspace->workspaceOwner !== null && $workspace->workspaceOwner !== $user) {
continue;
}
// Skip own personal workspace
if ($workspace->workspaceName->value === $this->userService->getPersonalWorkspaceName()) {
continue;
}

if ($workspace->isPersonalWorkspace()) {
// Skip other personal workspaces
continue;
}

$workspaceArray = [
'name' => $workspace->workspaceName->jsonSerialize(),
'title' => $workspace->workspaceTitle->jsonSerialize(),
'description' => $workspace->workspaceDescription->jsonSerialize(),
'readonly' => !$this->domainUserService->currentUserCanPublishToWorkspace($workspace)
];
$workspacesArray[$workspace->workspaceName->jsonSerialize()] = $workspaceArray;
}

return $workspacesArray;
}

private function getTypeOfChange(Change $change): int
{
$result = 0;
Expand Down
23 changes: 9 additions & 14 deletions Classes/Controller/BackendController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Mvc\Controller\ActionController;
use Neos\Flow\Persistence\PersistenceManagerInterface;
use Neos\Flow\Security\Context;
use Neos\Neos\Domain\Repository\DomainRepository;
use Neos\Neos\Domain\Repository\SiteRepository;
use Neos\Neos\Domain\Service\NodeTypeNameFactory;
use Neos\Neos\Domain\Service\WorkspaceNameBuilder;
use Neos\Neos\Domain\Service\WorkspaceService;
use Neos\Neos\FrontendRouting\NodeAddressFactory;
use Neos\Neos\FrontendRouting\NodeUriBuilderFactory;
use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult;
Expand Down Expand Up @@ -78,12 +77,6 @@ class BackendController extends ActionController
*/
protected $contentRepositoryRegistry;

/**
* @Flow\Inject
* @var Context
*/
protected $securityContext;

/**
* @Flow\Inject
* @var ConfigurationProviderInterface
Expand Down Expand Up @@ -126,6 +119,12 @@ class BackendController extends ActionController
*/
protected $nodeUriBuilderFactory;

/**
* @Flow\Inject
* @var WorkspaceService
*/
protected $workspaceService;

/**
* Displays the backend interface
*
Expand All @@ -138,23 +137,19 @@ public function indexAction(string $node = null)
$contentRepository = $this->contentRepositoryRegistry->get($siteDetectionResult->contentRepositoryId);

$nodeAddress = $node !== null ? NodeAddressFactory::create($contentRepository)->createFromUriString($node) : null;
unset($node);
$user = $this->userService->getBackendUser();

if ($user === null) {
$this->redirectToUri($this->uriBuilder->uriFor('index', [], 'Login', 'Neos.Neos'));
}

$currentAccount = $this->securityContext->getAccount();
assert($currentAccount !== null);
$workspaceName = WorkspaceNameBuilder::fromAccountIdentifier($currentAccount->getAccountIdentifier());

try {
$contentGraph = $contentRepository->getContentGraph($workspaceName);
$workspace = $this->workspaceService->getPersonalWorkspaceForUser($siteDetectionResult->contentRepositoryId, $user->getId());
} catch (WorkspaceDoesNotExist) {
// todo will cause infinite loop: https://github.com/neos/neos-development-collection/issues/4401
$this->redirectToUri($this->uriBuilder->uriFor('index', [], 'Login', 'Neos.Neos'));
}
$contentGraph = $contentRepository->getContentGraph($workspace->workspaceName);

$backendControllerInternals = $this->contentRepositoryRegistry->buildService(
$siteDetectionResult->contentRepositoryId,
Expand Down
Loading

0 comments on commit 0daa55c

Please sign in to comment.