Skip to content
Open
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
12 changes: 12 additions & 0 deletions application/controllers/HostController.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Icinga\Module\Icingadb\Model\Host;
use Icinga\Module\Icingadb\Model\Service;
use Icinga\Module\Icingadb\Model\ServicestateSummary;
use Icinga\Module\Icingadb\Notifications\SubscribeIncidents;
use Icinga\Module\Icingadb\Redis\VolatileStateResults;
use Icinga\Module\Icingadb\Util\OptimizerHints;
use Icinga\Module\Icingadb\Web\Control\SearchBar\ObjectSuggestions;
Expand All @@ -45,6 +46,7 @@ class HostController extends Controller
{
use CommandActions;
use HookActions;
use SubscribeIncidents;

/** @var Host The host object */
protected $host;
Expand Down Expand Up @@ -590,6 +592,16 @@ public function servicesSearchEditorAction(): void
$this->setTitle($this->translate('Adjust Filter'));
}

public function subscribeAction(): void
{
$this->handleSubscription(true, $this->host, $this->getCommandTargetsUrl());
}

public function unsubscribeAction(): void
{
$this->handleSubscription(false, $this->host, $this->getCommandTargetsUrl());
}

/**
* Fetch the dependency nodes of the current host
*
Expand Down
12 changes: 12 additions & 0 deletions application/controllers/ServiceController.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Icinga\Module\Icingadb\Model\DependencyNode;
use Icinga\Module\Icingadb\Model\History;
use Icinga\Module\Icingadb\Model\Service;
use Icinga\Module\Icingadb\Notifications\SubscribeIncidents;
use Icinga\Module\Icingadb\Redis\VolatileStateResults;
use Icinga\Module\Icingadb\Util\OptimizerHints;
use Icinga\Module\Icingadb\Web\Control\SearchBar\ObjectSuggestions;
Expand All @@ -43,6 +44,7 @@ class ServiceController extends Controller
{
use CommandActions;
use HookActions;
use SubscribeIncidents;

/** @var Service The service object */
protected $service;
Expand Down Expand Up @@ -600,6 +602,16 @@ protected function getCommandTargetsUrl(): Url
return Links::service($this->service, $this->service->host);
}

public function subscribeAction(): void
{
$this->handleSubscription(true, $this->service, $this->getCommandTargetsUrl());
}

public function unsubscribeAction(): void
{
$this->handleSubscription(false, $this->service, $this->getCommandTargetsUrl());
}

