Skip to content

Commit

Permalink
Merge pull request #16 from pKallert/feature/tagsCommand
Browse files Browse the repository at this point in the history
FEATURE: Import custom fields as tags and collections
  • Loading branch information
kdambekalns committed Oct 26, 2021
2 parents 9e1b844 + 51b4c28 commit 376138d
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 18 deletions.
8 changes: 1 addition & 7 deletions Classes/AssetSource/CantoAssetProxyQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,6 @@ public function getArrayResult(): array
* @param int $limit
* @param array $orderings
* @return Response
* @throws AuthenticationFailedException
* @throws IdentityProviderException
* @throws OAuthClientException
* @throws GuzzleException
*/
Expand Down Expand Up @@ -296,8 +294,6 @@ private function sendSearchRequest(int $limit, array $orderings): Response

/**
* @return void
* @throws AuthenticationFailedException
* @throws IdentityProviderException
* @throws OAuthClientException
* @throws GuzzleException
*/
Expand Down Expand Up @@ -331,8 +327,6 @@ public function prepareTagQuery(): void

/**
* @return void
* @throws AuthenticationFailedException
* @throws IdentityProviderException
* @throws OAuthClientException
* @throws GuzzleException
*/
Expand All @@ -343,7 +337,7 @@ public function prepareUntaggedQuery(): void
if ($this->activeAssetCollection !== null) {
$cantoCustomFields = $this->assetSource->getCantoClient()->getCustomFields();
foreach ($cantoCustomFields as $cantoCustomField) {
if ($this->mapping['customFields'][$cantoCustomField->id]['asAssetCollection'] && $cantoCustomField->name === $this->activeAssetCollection->getTitle()) {
if (array_key_exists($cantoCustomField->id, $this->mapping['customFields']) && $this->mapping['customFields'][$cantoCustomField->id]['asAssetCollection'] && $cantoCustomField->name === $this->activeAssetCollection->getTitle()) {
$this->tagQuery .= '&' . $cantoCustomField->id . '.keyword="__null__"';
}
}
Expand Down
1 change: 0 additions & 1 deletion Classes/AssetSource/CantoAssetProxyRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ public function __construct(CantoAssetSource $assetSource)
* @return AssetProxyInterface
* @throws AssetNotFoundExceptionInterface
* @throws AssetSourceConnectionExceptionInterface
* @throws AuthenticationFailedException
* @throws AssetNotFoundException
* @throws Exception
*/
Expand Down
6 changes: 1 addition & 5 deletions Classes/AssetSource/CantoAssetSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@
* source code.
*/

use Flownative\Canto\Exception\AuthenticationFailedException;
use Flownative\Canto\Service\CantoClient;
use GuzzleHttp\Psr7\Uri;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use Neos\Cache\Frontend\StringFrontend;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\ObjectManagement\DependencyInjection\DependencyProxy;
Expand Down Expand Up @@ -238,7 +236,7 @@ public function getDescription(): string
return $this->description;
}

public function getApiBaseUri()
public function getApiBaseUri(): string
{
return $this->apiBaseUri;
}
Expand All @@ -255,8 +253,6 @@ public function getAppSecret(): string

/**
* @return CantoClient
* @throws AuthenticationFailedException
* @throws IdentityProviderException
*/
public function getCantoClient(): CantoClient
{
Expand Down
110 changes: 107 additions & 3 deletions Classes/Command/CantoCommandController.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php
declare(strict_types=1);

namespace Flownative\Canto\Command;

use Flownative\Canto\AssetSource\CantoAssetProxy;
Expand All @@ -8,10 +9,17 @@
use Flownative\Canto\Exception\AccessToAssetDeniedException;
use Flownative\Canto\Exception\AuthenticationFailedException;
use Flownative\Canto\Exception\MissingClientSecretException;
use Flownative\OAuth2\Client\OAuthClientException;
use GuzzleHttp\Exception\GuzzleException;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Cli\CommandController;
use Neos\Flow\Persistence\Exception\IllegalObjectTypeException;
use Neos\Media\Domain\Model\Asset;
use Neos\Media\Domain\Model\AssetCollection;
use Neos\Media\Domain\Model\Tag;
use Neos\Media\Domain\Repository\AssetCollectionRepository;
use Neos\Media\Domain\Repository\AssetRepository;
use Neos\Media\Domain\Repository\TagRepository;
use Neos\Media\Domain\Service\AssetSourceService;

class CantoCommandController extends CommandController
Expand All @@ -28,6 +36,24 @@ class CantoCommandController extends CommandController
*/
protected $assetSourceService;

/**
* @Flow\Inject
* @var TagRepository
*/
protected $tagRepository;

/**
* @Flow\Inject
* @var AssetCollectionRepository
*/
protected $assetCollectionRepository;

/**
* @Flow\InjectConfiguration(path="mapping", package="Flownative.Canto")
* @var array
*/
protected $mapping = [];

/**
* Tag used assets
*
Expand All @@ -43,19 +69,20 @@ public function tagUsedAssetsCommand(string $assetSource = CantoAssetSource::ASS
!$quiet && $this->outputLine('<b>Tagging used assets of asset source "%s" via Canto API:</b>', [$assetSourceIdentifier]);

try {
/** @var CantoAssetSource $cantoAssetSource */
$cantoAssetSource = $this->assetSourceService->getAssetSources()[$assetSourceIdentifier];
$cantoClient = $cantoAssetSource->getCantoClient();
} catch (MissingClientSecretException $e) {
$this->outputLine('<error>Authentication error: Missing client secret</error>');
exit(1);
$this->quit(1);
} catch (AuthenticationFailedException $e) {
$this->outputLine('<error>Authentication error: %s</error>', [$e->getMessage()]);
exit(1);
$this->quit(1);
}

if (!$cantoAssetSource->isAutoTaggingEnabled()) {
$this->outputLine('<error>Auto-tagging is disabled</error>');
exit(1);
$this->quit(1);
}

$assetProxyRepository = $cantoAssetSource->getAssetProxyRepository();
Expand Down Expand Up @@ -109,4 +136,81 @@ public function tagUsedAssetsCommand(string $assetSource = CantoAssetSource::ASS
}
}
}

