Skip to content

[Improvement] Add possibility to retrieve specific versions #939

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 17 commits into from
Closed
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
5 changes: 5 additions & 0 deletions src/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ public function skipPermisssionCheck()
return $this->configuration['security']['skipPermissionCheck'] ?? false;
}

public function disableVersionedRequests(): bool|string
{
return $this->configuration['security']['disableVersionedRequests'] ?? false;
Copy link
Contributor

Choose a reason for hiding this comment

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

for safety reasons, shouldn't this default to true?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, that is probably right!

}

/**
* @param string|null $path
*/
Expand Down
25 changes: 24 additions & 1 deletion src/GraphQL/Query/QueryType.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,19 @@ public function buildFolderQueries($type, &$config = [], $context = [])
}
}

protected function versionWrapper(callable $resolver)
{
return function ($root, $args, $context, $info) use ($resolver) {
$resolvedData = $resolver($root, $args, $context, $info);

if (isset($args['version'])) {
$resolvedData['versionRequest'] = $args['version'];
}

return $resolvedData;
};
}

/**
* @param array $config
* @param array $context
Expand All @@ -135,12 +148,20 @@ public function buildAssetQueries(&$config = [], $context = [])
'id' => ['type' => Type::int()],
'fullpath' => ['type' => Type::string()],
'defaultLanguage' => ['type' => Type::string()],
'version' => ['type' => Type::int()],
],
'type' => $assetType,
'resolve' => [$resolver, 'resolveAssetGetter'],
'resolve' => $this->versionWrapper([$resolver, 'resolveAssetGetter']),
];

$config['fields']['getAsset'] = $defGet;

foreach ($config['fields'] as &$field) {

if (isset($field['resolve']) && is_callable($field['resolve'])) {
$field['resolve'] = $this->versionWrapper($field['resolve']);
}
}
}
}

Expand All @@ -165,6 +186,7 @@ public function buildDocumentQueries(&$config = [], $context = [])
'path' => ['type' => Type::string(), 'description' => "Get document by 'path' is deprecated as it is wrongly named. The 'path' argument will be replaced by 'fullpath' for Release 1.0."],
'fullpath' => ['type' => Type::string()],
'defaultLanguage' => ['type' => Type::string()],
'version' => ['type' => Type::int()],
],
'type' => $this->getGraphQlService()->getDocumentTypeDefinition('document'),
'resolve' => [$resolver, 'resolveDocumentGetter'],
Expand Down Expand Up @@ -218,6 +240,7 @@ public function buildDataObjectQueries(&$config = [], $context = []): void
'id' => ['type' => Type::int()],
'fullpath' => ['type' => Type::string()],
'defaultLanguage' => ['type' => Type::string()],
'version' => ['type' => Type::int()],
],
'type' => ClassTypeDefinitions::get($class),
'resolve' => [$resolver, 'resolveObjectGetter'],
Expand Down
62 changes: 50 additions & 12 deletions src/GraphQL/Resolver/AssetType.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
use GraphQL\Type\Definition\ResolveInfo;
use Pimcore\Bundle\DataHubBundle\Event\GraphQL\AssetMetadataEvents;
use Pimcore\Bundle\DataHubBundle\GraphQL\ElementDescriptor;
use Pimcore\Bundle\DataHubBundle\GraphQL\Exception\ClientSafeException;
use Pimcore\Bundle\DataHubBundle\GraphQL\Traits\ElementTagTrait;
use Pimcore\Bundle\DataHubBundle\GraphQL\Traits\ServiceTrait;
use Pimcore\Bundle\DataHubBundle\WorkspaceHelper;
use Pimcore\Event\Model\AssetEvent;
use Pimcore\Model\Asset;
use Pimcore\Model\Version;
use Symfony\Component\EventDispatcher\EventDispatcher;

/**
Expand All @@ -44,7 +46,7 @@ final class AssetType
*/
public function resolveTag($value = null, $args = [], $context = [], ?ResolveInfo $resolveInfo = null)
{
$asset = $this->getAssetFromValue($value, $context);
$asset = $this->resolveVersionData($value, $context);

if ($asset) {
$result = $this->getTags('asset', $asset->getId());
Expand All @@ -67,7 +69,8 @@ public function resolveTag($value = null, $args = [], $context = [], ?ResolveInf
*/
public function resolveMetadata($value = null, $args = [], $context = [], ?ResolveInfo $resolveInfo = null)
{
$asset = $this->getAssetFromValue($value, $context);
$asset = $this->resolveVersionData($value, $context);

$metadata = $asset?->getMetadata(raw: true);
if (!$metadata) {
return null;
Expand Down Expand Up @@ -130,7 +133,8 @@ public function resolveMetadata($value = null, $args = [], $context = [], ?Resol
*/
public function resolveEmbeddedMetaInfo($value = null, $args = [], $context = [], ?ResolveInfo $resolveInfo = null)
{
$asset = $this->getAssetFromValue($value, $context);
$asset = $this->resolveVersionData($value, $context);

if (!$asset) {
return null;
}
Expand All @@ -153,7 +157,8 @@ public function resolveEmbeddedMetaInfo($value = null, $args = [], $context = []
*/
public function resolvePath($value = null, $args = [], $context = [], ?ResolveInfo $resolveInfo = null)
{
$asset = $this->getAssetFromValue($value, $context);
$asset = $this->resolveVersionData($value, $context);

$thumbNailConfig = $args['thumbnail'] ?? null;
$thumbNailFormat = $args['format'] ?? null;
$deferred = $args['deferred'] ?? false;
Expand All @@ -177,7 +182,8 @@ public function resolvePath($value = null, $args = [], $context = [], ?ResolveIn
*/
public function resolveData($value = null, $args = [], $context = [], ?ResolveInfo $resolveInfo = null)
{
$asset = $this->getAssetFromValue($value, $context);
$asset = $this->resolveVersionData($value, $context);

$thumbNailConfig = $args['thumbnail'] ?? null;
$thumbNailFormat = $args['format'] ?? null;
$deferred = $args['deferred'] ?? false;
Expand All @@ -202,7 +208,8 @@ public function resolveData($value = null, $args = [], $context = [], ?ResolveIn
*/
public function resolveSrcSet($value = null, $args = [], $context = [], ?ResolveInfo $resolveInfo = null)
{
$asset = $this->getAssetFromValue($value, $context);
$asset = $this->resolveVersionData($value, $context);

$thumbNailConfig = $args['thumbnail'] ?? null;
$thumbNailFormat = $args['format'] ?? null;
$deferred = $args['deferred'] ?? null;
Expand Down Expand Up @@ -238,6 +245,8 @@ public function resolveSrcSet($value = null, $args = [], $context = [], ?Resolve
*/
public function resolveResolutions($value = null, $args = [], $context = [], ?ResolveInfo $resolveInfo = null)
{
$asset = $this->resolveVersionData($value, $context);

$types = $args['types'];
$thumbnail = $value['url'] ?? null;

Expand Down Expand Up @@ -271,7 +280,6 @@ public function resolveResolutions($value = null, $args = [], $context = [], ?Re
$assetFieldHelper = $this->getGraphQLService()->getAssetFieldHelper();

/** @var Asset\Image $asset */
$asset = $this->getAssetFromValue($value, $context);
$thumbnail = $assetFieldHelper->getAssetThumbnail($asset, $thumbnailName, $thumbnailFormat);
if (isset($thumbnail)) {
$thumbnailConfig = $thumbnail->getConfig();
Expand All @@ -292,6 +300,32 @@ public function resolveResolutions($value = null, $args = [], $context = [], ?Re
return [];
}

/**
* @throws Exception
*/
private function resolveVersionData($value = null, $context = [])
{
$versionId = null;

if (is_array($value) && isset($value['versionRequest'])) {
$versionId = $value['versionRequest'];
} elseif (is_object($value) && isset($value->versionRequest)) {
$versionId = $value->versionRequest;
}

if ($versionId !== null) {
$version = Version::getById($versionId);
$versionData = $version->getData();
if (!$versionData) {
throw new ClientSafeException("Failed to load version data for version '{$versionId}'.");
}

return $version->getData();
} else {
return $this->getAssetFromValue($value, $context);
}
}

/**
* @param ElementDescriptor|null $value
* @param array $args
Expand All @@ -303,9 +337,11 @@ public function resolveResolutions($value = null, $args = [], $context = [], ?Re
*/
public function resolveDimensions($value = null, $args = [], $context = [], ?ResolveInfo $resolveInfo = null)
{

$asset = $this->resolveVersionData($value, $context);

if ($value instanceof ElementDescriptor) {
$thumbnailName = $args['thumbnail'] ?? null;
$asset = $this->getAssetFromValue($value, $context);

if ($asset instanceof Asset\Video) {
$width = $asset->getCustomSetting('videoWidth');
Expand Down Expand Up @@ -354,12 +390,12 @@ public function resolveDimensions($value = null, $args = [], $context = [], ?Res
*/
public function resolveDuration(ElementDescriptor | null $value = null, array $context = []): ?float
{
$asset = $this->resolveVersionData($value, $context);

if (!$value instanceof ElementDescriptor) {
return null;
}

$asset = $this->getAssetFromValue($value, $context);

if (!$asset instanceof Asset\Video) {
return null;
}
Expand All @@ -372,7 +408,8 @@ public function resolveDuration(ElementDescriptor | null $value = null, array $c
*/
public function resolveVersion($value = null, $args = [], $context = [], ?ResolveInfo $resolveInfo = null)
{
$asset = $this->getAssetFromValue($value, $context);
$asset = $this->resolveVersionData($value, $context);

if ($asset) {
foreach (array_reverse($asset->getVersions()) as $version) {
if ($asset->getModificationDate() === $version->getDate()) {
Expand All @@ -390,7 +427,8 @@ public function resolveVersion($value = null, $args = [], $context = [], ?Resolv
public function resolveModificationDate(
ElementDescriptor $value
): ?string {
$asset = $this->getAssetFromValue($value, []);
$asset = $this->resolveVersionData($value);

if (!$asset) {
return null;
}
Expand Down
62 changes: 60 additions & 2 deletions src/GraphQL/Resolver/QueryType.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@
use Pimcore\Bundle\DataHubBundle\GraphQL\Traits\ServiceTrait;
use Pimcore\Bundle\DataHubBundle\WorkspaceHelper;
use Pimcore\Db;
use Pimcore\Logger;
use Pimcore\Model\DataObject\AbstractObject;
use Pimcore\Model\DataObject\ClassDefinition;
use Pimcore\Model\DataObject\Listing;
use Pimcore\Model\DataObject\Service;
use Pimcore\Model\Translation;
use Pimcore\Model\Version;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

final class QueryType
Expand Down Expand Up @@ -161,7 +163,19 @@ public function resolveDocumentGetter($value = null, $args = [], $context = [],
$this->getGraphQlService()->getLocaleService()->setLocale($args['defaultLanguage']);
}

$documentElement = $this->getElementByTypeAndIdOrPath($args, 'document');
$configuration = $context['configuration'];
if ($configuration->disableVersionedRequests() && isset($args['version'])) {
unset($args['version']);
}

$documentElement = null;

if (isset($args['version'])) {
$version = Version::getById($args['version']);
$documentElement = $version->getData();
} else {
$documentElement = $this->getElementByTypeAndIdOrPath($args, 'document');
}

if (!$documentElement) {
return null;
Expand Down Expand Up @@ -200,6 +214,11 @@ public function resolveAssetGetter($value = null, $args = [], $context = [], ?Re
return null;
}

$configuration = $context['configuration'];
if ($configuration->disableVersionedRequests() && isset($args['version'])) {
unset($args['version']);
}

if (!$this->omitPermissionCheck) {
if (!WorkspaceHelper::checkPermission($assetElement, 'read')) {
return null;
Expand Down Expand Up @@ -246,6 +265,37 @@ public function resolveTranslationGetter(mixed $value = null, array $args = [],
);
}

/**
* @throws ClientSafeException
*/
private function resolveVersionObject($args, $currentObject)
{
if (!isset($args['version'])) {
return $currentObject;
}

if (!isset($args['id'])) {
throw new ClientSafeException('Version query requires object id to be set');
}

$versionId = (int)$args['version'];
$version = Version::getById($versionId);

if (!$version || $version->getCid() !== $currentObject->getId()) {
throw new ClientSafeException("Version with id '{$versionId}' not found for object with id "
. "'{$currentObject->getId()}'.");
}

$versionData = $version->getData();
if (!$versionData) {
throw new ClientSafeException("Failed to load version data for version '{$versionId}'.");
}

Logger::debug('Version data loaded successfully for version: ' . $versionId);

return $versionData;
}

/**
* @param ElementDescriptor|null $value
* @param array $args
Expand All @@ -260,6 +310,11 @@ public function resolveObjectGetter($value = null, $args = [], $context = [], ?R
$isIdSet = $args['id'] ?? false;
$isFullpathSet = $args['fullpath'] ?? false;

$configuration = $context['configuration'];
if ($configuration->disableVersionedRequests() && isset($args['version'])) {
unset($args['version']);
}

if (!$isIdSet && !$isFullpathSet) {
throw new ClientSafeException('object id or fullpath expected');
}
Expand Down Expand Up @@ -296,7 +351,10 @@ public function resolveObjectGetter($value = null, $args = [], $context = [], ?R

throw new ClientSafeException($errorMessage);
}
$object = $objectList[0];

$currentObject = $objectList[0];

$object = $this->resolveVersionObject($args, $currentObject);

if (!$this->omitPermissionCheck) {
if (!WorkspaceHelper::checkPermission($object, 'read')) {
Expand Down
10 changes: 9 additions & 1 deletion src/Resources/public/js/configuration/graphql/configItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,13 @@ pimcore.plugin.datahub.configuration.graphql.configItem = Class.create(pimcore.e
value: this.data.security ? this.data.security.skipPermissionCheck : ""
});

let disableVersionedRequests = new Ext.form.Checkbox({
fieldLabel: t('plugin_pimcore_datahub_disable_versioned_requests'),
labelWidth: 200,
name: "disableVersionedRequests",
value: this.data.security ? this.data.security.disableVersionedRequests : ""
});

this.securityForm = new Ext.form.FormPanel({
bodyStyle: "padding:10px;",
autoScroll: true,
Expand Down Expand Up @@ -260,7 +267,8 @@ pimcore.plugin.datahub.configuration.graphql.configItem = Class.create(pimcore.e
readOnly: true,
disabled: true
},
skipPermissionCheck
skipPermissionCheck,
disableVersionedRequests
]
});

Expand Down
1 change: 1 addition & 0 deletions src/Resources/translations/admin.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ plugin_pimcore_datahub_graphql_special_translation_listing: "Translation Listing
plugin_pimcore_datahub_graphql_special_translation: "Translation"
read: "Read"
plugin_pimcore_datahub_skip_permission_check: "Skip Permission Check"
plugin_pimcore_datahub_disable_versioned_requests: "Disabled Versioned Requests"
plugin_pimcore_datahub_configpanel_permissions: "Permissions"
plugin_pimcore_datahub_graphql_permissions_roles: "Role Permissions"
plugin_pimcore_datahub_graphql_permissions_users: "User Permissions"
Expand Down