Merge branch 'ent-3371-sistema-de-notificaciones-pandora' into 'ent-3430-discovery'

Ent 3371 sistema de notificaciones pandora

See merge request artica/pandorafms!2129

Former-commit-id: 3a3a2a28f817cf13365bace9d6b963055b0fef75
This commit is contained in:
fbsanchez 2019-02-14 10:50:29 +01:00
commit beb47ec480
18 changed files with 1869 additions and 374 deletions

View File

@ -1975,4 +1975,9 @@ CREATE TABLE `tnotification_source_group_user` (
ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (`id_group`) REFERENCES `tnotification_source_group`(`id_group`)
ON UPDATE CASCADE ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- Add alert command 'Generate notification'
-- ----------------------------------------------------------------------
INSERT INTO `talert_commands` (`name`, `command`, `description`, `internal`, `fields_descriptions`, `fields_values`) VALUES ('Generate Notification','Internal type','This command allows you to send an internal notification to any user or group.',1,'[\"Destination user\",\"Destination group\",\"Title\",\"Message\",\"Link\",\"Criticity\",\"\",\"\",\"\",\"\",\"\"]','[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]');

View File

@ -1,5 +1,4 @@
<?php
// Pandora FMS - http://pandorafms.com
// ==================================================
// Copyright (c) 2005-2011 Artica Soluciones Tecnologicas
@ -13,6 +12,7 @@
// GNU General Public License for more details.
require_once 'include/functions_messages.php';
require_once 'include/functions_servers.php';
require_once 'include/functions_notifications.php';
// Check permissions
// Global errors/warnings checking.
@ -57,7 +57,7 @@ config_check();
$table->cellspacing = 0;
$table->head = [];
$table->data = [];
$table->style[0] = $table->style['clippy'] = $table->style[1] = $table->style[3] = $table->style[4] = $table->style[5] = $table->style[6] = $table->style[8] = $table->style[9] = $table->style['qr'] = $table->style['notifications'] = 'width: 22px; text-align:center; height: 22px; padding-right: 9px;padding-left: 9px;';
$table->style['clippy'] = $table->style[1] = $table->style[4] = $table->style[5] = $table->style[6] = $table->style[8] = $table->style[9] = $table->style['qr'] = $table->style['notifications'] = 'width: 22px; text-align:center; height: 22px; padding-right: 9px;padding-left: 9px;';
$table->style[7] = 'width: 20px; padding-right: 9px;';
$table->style['searchbar'] = 'width: 180px; min-width: 180px;';
$table->style[11] = 'padding-left: 10px; padding-right: 5px;width: 16px;';
@ -110,27 +110,6 @@ config_check();
$table->data[0]['searchbar'] = $search_bar;
}
// Servers check
$servers = [];
$servers['all'] = (int) db_get_value('COUNT(id_server)', 'tserver');
$servers['up'] = (int) servers_check_status();
$servers['down'] = ($servers['all'] - $servers['up']);
if ($servers['up'] == 0) {
// All Servers down or no servers at all
$servers_check_img = html_print_image('images/header_down.png', true, ['alt' => 'cross', 'class' => 'bot', 'title' => __('All systems').': '.__('Down')]);
} else if ($servers['down'] != 0) {
// Some servers down
$servers_check_img = html_print_image('images/header_warning.png', true, ['alt' => 'error', 'class' => 'bot', 'title' => $servers['down'].' '.__('servers down')]);
} else {
// All servers up
$servers_check_img = html_print_image('images/header_ready.png', true, ['alt' => 'ok', 'class' => 'bot', 'title' => __('All systems').': '.__('Ready')]);
}
unset($servers);
// Since this is the header, we don't like to trickle down variables.
$servers_link_open = '<a class="white" href="index.php?sec=gservers&amp;sec2=godmode/servers/modificar_server&amp;refr=60">';
$servers_link_close = '</a>';
if ($config['show_qr_code_header'] == 0) {
$show_qr_code_header = 'display: none;';
} else {
@ -175,12 +154,6 @@ config_check();
).'</a>';
}
$table->data[0][0] = $servers_link_open.$servers_check_img.$servers_link_close;
// ======= Autorefresh code =============================
$autorefresh_txt = '';
$autorefresh_additional = '';
@ -256,42 +229,6 @@ config_check();
// ======================================================
$pandora_management = check_acl($config['id_user'], 0, 'PM');
echo '<div id="alert_messages" style="display: none"></div>';
if ($config['alert_cnt'] > 0) {
$maintenance_link = 'javascript:';
$maintenance_title = __('System alerts detected - Please fix as soon as possible');
$maintenance_class = $maintenance_id = 'show_systemalert_dialog white';
$maintenance_link_open_txt = '<a href="'.$maintenance_link.'" title="'.$maintenance_title.'" class="'.$maintenance_class.'" id="show_systemalert_dialog">';
$maintenance_link_open_img = '<a href="'.$maintenance_link.'" title="'.$maintenance_title.'" class="'.$maintenance_class.'">';
$maintenance_link_close = '</a>';
if (!$pandora_management) {
$maintenance_img = '';
} else {
$maintenance_img = $maintenance_link_open_img.html_print_image(
'images/header_yellow.png',
true,
[
'title' => __(
'You have %d warning(s)',
$config['alert_cnt']
),
'id' => 'yougotalert',
'class' => 'bot',
]
).$maintenance_link_close;
}
} else {
if (!$pandora_management) {
$maintenance_img = '';
} else {
$maintenance_img = html_print_image('images/header_ready.png', true, ['title' => __('There are not warnings'), 'id' => 'yougotalert', 'class' => 'bot']);
}
}
$table->data[0][3] = $maintenance_img;
// Main help icon
if (!$config['disable_help']) {
$table->data[0][4] = '<a href="#" class="modalpopup" id="helpmodal">'.html_print_image(
@ -305,6 +242,12 @@ config_check();
).'</a>';
}
$notifications_numbers = notifications_get_counters();
$table->data[0]['notifications'] = notifications_print_ball(
$notifications_numbers['notifications'],
$notifications_numbers['last_id']
);
// Logout
$table->data[0][5] = '<a class="white" href="'.ui_get_full_url('index.php?bye=bye').'">';
$table->data[0][5] .= html_print_image('images/header_logout.png', true, ['alt' => __('Logout'), 'class' => 'bot', 'title' => __('Logout')]);
@ -328,18 +271,6 @@ config_check();
$table->data[0][8] .= '</a>';
$table->data[0][8] .= '</span>';
// Messages
$msg_cnt = messages_get_count($config['id_user']);
if ($msg_cnt > 0) {
echo '<div id="dialog_messages" style="display: none"></div>';
$table->data[0][9] = '<a href="ajax.php?page=operation/messages/message_list" title="'.__('Message overview').'" id="show_messages_dialog">';
$table->data[0][9] .= html_print_image('images/header_email.png', true, ['title' => __('You have %d unread message(s)', $msg_cnt), 'id' => 'yougotmail', 'class' => 'bot', 'style' => 'width:24px;']);
$table->data[0][9] .= '</a>';
}
$table->data[0]['notifications'] = notifications_print_ball();
html_print_table($table);
unset($table);
@ -360,6 +291,9 @@ config_check();
</tr>
</table>
<!-- Notifications content wrapper-->
<div id='notification-content' style='display:none;' /></div>
<script type="text/javascript">
/* <![CDATA[ */
@ -368,12 +302,223 @@ config_check();
if (isset($config['fixed_header'])) {
$config_fixed_header = $config['fixed_header'];
}
?>
function addNotifications(event) {
var element = document.getElementById("notification-content");
if (!element) {
console.error('Cannot locate the notification content element.');
return;
}
// If notification-content is empty, retrieve the notifications.
if (!element.firstChild) {
jQuery.post ("ajax.php",
{
"page" : "godmode/setup/setup_notifications",
"get_notifications_dropdown" : 1,
},
function (data, status) {
// Apppend data
element.innerHTML = data;
// Show the content
element.style.display = "block";
attatch_to_image();
},
"html"
);
} else {
// If there is some notifications retrieved, only show it.
element.style.display = "block";
attatch_to_image();
}
}
function attatch_to_image() {
var notification_elem = document.getElementById("notification-wrapper");
if (!notification_elem) return;
var image_attached =
document.getElementById("notification-ball-header")
.getBoundingClientRect()
.left
;
notification_elem.style.left = image_attached - 300 + "px";
}
function notifications_clean_ui(action, self_id) {
switch(action) {
case 'item':
// Recalculate the notification ball.
check_new_notifications();
break;
case 'toast':
// Only remove the toast element.
document.getElementById(self_id).remove();
break;
}
}
function notifications_hide() {
var element = document.getElementById("notification-content");
element.style.display = "none"
}
function click_on_notification_toast(event) {
var match = /notification-(.*)-id-([0-9]+)/.exec(event.target.id);
if (!match) {
console.error(
"Cannot handle toast click event. Id not valid: ",
event.target.id
);
return;
}
jQuery.post ("ajax.php",
{
"page" : "godmode/setup/setup_notifications",
"mark_notification_as_read" : 1,
"message": match[2]
},
function (data, status) {
if (!data.result) {
console.error("Cannot redirect to URL.");
return;
}
notifications_clean_ui(match[1], event.target.id);
},
"json"
)
.fail(function(xhr, textStatus, errorThrown){
console.error(
"Failed onclik event on toast. Error: ",
xhr.responseText
);
});
}
function print_toast(title, subtitle, severity, url, id, onclick) {
// TODO severity.
severity = '';
// Start the toast.
var toast = document.createElement('a');
toast.setAttribute('onclick', onclick);
toast.setAttribute('href', url);
toast.setAttribute('target', '_blank');
// Fill toast.
var toast_div = document.createElement('div');
toast_div.className = 'snackbar ' + severity;
toast_div.id = id;
var toast_title = document.createElement('h3');
var toast_text = document.createElement('p');
toast_title.innerHTML = title;
toast_text.innerHTML = subtitle;
toast_div.appendChild(toast_title);
toast_div.appendChild(toast_text);
toast.appendChild(toast_div);
// Show and program the hide event.
toast_div.className = toast_div.className + ' show';
setTimeout(function(){
toast_div.className = toast_div.className.replace("show", "");
}, 8000);
return toast;
}
function check_new_notifications() {
var last_id = document.getElementById('notification-ball-header')
.getAttribute('last_id');
if (last_id === null) {
console.error('Cannot retrieve notifications ball last_id.');
return;
}
jQuery.post ("ajax.php",
{
"page" : "godmode/setup/setup_notifications",
"check_new_notifications" : 1,
"last_id": last_id
},
function (data, status) {
// Clean the toasts wrapper at first.
var toast_wrapper = document.getElementById(
'notifications-toasts-wrapper'
);
if (toast_wrapper === null) {
console.error('Cannot place toast notifications.');
return;
}
while (toast_wrapper.firstChild) {
toast_wrapper.removeChild(toast_wrapper.firstChild);
}
// Return if no new notification.
if(!data.has_new_notifications) return;
// Substitute the ball
var new_ball = atob(data.new_ball);
var ball_wrapper = document
.getElementById('notification-ball-header')
.parentElement;
if (ball_wrapper === null) {
console.error('Cannot update notification ball');
return;
}
// Print the new ball and clean old notifications
ball_wrapper.innerHTML = new_ball;
var not_drop = document.getElementById('notification-content');
while (not_drop.firstChild && not_drop) {
not_drop.removeChild(not_drop.firstChild);
}
// Add the new toasts.
if (Array.isArray(data.new_notifications)) {
data.new_notifications.forEach(function(ele) {
toast_wrapper.appendChild(
print_toast(
ele.subject,
ele.mensaje,
ele.criticity,
ele.full_url,
'notification-toast-id-' + ele.id_mensaje,
'click_on_notification_toast(event)'
)
);
});
}
},
"json"
)
.fail(function(xhr, textStatus, errorThrown){
console.error(
"Cannot get new notifications. Error: ",
xhr.responseText
);
});
}
// Resize event
window.addEventListener("resize", function() {
attatch_to_image();
});
var fixed_header = <?php echo json_encode((bool) $config_fixed_header); ?>;
var new_chat = <?php echo (int) $_SESSION['new_chat']; ?>;
$(document).ready (function () {
// Check new notifications on a periodic way
setInterval(check_new_notifications, 10000);
// Print the wrapper for notifications
var notifications_toasts_wrapper = document.createElement('div');
notifications_toasts_wrapper.id = 'notifications-toasts-wrapper';
document.body.insertBefore(
notifications_toasts_wrapper,
document.body.firstChild
);
<?php
if (($autorefresh_list !== null) && (array_search($_GET['sec2'], $autorefresh_list) !== false) && (!isset($_GET['refr']))) {
$do_refresh = true;
@ -425,33 +570,12 @@ config_check();
$("#ui_close_dialog_titlebar").click(function () {
$("#agent_access").css("display","");
});
function blinkmail(){
$("#yougotmail").delay(100).fadeTo(300,0.2).delay(100).fadeTo(300,1, blinkmail);
}
function blinkalert(){
$("#yougotalert").delay(100).fadeTo(300,0.2).delay(100).fadeTo(300,1, blinkalert);
}
function blinkpubli(){
$(".publienterprise").delay(100).fadeTo(300,0.2).delay(100).fadeTo(300,1, blinkpubli);
}
<?php
if ($msg_cnt > 0) {
?>
blinkmail();
<?php
}
?>
<?php
if ($config['alert_cnt'] > 0) {
?>
blinkalert();
<?php
}
?>
blinkpubli();
blinkpubli();
<?php
if ($_GET['refr']) {
@ -486,4 +610,4 @@ config_check();
});
});
/* ]]> */
</script>
</script>