/**
* Import Canto Custom Fields as Tags and Collections
*
* @param string $assetSourceIdentifier Name of the canto asset source
* @param bool $quiet If set, only errors will be displayed.
* @return void
* @throws OAuthClientException
* @throws GuzzleException
* @throws IllegalObjectTypeException
*/
public function importCustomFieldsAsCollectionsAndTagsCommand(string $assetSourceIdentifier = CantoAssetSource::ASSET_SOURCE_IDENTIFIER, bool $quiet = true): void
{
!$quiet && $this->outputLine('<b>Importing custom fields as tags and asset collections via Canto API</b>');

$customFieldsMapping = $this->mapping['customFields'];
if (empty($customFieldsMapping)) {
$this->outputLine('<error>No custom fields configured for mapping</error>');
$this->quit(1);
}

try {
/** @var CantoAssetSource $cantoAssetSource */
$cantoAssetSource = $this->assetSourceService->getAssetSources()[$assetSourceIdentifier];
$cantoClient = $cantoAssetSource->getCantoClient();
$cantoClient->allowClientCredentialsAuthentication(true);
} catch (\Exception $e) {
$this->outputLine('<error>Canto client could not be created</error>');
$this->quit(1);
}

$cantoCustomFields = $cantoClient->getCustomFields();
foreach ($cantoCustomFields as $cantoCustomField) {
if (array_key_exists($cantoCustomField->id, $customFieldsMapping) && $customFieldsMapping[$cantoCustomField->id]['asAssetCollection']) {
$assetCollection = $this->assetCollectionRepository->findOneByTitle($cantoCustomField->name);

if (!($assetCollection instanceof AssetCollection)) {
$assetCollection = new AssetCollection($cantoCustomField->name);
$this->assetCollectionRepository->add($assetCollection);
!$quiet && $this->outputLine('+ %s', [$cantoCustomField->name]);
} else {
!$quiet && $this->outputLine('= %s', [$cantoCustomField->name]);
}

if ($customFieldsMapping[$cantoCustomField->id]['valuesAsTags'] !== true) {
continue;
}

foreach ($cantoCustomField->values as $cantoCustomFieldValue) {
if (!empty($customFieldsMapping[$cantoCustomField->id]['include']) && !in_array($cantoCustomFieldValue, $customFieldsMapping[$cantoCustomField->id]['include'], true)) {
continue;
}
if (!empty($customFieldsMapping[$cantoCustomField->id]['exclude']) && in_array($cantoCustomFieldValue, $customFieldsMapping[$cantoCustomField->id]['exclude'], true)) {
continue;
}

$tag = $this->tagRepository->findOneByLabel($cantoCustomFieldValue);

if ($tag === null) {
$tag = new Tag($cantoCustomFieldValue);
$this->tagRepository->add($tag);
$assetCollection->addTag($tag);
$this->assetCollectionRepository->update($assetCollection);
!$quiet && $this->outputLine(' + %s', [$cantoCustomFieldValue]);
} elseif (!$assetCollection->getTags()->contains($tag)) {
$assetCollection->addTag($tag);
$this->assetCollectionRepository->update($assetCollection);
!$quiet && $this->outputLine(' ~ %s', [$cantoCustomFieldValue]);
}
}

!$quiet && $this->outputLine();
}
}

!$quiet && $this->outputLine('<success>Import done.</success>');
}
}
2 changes: 1 addition & 1 deletion Classes/Service/CantoClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use Neos\Flow\Mvc\Routing\UriBuilder;
use Neos\Flow\Security\Context;
use Neos\Media\Domain\Model\AssetSource\SupportsSortingInterface;
use Neos\Neos\Domain\Model\User;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;
Expand Down Expand Up @@ -111,7 +112,6 @@ public function allowClientCredentialsAuthentication(bool $allowed): void
private function authenticate(): void
{
$oAuthClient = new CantoOAuthClient($this->serviceName);

if ($this->securityContext->isInitialized()) {
$account = $this->securityContext->getAccount();
$accountAuthorization = $account ? $this->accountAuthorizationRepository->findOneByFlowAccountIdentifier($account->getAccountIdentifier()) : null;
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ $ composer require flownative/neos-canto
using your own domain(!)
5. Note down "App ID", "App Secret" and "Website" of the new key

### Allow client credentials mode for API key
#### Allow client credentials mode for API key

To be able to use the Canto connection from the command line, client credentials
mode must be enabled.
Expand Down

0 comments on commit 376138d

Please sign in to comment.