Skip to content

Commit

Permalink
3208: Cleaned up implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
tuj committed Dec 18, 2024
1 parent c59f5bd commit b6c052b
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 147 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ REDIS_CACHE_DSN=redis://redis:6379/0
###< redis ###

###> Calendar Api Feed Source ###
# See docs/calendar-api-feed.md for variable explainations.
# See docs/feed/calendar-api-feed.md for variable explainations.
CALENDAR_API_FEED_SOURCE_LOCATION_ENDPOINT=
CALENDAR_API_FEED_SOURCE_RESOURCE_ENDPOINT=
CALENDAR_API_FEED_SOURCE_EVENT_ENDPOINT=
Expand Down
11 changes: 11 additions & 0 deletions src/Feed/OutputModel/ConfigOption.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace App\Feed\OutputModel;

class ConfigOption {
public function __construct(
public readonly string $id,
public readonly string $title,
public readonly string $value
) {}
}
132 changes: 18 additions & 114 deletions src/Feed/SourceType/Colibo/ApiClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,30 @@ public function __construct(
*
* @return mixed
*/
public function getFeedEntriesNews(FeedSource $feedSource, array $recipients, array $publishers): mixed
public function getFeedEntriesNews(FeedSource $feedSource, array $recipients = [], array $publishers = []): mixed
{
try {
$client = $this->getApiClient($feedSource);

$response = $client->request('GET', '/api/feedentries/news', [
$options = [
'headers' => [
'Content-Type' => 'application/json',
],
'query' => [
'getQuery.recipients' => $recipients,
'recipients' => array_map(fn($recipient) => (object) [
'Id' => $recipient,
'Type' => 'Group'
], $recipients),
'publishers' => array_map(fn($publisher) => (object) [
'Id' => $publisher,
'Type' => 'Group'
], $publishers),
],
]);
];

$response = $client->request('GET', '/api/feedentries/news', $options);

return json_decode($response->getContent(), false, 512, JSON_THROW_ON_ERROR);
} catch (ColiboException $exception) {
return [];
} catch (\Throwable $throwable) {
$this->logger->error('{code}: {message}', [
'code' => $throwable->getCode(),
Expand Down Expand Up @@ -94,47 +101,6 @@ public function getSearchGroups(FeedSource $feedSource, string $type = 'WorkGrou
}

return $groups;
} catch (ColiboException $exception) {
return [];
} catch (\Throwable $throwable) {
$this->logger->error('{code}: {message}', [
'code' => $throwable->getCode(),
'message' => $throwable->getMessage(),
]);

return [];
}
}

/**
* @param FeedSource $feedSource
*
* @return array
*/
public function getFeedEntryPublishersGroups(FeedSource $feedSource): array
{
try {
$client = $this->getApiClient($feedSource);

$response = $client->request('GET', '/api/feedentries/publishers/groups', [
'query' => ['groupType' => 'Department'],
]);

$groups = [];
$childGroupIds = [];
foreach ($response->toArray() as $group) {
$groups[] = $group;

if (isset($group['hasChildren']) && $group['hasChildren']) {
$childGroupIds[] = $group['id'];
}
}

$this->getFeedEntryPublishersGroupsChildren($feedSource, $childGroupIds, $groups);

return $groups;
} catch (ColiboException $exception) {
return [];
} catch (\Throwable $throwable) {
$this->logger->error('{code}: {message}', [
'code' => $throwable->getCode(),
Expand Down Expand Up @@ -170,64 +136,6 @@ private function getSearchGroupsPage(FeedSource $feedSource, string $type, int $
} catch (ColiboException $exception) {
throw $exception;
} catch (\Throwable $throwable) {
$this->logger->error('{code}: {message}', [
'code' => $throwable->getCode(),
'message' => $throwable->getMessage(),
]);

throw new ColiboException($throwable->getMessage(), $throwable->getCode(), $throwable);
}
}

/**
* Get
*
* @param FeedSource $feedSource
* @param array $childGroupIds
* @param array $groups
*
* @return void
*
* @throws ColiboException
*/
private function getFeedEntryPublishersGroupsChildren(FeedSource $feedSource, array $childGroupIds, array &$groups): void
{
try {
$client = $this->getApiClient($feedSource);

$batches = array_chunk($childGroupIds, self::BATCH_SIZE);

foreach ($batches as $batch) {
// @see https://symfony.com/doc/current/http_client.html#concurrent-requests
$responses = [];
foreach ($batch as $childGroupId) {
$uri = sprintf('/api/feedentries/publishers/groups/%d/children', $childGroupId);
$responses[] = $client->request('GET', $uri, []);
}

$childGroupIds = [];
foreach ($responses as $response) {
foreach ($response->toArray() as $group) {
$groups[] = $group;

if (isset($group['hasChildren']) && $group['hasChildren']) {
$childGroupIds[] = $group['id'];
}
}
}
}

if (!empty($childGroupIds)) {
$this->getFeedEntryPublishersGroupsChildren($feedSource, $childGroupIds, $groups);
}
} catch (ColiboException $exception) {
throw $exception;
} catch (\Throwable $throwable) {
$this->logger->error('{code}: {message}', [
'code' => $throwable->getCode(),
'message' => $throwable->getMessage(),
]);

throw new ColiboException($throwable->getMessage(), $throwable->getCode(), $throwable);

Check failure on line 139 in src/Feed/SourceType/Colibo/ApiClient.php

View workflow job for this annotation

GitHub Actions / Psalm (PHP 8.3)

PossiblyInvalidArgument

src/Feed/SourceType/Colibo/ApiClient.php:139:65: PossiblyInvalidArgument: Argument 2 of App\Feed\SourceType\Colibo\ColiboException::__construct expects int, but possibly different type int|string provided (see https://psalm.dev/092)
}
}
Expand All @@ -252,7 +160,7 @@ private function getApiClient(FeedSource $feedSource): HttpClientInterface
$secrets = new SecretsDTO($feedSource);
$this->apiClients[$id] = HttpClient::createForBaseUri($secrets->apiBaseUri)->withOptions([
'headers' => [
'Authorization' => 'Bearer ' . $this->fetchColiboToken($feedSource),
'Authorization' => 'Bearer ' . $this->fetchToken($feedSource),
'Accept' => 'application/json',
],
]);
Expand All @@ -261,15 +169,15 @@ private function getApiClient(FeedSource $feedSource): HttpClientInterface
}

/**
* Get Colibo auth token for the given FeedSource
* Get the auth token for the given FeedSource
*
* @param FeedSource $feedSource
*
* @return string
*
* @throws ColiboException
*/
private function fetchColiboToken(FeedSource $feedSource): string
private function fetchToken(FeedSource $feedSource): string
{
$id = ColiboFeedType::getIdKey($feedSource);

Expand All @@ -287,6 +195,7 @@ private function fetchColiboToken(FeedSource $feedSource): string
$response = $client->request('POST', '/auth/oauth2/connect/token', [
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
'Accept' => 'application/json',
],
'body' => [
'grant_type' => self::GRANT_TYPE,
Expand All @@ -308,15 +217,10 @@ private function fetchColiboToken(FeedSource $feedSource): string
$cacheItem->expiresAfter($expireSeconds);
$this->feedsCache->save($cacheItem);

Check failure on line 218 in src/Feed/SourceType/Colibo/ApiClient.php

View workflow job for this annotation

GitHub Actions / Psalm (PHP 8.3)

UndefinedInterfaceMethod

src/Feed/SourceType/Colibo/ApiClient.php:218:36: UndefinedInterfaceMethod: Method Symfony\Contracts\Cache\CacheInterface::save does not exist (see https://psalm.dev/181)
} catch (\Throwable $throwable) {
$this->logger->error('{code}: {message}', [
'code' => $throwable->getCode(),
'message' => $throwable->getMessage(),
]);

throw new ColiboException($throwable->getMessage(), $throwable->getCode(), $throwable);

Check failure on line 220 in src/Feed/SourceType/Colibo/ApiClient.php

View workflow job for this annotation

GitHub Actions / Psalm (PHP 8.3)

PossiblyInvalidArgument

src/Feed/SourceType/Colibo/ApiClient.php:220:69: PossiblyInvalidArgument: Argument 2 of App\Feed\SourceType\Colibo\ColiboException::__construct expects int, but possibly different type int|string provided (see https://psalm.dev/092)
}
}

return $token;
}
}
}
99 changes: 68 additions & 31 deletions src/Feed/SourceType/Colibo/ColiboFeedType.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
use App\Entity\Tenant\FeedSource;
use App\Feed\FeedOutputModels;
use App\Feed\FeedTypeInterface;
use App\Feed\OutputModel\ConfigOption;
use App\Service\FeedService;
use FeedIo\Feed\Item;
use FeedIo\Feed\Node\Category;
use Psr\Cache\CacheItemInterface;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Uid\Ulid;
Expand All @@ -36,29 +38,28 @@ public function __construct(

public function getAdminFormOptions(FeedSource $feedSource): array
{
$feedEntryPublishers = $this->feedService->getFeedSourceConfigUrl($feedSource, 'FeedEntryPublishers');
$feedEntryRecipients = $this->feedService->getFeedSourceConfigUrl($feedSource, 'FeedEntryRecipients');
$feedEntryRecipients = $this->feedService->getFeedSourceConfigUrl($feedSource, 'recipients');
$feedEntryPublishers = $this->feedService->getFeedSourceConfigUrl($feedSource, 'publishers');

// @TODO: Translation.
return [
[
'key' => 'colibo-feed-entry-publishers-selector',
'key' => 'colibo-feed-type-publishers-selector',
'input' => 'multiselect-from-endpoint',
'endpoint' => $feedEntryPublishers,
'name' => 'colibo-feed-entry-publishers',
'label' => 'Vælg afsender grupper for de nyheder du ønsker at vise',
'helpText' => 'Her vælger du hvilke afsender grupper der skal hentes nyheder fra.',
'formGroupClasses' => 'col-md-6 mb-3',
'endpoint' => $feedEntryRecipients,
'name' => 'recipients',
'label' => 'Modtagergrupper',
'helpText' => 'Vælg hvilke grupper, der skal hentes nyheder fra.',
'formGroupClasses' => 'mb-3',
],
[
'key' => 'colibo-feed-entry-recipients-selector',
'key' => 'colibo-feed-type-publishers-selector',
'input' => 'multiselect-from-endpoint',
'endpoint' => $feedEntryRecipients,
'name' => 'colibo-feed-entry-recipients',
'label' => 'Vælg modtager grupper for de nyheder du ønsker at vise',
'helpText' => 'Her vælger du hvilke afsender grupper der skal hentes nyheder fra.',
'formGroupClasses' => 'col-md-6 mb-3',
],
'endpoint' => $feedEntryPublishers,
'name' => 'publishers',
'label' => 'Afsendergrupper',
'helpText' => 'Vælg afsendergrupper for at begrænse hvilke afsenderes nyheder, der vises fra modtagergruppen. Hvis den ikke er valgt vises alle nyheder fra modtagergruppen.',
'formGroupClasses' => 'mb-3',
]
];
}

Expand All @@ -67,13 +68,21 @@ public function getData(Feed $feed): array
$configuration = $feed->getConfiguration();
$baseUri = $feed->getFeedSource()->getSecrets()['api_base_uri'];

Check failure on line 69 in src/Feed/SourceType/Colibo/ColiboFeedType.php

View workflow job for this annotation

GitHub Actions / Psalm (PHP 8.3)

PossiblyNullArrayAccess

src/Feed/SourceType/Colibo/ColiboFeedType.php:69:20: PossiblyNullArrayAccess: Cannot access array value on possibly null variable of type array<array-key, mixed>|null (see https://psalm.dev/079)

Check failure on line 69 in src/Feed/SourceType/Colibo/ColiboFeedType.php

View workflow job for this annotation

GitHub Actions / Psalm (PHP 8.3)

PossiblyNullReference

src/Feed/SourceType/Colibo/ColiboFeedType.php:69:44: PossiblyNullReference: Cannot call method getSecrets on possibly null value (see https://psalm.dev/083)

$entries = $this->apiClient->getFeedEntriesNews($feed->getFeedSource(), $configuration['colibo-feed-entry-recipients'], $configuration['colibo-feed-entry-publishers']);

$result = [
'title' => 'Colibo Feed',
'title' => 'Intranet',
'entries' => [],
];

$recipients = $configuration['recipients'] ?? null;
$publishers = $configuration['publishers'] ?? [];

if (null === $recipients) {
return $result;
}

$entries = $this->apiClient->getFeedEntriesNews($feed->getFeedSource(), $recipients, $publishers);

Check failure on line 83 in src/Feed/SourceType/Colibo/ColiboFeedType.php

View workflow job for this annotation

GitHub Actions / Psalm (PHP 8.3)

PossiblyNullArgument

src/Feed/SourceType/Colibo/ColiboFeedType.php:83:57: PossiblyNullArgument: Argument 1 of App\Feed\SourceType\Colibo\ApiClient::getFeedEntriesNews cannot be null, possibly null value provided (see https://psalm.dev/078)


foreach ($entries as $entry) {
$item = new Item();
$item->setTitle($entry->fields->title);
Expand Down Expand Up @@ -139,25 +148,26 @@ public function getData(Feed $feed): array
public function getConfigOptions(Request $request, FeedSource $feedSource, string $name): ?array
{
switch ($name) {
case 'FeedEntryPublishers':
case 'FeedEntryRecipients':
case 'recipients':
case 'publishers':
$id = self::getIdKey($feedSource);

/** @var CacheItemInterface $cacheItem */
$cacheItem = $this->feedsCache->getItem('colibo_feed_entry_publishers_groups_'.$id);
$cacheItem = $this->feedsCache->getItem('colibo_feed_entry_groups_'.$id);

if ($cacheItem->isHit()) {
$groups = $cacheItem->get();
} else {
$groups = $this->apiClient->getSearchGroups($feedSource);

$groups = array_map(fn (array $item) => [
'id' => Ulid::generate(),
'title' => sprintf('%s (%d)', $item['model']['title'], $item['model']['id']),
'value' => (string) $item['model']['id'],
], $groups);
$groups = array_map(fn (array $item) =>
new ConfigOption(
Ulid::generate(),
sprintf('%s (%d)', $item['model']['title'], $item['model']['id']),
(string) $item['model']['id']
), $groups);

usort($groups, fn ($a, $b) => strcmp($a['title'], $b['title']));
usort($groups, fn ($a, $b) => strcmp($a->title, $b->title));

$cacheItem->set($groups);
$cacheItem->expiresAfter(self::CACHE_TTL);
Expand All @@ -173,12 +183,23 @@ public function getConfigOptions(Request $request, FeedSource $feedSource, strin

public function getRequiredSecrets(): array
{
return ['client_id', 'client_secret'];
return [
'api_base_uri' => [
'type' => 'string',
'exposeValue' => true,
],
'client_id' => [
'type' => 'string'
],
'client_secret' => [
'type' => 'string'
],
];
}

public function getRequiredConfiguration(): array
{
return ['api_base_uri'];
return ['recipients', 'publishers'];
}

public function getSupportedFeedOutputType(): string
Expand All @@ -188,7 +209,23 @@ public function getSupportedFeedOutputType(): string

public function getSchema(): array
{
return [];
return [
'$schema' => 'http://json-schema.org/draft-04/schema#',
'type' => 'object',
'properties' => [
'api_base_uri' => [
'type' => 'string',
'format' => 'uri',
],
'client_id' => [
'type' => 'string',
],
'client_secret' => [
'type' => 'string',
],
],
'required' => ['api_base_uri', 'client_id', 'client_secret'],
];
}

public static function getIdKey(FeedSource $feedSource): string
Expand Down
Loading

0 comments on commit b6c052b

Please sign in to comment.