diff --git a/application/controllers/FeedController.php b/application/controllers/FeedController.php index 4f61058..d2ff2e0 100644 --- a/application/controllers/FeedController.php +++ b/application/controllers/FeedController.php @@ -48,7 +48,7 @@ public function indexAction(): void $this->addTitle($this->translate('Feed'), $controlWrapper); - [$url, $type, $name] = $this->getFeedInfo(); + [$url, $type, $name, $interval] = $this->getFeedInfo(); if ($url === null) { $this->displayError($this->translate('No such feed configured')); @@ -66,7 +66,7 @@ public function indexAction(): void try { $reader = new FeedReader($url, $this->Config(), $type); - $data = $reader->fetch($name); + $data = $reader->fetch($name, $interval); } catch (Exception $ex) { $this->displayError($ex->getMessage()); return; @@ -103,16 +103,16 @@ protected function getFeedInfo(): array $feed = $storage->getFeedByName($name); if ($feed === null) { - return [null, null, null]; + return [null, null, null, null]; } - return [$feed->url, $feed->type, 'feed-' . $feed->name]; + return [$feed->url, $feed->type, 'feed-' . $feed->name, $feed->pollingInterval]; } $url = $this->params->shift('url'); if ($url === null or $url === '') { - return [null, null, null]; + return [null, null, null, null]; } $this->assertPermission('feeds/view/arbitrary'); @@ -120,7 +120,7 @@ protected function getFeedInfo(): array $type = $this->params->shift('type') ?? 'auto'; $name = 'url-' . sha1($url . ':' . $type); - return [$url, FeedType::fromDisplay($type), $name]; + return [$url, FeedType::fromDisplay($type), $name, null]; } /** @@ -140,7 +140,7 @@ public function createAction(): void $this->addTitle($this->translate('Create a new feed')); $storage = StorageFactory::getStorage(); - $form = new FeedForm($storage, null); + $form = new FeedForm($this->Config(), $storage, null); $form->on(Form::ON_SUCCESS, function () { Notification::success($this->translate('Created new feed')); @@ -181,7 +181,7 @@ public function editAction(): void $title = $this->translate('Edit feed'); $this->setTitle($title); - $form = new FeedForm($storage, $feed); + $form = new FeedForm($this->Config(), $storage, $feed); $form->populate([ 'name' => $feed->name, @@ -189,6 +189,7 @@ public function editAction(): void 'description' => $feed->description, 'is_visible' => $feed->isVisible, 'type' => $feed->type->display(), + 'polling_interval' => $feed->pollingInterval, ]); $form->on(Form::ON_SUCCESS, function () { diff --git a/application/controllers/FeedsController.php b/application/controllers/FeedsController.php index 8a025d9..5fcfb46 100644 --- a/application/controllers/FeedsController.php +++ b/application/controllers/FeedsController.php @@ -100,7 +100,7 @@ public function indexAction(): void try { $reader = new FeedReader($feed->url, $this->Config(), $feed->type); - $data = $reader->fetch('feed-' . $feed->name); + $data = $reader->fetch('feed-' . $feed->name, $feed->pollingInterval); $feedsCounter++; } catch (Exception) { $failed[] = $feed->name; diff --git a/application/forms/FeedForm.php b/application/forms/FeedForm.php index 0b5377c..78eb273 100644 --- a/application/forms/FeedForm.php +++ b/application/forms/FeedForm.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Feeds\Forms; +use Icinga\Application\Config; use Icinga\Module\Feeds\FeedCache; use Icinga\Module\Feeds\Parser\FeedType; @@ -24,10 +25,11 @@ class FeedForm extends CompatForm protected ?string $deleteButtonName = null; - // Pattern to valide feed names + // Pattern to validate feed names protected const VALID_NAME = '/^[a-zA-Z0-9\-_\. ]+$/'; public function __construct( + protected Config $config, protected StorageInterface $storage, protected ?FeedDefinition $feed, ) { @@ -98,6 +100,19 @@ protected function assemble(): void ] ); + $cacheDurationInSeconds = $this->config->get('cache', 'duration', 43200); + $this->addElement( + 'number', + 'polling_interval', + [ + 'label' => $this->translate('Polling interval'), + 'description' => $this->translate( + 'How often the feed should be updated from the source (in seconds)' + ), + 'placeholder' => $cacheDurationInSeconds . " (" . $this->translate('inherited from module configuration') . ")", + ] + ); + $this->addElement('textarea', 'description', [ 'label' => $this->translate('Description'), 'description' => $this->translate( @@ -181,6 +196,7 @@ protected function onSuccess(): void $url = trim($this->getValue('url')); $isVisible = $this->getElement('is_visible')->isChecked(); $type = FeedType::fromDisplay($this->getValue('type') ?? 'auto'); + $pollingInterval = $this->getValue('polling_interval') ?? null; $description = trim($this->getValue('description')); if ($this->isCreateForm()) { @@ -190,6 +206,7 @@ protected function onSuccess(): void $description, $isVisible, $type, + $pollingInterval, ); if ($this->storage->getFeedByName($name) !== null) { @@ -218,6 +235,7 @@ protected function onSuccess(): void $this->feed->type = $type; $this->feed->isVisible = $isVisible; $this->feed->description = $description; + $this->feed->pollingInterval = $pollingInterval; if ($isRename) { $this->storage->addFeed($this->feed); diff --git a/library/Feeds/FeedReader.php b/library/Feeds/FeedReader.php index 1d75e16..766d64b 100644 --- a/library/Feeds/FeedReader.php +++ b/library/Feeds/FeedReader.php @@ -122,11 +122,13 @@ protected function fetchAndParse(): ?Feed /** * fetch loads a feed either from the cache or from its URL */ - public function fetch(?string $cacheKey = null): ?Feed + public function fetch(?string $cacheKey = null, ?int $cacheDurationInSeconds = null): ?Feed { // We don't expect feeds to update very frequently, to avoid // 429 errors we set the default to 12 hours - $cacheDurationInSeconds = $this->config->get('cache', 'duration', 43200); + if ($cacheDurationInSeconds === null) { + $cacheDurationInSeconds = $this->config->get('cache', 'duration', 43200); + } $cache = FeedCache::instance('feeds'); if ($cacheKey !== null && $cacheDurationInSeconds > 0) { diff --git a/library/Feeds/Storage/FeedDefinition.php b/library/Feeds/Storage/FeedDefinition.php index 6918e98..8497471 100644 --- a/library/Feeds/Storage/FeedDefinition.php +++ b/library/Feeds/Storage/FeedDefinition.php @@ -15,6 +15,7 @@ public function __construct( public string $description = '', public bool $isVisible = true, public FeedType $type = FeedType::Auto, + public ?int $pollingInterval = null, ) { } @@ -29,6 +30,7 @@ public function toArray(): array 'description' => trim($this->description), 'is_visible' => $this->isVisible, 'type' => $this->type->display(), + 'polling_interval' => $this->pollingInterval, ]; } @@ -43,6 +45,7 @@ public static function fromArray(array $data): FeedDefinition trim($data['description'] ?? ''), $data['is_visible'] ?? true, FeedType::fromDisplay(trim($data['type']) ?? 'auto'), + $data['polling_interval'] ?? null, ); } }