From b7c92eebb7620443aa786547edfc5b9a8a3a843b Mon Sep 17 00:00:00 2001 From: Neil Lathwood Date: Thu, 26 Apr 2018 06:00:56 +0100 Subject: [PATCH] alert: Added ability to make notes for acking alerts + record who did so (#8433) * alert: Added ability to make notes for acking alerts + record who did so * Updated schema * moved sql file * Updated from comments in PR * warning changed to blue * reset notes + keep notes on ack --- html/includes/common/alerts.inc.php | 60 +++++++++++------ html/includes/forms/ack-alert.inc.php | 75 ++++++++++++++++------ html/includes/forms/alert-notes.inc.php | 53 +++++++++++++++ html/includes/forms/alert-rules.inc.php | 3 +- html/includes/modal/alert_notes.inc.php | 66 +++++++++++++++++++ html/includes/modal/alert_template.inc.php | 1 - html/includes/table/alerts.inc.php | 13 +++- html/pages/alerts.inc.php | 1 + html/pages/front/tiles.php | 2 + includes/alerts.inc.php | 2 +- misc/db_schema.yaml | 1 + sql-schema/248.sql | 1 + 12 files changed, 229 insertions(+), 49 deletions(-) create mode 100644 html/includes/forms/alert-notes.inc.php create mode 100644 html/includes/modal/alert_notes.inc.php create mode 100644 sql-schema/248.sql diff --git a/html/includes/common/alerts.inc.php b/html/includes/common/alerts.inc.php index 69b63df5beb1..702da465f86e 100644 --- a/html/includes/common/alerts.inc.php +++ b/html/includes/common/alerts.inc.php @@ -193,7 +193,8 @@ Rule Hostname - ACK'; + ACK + Notes'; if ($proc == '1') { $common_output[] = 'URL'; @@ -252,7 +253,7 @@ $(this).find(".incident-toggle").fadeIn(200); }).on("mouseleave", function() { $(this).find(".incident-toggle").fadeOut(200); - }).on("click", "td:not(.incident-toggle-td)", function() { + }).on("click", "td(.incident-toggle-td)", function() { var target = $(this).parent().find(".incident-toggle").data("target"); if( $(this).parent().find(".incident-toggle").hasClass(\'fa-plus\') ) { $(this).parent().find(".incident-toggle").toggleClass(\'fa-plus fa-minus\'); @@ -262,26 +263,43 @@ }); alerts_grid.find(".command-ack-alert").on("click", function(e) { e.preventDefault(); - var alert_id = $(this).data("alert_id"); - var state = $(this).data("state"); - $.ajax({ - type: "POST", - url: "ajax_form.php", - data: { type: "ack-alert", alert_id: alert_id, state: state }, - success: function(msg){ - toastr.success(msg); - if(msg.indexOf("ERROR:") <= -1) { - $(".alerts").each(function(index) { - var $sortDictionary = $(this).bootgrid("getSortDictionary"); - $(this).reload; - $(this).bootgrid("sort", $sortDictionary); - }); + var alert_state = $(this).data("alert_state"); + if (alert_state != 2) { + var ack_msg = window.prompt("Enter the reason you are acknowledging this alert:"); + } else { + var ack_msg = ""; + } + if (typeof ack_msg == "string") { + var alert_id = $(this).data("alert_id"); + var state = $(this).data("state"); + $.ajax({ + type: "POST", + url: "ajax_form.php", + dataType: "json", + data: { type: "ack-alert", alert_id: alert_id, state: state, ack_msg: ack_msg }, + success: function (data) { + if (data.status == "ok") { + toastr.success(data.message); + $(".alerts").each(function(index) { + var $sortDictionary = $(this).bootgrid("getSortDictionary"); + $(this).reload; + $(this).bootgrid("sort", $sortDictionary); + }); + } else { + toastr.error(data.message); + } + }, + error: function(){ + toastr.error(data.message); } - }, - error: function(){ - toastr.error("An error occurred acking this alert"); - } - }); + }); + } + }); + alerts_grid.find(".command-alert-note").on("click", function(e) { + e.preventDefault(); + var alert_id = $(this).data(\'alert_id\'); + $(\'#alert_id\').val(alert_id); + $("#alert_notes_modal").modal(\'show\'); }); }); '; diff --git a/html/includes/forms/ack-alert.inc.php b/html/includes/forms/ack-alert.inc.php index 29f0532336c8..2e7c60f98ae9 100644 --- a/html/includes/forms/ack-alert.inc.php +++ b/html/includes/forms/ack-alert.inc.php @@ -1,26 +1,42 @@ + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. Please see LICENSE.txt at the top level of - * the source code distribution for details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Neil Lathwood + * @author Neil Lathwood */ -header('Content-type: text/plain'); -$alert_id = mres($_POST['alert_id']); -$state = mres($_POST['state']); +use LibreNMS\Config; + +header('Content-type: application/json'); + +$alert_id = $vars['alert_id']; +$state = $vars['state']; +$ack_msg = $vars['ack_msg']; + +$status = 'error'; + if (!is_numeric($alert_id)) { - echo 'ERROR: No alert selected'; - exit; + $message = 'No alert selected'; } elseif (!is_numeric($state)) { - echo 'ERROR: No state passed'; - exit; + $message = 'No state passed'; } else { if ($state == 2) { $state = 1; @@ -30,11 +46,28 @@ $open = 1; } - if (dbUpdate(array('state' => $state, 'open' => $open), 'alerts', 'id=?', array($alert_id)) >= 0) { - echo 'Alert acknowledged status changed.'; - exit; + $data = ['state' => $state, 'open' => $open]; + if (!empty($ack_msg)) { + $note = dbFetchCell('SELECT note FROM alerts WHERE id=?', [$alert_id]); + if (!empty($note)) { + $note .= PHP_EOL; + } + $data['note'] = $note . date(Config::get('dateformat.long')) . " - Ack ({$_SESSION['username']}) $ack_msg"; + } + + if (dbUpdate($data, 'alerts', 'id=?', array($alert_id)) >= 0) { + if ($state === 2) { + $alert_info = dbFetchRow("SELECT `alert_rules`.`name`,`alerts`.`device_id` FROM `alert_rules` LEFT JOIN `alerts` ON `alerts`.`rule_id` = `alert_rules`.`id` WHERE `alerts`.`id` = ?", [$alert_id]); + log_event("{$_SESSION['username']} acknowledged alert {$alert_info['name']}", $alert_info['device_id'], 'alert', 2, $alert_id); + } + $message = 'Alert acknowledged status changed.'; + $status = 'ok'; } else { - echo 'ERROR: Alert has not been acknowledged.'; - exit; + $message = 'Alert has not been acknowledged.'; } }//end if + +die(json_encode([ + 'status' => $status, + 'message' => $message, +])); diff --git a/html/includes/forms/alert-notes.inc.php b/html/includes/forms/alert-notes.inc.php new file mode 100644 index 000000000000..41c7b7461e0b --- /dev/null +++ b/html/includes/forms/alert-notes.inc.php @@ -0,0 +1,53 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2018 Neil Lathwood + * @author Neil Lathwood + */ + +header('Content-type: application/json'); + +$alert_id = $vars['alert_id']; +$sub_type = $vars['sub_type']; +$note = $vars['note'] ?: ''; +$status = 'error'; + +if (is_numeric($alert_id)) { + if ($sub_type === 'get_note') { + $note = dbFetchCell("SELECT `note` FROM `alerts` WHERE `id` = ?", [$alert_id]); + $message = 'Alert note retrieved'; + $status = 'ok'; + } else { + if (dbUpdate(['note' => $note], 'alerts', '`id` = ?', [$alert_id])) { + $status = 'ok'; + $message = 'Note updated'; + } else { + $message = 'Could not update note'; + } + } +} else { + $message = 'Invalid alert id'; +} +die(json_encode([ + 'status' => $status, + 'message' => $message, + 'note' => $note, +])); diff --git a/html/includes/forms/alert-rules.inc.php b/html/includes/forms/alert-rules.inc.php index 0d16da9ef77d..06cca2a3e27b 100644 --- a/html/includes/forms/alert-rules.inc.php +++ b/html/includes/forms/alert-rules.inc.php @@ -2,7 +2,7 @@ /** * alert-rules.inc.php * - * LibreNMS alert-rules.inc.php for processor + * LibreNMS alert-rules.inc.php * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -150,7 +150,6 @@ dbSyncRelationship('alert_group_map', 'rule_id', $rule_id, 'group_id', $groups); } - die(json_encode([ 'status' => $status, 'message' => $message, diff --git a/html/includes/modal/alert_notes.inc.php b/html/includes/modal/alert_notes.inc.php new file mode 100644 index 000000000000..cf2f2b89d921 --- /dev/null +++ b/html/includes/modal/alert_notes.inc.php @@ -0,0 +1,66 @@ +
+ +
+ + \ No newline at end of file diff --git a/html/includes/modal/alert_template.inc.php b/html/includes/modal/alert_template.inc.php index fae77126fc3e..f1207cfa23b8 100644 --- a/html/includes/modal/alert_template.inc.php +++ b/html/includes/modal/alert_template.inc.php @@ -210,7 +210,6 @@ }); $('div').on('click', 'button#reset-default', function(e) { - console.log('zart'); e.preventDefault(); var template_id = $("#template_id").val(); var template = '%title\r\nSeverity: %severity\r\n{if %state == 0}Time elapsed: %elapsed\r\n{/if}Timestamp: %timestamp\r\nUnique-ID: %uid\r\nRule: {if %name}%name{else}%rule{/if}\r\n{if %faults}Faults:\r\n{foreach %faults} #%key: %value.string\r\n{/foreach}{/if}Alert sent to: {foreach %contacts}%value <%key> {/foreach}'; diff --git a/html/includes/table/alerts.inc.php b/html/includes/table/alerts.inc.php index e2bce008a907..c3d49f45e7dd 100644 --- a/html/includes/table/alerts.inc.php +++ b/html/includes/table/alerts.inc.php @@ -119,8 +119,8 @@ $log = dbFetchCell('SELECT details FROM alert_log WHERE rule_id = ? AND device_id = ? ORDER BY id DESC LIMIT 1', array($alert['rule_id'], $alert['device_id'])); $fault_detail = alert_details($log); - $alert_to_ack = ''; - $alert_to_nack = ''; + $alert_to_ack = ''; + $alert_to_nack = ''; $ack_ico = $alert_to_ack; @@ -164,7 +164,7 @@ } if ((int)$alert['state'] === 2) { - $severity_ico = ' '; + $severity_ico = ' '; } $proc = dbFetchCell('SELECT proc FROM alerts,alert_rules WHERE alert_rules.id = alerts.rule_id AND alerts.id = ?', array($alert['id'])); @@ -178,6 +178,12 @@ } } + if (empty($alert['note'])) { + $note_class = 'default'; + } else { + $note_class = 'warning'; + } + $response[] = array( 'id' => $rulei++, 'rule' => '' . htmlentities($alert['name']) . '', @@ -189,6 +195,7 @@ 'alert_id' => $alert['id'], 'ack_ico' => $ack_ico, 'proc' => $has_proc, + 'notes' => "", ); } diff --git a/html/pages/alerts.inc.php b/html/pages/alerts.inc.php index 82769f48beec..b185bcf66356 100644 --- a/html/pages/alerts.inc.php +++ b/html/pages/alerts.inc.php @@ -23,6 +23,7 @@ 0, 'device_id' => $device_id, 'rule_id' => $rule['id']), 'alert_log')) { - if (!dbUpdate(array('state' => 0, 'open' => 1), 'alerts', 'device_id = ? && rule_id = ?', array($device_id,$rule['id']))) { + if (!dbUpdate(array('state' => 0, 'open' => 1, 'note' => ''), 'alerts', 'device_id = ? && rule_id = ?', array($device_id,$rule['id']))) { dbInsert(array('state' => 0, 'device_id' => $device_id, 'rule_id' => $rule['id'], 'open' => 1, 'alerted' => 0), 'alerts'); } c_echo(PHP_EOL . 'Status: %gOK'); diff --git a/misc/db_schema.yaml b/misc/db_schema.yaml index c62d794308c9..682bea0025f5 100644 --- a/misc/db_schema.yaml +++ b/misc/db_schema.yaml @@ -27,6 +27,7 @@ alerts: - { Field: state, Type: int(11), 'Null': false, Extra: '' } - { Field: alerted, Type: int(11), 'Null': false, Extra: '' } - { Field: open, Type: int(11), 'Null': false, Extra: '' } + - { Field: note, Type: text, 'Null': false, Extra: '' } - { Field: timestamp, Type: timestamp, 'Null': false, Extra: 'on update CURRENT_TIMESTAMP', Default: CURRENT_TIMESTAMP } Indexes: PRIMARY: { Name: PRIMARY, Columns: [id], Unique: true, Type: BTREE } diff --git a/sql-schema/248.sql b/sql-schema/248.sql new file mode 100644 index 000000000000..0c200256dc77 --- /dev/null +++ b/sql-schema/248.sql @@ -0,0 +1 @@ +ALTER TABLE `alerts` ADD `note` TEXT NOT NULL AFTER `open`; \ No newline at end of file