From 35cf592a863efcfb43bc164df1696ffbb481a2fc Mon Sep 17 00:00:00 2001 From: Daniel Kestler <> Date: Thu, 8 Sep 2022 08:00:43 +0200 Subject: [PATCH 1/4] FEATURE: Implement actual Canto tags to be used as Neos tags --- Classes/AssetSource/CantoAssetProxyQuery.php | 4 ++ Classes/Command/CantoCommandController.php | 56 ++++++++++++++++++++ Classes/Service/CantoClient.php | 25 +++++++++ Configuration/Settings.yaml | 7 +++ 4 files changed, 92 insertions(+) diff --git a/Classes/AssetSource/CantoAssetProxyQuery.php b/Classes/AssetSource/CantoAssetProxyQuery.php index 1b58e0a..e82d663 100644 --- a/Classes/AssetSource/CantoAssetProxyQuery.php +++ b/Classes/AssetSource/CantoAssetProxyQuery.php @@ -248,6 +248,10 @@ public function prepareTagQuery(): void } } } + + if (!empty($this->mapping['tags'])) { + $this->tagQuery .= '&tags="' . $this->activeTag->getLabel() . '"'; + } } /** diff --git a/Classes/Command/CantoCommandController.php b/Classes/Command/CantoCommandController.php index 334ed1c..6376a3f 100644 --- a/Classes/Command/CantoCommandController.php +++ b/Classes/Command/CantoCommandController.php @@ -207,4 +207,60 @@ public function importCustomFieldsAsCollectionsAndTagsCommand(string $assetSourc !$quiet && $this->outputLine('Import done.'); } + + /** + * Import Canto Tags as Tags + * + * @param string $assetSourceIdentifier Name of the canto asset source + * @param bool $quiet If set, only errors will be displayed. + * @throws GuzzleException + * @throws IllegalObjectTypeException + * @throws OAuthClientException + * @throws StopCommandException + * @throws AuthenticationFailedException + */ + public function importTagsCommand(string $assetSourceIdentifier = CantoAssetSource::ASSET_SOURCE_IDENTIFIER, bool $quiet = true): void + { + !$quiet && $this->outputLine('Importing tags via Canto API'); + + $tagMapping = $this->mapping['tags']; + if (empty($tagMapping)) { + $this->outputLine('No tags mapping configured'); + $this->quit(1); + } + + try { + /** @var CantoAssetSource $cantoAssetSource */ + $cantoAssetSource = $this->assetSourceService->getAssetSources()[$assetSourceIdentifier]; + $cantoClient = $cantoAssetSource->getCantoClient(); + $cantoClient->allowClientCredentialsAuthentication(true); + } catch (\Exception) { + $this->outputLine('Canto client could not be created'); + $this->quit(1); + } + + $tags = $cantoClient->getFacetValues($tagMapping['field']); + $relevantTags = array_chunk($tags, $tagMapping['limit']); + foreach ($relevantTags[0] as $tagLabel) { + + if (!empty($tagMapping['include']) && !in_array($tagLabel, $tagMapping['include'], true)) { + continue; + } + if (!empty($tagMapping['exclude']) && in_array($tagLabel, $tagMapping['exclude'], true)) { + continue; + } + + $tag = $this->tagRepository->findOneByLabel($tagLabel); + + if ($tag === null) { + $tag = new Tag($tagLabel); + $this->tagRepository->add($tag); + !$quiet && $this->outputLine(' + %s', [$tagLabel]); + } + + !$quiet && $this->outputLine(); + } + + !$quiet && $this->outputLine('Import done.'); + } } diff --git a/Classes/Service/CantoClient.php b/Classes/Service/CantoClient.php index 6aa5b7f..21be234 100644 --- a/Classes/Service/CantoClient.php +++ b/Classes/Service/CantoClient.php @@ -240,6 +240,31 @@ public function getCustomFields(): array return []; } + /** + * @throws AuthenticationFailedException + * @throws GuzzleException + * @throws HttpException + * @throws IdentityProviderException + * @throws MissingActionNameException + * @throws MissingClientSecretException + * @throws OAuthClientException + * @todo perhaps cache the result + */ + public function getFacetValues(string $facetName): array + { + $response = $this->sendAuthenticatedRequest('search'); + if ($response->getStatusCode() === 200) { + $result = json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR); + + foreach ($result['facets'] as $facet) { + if ($facet['name'] === $facetName) { + return $facet['value']; + } + } + } + return []; + } + /** * @throws AuthenticationFailedException * @throws GuzzleException diff --git a/Configuration/Settings.yaml b/Configuration/Settings.yaml index 113c791..8e97b3b 100644 --- a/Configuration/Settings.yaml +++ b/Configuration/Settings.yaml @@ -1,8 +1,15 @@ Flownative: Canto: + # At the moment, this is "either or", so use custom fields or tags for mapping, not both mapping: # map "Custom Fields" from Canto to Neos customFields: [] + # map "Tags" from Canto to Neos + tags: + field: 'tags' + limit: 20 + include: [] + exclude: ['Untagged'] webhook: pathPrefix: '/flownative-canto/webhook/' # A token that can be used to secure webhook invocations; used only if set From 7d946fcb804a8670b325f21ce7353f905867808f Mon Sep 17 00:00:00 2001 From: Daniel Kestler <> Date: Fri, 23 Sep 2022 11:40:26 +0200 Subject: [PATCH 2/4] Bugfix remove tags output for now --- Classes/AssetSource/CantoAssetProxy.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Classes/AssetSource/CantoAssetProxy.php b/Classes/AssetSource/CantoAssetProxy.php index 97ab72b..bfe4828 100644 --- a/Classes/AssetSource/CantoAssetProxy.php +++ b/Classes/AssetSource/CantoAssetProxy.php @@ -202,7 +202,8 @@ public function getLocalAssetIdentifier(): ?string public function getTags(): array { - return $this->tags; + return []; + // return $this->tags; } public function isImported(): bool From 1182e36ccdb381219285b45819dc0cc60fc0a32a Mon Sep 17 00:00:00 2001 From: Daniel Kestler <> Date: Fri, 23 Sep 2022 11:46:51 +0200 Subject: [PATCH 3/4] Bugfix remove tag in object assignment --- Classes/AssetSource/CantoAssetProxy.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Classes/AssetSource/CantoAssetProxy.php b/Classes/AssetSource/CantoAssetProxy.php index bfe4828..e33cce2 100644 --- a/Classes/AssetSource/CantoAssetProxy.php +++ b/Classes/AssetSource/CantoAssetProxy.php @@ -81,7 +81,6 @@ public static function fromJsonObject(stdClass $jsonObject, CantoAssetSource $as $assetProxy->lastModified = \DateTime::createFromFormat('YmdHisv', $jsonObject->default->{'Date modified'}); $assetProxy->fileSize = (int)$jsonObject->size; $assetProxy->mediaType = MediaTypes::getMediaTypeFromFilename($jsonObject->name); - $assetProxy->tags = $jsonObject->tag ?? []; $assetProxy->iptcProperties['CopyrightNotice'] = $jsonObject->copyright ?? ($jsonObject->default->Copyright ?? ''); From 18dd39a4890fe91a694e0351b45bfa19e9efda45 Mon Sep 17 00:00:00 2001 From: Daniel Kestler <> Date: Wed, 19 Oct 2022 10:48:36 +0200 Subject: [PATCH 4/4] Bugfix: OAuth authorization flow not working --- Classes/Service/CantoClient.php | 2 +- Resources/Private/Templates/Canto/Index.html | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Classes/Service/CantoClient.php b/Classes/Service/CantoClient.php index 21be234..15a29a2 100644 --- a/Classes/Service/CantoClient.php +++ b/Classes/Service/CantoClient.php @@ -148,7 +148,7 @@ private function getCurrentUri(): UriInterface private function redirectToUri(string $uri): void { header('Location: ' . $uri); - throw new StopActionException('Canto login required', 1625222167); + throw new AuthenticationFailedException('Canto login required', 1625222167); } /** diff --git a/Resources/Private/Templates/Canto/Index.html b/Resources/Private/Templates/Canto/Index.html index c3611ed..5e7fc5c 100644 --- a/Resources/Private/Templates/Canto/Index.html +++ b/Resources/Private/Templates/Canto/Index.html @@ -2,7 +2,7 @@

{neos:backend.translate(id: 'cantoConnectionSettings', source: 'Main', package: 'Flownative.Canto')}


- +
@@ -19,13 +19,17 @@

{neos:backend.translate(id: 'cantoConnectionSettings', source: 'Main', packa {user.firstName} {user.lastName} {user.email} +

-

{authenticationError}

+
+

{authenticationError}

+
+