Skip to content

Commit

Permalink
EventRuleConfig: Consider changed_at, deleted column
Browse files Browse the repository at this point in the history
Only update if changes have been made
  • Loading branch information
sukhwinder33445 committed Jul 1, 2024
1 parent cd317e1 commit bdc5beb
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 32 deletions.
17 changes: 13 additions & 4 deletions application/controllers/EventRuleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use Icinga\Module\Notifications\Forms\EventRuleForm;
use Icinga\Module\Notifications\Forms\SaveEventRuleForm;
use Icinga\Module\Notifications\Model\Incident;
use Icinga\Module\Notifications\Model\ObjectExtraTag;
use Icinga\Module\Notifications\Model\Rule;
use Icinga\Module\Notifications\Web\Control\SearchBar\ExtraTagSuggestions;
use Icinga\Module\Notifications\Widget\EventRuleConfig;
Expand Down Expand Up @@ -151,7 +150,7 @@ public function indexAction(): void
public function fromDb(int $ruleId): array
{
$query = Rule::on(Database::get())
->withoutColumns('timeperiod_id')
->columns(['id', 'name', 'object_filter', 'is_active'])
->filter(Filter::all(
Filter::equal('id', $ruleId),
Filter::equal('deleted', 'n')
Expand All @@ -164,12 +163,22 @@ public function fromDb(int $ruleId): array

$config = iterator_to_array($rule);

foreach ($rule->rule_escalation as $re) {
$ruleEscalations = $rule
->rule_escalation
->withoutColumns(['changed_at', 'deleted'])
->filter(Filter::equal('deleted', 'n'));

foreach ($ruleEscalations as $re) {
foreach ($re as $k => $v) {
$config[$re->getTableName()][$re->position][$k] = $v;
}

foreach ($re->rule_escalation_recipient as $recipient) {
$escalationRecipients = $re
->rule_escalation_recipient
->withoutColumns(['changed_at', 'deleted'])
->filter(Filter::equal('deleted', 'n'));

foreach ($escalationRecipients as $recipient) {
$config[$re->getTableName()][$re->position]['recipient'][] = iterator_to_array($recipient);
}
}
Expand Down
199 changes: 171 additions & 28 deletions application/forms/SaveEventRuleForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
namespace Icinga\Module\Notifications\Forms;

use Exception;
use Icinga\Exception\Http\HttpNotFoundException;
use Icinga\Module\Notifications\Common\Database;
use Icinga\Module\Notifications\Model\Rule;
use Icinga\Module\Notifications\Model\RuleEscalation;
use Icinga\Module\Notifications\Model\RuleEscalationRecipient;
use Icinga\Web\Notification;
Expand Down Expand Up @@ -47,6 +49,9 @@ class SaveEventRuleForm extends Form
/** @var bool Whether to disable the remove button */
protected $disableRemoveButton = false;

/** @var int The rule id */
protected $ruleId;

/**
* Create a new SaveEventRuleForm
*/
Expand Down Expand Up @@ -294,6 +299,7 @@ public function addRule(array $config): int
*/
private function insertOrUpdateEscalations($ruleId, array $escalations, Connection $db, bool $insert = false): void
{
$changedAt = time() * 1000;
foreach ($escalations as $position => $escalationConfig) {
if ($insert) {
$db->insert('rule_escalation', [
Expand All @@ -307,18 +313,21 @@ private function insertOrUpdateEscalations($ruleId, array $escalations, Connecti
$escalationId = $db->lastInsertId();
} else {
$escalationId = $escalationConfig['id'];

$db->update('rule_escalation', [
'position' => $position,
'condition' => $escalationConfig['condition'] ?? null,
'name' => $escalationConfig['name'] ?? null,
'fallback_for' => $escalationConfig['fallback_for'] ?? null
'fallback_for' => $escalationConfig['fallback_for'] ?? null,
'changed_at' => $changedAt
], ['id = ?' => $escalationId, 'rule_id = ?' => $ruleId]);
$recipientsToRemove = [];

$recipients = RuleEscalationRecipient::on($db)
->columns('id')
->filter(Filter::equal('rule_escalation_id', $escalationId));
->filter(Filter::all(
Filter::equal('rule_escalation_id', $escalationId),
Filter::equal('deleted', 'n')
));

foreach ($recipients as $recipient) {
$recipientId = $recipient->id;
Expand All @@ -336,7 +345,11 @@ function (array $element) use ($recipientId) {
}

if (! empty($recipientsToRemove)) {
$db->delete('rule_escalation_recipient', ['id IN (?)' => $recipientsToRemove]);
$db->update(
'rule_escalation_recipient',
['changed_at' => $changedAt, 'deleted' => 'y'],
['id IN (?)' => $recipientsToRemove]
);
}
}

Expand Down Expand Up @@ -367,7 +380,11 @@ function (array $element) use ($recipientId) {
if (! isset($recipientConfig['id'])) {
$db->insert('rule_escalation_recipient', $data);
} else {
$db->update('rule_escalation_recipient', $data, ['id = ?' => $recipientConfig['id']]);
$db->update(
'rule_escalation_recipient',
$data + ['changed_at' => $changedAt],
['id = ?' => $recipientConfig['id']]
);
}
}
}
Expand All @@ -383,27 +400,45 @@ function (array $element) use ($recipientId) {
*/
public function editRule(int $id, array $config): void
{
$this->ruleId = $id;

$db = Database::get();

$db->beginTransaction();

$db->update('rule', [
'name' => $config['name'],
'timeperiod_id' => $config['timeperiod_id'] ?? null,
'object_filter' => $config['object_filter'] ?? null,
'is_active' => $config['is_active'] ?? 'n'
], ['id = ?' => $id]);
$storedValues = $this->fetchDbValues();

$values = $this->getChanges($storedValues, $config);

$changedAt = time() * 1000;
if (
isset($values['name'])
|| isset($values['timeperiod_id'])
|| isset($values['object_filter'])
|| isset($values['is_active'])
) {
$db->update('rule', [
'name' => $values['name'],
'timeperiod_id' => $values['timeperiod_id'] ?? null,
'object_filter' => $values['object_filter'] ?? null,
'is_active' => $values['is_active'] ?? 'n',
'changed_at' => $changedAt
], ['id = ?' => $id]);
}

$escalationsFromDb = RuleEscalation::on($db)
->filter(Filter::equal('rule_id', $id));
if (! isset($values['rule_escalation'])) {
$db->commitTransaction();

return;
}

$escalationsInCache = $config['rule_escalation'];

$escalationsToUpdate = [];
$escalationsToRemove = [];

foreach ($escalationsFromDb as $escalationInDB) {
$escalationId = $escalationInDB->id;
foreach ($storedValues['rule_escalation'] as $escalationInDB) {
$escalationId = $escalationInDB['id'];
$escalationInCache = array_filter($escalationsInCache, function (array $element) use ($escalationId) {
return (int) $element['id'] === $escalationId;
});
Expand All @@ -422,9 +457,19 @@ public function editRule(int $id, array $config): void
// Escalations to add
$escalationsToAdd = $escalationsInCache;

$markAsDeleted = ['changed_at' => $changedAt, 'deleted' => 'y'];
if (! empty($escalationsToRemove)) {
$db->delete('rule_escalation_recipient', ['rule_escalation_id IN (?)' => $escalationsToRemove]);
$db->delete('rule_escalation', ['id IN (?)' => $escalationsToRemove]);
$db->update(
'rule_escalation_recipient',
$markAsDeleted,
['rule_escalation_id IN (?)' => $escalationsToRemove]
);

$db->update(
'rule_escalation',
$markAsDeleted + ['position' => null],
['id IN (?)' => $escalationsToRemove]
);
}

if (! empty($escalationsToAdd)) {
Expand All @@ -451,21 +496,26 @@ public function removeRule(int $id): void

$db->beginTransaction();

$escalations = RuleEscalation::on($db)
->columns('id')
->filter(Filter::equal('rule_id', $id));

$escalationsToRemove = [];
foreach ($escalations as $escalation) {
$escalationsToRemove[] = $escalation->id;
}
$escalationsToRemove = $db->fetchCol(
RuleEscalation::on($db)
->columns('id')
->filter(Filter::all(
Filter::equal('rule_id', $id),
Filter::equal('deleted', 'n')
))->assembleSelect()
);

$markAsDeleted = ['changed_at' => time() * 1000, 'deleted' => 'y'];
if (! empty($escalationsToRemove)) {
$db->delete('rule_escalation_recipient', ['rule_escalation_id IN (?)' => $escalationsToRemove]);
$db->update(
'rule_escalation_recipient',
$markAsDeleted,
['rule_escalation_id IN (?)' => $escalationsToRemove]
);
}

$db->delete('rule_escalation', ['rule_id = ?' => $id]);
$db->delete('rule', ['id = ?' => $id]);
$db->update('rule_escalation', $markAsDeleted + ['position' => null], ['rule_id = ?' => $id]);
$db->update('rule', $markAsDeleted, ['id = ?' => $id]);

$db->commitTransaction();
}
Expand All @@ -478,4 +528,97 @@ protected function onError()
}
}
}

/**
* Fetch the values from the database
*
* @return array
*
* @throws HttpNotFoundException
*/
private function fetchDbValues(): array
{
$query = Rule::on(Database::get())
->columns(['id', 'name', 'object_filter', 'is_active'])
->filter(Filter::all(
Filter::equal('id', $this->ruleId),
Filter::equal('deleted', 'n')
));

$rule = $query->first();
if ($rule === null) {
throw new HttpNotFoundException($this->translate('Rule not found'));
}

$config = iterator_to_array($rule);

$ruleEscalations = $rule
->rule_escalation
->withoutColumns(['changed_at', 'deleted'])
->filter(Filter::equal('deleted', 'n'));

foreach ($ruleEscalations as $re) {
foreach ($re as $k => $v) {
$config[$re->getTableName()][$re->position][$k] = $v;
}

$escalationRecipients = $re
->rule_escalation_recipient
->withoutColumns(['changed_at', 'deleted'])
->filter(Filter::equal('deleted', 'n'));

foreach ($escalationRecipients as $recipient) {
$config[$re->getTableName()][$re->position]['recipient'][] = iterator_to_array($recipient);
}
}

$config['showSearchbar'] = ! empty($config['object_filter']);

return $config;
}

/**
* Get the newly made changes
*
* @return array
*/
public function getChanges(array $storedValues, array $formValues): array
{
unset($formValues['conditionPlusButtonPosition']);
$dbValuesToCompare = array_intersect_key($storedValues, $formValues);

if (count($formValues, COUNT_RECURSIVE) < count($dbValuesToCompare, COUNT_RECURSIVE)) {
// fewer values in the form than in the db, escalation(s) has been removed
if ($formValues['name'] === $dbValuesToCompare['name']) {
unset($formValues['name']);
}

if (
isset($formValues['timeperiod_id'])
&& $formValues['timeperiod_id'] === $dbValuesToCompare['timeperiod_id']
) {
unset($formValues['timeperiod_id']);
}

if ($formValues['object_filter'] === $dbValuesToCompare['object_filter']) {
unset($formValues['object_filter']);
}

if ($formValues['is_active'] === $dbValuesToCompare['is_active']) {
unset($formValues['is_active']);
}

return $formValues;
}

$checker = static function ($a, $b) use (&$checker) {
if (! is_array($a) || ! is_array($b)) {
return $a <=> $b;
}

return empty(array_udiff_assoc($a, $b, $checker)) ? 0 : 1;
};

return array_udiff_assoc($formValues, $dbValuesToCompare, $checker);
}
}

0 comments on commit bdc5beb

Please sign in to comment.