View File

@ -269,6 +269,9 @@ if (check_acl($config['id_user'], 0, 'PM')) {
$sub2['godmode/setup/setup&amp;section=ehorus']['text'] = __('eHorus');
$sub2['godmode/setup/setup&amp;section=ehorus']['refr'] = 0;
$sub2['godmode/setup/setup&amp;section=notifications']['text'] = __('Notifications');
$sub2['godmode/setup/setup&amp;section=notifications']['refr'] = 0;
if ($config['activate_gis']) {
$sub2['godmode/setup/gis']['text'] = __('Map conections GIS');
}

View File

@ -82,6 +82,18 @@ if (enterprise_installed()) {
$table->data[12][1] = html_print_input_text('inventory_purge', $config['inventory_purge'], '', 5, 5, true);
}
$table->data[] = [
__('Max. days before delete old messages'),
html_print_input_text(
'delete_old_messages',
$config['delete_old_messages'],
'',
5,
5,
true
),
];
$table_other = new stdClass();
$table_other->width = '100%';
$table_other->class = 'databox filters';

View File

@ -107,6 +107,12 @@ $buttons['ehorus'] = [
'text' => '<a href="index.php?sec=gsetup&sec2=godmode/setup/setup&section=ehorus">'.html_print_image('images/ehorus/ehorus.png', true, ['title' => __('eHorus')]).'</a>',
];
// FIXME: Not definitive icon
$buttons['notifications'] = [
'active' => false,
'text' => '<a href="index.php?sec=gsetup&sec2=godmode/setup/setup&section=notifications">'.html_print_image('images/alerts_template.png', true, ['title' => __('Notifications')]).'</a>',
];
$help_header = '';
if (enterprise_installed()) {
$subpage = setup_enterprise_add_subsection_main($section, $buttons, $help_header);
@ -143,6 +149,11 @@ switch ($section) {
$buttons['ehorus']['active'] = true;
$subpage = ' &raquo '.__('eHorus');
break;
case 'notifications':
$buttons['notifications']['active'] = true;
$subpage = ' &raquo '.__('Notifications');
break;
}
// Header
@ -183,6 +194,10 @@ switch ($section) {
include_once $config['homedir'].'/godmode/setup/setup_ehorus.php';
break;
case 'notifications':
include_once $config['homedir'].'/godmode/setup/setup_notifications.php';
break;
default:
enterprise_hook('setup_enterprise_select_tab', [$section]);
break;

View File

@ -1,18 +1,31 @@
<?php
/**
* Library. Notification system auxiliary functions.
*
* @category UI file
* @package Pandora FMS
* @subpackage Community
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2005-2019 Artica Soluciones Tecnologicas
* Please see http://pandorafms.org for full contribution list
* 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 for version 2.
* 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.
* ============================================================================
*/
// Pandora FMS - http://pandorafms.com
// ==================================================
// Copyright (c) 2005-2019 Artica Soluciones Tecnologicas
// Please see http://pandorafms.org for full contribution list
// 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 for version 2.
// 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.
// Warning: This file may be required into the metaconsole's setup
// Load global vars
global $config;
require_once $config['homedir'].'/include/functions_notifications.php';
@ -26,66 +39,127 @@ if (! check_acl($config['id_user'], 0, 'PM') && ! is_user_admin($config['id_user
}
// AJAX actions.
$source_id = get_parameter('source_id', '');
$source = get_parameter('source', '');
$users = get_parameter('users', '');
$elements = get_parameter('elements', []);
$id = empty($source_id) ? 0 : get_notification_source_id($source_id);
$is_users = $users === 'users';
if (get_parameter('get_selection_two_ways_form', 0)) {
$info_selec = $is_users ? notifications_get_user_source_not_configured($id) : notifications_get_group_source_not_configured($id);
$info_selec = ($is_users === true) ? notifications_get_user_source_not_configured($source) : notifications_get_group_source_not_configured($source);
echo notifications_print_two_ways_select(
$info_selec,
$users,
$source_id
$source
);
return;
}
if (get_parameter('add_source_to_database', 0)) {
$res = $is_users ? notifications_add_users_to_source($id, $elements) : notifications_add_group_to_source($id, $elements);
$res = ($is_users) ? notifications_add_users_to_source($source, $elements) : notifications_add_group_to_source($source, $elements);
$result = ['result' => $res];
echo json_encode($result);
return;
}
if (get_parameter('remove_source_on_database', 0)) {
$res = $is_users ? notifications_remove_users_from_source($id, $elements) : notifications_remove_group_from_source($id, $elements);
$res = ($is_users) ? notifications_remove_users_from_source($source, $elements) : notifications_remove_group_from_source($source, $elements);
$result = ['result' => $res];
echo json_encode($result);
return;
}
// Form actions.
if (get_parameter('update_config', 0)) {
$res_global = array_reduce(
notifications_get_all_sources(),
function ($carry, $source) {
$id = notifications_desc_to_id($source['description']);
if (empty($id)) {
return false;
}
$element = (string) get_parameter('element', '');
$value = (int) get_parameter('value', 0);
$enable_value = switch_to_int(get_parameter("enable-$id"));
$mail_value = (int) get_parameter("mail-{$id}", 0);
$user_value = (int) get_parameter("user-{$id}", 0);
$postpone_value = (int) get_parameter("postpone-{$id}", 0);
$all_users = (int) get_parameter("all-{$id}", 0);
$res = db_process_sql_update(
// Update the label value.
ob_clean();
$res = false;
switch ($element) {
// All users has other action.
case 'all_users':
$res = ($value) ? notifications_add_group_to_source($source, [0]) : notifications_remove_group_from_source($source, [0]);
break;
default:
$res = (bool) db_process_sql_update(
'tnotification_source',
[
'enabled' => $enable_value,
'user_editable' => $user_value,
'also_mail' => $mail_value,
'max_postpone_time' => $postpone_value,
],
['id' => $source['id']]
[$element => $value],
['id' => $source]
);
$all_users_res = $all_users ? notifications_add_group_to_source($source['id'], [0]) : notifications_remove_group_from_source($source['id'], [0]);
return $all_users_res && $res && $carry;
},
true
break;
}
echo json_encode(['result' => $res]);
return;
}
if (get_parameter('check_new_notifications', 0)) {
$last_id_ui = (int) get_parameter('last_id', 0);
$counters = notifications_get_counters();
if ((int) $last_id_ui === (int) $counters['last_id']) {
echo json_encode(['has_new_notifications' => false]);
return;
}
$messages = messages_get_overview(
'timestamp',
'ASC',
false,
true,
0,
['id_mensaje' => '>'.$last_id_ui]
);
if ($messages === false) {
$messages = [];
}
// If there is new messages, get the info.
echo json_encode(
[
'has_new_notifications' => true,
'new_ball' => base64_encode(
notifications_print_ball(
$counters['notifications'],
$counters['last_id']
)
),
'new_notifications' => array_map(
function ($elem) {
$elem['full_url'] = messages_get_url($elem['id_mensaje']);
return $elem;
},
$messages
),
]
);
return;
}
if (get_parameter('mark_notification_as_read', 0)) {
$message = (int) get_parameter('message', 0);
messages_process_read($message);
// TODO check read.
$url = messages_get_url($message);
// Return false if cannot get the URL.
if ($url === false) {
echo json_encode(['result' => false]);
return;
}
// If there is new messages, get the info.
echo json_encode(
[
'result' => true,
'url' => $url,
]
);
return;
}
if (get_parameter('get_notifications_dropdown', 0)) {
echo notifications_print_dropdown();
return;
}
// Notification table. It is just a wrapper.
@ -96,36 +170,18 @@ $table_content->id = 'notifications-wrapper';
$table_content->class = 'databox filters';
$table_content->size['name'] = '30%';
// Print each source configuration
// Print each source configuration.
$table_content->data = array_map(
function ($source) {
return notifications_print_global_source_configuration($source);
},
notifications_get_all_sources()
);
$table_content->data[] = html_print_submit_button(
__('Update'),
'update_button',
false,
'class="sub upd" style="display: flex; "',
true
);
echo '<form id="form_enable" method="post">';
html_print_input_hidden('update_config', 1);
html_print_table($table_content);
echo '</form>';
?>
<script>
// Get the source id
function notifications_get_source_id(id) {
var matched = id.match(/.*-(.*)/);
if (matched == null) return '';
return matched[1];
}
// Get index of two ways element dialog.
function notifications_two_ways_element_get_dialog (id, source_id) {
return 'global_config_notifications_dialog_add-' + id + '-' + source_id;
@ -136,16 +192,6 @@ function notifications_two_ways_element_get_sufix (id, source_id) {
return 'multi-' + id + '-' + source_id;
}
// Disable or enable the select seeing the checked value of notify all users
function notifications_disable_source(event) {
var id = notifications_get_source_id(event.target.id);
var is_checked = document.getElementById(event.target.id).checked;
var selectors = ['groups', 'users'];
selectors.map(function (select) {
document.getElementById(notifications_two_ways_element_get_sufix(select, id)).disabled = is_checked;
});
}
// Open a dialog with selector of source elements.
function add_source_dialog(users, source_id) {
// Display the dialog
@ -155,7 +201,10 @@ function add_source_dialog(users, source_id) {
if (previous_dialog !== null) previous_dialog.remove();
// Create or recreate the content.
var not_dialog = document.createElement('div');
not_dialog.setAttribute('class', 'global_config_notifications_dialog_add_wrapper');
not_dialog.setAttribute(
'class',
'global_config_notifications_dialog_add_wrapper'
);
not_dialog.setAttribute('id', dialog_id);
document.body.appendChild(not_dialog);
$("#" + dialog_id).dialog({
@ -175,7 +224,7 @@ function add_source_dialog(users, source_id) {
{"page" : "godmode/setup/setup_notifications",
"get_selection_two_ways_form" : 1,
"users" : users,
"source_id" : source_id
"source" : source_id
},
function (data, status) {
not_dialog.innerHTML = data
@ -204,7 +253,8 @@ function notifications_modify_two_ways_element (id, source_id, operation) {
// Add elements to database and close dialog
function notifications_add_source_element_to_database(id, source_id) {
var index = 'selected-' + notifications_two_ways_element_get_sufix (id, source_id);
var index = 'selected-' +
notifications_two_ways_element_get_sufix (id, source_id);
var select = document.getElementById(index);
var selected = [];
for (var i = select.options.length - 1; i >= 0; i--) {
@ -214,7 +264,7 @@ function notifications_add_source_element_to_database(id, source_id) {
{"page" : "godmode/setup/setup_notifications",
"add_source_to_database" : 1,
"users" : id,
"source_id" : source_id,
"source" : source_id,
"elements": selected
},
function (data, status) {
@ -227,7 +277,11 @@ function notifications_add_source_element_to_database(id, source_id) {
out_select.appendChild(select.options[i]);
}
// Close the dialog
$("#" + notifications_two_ways_element_get_dialog(id, source_id)).dialog("close");
$("#" + notifications_two_ways_element_get_dialog(
id,
source_id
))
.dialog("close");
} else {
console.log("Cannot update element.");
}
@ -252,13 +306,13 @@ function remove_source_elements(id, source_id) {
{"page" : "godmode/setup/setup_notifications",
"remove_source_on_database" : 1,
"users" : id,
"source_id" : source_id,
"source" : source_id,
"elements": selected
},
function (data, status) {
if (data.result) {
// Append to other element
for (var i = selected_index.length - 1; i >= 0; i--) {
for (var i = 0; i < selected_index.length; i++) {
select.remove(selected_index[i]);
}
} else {
@ -268,4 +322,94 @@ function remove_source_elements(id, source_id) {
"json"
);
}
function notifications_handle_change_element(event) {
event.preventDefault();
var match = /nt-([0-9]+)-(.*)/.exec(event.target.id);
if (!match) {
console.error(
"Cannot handle change element. Id not valid: ", event.target.id
);
return;
}
var action = {source: match[1], bit: match[2]};
var element = document.getElementById(event.target.id);
if (element === null) {
console.error(
"Cannot get element. Id: ", event.target.id
);
return;
}
var value;
switch (action.bit) {
case 'enabled':
case 'also_mail':
case 'user_editable':
case 'all_users':
value = element.checked ? 1 : 0;
break;
case 'max_postpone_time':
value = element.value;
break;
default:
console.error("Unregonized action", action.bit, '.');
return;
}
jQuery.post ("ajax.php",
{
"page" : "godmode/setup/setup_notifications",
"update_config" : 1,
"source" : match[1],
"element" : match[2],
"value": value
},
function (data, status) {
if (!data.result) {
console.error("Error changing configuration in database.");
} else {
switch (action.bit) {
case 'enabled':
case 'also_mail':
case 'user_editable':
case 'all_users':
element.checked = !element.checked;
break;
case 'max_postpone_time':
value = element.value;
break;
default:
console.error(
"Unregonized action (insert on db)", action.bit, '.'
);
return;
}
}
},
"json"
)
.done(function(m){})
.fail(function(xhr, textStatus, errorThrown){
console.error(
"Cannot change configuration in database. Server error.",
xhr.responseText
);
});
}
(function(){
// Add listener to all componentes marked
var all_clickables = document.getElementsByClassName('elem-clickable');
for (var i = 0; i < all_clickables.length; i++) {
all_clickables[i].addEventListener(
'click', notifications_handle_change_element, false
);
}
var all_changes = document.getElementsByClassName('elem-changeable');
for (var i = 0; i < all_changes.length; i++) {
all_changes[i].addEventListener(
'change', notifications_handle_change_element, false
);
}
})();
</script>

View File

@ -748,6 +748,10 @@ function config_update_config()
}
}
if (!config_update_value('delete_old_messages', get_parameter('delete_old_messages'))) {
$error_update[] = __('Max. days before delete old messages');
}
if (!config_update_value('max_graph_container', get_parameter('max_graph_container'))) {
$error_update[] = __('Graph container - Max. Items');
}
@ -1535,6 +1539,10 @@ function config_process_config()
}
}
if (!isset($config['delete_old_messages'])) {
config_update_value('delete_old_messages', 21);
}
if (!isset($config['max_graph_container'])) {
config_update_value('max_graph_container', 10);
}

View File

@ -2998,14 +2998,35 @@ function html_print_csrf_error()
* @param array $atributes. Valid params:
* name: Usefull to handle in forms
* value: If is checked or not
* disabled: Disabled. Cannot be pressed.
* id: Optional id for the switch.
* class: Additional classes (string).
* @return string with HTML of button
*/
function html_print_switch($attributes=[])
{
$name_html = isset($attributes['name']) ? "name = {$attributes['name']}" : '';
$checked_html = (bool) $attributes['value'] ? 'checked' : '';
$html_expand = '';
// Check the load values on status.
$html_expand .= (bool) $attributes['value'] ? ' checked' : '';
$html_expand .= (bool) $attributes['disabled'] ? ' disabled' : '';
// Only load the valid attributes.
$valid_attrs = [
'id',
'class',
'name',
];
foreach ($valid_attrs as $va) {
if (!isset($attributes[$va])) {
continue;
}
$html_expand .= ' '.$va.'="'.$attributes[$va].'"';
}
return "<label class='p-switch'>
<input type='checkbox' $name_html $checked_html>
<input type='checkbox' $html_expand>
<span class='p-slider'></span>
</label>";
}

View File

@ -215,7 +215,6 @@ function messages_process_read(
bool $read=true
) {
global $config;
// Check if user has grants to read the message.
if (check_notification_readable($message_id) === false) {
return false;
@ -339,14 +338,16 @@ function messages_get_message_sent(int $message_id)
/**
* Counts private messages
*
* @param string $user Target user.
* @param boolean $incl_read Whether or not to include read messages.
* @param string $user Target user.
* @param boolean $incl_read Whether or not to include read messages.
* @param boolean $ignore_source Ignore source.
*
* @return integer The number of messages this user has
*/
function messages_get_count(
string $user='',
bool $incl_read=false
bool $incl_read=false,
bool $ignore_source=false
) {
if (empty($user)) {
global $config;
@ -361,20 +362,33 @@ function messages_get_count(
$read = 'where t.read is null';
}
if ($ignore_source === true) {
$source_sql = '';
} else {
$source_sql = 'INNER JOIN tnotification_source ns
ON tm.id_source = ns.id
AND ns.enabled = 1';
}
$sql = sprintf(
'SELECT count(*) FROM (
SELECT tm.*, utimestamp_read > 0 as "read" FROM tmensajes tm
SELECT DISTINCT tm.*, utimestamp_read > 0 as "read"
FROM tmensajes tm
%s
LEFT JOIN tnotification_user nu
ON tm.id_mensaje=nu.id_mensaje
AND nu.id_user="%s"
LEFT JOIN (tnotification_group ng
INNER JOIN tusuario_perfil up
ON ng.id_group=up.id_grupo
AND up.id_grupo=ng.id_group
) ON tm.id_mensaje=ng.id_mensaje
WHERE utimestamp_erased is null
AND (up.id_usuario="%s" OR nu.id_user="%s" OR ng.id_group=0)
AND (nu.id_user="%s" OR (up.id_usuario="%s" AND ng.id_group=0))
) t
%s',
$source_sql,
$user,
$user,
$user,
$read
@ -411,18 +425,24 @@ function messages_get_count_sent(string $user='')
/**
* Get message overview in array
*
* @param string $order How to order them valid:
* (status (default), subject, timestamp, sender).
* @param string $order_dir Direction of order
* (ASC = Ascending, DESC = Descending).
* @param boolean $incl_read Include read messages in return.
* @param string $order How to order them valid:
* (status (default), subject, timestamp, sender).
* @param string $order_dir Direction of order
* (ASC = Ascending, DESC = Descending).
* @param boolean $incl_read Include read messages in return.
* @param boolean $incl_source_info Include source info.
* @param integer $limit Maximum number of result in the query.
* @param array $other_filter Add a filter on main query.
*
* @return integer The number of messages this user has
*/
function messages_get_overview(
string $order='status',
string $order_dir='ASC',
bool $incl_read=true
bool $incl_read=true,
bool $incl_source_info=false,
int $limit=0,
array $other_filter=[]
) {
global $config;
@ -453,25 +473,44 @@ function messages_get_overview(
$read = 'where t.read is null';
}
$source_fields = '';
$source_join = '';
if ($incl_source_info) {
$source_fields = ', tns.*';
$source_join = 'INNER JOIN tnotification_source tns
ON tns.id=tm.id_source';
}
// Using distinct because could be double assignment due group/user.
$sql = sprintf(
'SELECT * FROM (
SELECT tm.*, utimestamp_read > 0 as "read" FROM tmensajes tm
SELECT DISTINCT tm.*, utimestamp_read > 0 as "read" %s
FROM tmensajes tm
LEFT JOIN tnotification_user nu
ON tm.id_mensaje=nu.id_mensaje
AND nu.id_user="%s"
LEFT JOIN (tnotification_group ng
INNER JOIN tusuario_perfil up
ON ng.id_group=up.id_grupo
AND up.id_grupo=ng.id_group
) ON tm.id_mensaje=ng.id_mensaje
) ON tm.id_mensaje=ng.id_mensaje
%s
WHERE utimestamp_erased is null
AND (up.id_usuario="%s" OR nu.id_user="%s" OR ng.id_group=0)
AND (nu.id_user="%s" OR (up.id_usuario="%s" AND ng.id_group=0))
) t
%s
ORDER BY %s',
%s
ORDER BY %s
%s',
$source_fields,
$config['id_user'],
$source_join,
$config['id_user'],
$config['id_user'],
$read,
$order
db_format_array_where_clause_sql($other_filter, 'AND', ' AND '),
$order,
($limit !== 0) ? ' LIMIT '.$limit : ''
);
return db_get_all_rows_sql($sql);
@ -520,3 +559,28 @@ function messages_get_overview_sent(
$order
);
}
/**
* Get the URL of a message. If field in db is null, it returs a link to
* messages view.
*
* @param integer $message_id Message id to get URL.
*
* @return mixed False if fails. A string with URL otherwise.
*/
function messages_get_url($message_id)
{
$messages = messages_get_message($message_id);
if ($messages === false) {
return false;
}
// Return URL stored if is set in database.
if (isset($messages['url'])) {
return $messages['url'];
}
// Return the message direction.
return ui_get_full_url('index.php?sec=message_list&sec2=operation/messages/message_edit&read_message=1&id_message='.$message_id);
}

View File

@ -26,6 +26,8 @@
* ============================================================================
*/
require_once $config['homedir'].'/include/functions_messages.php';
define('NOTIFICATIONS_POSTPONE_FOREVER', -1);
@ -43,28 +45,16 @@ function get_notification_source_id(string $source)
}
return db_get_value_sql(
"SELECT id
FROM `tnotification_source`
WHERE `description` LIKE '".$source."%'"
sprintf(
'SELECT id
FROM `tnotification_source`
WHERE lower(`description`) = lower("%s")',
$source
)
);
}
/**
* Converts description into a handable identifier
*
* @param string $desc Full description.
*
* @return string First word in lowercase. Empty string if no word detected.
*/
function notifications_desc_to_id(string $desc)
{
preg_match('/^[a-zA-Z]*/', $desc, $matches);
$match = $matches[0];
return isset($match) ? $match : '';
}
/**
* Retrieve all targets for given message.
*
@ -141,10 +131,13 @@ function check_notification_readable(int $id_message)
return false;
}
// Using distinct to avoid double response on group messages read by user.
$sql = sprintf(
'SELECT tm.*, utimestamp_read > 0 as "read" FROM tmensajes tm
'SELECT DISTINCT tm.*, utimestamp_read > 0 as "read"
FROM tmensajes tm
LEFT JOIN tnotification_user nu
ON tm.id_mensaje=nu.id_mensaje
AND nu.id_user="%s"
AND tm.id_mensaje=%d
LEFT JOIN (tnotification_group ng
INNER JOIN tusuario_perfil up
@ -152,7 +145,8 @@ function check_notification_readable(int $id_message)
AND up.id_grupo=ng.id_group
) ON tm.id_mensaje=ng.id_mensaje
WHERE utimestamp_erased is null
AND (up.id_usuario="%s" OR nu.id_user="%s" OR ng.id_group=0)',
AND (nu.id_user="%s" OR (up.id_usuario="%s" AND ng.id_group=0))',
$config['id_user'],
$id_message,
$config['id_user'],
$config['id_user']
@ -166,7 +160,7 @@ function check_notification_readable(int $id_message)
* Returns the target users and groups assigned to be notified on
* desired source.
*
* @param integer $id_source
* @param integer $id_source Source identificator.
*
* @return array [users] and [groups] with the targets.
*/
@ -224,41 +218,62 @@ function get_notification_source_targets(int $id_source)
/**
* Return all info from tnotification_source
*
* @param array $filter Filter to table tnotification_source.
*
* @return array with sources info
*/
function notifications_get_all_sources()
function notifications_get_all_sources($filter=[])
{
return db_get_all_rows_in_table('tnotification_source');
return db_get_all_rows_filter('tnotification_source', $filter);
}
/**
* Return the user sources to be inserted into a select
*
* @param integer $source_id Source database identificator
* @param integer $source_id Source database identificator.
*
* @return array with the user id in keys and user id in value too
*/
function notifications_get_user_sources_for_select($source_id)
{
$users = db_get_all_rows_filter(
'tnotification_source_user',
$users = notifications_get_user_sources(
['id_source' => $source_id],
'id_user'
['id_user']
);
// If fails or no one is selected, return empty array
if ($users === false) {
return [];
}
return index_array($users, 'id_user', 'id_user');
}
/**
* Get the user sources
*
* @param array $filter Filter of sql query.
* @param array $fields Fields to get of query.
*
* @return array Array with user sources data.
*/
function notifications_get_user_sources($filter=[], $fields=[])
{
$users = db_get_all_rows_filter(
'tnotification_source_user',
$filter,
$fields
);
// If fails or no one is selected, return empty array.
if ($users === false) {
return [];
}
return $users;
}
/**
* Return the groups sources to be inserted into a select
*
* @param integer $source_id Source database identificator
* @param integer $source_id Source database identificator.
*
* @return array with the group id in keys and group name in value
*/
@ -276,6 +291,9 @@ function notifications_get_group_sources_for_select($source_id)
* Get the group sources
*
* @param array $filter Filter of sql query.
* @param array $fields Fields retrieved.
*
* @return array With the group info
*/
function notifications_get_group_sources($filter=[], $fields=[])
{
@ -287,7 +305,7 @@ function notifications_get_group_sources($filter=[], $fields=[])
$fields = array_map(
function ($field) {
if (!preg_match('/^tnsg./', $field)) {
$field = "tnsg.{$field}";
$field = 'tnsg.'.$field;
}
return $field;
@ -303,7 +321,7 @@ function notifications_get_group_sources($filter=[], $fields=[])
array_merge($fields, ['IFNULL(tg.nombre, "All") AS name'])
);
// If fails or no one is selected, return empty array
// If fails or no one is selected, return empty array.
if ($groups === false) {
return [];
}
@ -315,19 +333,19 @@ function notifications_get_group_sources($filter=[], $fields=[])
/**
* Delete a set of groups from notification source
*
* @param int Source id
* @param array Id of groups to be deleted
* @param integer $source_id Source id.
* @param array $groups Id of groups to be deleted.
*
* @return boolean True if success. False otherwise.
*/
function notifications_remove_group_from_source($source_id, $groups)
{
// Source id is mandatory
// Source id is mandatory.
if (!isset($source_id)) {
return false;
}
// Delete from database
// Delete from database.
return db_process_sql_delete(
'tnotification_source_group',
[
@ -341,19 +359,19 @@ function notifications_remove_group_from_source($source_id, $groups)
/**
* Delete a set of users from notification source
*
* @param int Source id
* @param array Id of users to be deleted
* @param integer $source_id Source id.
* @param array $users Id of users to be deleted.
*
* @return boolean True if success. False otherwise.
*/
function notifications_remove_users_from_source($source_id, $users)
{
// Source id is mandatory
// Source id is mandatory.
if (!isset($source_id)) {
return false;
}
// Delete from database
// Delete from database.
return db_process_sql_delete(
'tnotification_source_user',
[
@ -367,22 +385,22 @@ function notifications_remove_users_from_source($source_id, $users)
/**
* Insert a set of groups to notification source
*
* @param int Source id
* @param array Id of groups to be deleted
* @param integer $source_id Source id.
* @param array $groups Id of groups to be deleted.
*
* @return boolean True if success. False otherwise.
*/
function notifications_add_group_to_source($source_id, $groups)
{
// Source id is mandatory
// Source id is mandatory.
if (!isset($source_id)) {
return false;
}
// Insert into database all groups passed
// Insert into database all groups passed.
$res = true;
foreach ($groups as $group) {
if (empty($group)) {
if (!isset($group)) {
continue;
}
@ -402,20 +420,26 @@ function notifications_add_group_to_source($source_id, $groups)
/**
* Insert a set of users to notification source
*
* @param int Source id
* @param array Id of users to be deleted
* @param integer $source_id Source id.
* @param array $users Id of users to be deleted.
*
* @return boolean True if success. False otherwise.
*/
function notifications_add_users_to_source($source_id, $users)
{
// Source id is mandatory
// Source id is mandatory.
if (!isset($source_id)) {
return false;
}
// Insert into database all groups passed
// Insert into database all groups passed.
$res = true;
$also_mail = db_get_value(
'also_mail',
'tnotification_source',
'id',
$source_id
);
foreach ($users as $user) {
if (empty($user)) {
continue;
@ -426,6 +450,8 @@ function notifications_add_users_to_source($source_id, $users)
[
'id_user' => $user,
'id_source' => $source_id,
'enabled' => 1,
'also_mail' => (int) $also_mail,
]
) !== false;
}
@ -438,7 +464,8 @@ function notifications_add_users_to_source($source_id, $users)
* Get the groups that not own to a source and, for that reason, they can be
* added to the source.
*
* @param integer $source_id Source id.
* @param integer $source_id Source id.
*
* @return array Indexed by id group all selectable groups.
*/
function notifications_get_group_source_not_configured($source_id)
@ -453,7 +480,8 @@ function notifications_get_group_source_not_configured($source_id)
* Get the users that not own to a source and, for that reason, they can be
* added to the source.
*
* @param integer $source_id
* @param integer $source_id Source id.
*
* @return array Indexed by id user, all selectable users.
*/
function notifications_get_user_source_not_configured($source_id)
@ -469,71 +497,223 @@ function notifications_get_user_source_not_configured($source_id)
/**
* Print the notification ball to see unread messages
* Build a data struct to handle the value of a label
*
* @return string with HTML code of notification ball
* @param mixed $status Status value.
* @param mixed $enabled Enabled value.
*
* @return array with status (1|0) and enabled (1|0)
*/
function notifications_print_ball()
function notifications_build_user_enable_return($status, $enabled)
{
$num_notifications = messages_get_count();
$class_status = $num_notifications == 0 ? 'notification-ball-no-messages' : 'notification-ball-new-messages';
return "<div class='notification-ball $class_status' id='notification-ball-header'>
$num_notifications
</div>";
return [
'status' => ((bool) $status === true) ? 1 : 0,
'enabled' => ((bool) $enabled === true) ? 1 : 0,
];
}
/**
* Get user label (enabled, also_mail...) status.
*
* @param integer $source Id of notification source.
* @param string $user User id.
* @param string $label Label id (enabled, also_email...).
*
* @return array Return of notifications_build_user_enable_return.
*/
function notifications_get_user_label_status($source, $user, $label)
{
// If not enabled, it cannot be modificable.
if (!$source['enabled'] || !$source[$label]) {
return notifications_build_user_enable_return(false, false);
}
// See at first for direct reference.
$user_source = notifications_get_user_sources(
[
'id_source' => $source['id'],
'id_user' => $user,
]
);
if (!empty($user_source)) {
return notifications_build_user_enable_return(
isset($user_source[0][$label]) ? $user_source[0][$label] : false,
$source['user_editable']
);
}
$common_groups = array_intersect(
array_keys(users_get_groups($user)),
array_keys(
notifications_get_group_sources_for_select($source['id'])
)
);
// No group found, return no permissions.
$value = empty($common_groups) ? false : $source[$label];
return notifications_build_user_enable_return($value, false);
}
/**
* Set the status to a single label on config of users notifications.
*
* @param integer $source Id of notification source.
* @param string $user User id.
* @param string $label Label id (enabled, also_email...).
* @param mixed $value Numeric value: 1 or 0.
*
* @return boolean True if success.
*/
function notifications_set_user_label_status($source, $user, $label, $value)
{
$source_info = notifications_get_all_sources(['id' => $source]);
if (!isset($source_info[0])
|| !$source_info[0]['enabled']
|| !$source_info[0][$label]
|| !$source_info[0]['user_editable']
) {
return false;
}
return (bool) db_process_sql_update(
'tnotification_source_user',
[$label => $value],
[
'id_user' => $user,
'id_source' => $source,
]
);
}
/**
* Get the counters of notification. Usefull to print the header notification
* ball.
*
* @return array With the fields:
* 'notifications' => Total new notifications,
* 'last_id' => Id of last read value. Usefull to make comparisons.
*/
function notifications_get_counters()
{
$num_notifications = 0;
$last_id = 0;
$last_message = messages_get_overview(
'timestamp',
'DESC',
false,
false,
1
);
if (!empty($last_message)) {
$num_notifications = messages_get_count();
$last_id = $last_message[0]['id_mensaje'];
}
return [
'notifications' => $num_notifications,
'last_id' => $last_id,
];
}
// /////////////////////////////////////////////////////////////////////////////
// UI FUNCTIONS
// /////////////////////////////////////////////////////////////////////////////
/**
* Print the notification ball to see unread messages.
*
* @param integer $num_notifications Number of messages shown
* in notification ball.
* @param integer $last_id Id of last message shown
* in the notification ball.
*
* @return string with HTML code of notification ball.
*/
function notifications_print_ball($num_notifications, $last_id)
{
$no_notifications = (int) $num_notifications === 0;
$class_status = ($no_notifications) ? 'notification-ball-no-messages' : 'notification-ball-new-messages';
return sprintf(
'<div
%s
class="notification-ball %s"
id="notification-ball-header"
last_id="%s"
>
%s
</div>',
($no_notifications) ? '' : 'onclick="addNotifications(event)"',
$class_status,
$last_id,
$num_notifications
);
}
/**
* Print notification configuration global
*
* @param array notification source data
* @param array $source Notification source data.
*
* @return string with HTML of source configuration
*/
function notifications_print_global_source_configuration($source)
{
// Get some values to generate the title
$id = notifications_desc_to_id($source['description']);
// Get some values to generate the title.
$switch_values = [
'name' => 'enable-'.$id,
'name' => 'enable-'.$source['id'],
'value' => $source['enabled'],
'id' => 'nt-'.$source['id'].'-enabled',
'class' => 'elem-clickable',
];
// Search if group all is set and handle that situation
// Search if group all is set and handle that situation.
$source_groups = notifications_get_group_sources_for_select($source['id']);
$is_group_all = isset($source_groups['0']);
if ($is_group_all) {
unset($source_groups['0']);
}
// Generate the title
// Generate the title.
$html_title = "<div class='global-config-notification-title'>";
$html_title .= html_print_switch($switch_values);
$html_title .= "<h2>{$source['description']}</h2>";
$html_title .= '<h2>'.$source['description'].'</h2>';
$html_title .= '</div>';
// Generate the html for title
// Generate the html for title.
$html_selectors = "<div class='global-config-notification-selectors'>";
$html_selectors .= notifications_print_source_select_box(notifications_get_user_sources_for_select($source['id']), 'users', $id, $is_group_all);
$html_selectors .= notifications_print_source_select_box($source_groups, 'groups', $id, $is_group_all);
$html_selectors .= notifications_print_source_select_box(
notifications_get_user_sources_for_select($source['id']),
'users',
$source['id']
);
$html_selectors .= notifications_print_source_select_box(
$source_groups,
'groups',
$source['id']
);
$html_selectors .= '</div>';
// Generate the checkboxes and time select
// Generate the checkboxes and time select.
$html_checkboxes = "<div class='global-config-notification-checkboxes'>";
$html_checkboxes .= ' <span>';
$html_checkboxes .= html_print_checkbox("all-$id", 1, $is_group_all, true, false, 'notifications_disable_source(event)');
$html_checkboxes .= html_print_checkbox_extended('all-'.$source['id'], 1, $is_group_all, false, '', 'class= "elem-clickable"', true, 'id="nt-'.$source['id'].'-all_users"');
$html_checkboxes .= __('Notify all users');
$html_checkboxes .= ' </span><br><span>';
$html_checkboxes .= html_print_checkbox("mail-$id", 1, $source['also_mail'], true);
$html_checkboxes .= html_print_checkbox_extended('mail-'.$source['id'], 1, $source['also_mail'], false, '', 'class= "elem-clickable"', true, 'id="nt-'.$source['id'].'-also_mail"');
$html_checkboxes .= __('Also email users with notification content');
$html_checkboxes .= ' </span><br><span>';
$html_checkboxes .= html_print_checkbox("user-$id", 1, $source['user_editable'], true);
$html_checkboxes .= __('Users cannot modify notification preferences');
$html_checkboxes .= html_print_checkbox_extended('user-'.$source['id'], 1, $source['user_editable'], false, '', 'class= "elem-clickable"', true, 'id="nt-'.$source['id'].'-user_editable"');
$html_checkboxes .= __('Users can modify notification preferences');
$html_checkboxes .= ' </span>';
$html_checkboxes .= '</div>';
// Generate the select with the time
// Generate the select with the time.
$html_select_pospone = __('Users can postpone notifications up to');
// FIXMEit should not be disabled.
$html_select_pospone .= html_print_select(
[
SECONDS_5MINUTES => __('5 minutes'),
@ -545,15 +725,19 @@ function notifications_print_global_source_configuration($source)
SECONDS_1MONTH => __('1 month'),
NOTIFICATIONS_POSTPONE_FOREVER => __('forever'),
],
"postpone-{$id}",
'nt-'.$source['id'].'-max_postpone_time',
$source['max_postpone_time'],
'',
'',
0,
true,
false,
true,
'elem-changeable',
true
);
// Return all html
// Return all html.
return $html_title.$html_selectors.$html_checkboxes.$html_select_pospone;
}
@ -561,32 +745,72 @@ function notifications_print_global_source_configuration($source)
/**
* Print select boxes of notified users or groups
*
* @param array $info_selec All info required for build the selector
* @param string $id users|groups
* @param string $source_id Id of source
* @param boolean $disabled Disable the selectors
* @param array $info_selec All info required for build the selector.
* @param string $id One of users|groups.
* @param string $source_id Id of source.
*
* @return string HTML with the generated selector
*/
function notifications_print_source_select_box($info_selec, $id, $source_id, $disabled)
{
$title = $id == 'users' ? __('Notified users') : __('Notified groups');
$add_title = $id == 'users' ? __('Add users') : __('Add groups');
$delete_title = $id == 'users' ? __('Delete users') : __('Delete groups');
function notifications_print_source_select_box(
$info_selec,
$id,
$source_id
) {
$title = ($id === 'users') ? __('Notified users') : __('Notified groups');
$add_title = ($id === 'users') ? __('Add users') : __('Add groups');
$delete_title = ($id === 'users') ? __('Delete users') : __('Delete groups');
// Generate the HTML
$html_select = "<div class='global-config-notification-single-selector'>";
$html_select .= ' <div>';
$html_select .= " <h4>$title</h4>";
// Put a true if empty sources to avoid to sow the 'None' value
$html_select .= html_print_select(empty($info_selec) ? true : $info_selec, "multi-{$id}-{$source_id}[]", 0, false, '', '', true, true, true, '', $disabled);
$html_select .= ' </div>';
$html_select .= " <div class='global-notifications-icons'>";
$html_select .= html_print_image('images/input_add.png', true, ['title' => $add_title, 'onclick' => "add_source_dialog('$id', '$source_id')"]);
$html_select .= html_print_image('images/input_delete.png', true, ['title' => $delete_title, 'onclick' => "remove_source_elements('$id', '$source_id')"]);
$html_select .= ' </div>';
$html_select .= '</div>';
return $html_select;
// Generate the HTML.
return sprintf(
"
<div class='global-config-notification-single-selector'>
<div>
<h4>%s</h4>
%s
</div>
<div class='global-notifications-icons'>
%s
%s
</div>
</div>
",
$title,
// Put a true if empty sources to avoid to sow the 'None' value.
html_print_select(
empty($info_selec) ? true : $info_selec,
'multi-'.$id.'-'.$source_id.'[]',
0,
false,
'',
'',
true,
true
),
html_print_image(
'images/input_add.png',
true,
[
'title' => $add_title,
'onclick' => sprintf(
"add_source_dialog('%s', '%s')",
$id,
$source_id
),
]
),
html_print_image(
'images/input_delete.png',
true,
[
'title' => $delete_title,
'onclick' => sprintf(
"remove_source_elements('%s', '%s')",
$id,
$source_id
),
]
)
);
}
@ -594,22 +818,180 @@ function notifications_print_source_select_box($info_selec, $id, $source_id, $di
* Print the select with right and left arrows to select new sources
* (groups or users).
*
* @param array $info_selec Array with source info.
* @param string $users users|groups.
* @param source $source_id Source id.
* @param array $info_selec Array with source info.
* @param string $users One of users|groups.
* @param source $source_id Source id.
*
* @return string HTML with the select code.
*/
function notifications_print_two_ways_select($info_selec, $users, $source_id)
{
$html_select = "<div class='global_config_notifications_dialog_add'>";
$html_select .= html_print_select(empty($info_selec) ? true : $info_selec, "all-multi-{$users}-{$source_id}[]", 0, false, '', '', true, true, true, '');
$html_select .= "<div class='global_config_notifications_two_ways_form_arrows'>";
$html_select .= html_print_image('images/darrowright.png', true, ['title' => $add_title, 'onclick' => "notifications_modify_two_ways_element('$users', '$source_id', 'add')"]);
$html_select .= html_print_image('images/darrowleft.png', true, ['title' => $add_title, 'onclick' => "notifications_modify_two_ways_element('$users', '$source_id', 'remove')"]);
$html_select .= '</div>';
$html_select .= html_print_select(true, "selected-multi-{$users}-{$source_id}[]", 0, false, '', '', true, true, true, '');
$html_select .= '</div>';
$html_select .= html_print_button(__('Add'), 'Add', false, "notifications_add_source_element_to_database('$users', '$source_id')", "class='sub add'", true);
return $html_select;
return sprintf(
"
<div class='global_config_notifications_dialog_add'>
%s
<div class='global_config_notifications_two_ways_form_arrows'>
%s
%s
</div>
%s
</div>
%s
",
html_print_select(
empty($info_selec) ? true : $info_selec,
'all-multi-'.$users.'-'.$source_id.'[]',
0,
false,
'',
'',
true,
true,
true,
''
),
html_print_image(
'images/darrowright.png',
true,
[
'title' => __('Add elements'),
'onclick' => sprintf(
"notifications_modify_two_ways_element('%s', '%s', 'add')",
$users,
$source_id
),
]
),
html_print_image(
'images/darrowleft.png',
true,
[
'title' => __('Remove elements'),
'onclick' => sprintf(
"notifications_modify_two_ways_element('%s', '%s', 'remove')",
$users,
$source_id
),
]
),
html_print_select(
true,
'selected-multi-'.$users.'-'.$source_id.'[]',
0,
false,
'',
'',
true,
true,
true,
''
),
html_print_button(
__('Add'),
'Add',
false,
sprintf(
"notifications_add_source_element_to_database('%s', '%s')",
$users,
$source_id
),
"class='sub add'",
true
)
);
}
/**
* Print a label status represented by a switch
*
* @param integer $source Source id.
* @param string $user User id.
* @param string $label Label (enabled, also_mail...).
*
* @return string With HTML code
*/
function notifications_print_user_switch($source, $user, $label)
{
$status = notifications_get_user_label_status($source, $user, $label);
return html_print_switch(
[
'name' => $label,
'value' => $status['status'],
'disabled' => !$status['enabled'],
'class' => 'notifications-user-label_individual',
'id' => 'notifications-user-'.$source['id'].'-label-'.$label,
]
);
}
/**
* Generates the dropdown notifications menu.
*
* @return string HTML with dropdown menu.
*/
function notifications_print_dropdown()
{
$mess = messages_get_overview('status', 'DESC', false, true);
if ($mess === false) {
$mess = [];
}
return sprintf(
"<div id='notification-wrapper'>
<div id='notification-wrapper-inner'>
%s
</div>
</div>
<div
id='notification-wrapper-shadow'
onclick='notifications_hide()'
>
</div>
",
array_reduce(
$mess,
function ($carry, $message) {
return $carry.notifications_print_dropdown_element($message);
},
''
)
);
}
/**
* Print a single notification box
*
* @param array $message_info Info of printed message.
*
* @return string HTML code of single message
*/
function notifications_print_dropdown_element($message_info)
{
return sprintf(
"<a
class='notification-item'
onclick='click_on_notification_toast(event)'
id='notification-item-id-%s'
href='%s'
target='_blank'
>
%s
<div class='notification-info'>
<h4 class='notification-title'>
%s
</h4>
<p class='notification-subtitle'>
%s
</p>
</div>
</a>",
$message_info['id_mensaje'],
messages_get_url($message_info['id_mensaje']),
html_print_image('images/'.$message_info['icon'], true),
$message_info['subject'],
str_replace([io_safe_input('<br>')], ' ', $message_info['mensaje'])
);
}

View File

@ -0,0 +1,49 @@
/* Chat containers */
.container {
border: 2px solid #dedede;
background-color: #f1f1f1;
border-radius: 5px;
padding: 10px;
margin: 10px 0;
}
/* Darker chat container */
.darker {
border-color: #ccc;
background-color: #ddd;
}
/* Clear floats */
.container::after {
content: "";
clear: both;
display: table;
}
/* Style images */
.container img {
float: left;
max-width: 60px;
width: 100%;
margin-right: 20px;
border-radius: 50%;
}
/* Style the right image */
.container img.right {
float: right;
margin-left: 20px;
margin-right: 0;
}
/* Style time text */
.time-right {
float: right;
color: #aaa;
}
/* Style time text */
.time-left {
float: left;
color: #999;
}

View File

@ -4287,15 +4287,89 @@ div#dialog_messages table th:last-child {
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.notification-ball-no-messages {
background-color: #82b92e;
cursor: pointer;
}
.notification-ball-new-messages {
background-color: #fc4444;
}
#notification-wrapper {
background: white;
border: #a5a5a5 solid 1px;
z-index: 900000;
position: absolute;
width: 400px;
margin-top: -5px;
}
#notification-wrapper::before {
content: "";
display: block;
position: absolute;
width: 0px;
height: 0;
border-color: transparent;
border-width: 12px;
border-style: solid;
bottom: 100%;
left: 78%;
left: calc(78% - 2px);
margin-left: -12px;
border-bottom-color: white;
}
#notification-wrapper-inner {
max-height: 400px;
overflow: auto;
}
#notification-wrapper-shadow {
height: 100%;
width: 100%;
background: #111;
position: fixed;
z-index: 9009;
top: 0;
opacity: 0.3;
}
.notification-item {
background: whitesmoke;
height: 100px;
margin: 7px;
border: #cccccc solid 1px;
display: flex;
flex-flow: row nowrap;
align-items: center;
padding: 5px;
}
.notification-item > * {
padding-left: 15px;
pointer-events: none;
}
.notification-item:hover {
text-decoration: none;
}
.notification-info {
width: 87%;
display: flex;
flex-flow: column nowrap;
}
.notification-item img {
max-width: 100%;
max-height: 100%;
}
.notification-title {
margin: 0;
}
.notification-subtitle {
margin: 0;
color: #373737;
}
.global-config-notification-title {
display: flex;
flex-direction: row;
@ -4356,8 +4430,392 @@ div#dialog_messages table th:last-child {
margin: 15px 0;
}
/* jQuery dialog */
.no-close .ui-dialog-titlebar-close {
display: none;
/* --- JQUERY-UI --- */
.ui-button-text-only .ui-button-text {
font-family: "nunito", sans-serif;
font-size: 9pt;
color: #82b92e;
}
/* jQuery dialog */
.ui-datepicker .ui-datepicker-title *,
.ui-datepicker th * {
color: white;
}
.ui-datepicker .ui-datepicker-title select,
.ui-datepicker .ui-datepicker-title option {
color: #111 !important;
}
.ui-dialog .ui-dialog-titlebar {
display: inherit;
text-align: center;
padding: 0.4em 1em;
height: 30px;
position: relative;
background-color: #82b92e !important;
}
.ui-dialog .ui-dialog-title {
font-family: "Nunito", sans-serif;
margin: 0.1em 0 !important;
white-space: nowrap !important;
width: 100% !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
font-size: 11pt;
position: relative;
top: 5px;
float: none !important;
}
.ui-dialog .ui-dialog-titlebar-close {
position: absolute !important;
right: 1em !important;
width: 21px !important;
margin: 0px 0 0 0 !important;
padding: 1px !important;
height: 20px !important;
bottom: 30% !important;
top: 20% !important;
}
.ui-dialog .ui-dialog-content {
position: relative !important;
border: 0;
padding: 0.5em 1em !important;
background: none !important;
overflow: auto !important;
margin-bottom: 1em;
}
.ui-dialog .ui-dialog-buttonpane {
text-align: left;
border-width: 1px 0 0 0;
background-image: none;
margin-top: 0.5em;
padding: 0.3em 1em 0.5em 0.4em;
}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
float: right;
}
.ui-dialog .ui-dialog-buttonpane button {
margin: 0.5em 1em 0.5em 0 !important;
cursor: pointer !important;
background: white !important;
background-color: white !important;
border: 1px solid #82b92e !important;
min-height: 35px !important;
width: 90px !important;
}
.ui-widget-content {
background: #ffffff url(include/styles/images/ui-bg_flat_75_ffffff_40x100.png)
50% 50% repeat-x;
}
.ui-state-default,
.ui-widget-content .ui-state-default,
.ui-widget-header .ui-state-default {
margin-top: 3px;
border: 1px solid #d3d3d3 !important;
border-bottom: 0 !important;
background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50%
repeat-x !important;
font-weight: normal !important;
color: #555555 !important;
}
.ui-corner-all,
.ui-corner-top,
.ui-corner-left,
.ui-corner-tl {
border-top-left-radius: 0 !important;
}
.ui-corner-all,
.ui-corner-top,
.ui-corner-right,
.ui-corner-tr {
border-top-right-radius: 0 !important;
}
.ui-corner-all,
.ui-corner-bottom,
.ui-corner-left,
.ui-corner-bl {
border-bottom-left-radius: 0 !important;
}
.ui-corner-all,
.ui-corner-bottom,
.ui-corner-right,
.ui-corner-br {
border-bottom-right-radius: 0 !important;
}
#ui-datepicker-div {
border-color: #b1b1b1;
background: #ffffff;
}
.ui-widget-header {
background: #b1b1b1 !important;
color: #ffffff !important;
}
.ui-datepicker-calendar th {
background-color: #3f3f3f;
}
.ui-dialog .ui-widget-header {
background-color: #82b92e;
}
.ui_tpicker_hour,
.ui_tpicker_minute,
.ui_tpicker_second,
.ui-slider-handle {
border: 1px solid #aaaaaa !important;
}
.ui-timepicker-div dd {
margin: 0px 15px 0px 15px;
}
.ui-timepicker-div .ui-datepicker-title {
color: white;
}
.ui-datepicker-buttonpane button {
border-color: #b1b1b1 !important;
}
.ui-datepicker-buttonpane .ui-datepicker-current {
margin-left: 0.2em !important;
}
.ui-dialog .ui-widget-content {
border: 0px !important;
}
.ui-dialog {
box-shadow: 5px 5px 19px #4e4e4e;
border: 0px !important;
padding: 0 !important;
}
.ui-dialog-titlebar {
border: 0px !important;
}
.ui-dialog-titlebar .ui-icon-closethick,
.ui-dialog-titlebar .ui-state-default,
.ui-dialog-titlebar .ui-state-hover,
.ui-dialog-titlebar button {
background: transparent;
border: 0px;
}
.ui-dialog-title {
color: #ffffff;
font-size: 9pt;
}
.ui-widget input,
.ui-widget select,
.ui-widget textarea,
.ui-widget button {
font-family: Verdana, Arial, sans-serif !important;
}
a.ui-button:active,
.ui-button:active,
.ui-button.ui-state-active:hover,
.ui-state-focus .ui-widget-content,
.ui-state-focus .ui-widget-header,
.ui-state-focus .ui-button:hover,
.ui-button:focus {
background: transparent !important;
border: none !important;
}
.ui-state-hover,
.ui-widget-content .ui-state-hover,
.ui-widget-header .ui-state-hover {
border: 1px solid #999999 !important;
border-bottom: 0 !important;
background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50%
repeat-x !important;
}
.ui-state-active,
.ui-widget-content .ui-state-active,
.ui-widget-header .ui-state-active {
border: 1px solid #aaaaaa !important;
border-bottom: 0 !important;
background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50%
repeat-x !important;
font-weight: normal !important;
color: #212121 !important;
}
.ui-state-active a,
.ui-state-active a:link,
.ui-state-active a:visited {
color: #212121 !important;
}
ul.ui-front {
z-index: 1000000 !important;
padding-right: 0px !important;
}
ul.ui-front li {
padding: 3px !important;
}
ul.ui-front li:hover {
background-color: #e1e3e1 !important;
}
ul.ui-front li a.ui-menu-item-wrapper {
background: transparent !important;
border: none !important;
}
ul.ui-front li a.ui-menu-item-wrapper span {
padding-left: 5px !important;
}
ul.ui-front li a.ui-menu-item-wrapper:hover {
text-decoration: none !important;
}
input[type="submit"].ui-button-dialog {
margin: 0.5em 1em 0.5em 0 !important;
cursor: pointer !important;
background: white !important;
background-color: white !important;
color: #82b92e !important;
text-align: center !important;
border: 1px solid #82b92e !important;
height: 30px !important;
width: 90px !important;
}
/* --- END - JQUERY-UI --- */
/* --- SWITCH --- */
.p-switch {
position: relative;
display: inline-block;
width: 30px;
height: 17px;
}
.p-switch input {
opacity: 0;
width: 0;
height: 0;
}
.p-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: 0.4s;
transition: 0.4s;
border-radius: 34px;
}
.p-slider:before {
position: absolute;
content: "";
height: 13px;
width: 13px;
left: 2px;
bottom: 2px;
background-color: white;
-webkit-transition: 0.4s;
transition: 0.4s;
border-radius: 50%;
}
input:checked + .p-slider {
background-color: #82b92e;
}
input:focus + .p-slider {
box-shadow: 0 0 1px #82b92e;
}
input:checked + .p-slider:before {
-webkit-transform: translateX(13px);
-ms-transform: translateX(13px);
transform: translateX(13px);
}
/* --- END SWITCH --- */
/* --- TOAST --- */
#notifications-toasts-wrapper {
position: fixed;
right: 20px;
top: 70px;
width: 270px;
height: 100%;
z-index: 6;
pointer-events: none;
}
.snackbar {
max-width: 270px;
background-color: #333;
color: #fff;
text-align: center;
/* border-radius: 2px; */
padding: 16px;
margin: 10px;
border-radius: 4px;
visibility: hidden;
pointer-events: all;
}
.snackbar.show {
visibility: visible;
-webkit-animation: fadein 0.5s, fadeout 0.5s 7.5s;
animation: fadein 0.5s, fadeout 0.5s 7.5s;
}
.snackbar p,
.snackbar h3 {
text-align: left;
margin: 0;
pointer-events: none;
}
.snackbar h3 {
color: white;
margin-bottom: 10px;
}
@-webkit-keyframes fadein {
from {
bottom: 0;
opacity: 0;
}
to {
bottom: 30px;
opacity: 1;
}
}
@keyframes fadein {
from {
bottom: 0;
opacity: 0;
}
to {
bottom: 30px;
opacity: 1;
}
}
@-webkit-keyframes fadeout {
from {
bottom: 30px;
opacity: 1;
}
to {
bottom: 0;
opacity: 0;
}
}
@keyframes fadeout {
from {
bottom: 30px;
opacity: 1;
}
to {
bottom: 0;
opacity: 0;
}
}
/* --- END TOAST --- */

View File

@ -106,34 +106,65 @@ if ($read_message) {
$dst_name = $message['id_usuario_destino'];
}
$table = new stdClass();
$table->width = '100%';
$table->class = 'databox filters';
$table->data = [];
echo '<h1>Conversation with '.$user_name.'</h1>';
echo '<h2>Subject: '.$message['subject'].'</h2>';
$table->data[0][0] = __('Sender');
$table->data[0][1] = $user_name.' '.__('at').' '.ui_print_timestamp(
$message['timestamp'],
true,
['prominent' => 'timestamp']
);
$conversation = [];
$target_str = $message['mensaje'];
$table->data[1][0] = __('Destination');
$table->data[1][1] = $dst_name;
while (preg_match_all(
'/(.*)On(.*)wrote:(.*)/',
$target_str,
$decoded,
PREG_PATTERN_ORDER
) !== false && empty($target_str) !== true) {
if (empty($decoded[2]) !== true) {
array_push(
$conversation,
[
'message' => array_pop($decoded)[0],
'date' => array_pop($decoded)[0],
]
);
} else {
array_push(
$conversation,
['message' => $target_str]
);
}
$target_str = $decoded[1][0];
}
ui_require_css_file('message_edit');
foreach ($conversation as $row) {
$date = $row['date'];
if ($date === null) {
$date = date(
$config['date_format'],
$message['timestamp']
).' '.$user_name;
}
$order = [
"\r\n",
"\n",
"\r",
];
$replace = '<br />';
$parsed_message = str_replace(
$order,
$replace,
trim(io_safe_output($row['message']))
);
echo '<div class="container">';
echo ' <p>'.$parsed_message.'</p>';
echo '<span class="time-left">'.$date.'</span>';
echo '</div>';
}
$table->data[2][0] = __('Subject');
$table->data[2][1] = html_print_input_text_extended(
'subject',
$message['subject'],
'text-subject',
'',
50,
70,
true,
false,
'',
'readonly'
);
$order = [
"\r\n",
@ -143,16 +174,6 @@ if ($read_message) {
$replace = '<br />';
$parsed_message = str_replace($order, $replace, $message['mensaje']);
$table->data[3][0] = __('Message');
$table->data[3][1] = html_print_textarea(
'message',
15,
255,
$message['mensaje'],
'readonly',
true
);
// Prevent RE: RE: RE:.
if (strstr($message['subject'], 'RE:')) {
$new_subj = $message['subject'];
@ -166,8 +187,8 @@ if ($read_message) {
$message['timestamp']
).' '.$user_name.' '.__('wrote').":\n\n".$message['mensaje'];
echo '<form id="delete_message" method="post" action="index.php?sec=message_list&amp;sec2=operation/messages/message_list&show_sent=1&amp;delete_message=1&amp;id='.$message_id.'">';
html_print_table($table);
echo '</form>';
echo '<form id="reply_message" method="post" action="index.php?sec=message_list&sec2=operation/messages/message_edit&amp;new_msg=1&amp;reply=1">';
@ -179,7 +200,7 @@ if ($read_message) {
echo "<div class= 'action-buttons' style=' width:".$table->width."'>";
html_print_submit_button(
__('Delete'),
__('Delete conversation'),
'delete_btn',
false,
'form="delete_message" class="sub delete"'
@ -294,7 +315,6 @@ if ($reply) {
}
if ($own_info['is_admin'] || check_acl($config['id_user'], 0, 'PM')) {
$return_all_groups = true;
} else {

View File

@ -115,13 +115,13 @@ if ($show_sent) {
$messages = messages_get_overview_sent('', 'DESC');
} else {
// Messages received.
$num_messages = messages_get_count($config['id_user'], true);
$num_messages = messages_get_count($config['id_user'], true, true);
if ($num_messages > 0 && !is_ajax()) {
$unread_messages = messages_get_count($config['id_user']);
$unread_messages = messages_get_count($config['id_user'], false, true);
echo '<p>'.__('You have').' <b>'.$unread_messages.'</b> '.__('unread message(s)').'.</p>';
$messages = messages_get_overview();
} else {
$messages = messages_get_overview('status', 'ASC', false);
$messages = messages_get_overview('status', 'ASC');
}
}

View File

@ -4,7 +4,6 @@
// ==================================================
// Copyright (c) 2005-2010 Artica Soluciones Tecnologicas
// Please see http://pandorafms.org for full contribution list
// 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 for version 2.
@ -12,13 +11,112 @@
// 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.
// Load global vars
global $config;
// Includes.
require_once $config['homedir'].'/include/functions_notifications.php';
// Load the header
require($config['homedir'] . "/operation/users/user_edit_header.php");
require $config['homedir'].'/operation/users/user_edit_header.php';
// TODO
if (get_parameter('change_label', 0)) {
$label = get_parameter('label', '');
$source = get_parameter('source', 0);
$user = get_parameter('user', '');
$value = get_parameter('value', 0) ? 1 : 0;
?>
// Update the label value.
ob_clean();
echo json_encode(
[
'result' => notifications_set_user_label_status(
$source,
$user,
$label,
$value
),
]
);
return;
}
// User notification table. It is just a wrapper.
$table_content = new StdClass();
$table_content->data = [];
$table_content->width = '100%';
$table_content->id = 'user-notifications-wrapper';
$table_content->class = 'databox filters';
$table_content->size[0] = '33%';
$table_content->size[1] = '33%';
$table_content->size[2] = '33%';
// Print the header.
$table_content->data[] = [
'',
__('Enable'),
__('Also receive an email'),
];
$sources = notifications_get_all_sources();
foreach ($sources as $source) {
$table_content->data[] = [
$source['description'],
notifications_print_user_switch($source, $id, 'enabled'),
notifications_print_user_switch($source, $id, 'also_mail'),
];
}
html_print_table($table_content);
// Print id user to handle it on js.
html_print_input_hidden('id_user', $id);
?>
<script>
// Encapsulate the code
(function() {
function notifications_change_label(event) {
event.preventDefault();
var check = document.getElementById(event.target.id);
if (check === null) return;
var match = /notifications-user-([0-9]+)-label-(.*)/
.exec(event.target.id);
jQuery.post ("ajax.php",
{
"page" : "operation/users/user_edit_notifications",
"change_label" : 1,
"label" : match[2],
"source" : match[1],
"user" : document.getElementById('hidden-id_user').value,
"value": check.checked ? 1 : 0
},
function (data, status) {
if (!data.result) {
console.error("Error changing configuration in database.");
} else {
check.checked = !check.checked;
}
},
"json"
).done(function(m){})
.fail(function(xhr, textStatus, errorThrown){
console.error(
"Cannot change configuration in database. Server error.",
xhr.responseText
);
});
}
var all_labels = document.getElementsByClassName(
'notifications-user-label_individual'
);
for (var i = 0; i < all_labels.length; i++) {
all_labels[i].addEventListener(
'click', notifications_change_label, false
);
}
}());
</script>

File diff suppressed because one or more lines are too long

View File

@ -249,6 +249,7 @@ our @EXPORT = qw(
pandora_delete_graph_source
pandora_delete_custom_graph
pandora_edit_custom_graph
notification_set_targets
);
# Some global variables
@ -1459,6 +1460,35 @@ sub pandora_execute_action ($$$$$$$$$;$) {
pandora_create_integria_ticket($pa_config, $api_path, $api_pass, $integria_user, $integria_user_pass, $ticket_name, $ticket_group_id, $ticket_priority, $ticket_email, $ticket_owner, $ticket_description);
# Generate notification
} elsif ($clean_name eq "Generate Notification") {
# Translate macros
$field3 = subst_alert_macros($field3, \%macros, $pa_config, $dbh, $agent, $module);
$field4 = subst_alert_macros($field4, \%macros, $pa_config, $dbh, $agent, $module);
# If no targets ignore notification
if (defined($field1) && defined($field2) && ($field1 ne "" || $field2 ne "")) {
my @user_list = map {clean_blank($_)} split /,/, $field1;
my @group_list = map {clean_blank($_)} split /,/, $field2;
my $notification = {};
$notification->{'subject'} = safe_input($field3);
$notification->{'mensaje'} = safe_input($field4);
$notification->{'id_source'} = get_db_value($dbh, 'SELECT id FROM tnotification_source WHERE description = ?', safe_input('System status'));
# Create message
my $notification_id = db_process_insert($dbh,'id_mensaje','tmensajes',$notification);
if (!$notification_id) {
logger($pa_config, "Failed action '" . $action->{'name'} . "' for alert '". $alert->{'name'} . "' agent '" . (defined($agent) ? $agent->{'alias'} : 'N/A') . "'.", 3);
} else {
notification_set_targets($pa_config, $dbh, $notification_id, \@user_list, \@group_list);
}
} else {
logger($pa_config, "Failed action '" . $action->{'name'} . "' for alert '". $alert->{'name'} . "' agent '" . (defined($agent) ? $agent->{'alias'} : 'N/A') . "' Empty targets. Ignored.", 3);
}
# Unknown
} else {
logger($pa_config, "Unknown action '" . $action->{'name'} . "' for alert '". $alert->{'name'} . "' agent '" . (defined ($agent) ? $agent->{'alias'} : 'N/A') . "'.", 3);
@ -5746,6 +5776,62 @@ sub pandora_safe_mode_modules_update {
}
}
##########################################################################
=head2 C<< message_set_targets (I<$dbh>, I<$pa_config>, I<$notification_id>, I<$users>, I<$groups>) >>
Set targets for given messaje (users and groups in hash ref)
=cut
##########################################################################
sub notification_set_targets {
my ($pa_config, $dbh, $notification_id, $users, $groups) = @_;
my $ret = undef;
if (!defined($pa_config)) {
return undef;
}
if (!defined($notification_id)) {
return undef;
}
if (ref($users) eq "ARRAY") {
my $values = {};
foreach my $user (@{$users}) {
if (defined($user) && $user eq "") {
next;
}
$values->{'id_mensaje'} = $notification_id;
$values->{'id_user'} = $user;
}
$ret = db_process_insert($dbh, '', 'tnotification_user', $values);
if (!$ret) {
return undef;
}
}
if (ref($groups) eq "ARRAY") {
my $values = {};
foreach my $group (@{$groups}) {
if ($group != 0 && empty($group)) {
next;
}
$values->{'id_mensaje'} = $notification_id;
$values->{'id_group'} = $group;
}
$ret = db_process_insert($dbh, '', 'tnotification_group', $values);
if (!$ret) {
return undef;
}
}
return 1;
}
# End of function declaration
# End of defined Code

View File

@ -437,6 +437,13 @@ sub pandora_purgedb ($$) {
# Delete old tgraph_source data
db_do ($dbh,"DELETE FROM tgraph_source WHERE id_graph NOT IN (SELECT id_graph FROM tgraph)");
# Delete old messages
log_message ('PURGE', "Deleting old messages.");
if ($conf->{'_delete_old_messages'} > 0) {
my $message_limit = time() - 86400 * $conf->{'_delete_old_messages'};
db_do ($dbh, "DELETE FROM tmensajes WHERE timestamp < ?", $message_limit);
}
}
###############################################################################
@ -656,6 +663,7 @@ sub pandora_load_config_pdb ($) {
$conf->{'_history_db_delay'} = get_db_value ($dbh, "SELECT value FROM tconfig WHERE token = 'history_db_delay'");
$conf->{'_days_delete_unknown'} = get_db_value ($dbh, "SELECT value FROM tconfig WHERE token = 'days_delete_unknown'");
$conf->{'_inventory_purge'} = get_db_value ($dbh, "SELECT value FROM tconfig WHERE token = 'inventory_purge'");
$conf->{'_delete_old_messages'} = get_db_value ($dbh, "SELECT value FROM tconfig WHERE token = 'delete_old_messages'");
$conf->{'_enterprise_installed'} = get_db_value ($dbh, "SELECT value FROM tconfig WHERE token = 'enterprise_installed'");
$conf->{'_metaconsole'} = get_db_value ($dbh, "SELECT value FROM tconfig WHERE token = 'metaconsole'");
$conf->{'_metaconsole_events_history'} = get_db_value ($dbh, "SELECT value FROM tconfig WHERE token = 'metaconsole_events_history'");