protected function getDefaultTabControls(): array
{
return [new ObjectHeader($this->service)];
Expand Down
4 changes: 4 additions & 0 deletions application/forms/Command/Object/AcknowledgeProblemForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Icinga\Module\Icingadb\Command\Object\AcknowledgeProblemCommand;
use Icinga\Module\Icingadb\Forms\Command\CommandForm;
use Icinga\Module\Icingadb\Model\Host;
use Icinga\Module\Icingadb\Notifications\ManagesIncidents;
use Icinga\Web\Notification;
use ipl\Html\Attributes;
use ipl\Html\HtmlElement;
Expand All @@ -27,13 +28,16 @@

class AcknowledgeProblemForm extends CommandForm
{
use ManagesIncidents;

public function __construct()
{
$this->on(self::ON_SUCCESS, function () {
if ($this->errorOccurred) {
return;
}

$this->manageIncidents(true);
$countObjects = count($this->getObjects());
if (iterable_value_first($this->getObjects()) instanceof Host) {
$message = sprintf(tp(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Icinga\Module\Icingadb\Command\Object\RemoveAcknowledgementCommand;
use Icinga\Module\Icingadb\Forms\Command\CommandForm;
use Icinga\Module\Icingadb\Model\Host;
use Icinga\Module\Icingadb\Notifications\ManagesIncidents;
use Icinga\Web\Notification;
use ipl\Orm\Model;
use ipl\Web\Widget\Icon;
Expand All @@ -19,13 +20,16 @@

class RemoveAcknowledgementForm extends CommandForm
{
use ManagesIncidents;

public function __construct()
{
$this->on(self::ON_SUCCESS, function () {
if ($this->errorOccurred) {
return;
}

$this->manageIncidents(false);
$countObjects = count($this->getObjects());
if (iterable_value_first($this->getObjects()) instanceof Host) {
$message = sprintf(tp(
Expand Down
4 changes: 4 additions & 0 deletions configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@
'icingadb/command/send-custom-notification',
$this->translate('Allow to send custom notifications for hosts and services')
);
$this->providePermission(
'icingadb/notifications/subscribe',
$this->translate('Allow to subscribe and manage incidents related to hosts and services')
);

$this->providePermission(
'icingadb/object/show-source',
Expand Down
10 changes: 10 additions & 0 deletions library/Icingadb/Common/HostLinks.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,14 @@ public static function services(Host $host): Url
{
return Url::fromPath('icingadb/host/services', ['name' => $host->name]);
}

public static function subscribe(Host $host): Url
{
return Url::fromPath('icingadb/host/subscribe', ['name' => $host->name]);
}

public static function unsubscribe(Host $host): Url
{
return Url::fromPath('icingadb/host/unsubscribe', ['name' => $host->name]);
}
Comment thread
sukhwinder33445 marked this conversation as resolved.
}
10 changes: 10 additions & 0 deletions library/Icingadb/Common/ServiceLinks.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,14 @@ public static function toggleFeatures(Service $service, Host $host): Url
['name' => $service->name, 'host.name' => $host->name]
);
}

public static function subscribe(Service $service, Host $host): Url
{
return Url::fromPath('icingadb/service/subscribe', ['name' => $service->name, 'host.name' => $host->name]);
}

public static function unsubscribe(Service $service, Host $host): Url
{
return Url::fromPath('icingadb/service/unsubscribe', ['name' => $service->name, 'host.name' => $host->name]);
}
Comment thread
sukhwinder33445 marked this conversation as resolved.
}
49 changes: 49 additions & 0 deletions library/Icingadb/Notifications/IncidentFinder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

// SPDX-FileCopyrightText: 2026 Icinga GmbH <https://icinga.com>
// SPDX-License-Identifier: GPL-3.0-or-later

namespace Icinga\Module\Icingadb\Notifications;

use Icinga\Module\Icingadb\Model\Host;
use Icinga\Module\Icingadb\Model\Service;
use Icinga\Module\Notifications\Integrations\Incidents;

class IncidentFinder
{
/**
* Find the open incidents related to the given object
*
* @param Host|Service $object
*
* @return Incidents
*/
public static function forObject(Host|Service $object): Incidents
{
return Incidents::find(self::buildTags($object));
}

/**
* Build the tags to match the given host/service
*
* @param Host|Service $object
*
* @return array<string, ?string>
*/
private static function buildTags(Host|Service $object): array
{
if ($object instanceof Host) {
return [
'host' => $object->name,
'service' => null,
'environment' => bin2hex($object->environment_id)
];
}

return [
'host' => $object->host->name,
'service' => $object->name,
'environment' => bin2hex($object->environment_id)
];
}
}
66 changes: 66 additions & 0 deletions library/Icingadb/Notifications/ManagesIncidents.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

// SPDX-FileCopyrightText: 2026 Icinga GmbH <https://icinga.com>
// SPDX-License-Identifier: GPL-3.0-or-later

namespace Icinga\Module\Icingadb\Notifications;

use Icinga\Application\Icinga;
use Icinga\Module\Icingadb\Forms\Command\CommandForm;
use Icinga\Web\Notification;
use InvalidArgumentException;

/**
* @phpstan-require-extends CommandForm
*/
trait ManagesIncidents
{
/**
* Add or remove the current user as manager of all incidents related to the form's objects
*
* @param bool $manage
*
* @return void
*/
protected function manageIncidents(bool $manage): void
{
if (! Icinga::app()->getModuleManager()->hasEnabled('notifications')) {
return;
}

$username = $this->getAuth()->getUser()->getUsername();
$count = 0;
try {
foreach ($this->getObjects() as $object) {
foreach (IncidentFinder::forObject($object) as $incident) {
if ($manage) {
$incident->addManager($username);
} else {
$incident->removeManager($username);
}

$count++;
}
}

if ($count > 0) {
Notification::success(sprintf(
$manage
? tp('Now managing the matching incident', 'Now managing %d matching incidents', $count)
: tp(
'No longer managing the matching incident',
'No longer managing %d matching incidents',
$count
),
$count
));
}
} catch (InvalidArgumentException) {
if ($manage) {
Notification::warning(
t('Cannot manage matching incident, no notification contact configured for your account.')
);
}
Comment thread
sukhwinder33445 marked this conversation as resolved.
}
}
}
45 changes: 45 additions & 0 deletions library/Icingadb/Notifications/SubscribeIncidents.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

// SPDX-FileCopyrightText: 2026 Icinga GmbH <https://icinga.com>
// SPDX-License-Identifier: GPL-3.0-or-later

namespace Icinga\Module\Icingadb\Notifications;

use Icinga\Application\Icinga;
use Icinga\Module\Icingadb\Model\Host;
use Icinga\Module\Icingadb\Model\Service;
use Icinga\Module\Icingadb\Web\Controller;
use ipl\Html\Form;
use ipl\Web\Url;

/**
* @phpstan-require-extends Controller
*/
trait SubscribeIncidents
{
/**
* Subscribe or unsubscribe all incidents matching the given tags
*
* @param bool $subscribe
* @param Host|Service $object
* @param Url $redirectUrl The URL to redirect to after the form has been handled
* @return void
*/
protected function handleSubscription(bool $subscribe, Host|Service $object, Url $redirectUrl): void
{
if (
Icinga::app()->getModuleManager()->hasEnabled('notifications')
&& $this->isGrantedOn('icingadb/notifications/subscribe', $object)
) {
$form = (new SubscriptionForm($subscribe, $object))
->setAction((string) Url::fromRequest())
->on(Form::ON_SUBMIT, function () use ($redirectUrl) {
$this->redirectNow($redirectUrl);
});

$form->handleRequest($this->getServerRequest());

$this->addContent($form);
}
}
}
Loading
Loading