diff --git a/src/bundle/Controller/Content/ContentTreeController.php b/src/bundle/Controller/Content/ContentTreeController.php
index f27bd5afcc..b372a2c9e8 100644
--- a/src/bundle/Controller/Content/ContentTreeController.php
+++ b/src/bundle/Controller/Content/ContentTreeController.php
@@ -13,12 +13,14 @@
use Ibexa\AdminUi\REST\Value\ContentTree\Node;
use Ibexa\AdminUi\REST\Value\ContentTree\NodeExtendedInfo;
use Ibexa\AdminUi\REST\Value\ContentTree\Root;
+use Ibexa\AdminUi\Siteaccess\SiteaccessResolverInterface;
use Ibexa\AdminUi\Specification\ContentType\ContentTypeIsUser;
use Ibexa\AdminUi\UI\Module\ContentTree\NodeFactory;
use Ibexa\Contracts\AdminUi\Permission\PermissionCheckerInterface;
use Ibexa\Contracts\Core\Limitation\Target;
use Ibexa\Contracts\Core\Repository\LocationService;
use Ibexa\Contracts\Core\Repository\PermissionResolver;
+use Ibexa\Contracts\Core\Repository\Values\Content\Content;
use Ibexa\Contracts\Core\Repository\Values\Content\Location;
use Ibexa\Contracts\Core\Repository\Values\Content\Query;
use Ibexa\Contracts\Core\Repository\Values\User\Limitation;
@@ -44,13 +46,16 @@ class ContentTreeController extends RestController
private ConfigResolverInterface $configResolver;
+ private SiteaccessResolverInterface $siteaccessResolver;
+
public function __construct(
LocationService $locationService,
PermissionCheckerInterface $permissionChecker,
LookupLimitationsTransformer $lookupLimitationsTransformer,
NodeFactory $contentTreeNodeFactory,
PermissionResolver $permissionResolver,
- ConfigResolverInterface $configResolver
+ ConfigResolverInterface $configResolver,
+ SiteaccessResolverInterface $siteaccessResolver
) {
$this->locationService = $locationService;
$this->permissionChecker = $permissionChecker;
@@ -58,6 +63,7 @@ public function __construct(
$this->contentTreeNodeFactory = $contentTreeNodeFactory;
$this->permissionResolver = $permissionResolver;
$this->configResolver = $configResolver;
+ $this->siteaccessResolver = $siteaccessResolver;
}
/**
@@ -145,7 +151,15 @@ public function loadNodeExtendedInfoAction(Location $location): NodeExtendedInfo
{
$locationPermissionRestrictions = $this->getLocationPermissionRestrictions($location);
- return new NodeExtendedInfo($locationPermissionRestrictions);
+ $content = $location->getContent();
+ $versionInfo = $content->getVersionInfo();
+ $translations = $versionInfo->languageCodes;
+ $previewableTranslations = array_filter(
+ $translations,
+ fn (string $languageCode): bool => $this->isPreviewable($location, $content, $languageCode)
+ );
+
+ return new NodeExtendedInfo($locationPermissionRestrictions, $previewableTranslations);
}
/**
@@ -245,6 +259,37 @@ private function canUserHideContent(Location $location): bool
[$target]
);
}
+
+ /**
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
+ * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
+ */
+ private function isPreviewable(
+ Location $location,
+ Content $content,
+ string $languageCode
+ ): bool {
+ $canPreview = $this->permissionResolver->canUser(
+ 'content',
+ 'versionread',
+ $content,
+ [$location]
+ );
+
+ if (!$canPreview) {
+ return false;
+ }
+
+ $versionNo = $content->getVersionInfo()->getVersionNo();
+
+ $siteAccesses = $this->siteaccessResolver->getSiteAccessesListForLocation(
+ $location,
+ $versionNo,
+ $languageCode
+ );
+
+ return !empty($siteAccesses);
+ }
}
class_alias(ContentTreeController::class, 'EzSystems\EzPlatformAdminUiBundle\Controller\Content\ContentTreeController');
diff --git a/src/lib/REST/Output/ValueObjectVisitor/ContentTree/Node.php b/src/lib/REST/Output/ValueObjectVisitor/ContentTree/Node.php
index 3e98d51fbb..41e666161f 100644
--- a/src/lib/REST/Output/ValueObjectVisitor/ContentTree/Node.php
+++ b/src/lib/REST/Output/ValueObjectVisitor/ContentTree/Node.php
@@ -41,7 +41,7 @@ public function visit(Visitor $visitor, Generator $generator, $data)
$generator->valueElement('translations', implode(',', $data->translations));
- $generator->valueElement('previewableTranslations', implode(',', $data->previewableTranslations));
+ $generator->valueElement('mainLanguageCode', $data->mainLanguageCode);
$generator->startValueElement('name', $data->name);
$generator->endValueElement('name');
diff --git a/src/lib/REST/Output/ValueObjectVisitor/ContentTree/NodeExtendedInfoVisitor.php b/src/lib/REST/Output/ValueObjectVisitor/ContentTree/NodeExtendedInfoVisitor.php
index 34e3057e6f..3d073f88d7 100644
--- a/src/lib/REST/Output/ValueObjectVisitor/ContentTree/NodeExtendedInfoVisitor.php
+++ b/src/lib/REST/Output/ValueObjectVisitor/ContentTree/NodeExtendedInfoVisitor.php
@@ -30,10 +30,27 @@ public function visit(Visitor $visitor, Generator $generator, $data): void
$visitor->setStatus(Response::HTTP_OK);
$this->buildPermissionNode($data->getPermissionRestrictions(), $generator);
+ $this->buildPreviewableTranslationsNode($data->getPreviewableTranslations(), $generator);
$generator->endObjectElement(self::MAIN_ELEMENT);
}
+ /**
+ * @param string[] $previewableTranslations
+ */
+ protected function buildPreviewableTranslationsNode(
+ array $previewableTranslations,
+ Generator $generator
+ ): void {
+ $generator->startHashElement('previewableTranslations');
+ $generator->startList('values');
+ foreach ($previewableTranslations as $value) {
+ $generator->valueElement('value', $value);
+ }
+ $generator->endList('values');
+ $generator->endHashElement('previewableTranslations');
+ }
+
/**
* @phpstan-param TPermissionRestrictions $permissionRestrictions
*/
diff --git a/src/lib/REST/Value/ContentTree/Node.php b/src/lib/REST/Value/ContentTree/Node.php
index 30201f4274..9aa1755652 100644
--- a/src/lib/REST/Value/ContentTree/Node.php
+++ b/src/lib/REST/Value/ContentTree/Node.php
@@ -26,9 +26,6 @@ class Node extends RestValue
/** @var string[] */
public array $translations;
- /** @var string[] */
- public array $previewableTranslations;
-
/** @var string */
public $name;
@@ -56,12 +53,13 @@ class Node extends RestValue
public string $pathString;
+ public string $mainLanguageCode;
+
/**
* @param int $depth
* @param int $locationId
* @param int $contentId
* @param string[] $translations
- * @param string[] $previewableTranslations
* @param string $name
* @param string $contentTypeIdentifier
* @param bool $isContainer
@@ -76,7 +74,6 @@ public function __construct(
int $contentId,
int $versionNo,
array $translations,
- array $previewableTranslations,
string $name,
string $contentTypeIdentifier,
bool $isContainer,
@@ -85,6 +82,7 @@ public function __construct(
int $totalChildrenCount,
int $reverseRelationsCount,
bool $isBookmarked,
+ string $mainLanguageCode,
array $children = [],
string $pathString = ''
) {
@@ -93,7 +91,6 @@ public function __construct(
$this->contentId = $contentId;
$this->versionNo = $versionNo;
$this->translations = $translations;
- $this->previewableTranslations = $previewableTranslations;
$this->name = $name;
$this->isInvisible = $isInvisible;
$this->contentTypeIdentifier = $contentTypeIdentifier;
@@ -104,6 +101,7 @@ public function __construct(
$this->isBookmarked = $isBookmarked;
$this->children = $children;
$this->pathString = $pathString;
+ $this->mainLanguageCode = $mainLanguageCode;
}
}
diff --git a/src/lib/REST/Value/ContentTree/NodeExtendedInfo.php b/src/lib/REST/Value/ContentTree/NodeExtendedInfo.php
index 5fc578f026..7258507c65 100644
--- a/src/lib/REST/Value/ContentTree/NodeExtendedInfo.php
+++ b/src/lib/REST/Value/ContentTree/NodeExtendedInfo.php
@@ -28,13 +28,20 @@ final class NodeExtendedInfo extends RestValue
/** @phpstan-var TPermissionRestrictions|null */
private ?array $permissions;
+ /** @var string[] */
+ private array $previewableTranslations;
+
/**
* @phpstan-param TPermissionRestrictions|null $permissions
+ *
+ * @param string[] $previewableTranslation
*/
public function __construct(
- ?array $permissions = null
+ ?array $permissions = null,
+ array $previewableTranslation = []
) {
$this->permissions = $permissions;
+ $this->previewableTranslations = $previewableTranslation;
}
/**
@@ -44,4 +51,12 @@ public function getPermissionRestrictions(): ?array
{
return $this->permissions;
}
+
+ /**
+ * @return string[]
+ */
+ public function getPreviewableTranslations(): array
+ {
+ return $this->previewableTranslations;
+ }
}
diff --git a/src/lib/UI/Module/ContentTree/NodeFactory.php b/src/lib/UI/Module/ContentTree/NodeFactory.php
index 5f7ef7e1da..73c2a11fc9 100644
--- a/src/lib/UI/Module/ContentTree/NodeFactory.php
+++ b/src/lib/UI/Module/ContentTree/NodeFactory.php
@@ -10,7 +10,6 @@
use Ibexa\AdminUi\REST\Value\ContentTree\LoadSubtreeRequestNode;
use Ibexa\AdminUi\REST\Value\ContentTree\Node;
-use Ibexa\AdminUi\Siteaccess\SiteaccessResolverInterface;
use Ibexa\Contracts\Core\Repository\BookmarkService;
use Ibexa\Contracts\Core\Repository\ContentService;
use Ibexa\Contracts\Core\Repository\Exceptions\NotImplementedException;
@@ -63,8 +62,6 @@ final class NodeFactory
private Repository $repository;
- private SiteaccessResolverInterface $siteaccessResolver;
-
/** @var int */
private $maxLocationIdsInSingleAggregation;
@@ -76,7 +73,6 @@ public function __construct(
ConfigResolverInterface $configResolver,
PermissionResolver $permissionResolver,
Repository $repository,
- SiteaccessResolverInterface $siteaccessResolver,
int $maxLocationIdsInSingleAggregation
) {
$this->bookmarkService = $bookmarkService;
@@ -86,7 +82,6 @@ public function __construct(
$this->configResolver = $configResolver;
$this->permissionResolver = $permissionResolver;
$this->repository = $repository;
- $this->siteaccessResolver = $siteaccessResolver;
$this->maxLocationIdsInSingleAggregation = $maxLocationIdsInSingleAggregation;
}
@@ -397,10 +392,7 @@ private function buildNode(
}
$translations = $versionInfo->getLanguageCodes();
- $previewableTranslations = array_filter(
- $translations,
- fn (string $languageCode): bool => $this->isPreviewable($location, $content, $languageCode)
- );
+ $mainLanguageCode = $versionInfo->getContentInfo()->getMainLanguageCode();
return new Node(
$depth,
@@ -408,7 +400,6 @@ private function buildNode(
$location->getContentId(),
$versionInfo->getVersionNo(),
$translations,
- $previewableTranslations,
'', // node name will be provided later by `supplyTranslatedContentName` method
null !== $contentType ? $contentType->getIdentifier() : '',
null === $contentType || $contentType->isContainer(),
@@ -417,6 +408,7 @@ private function buildNode(
$totalChildrenCount,
$this->getReverseRelationsCount($contentInfo),
isset($bookmarkLocations[$location->getId()]),
+ $mainLanguageCode,
$children,
$location->getPathString()
);
@@ -468,33 +460,6 @@ private function supplyChildrenCount(
$this->supplyChildrenCount($child, $aggregationResult, $requestFilter);
}
}
-
- /**
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException
- * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException
- */
- private function isPreviewable(
- Location $location,
- Content $content,
- string $languageCode
- ): bool {
- $versionNo = $content->getVersionInfo()->getVersionNo();
-
- $siteAccesses = $this->siteaccessResolver->getSiteAccessesListForLocation(
- $location,
- $versionNo,
- $languageCode
- );
-
- $canPreview = $this->permissionResolver->canUser(
- 'content',
- 'versionread',
- $content,
- [$location]
- );
-
- return $canPreview && !empty($siteAccesses);
- }
}
class_alias(NodeFactory::class, 'EzSystems\EzPlatformAdminUi\UI\Module\ContentTree\NodeFactory');
diff --git a/tests/integration/REST/GetContentTreeExtendedInfoTest.php b/tests/integration/REST/GetContentTreeExtendedInfoTest.php
index 9e8472a918..847e5465b4 100644
--- a/tests/integration/REST/GetContentTreeExtendedInfoTest.php
+++ b/tests/integration/REST/GetContentTreeExtendedInfoTest.php
@@ -35,6 +35,7 @@ protected function setUp(): void
[
'user/login' => [],
'content/read' => [],
+ 'content/versionread' => [],
'content/create' => [
new ContentTypeLimitation(
['limitationValues' => ['1', '16']]
diff --git a/tests/integration/Resources/REST/Schemas/ContentTreeNodeExtendedInfo.json b/tests/integration/Resources/REST/Schemas/ContentTreeNodeExtendedInfo.json
index 632e43c99e..753b688a84 100644
--- a/tests/integration/Resources/REST/Schemas/ContentTreeNodeExtendedInfo.json
+++ b/tests/integration/Resources/REST/Schemas/ContentTreeNodeExtendedInfo.json
@@ -53,11 +53,25 @@
"hasAccess"
]
}
- }
+ },
+ "previewableTranslations": {
+ "type": "object",
+ "properties": {
+ "values": {
+ "type": "array",
+ "items": [
+ {
+ "type": "string"
+ }
+ ]
+ }
+ }
+ }
},
"required": [
"_media-type",
- "permissions"
+ "permissions",
+ "previewableTranslations"
]
}
},
diff --git a/tests/integration/Resources/REST/Schemas/ContentTreeNodeExtendedInfo.xsd b/tests/integration/Resources/REST/Schemas/ContentTreeNodeExtendedInfo.xsd
index 38cebade76..cd01c211ce 100644
--- a/tests/integration/Resources/REST/Schemas/ContentTreeNodeExtendedInfo.xsd
+++ b/tests/integration/Resources/REST/Schemas/ContentTreeNodeExtendedInfo.xsd
@@ -26,6 +26,13 @@
+
+
+
+
+
+
+
diff --git a/tests/integration/Resources/REST/Snapshots/ContentTreeNodeExtendedInfo.json b/tests/integration/Resources/REST/Snapshots/ContentTreeNodeExtendedInfo.json
index ceef092019..85be359381 100644
--- a/tests/integration/Resources/REST/Snapshots/ContentTreeNodeExtendedInfo.json
+++ b/tests/integration/Resources/REST/Snapshots/ContentTreeNodeExtendedInfo.json
@@ -35,6 +35,9 @@
"_name": "hide",
"hasAccess": false
}
- ]
+ ],
+ "previewableTranslations": {
+ "values": ["eng-GB"]
+ }
}
}
diff --git a/tests/integration/Resources/REST/Snapshots/ContentTreeNodeExtendedInfo.xml b/tests/integration/Resources/REST/Snapshots/ContentTreeNodeExtendedInfo.xml
index 64fed756ca..926eeef47f 100644
--- a/tests/integration/Resources/REST/Snapshots/ContentTreeNodeExtendedInfo.xml
+++ b/tests/integration/Resources/REST/Snapshots/ContentTreeNodeExtendedInfo.xml
@@ -23,4 +23,7 @@
false
+
+ eng-GB
+
diff --git a/tests/integration/Resources/REST/Snapshots/ContentTreeRoot.json b/tests/integration/Resources/REST/Snapshots/ContentTreeRoot.json
index 2fdf2a13f9..1a7c7c051d 100644
--- a/tests/integration/Resources/REST/Snapshots/ContentTreeRoot.json
+++ b/tests/integration/Resources/REST/Snapshots/ContentTreeRoot.json
@@ -5,10 +5,10 @@
{
"_media-type": "application\/vnd.ibexa.api.ContentTreeNode+json",
"locationId": 2,
+ "mainLanguageCode": "eng-GB",
"contentId": 57,
"versionNo": 1,
"translations": "eng-GB",
- "previewableTranslations": "eng-GB",
"name": "Home",
"pathString": "/1/2/",
"contentTypeIdentifier": "landing_page",
@@ -22,10 +22,10 @@
{
"_media-type": "application\/vnd.ibexa.api.ContentTreeNode+json",
"locationId": 60,
+ "mainLanguageCode": "eng-GB",
"contentId": 58,
"versionNo": 1,
"translations": "eng-GB",
- "previewableTranslations": "eng-GB",
"name": "Contact Us",
"pathString": "/1/2/60/",
"contentTypeIdentifier": "feedback_form",