Merge remote-tracking branch 'origin/develop' into ent-4755-base-de-datos-historico-revision

Conflicts:
	pandora_console/include/functions_ui.php
This commit is contained in:
fbsanchez 2021-02-22 12:01:29 +01:00
commit 85f37a91de
96 changed files with 4497 additions and 1440 deletions

View File

@ -120,7 +120,7 @@ check_repo_connection
execute_cmd "systemctl status" "Cheking SystemD" 'This is not a SystemD enable system, if tryng to use in a docker env plese check: https://github.com/pandorafms/pandorafms/tree/develop/extras/docker/centos8'
# Check memomry greather or equal to 2G
execute_cmd "[ $(grep MemTotal /proc/meminfo | awk '{print $2}') -le 2000000 ]" 'Checking memory (required: 2 GB)'
execute_cmd "[ $(grep MemTotal /proc/meminfo | awk '{print $2}') -ge 1700000 ]" 'Checking memory (required: 2 GB)'
# Check disk size at least 10 Gb free space
execute_cmd "[ $(df -BM / | tail -1 | awk '{print $4}' | tr -d M) -gt 10000 ]" 'Checking Disk (required: 10 GB free min)'

View File

@ -1,5 +1,5 @@
package: pandorafms-agent-unix
Version: 7.0NG.752-210201
Version: 7.0NG.752-210222
Architecture: all
Priority: optional
Section: admin

View File

@ -14,7 +14,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
pandora_version="7.0NG.752-210201"
pandora_version="7.0NG.752-210222"
echo "Test if you has the tools for to make the packages."
whereis dpkg-deb | cut -d":" -f2 | grep dpkg-deb > /dev/null

View File

@ -1016,7 +1016,7 @@ my $Sem = undef;
my $ThreadSem = undef;
use constant AGENT_VERSION => '7.0NG.752';
use constant AGENT_BUILD => '210201';
use constant AGENT_BUILD => '210222';
# Agent log default file size maximum and instances
use constant DEFAULT_MAX_LOG_SIZE => 600000;

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_agent_unix
%define version 7.0NG.752
%define release 210201
%define release 210222
Summary: Pandora FMS Linux agent, PERL version
Name: %{name}

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_agent_unix
%define version 7.0NG.752
%define release 210201
%define release 210222
Summary: Pandora FMS Linux agent, PERL version
Name: %{name}
@ -62,8 +62,9 @@ cp -aRf $RPM_BUILD_ROOT%{prefix}/pandora_agent/Linux/pandora_agent.conf $RPM_BUI
rm -Rf $RPM_BUILD_ROOT
%pre
if [ "`id pandora | grep uid | wc -l`" = 0 ]
if [ "`id pandora 2>/dev/null | grep uid | wc -l`" = 0 ]
then
echo "User pandora does not exist. Creating it..."
/usr/sbin/useradd -d %{prefix}/pandora -s /bin/false -M -g 0 pandora
fi
@ -105,12 +106,17 @@ then
echo "Copying new version of pandora_agent_daemon service"
cp -f /usr/share/pandora_agent/pandora_agent_daemon.service /usr/lib/systemd/system/
chmod -x /usr/lib/systemd/system/pandora_agent_daemon.service
# Enable the services on SystemD
systemctl enable pandora_agent_daemon.service
# Enable the services on SystemD
systemctl enable pandora_agent_daemon.service || chkconfig pandora_agent_daemon on
else
chkconfig pandora_agent_daemon on
fi
if [ "$?" -gt 0 ]
then
echo "There was a problem configuring pandora_agent_daemon service to run on boot. Please enable it manually."
fi
if [ "$1" -gt 1 ]
then

View File

@ -10,7 +10,7 @@
# **********************************************************************
PI_VERSION="7.0NG.752"
PI_BUILD="210201"
PI_BUILD="210222"
OS_NAME=`uname -s`
FORCE=0

View File

@ -186,7 +186,7 @@ UpgradeApplicationID
{}
Version
{210201}
{210222}
ViewReadme
{Yes}

View File

@ -30,7 +30,7 @@ using namespace Pandora;
using namespace Pandora_Strutils;
#define PATH_SIZE _MAX_PATH+1
#define PANDORA_VERSION ("7.0NG.752(Build 210201)")
#define PANDORA_VERSION ("7.0NG.752(Build 210222)")
string pandora_path;
string pandora_dir;

View File

@ -11,7 +11,7 @@ BEGIN
VALUE "LegalCopyright", "Artica ST"
VALUE "OriginalFilename", "PandoraAgent.exe"
VALUE "ProductName", "Pandora FMS Windows Agent"
VALUE "ProductVersion", "(7.0NG.752(Build 210201))"
VALUE "ProductVersion", "(7.0NG.752(Build 210222))"
VALUE "FileVersion", "1.0.0.0"
END
END

View File

@ -1,5 +1,5 @@
package: pandorafms-console
Version: 7.0NG.752-210201
Version: 7.0NG.752-210222
Architecture: all
Priority: optional
Section: admin

View File

@ -14,7 +14,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
pandora_version="7.0NG.752-210201"
pandora_version="7.0NG.752-210222"
package_pear=0
package_pandora=1

View File

@ -80,9 +80,8 @@ if (isset($_GET['loginhash']) === true) {
} else {
include_once 'general/login_page.php';
db_pandora_audit('Logon Failed (loginhash', '', 'system');
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}
exit('</html>');
@ -149,7 +148,9 @@ if (__PAN_XHPROF__ === 1) {
}
if ($config['force_instant_logout'] === true) {
if (isset($config['force_instant_logout']) === true
&& $config['force_instant_logout'] === true
) {
// Force user logout.
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
@ -169,7 +170,6 @@ if ($config['force_instant_logout'] === true) {
}
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}

View File

@ -85,33 +85,7 @@ SET @insert_name = 'IPAM Recon';
SET @insert_description = 'This script is used to automatically detect network hosts availability and name, used as Recon Custom Script in the recon task. Parameters used are:\n\n* custom_field1 = network. i.e.: 192.168.100.0/24\n* custom_field2 = associated IPAM network id. i.e.: 4. Please do not change this value, it is assigned automatically in IPAM management.\n\nSee documentation for more information.';
SET @insert_script = '/usr/share/pandora_server/util/recon_scripts/IPAMrecon.pl';
SET @insert_macros = '{"1":{"macro":"_field1_","desc":"Network","help":"i.e.:&#x20;192.168.100.0/24","value":"","hide":""}}';
INSERT IGNORE INTO trecon_script (`id_recon_script`,`type`, `name`, `description`, `script`, `macros`)
SELECT `id_recon_script`,`type`, `name`, `description`, `script`, `macros` FROM (
SELECT `id_recon_script`,`type`, `name`, `description`, `script`, `macros` FROM `trecon_script` WHERE `name` = @insert_name
UNION
SELECT (SELECT max(`id_recon_script`)+1 FROM `trecon_script`) AS `id_recon_script`,
@insert_type as `type`,
@insert_name as `name`,
@insert_description as `description`,
@insert_script as `script`,
@insert_macros as `macros`
) t limit 1;
ALTER TABLE `tipam_ip` ADD COLUMN `leased` tinyint(2) DEFAULT '0';
ALTER TABLE `tipam_ip` ADD COLUMN `leased_expiration` bigint(20) DEFAULT '0';
ALTER TABLE `tipam_ip` ADD COLUMN `mac_address` varchar(20) DEFAULT NULL;
ALTER TABLE `tipam_ip` ADD COLUMN `leased_mode` tinyint(2) DEFAULT '0';
ALTER TABLE `tipam_network` ADD COLUMN `monitoring` tinyint(2) default '0';
ALTER TABLE `tipam_network` ADD COLUMN `id_group` mediumint(8) unsigned NULL default '0';
ALTER TABLE `tipam_network` ADD COLUMN `lightweight_mode` tinyint(2) default '0';
ALTER TABLE `tipam_network` ADD COLUMN `name_network` varchar(255) default '';
INSERT IGNORE INTO trecon_script (`id_recon_script`,`type`, `name`, `description`, `script`, `macros`) SELECT `id_recon_script`,`type`, `name`, `description`, `script`, `macros` FROM (SELECT `id_recon_script`,`type`, `name`, `description`, `script`, `macros` FROM `trecon_script` WHERE `name` = @insert_name UNION SELECT (SELECT max(`id_recon_script`)+1 FROM `trecon_script`) AS `id_recon_script`, @insert_type as `type`, @insert_name as `name`, @insert_description as `description`, @insert_script as `script`, @insert_macros as `macros`) t limit 1;
DELETE FROM `tconfig` WHERE `token` = 'ipam_installed';

View File

@ -1410,13 +1410,13 @@ ALTER TABLE `ttag` MODIFY COLUMN `name` text NOT NULL default '';
INSERT INTO `tconfig` (`token`, `value`) VALUES ('big_operation_step_datos_purge', '100');
INSERT INTO `tconfig` (`token`, `value`) VALUES ('small_operation_step_datos_purge', '1000');
INSERT INTO `tconfig` (`token`, `value`) VALUES ('days_autodisable_deletion', '30');
INSERT INTO `tconfig` (`token`, `value`) VALUES ('MR', 42);
INSERT INTO `tconfig` (`token`, `value`) VALUES ('MR', 44);
INSERT INTO `tconfig` (`token`, `value`) VALUES ('custom_docs_logo', 'default_docs.png');
INSERT INTO `tconfig` (`token`, `value`) VALUES ('custom_support_logo', 'default_support.png');
INSERT INTO `tconfig` (`token`, `value`) VALUES ('custom_logo_white_bg_preview', 'pandora_logo_head_white_bg.png');
UPDATE tconfig SET value = 'https://licensing.artica.es/pandoraupdate7/server.php' WHERE token='url_update_manager';
DELETE FROM `tconfig` WHERE `token` = 'current_package_enterprise';
INSERT INTO `tconfig` (`token`, `value`) VALUES ('current_package_enterprise', 750);
INSERT INTO `tconfig` (`token`, `value`) VALUES ('current_package_enterprise', 752);
INSERT INTO `tconfig` (`token`, `value`) VALUES ('status_monitor_fields', 'policy,agent,data_type,module_name,server_type,interval,status,graph,warn,data,timestamp');
UPDATE `tconfig` SET `value` = 'mini_severity,evento,id_agente,estado,timestamp' WHERE `token` LIKE 'event_fields';
DELETE FROM `tconfig` WHERE `token` LIKE 'integria_api_password';

View File

@ -3279,7 +3279,7 @@ function print_SLA_list($width, $action, $idItem=null)
<tr id="sla_form" style="" class="datos">
<td class="sla_list_agent_col">
<input id="hidden-id_agent_sla" name="id_agent_sla" value="" type="hidden">
<input id="hidden-server_name" name="server_name" value="" type="hidden">
<input id="hidden-id_server" name="id_server" value="" type="hidden">
<?php
$params = [];
$params['show_helptip'] = true;

View File

@ -119,6 +119,7 @@ foreach ($layoutDatas as $layoutData) {
}
switch ($layoutData['type']) {
case NETWORK_LINK:
case LINE_ITEM:
visual_map_print_user_line_handles($layoutData);
visual_map_print_user_lines($layoutData);

View File

@ -271,6 +271,7 @@ foreach ($layoutDatas as $layoutData) {
);
break;
case NETWORK_LINK:
case LINE_ITEM:
$table->data[($i + 1)]['icon'] = html_print_image(
'images/line_item.png',
@ -303,6 +304,7 @@ foreach ($layoutDatas as $layoutData) {
switch ($layoutData['type']) {
case ICON:
case BOX_ITEM:
case NETWORK_LINK:
case LINE_ITEM:
// hasn't the label.
$table->data[($i + 1)][0] = '';
@ -345,6 +347,7 @@ foreach ($layoutDatas as $layoutData) {
// Width and height
switch ($layoutData['type']) {
case NETWORK_LINK:
case LINE_ITEM:
// hasn't the width and height.
$table->data[($i + 1)][2] = '';
@ -361,6 +364,7 @@ foreach ($layoutDatas as $layoutData) {
// Position
switch ($layoutData['type']) {
case NETWORK_LINK:
case LINE_ITEM:
// hasn't the width and height.
$table->data[($i + 1)][3] = '';
@ -375,6 +379,7 @@ foreach ($layoutDatas as $layoutData) {
// Parent
switch ($layoutData['type']) {
case BOX_ITEM:
case NETWORK_LINK:
case LINE_ITEM:
case COLOR_CLOUD:
$table->data[($i + 1)][4] = '';
@ -434,6 +439,7 @@ foreach ($layoutDatas as $layoutData) {
case BOX_ITEM:
case ICON:
case LABEL:
case NETWORK_LINK:
case LINE_ITEM:
$table->data[($i + 2)][0] = '';
break;
@ -494,6 +500,7 @@ foreach ($layoutDatas as $layoutData) {
case ICON:
case LABEL:
case BOX_ITEM:
case NETWORK_LINK:
case LINE_ITEM:
case GROUP_ITEM:
$table->data[($i + 2)][1] = '';
@ -598,6 +605,7 @@ foreach ($layoutDatas as $layoutData) {
// Map linked
switch ($layoutData['type']) {
case NETWORK_LINK:
case LINE_ITEM:
case BOX_ITEM:
case AUTO_SLA_GRAPH:

View File

@ -623,6 +623,30 @@ $table_other->data[14][1] = html_print_input_text(
true
);
$table_other->data[15][0] = __('SNMP walk binary');
$table_other->data[15][1] = html_print_input_text(
'snmpwalk',
$config['snmpwalk'],
'',
50,
10,
true
);
$tip = ui_print_help_tip(
__('SNMP bulk walk is not able to request V1 SNMP, this option will be used instead (by default snmpwalk, slower).'),
true
);
$table_other->data[16][0] = __('SNMP walk binary (fallback)').$tip;
$table_other->data[16][1] = html_print_input_text(
'snmpwalk_fallback',
$config['snmpwalk_fallback'],
'',
50,
10,
true
);
echo '<form id="form_setup" method="post">';
echo '<fieldset>';

View File

@ -110,56 +110,147 @@ $table->data[$i++][1] = html_print_select_from_sql(
);
$table->data[$i][0] = __('Remote config directory');
$table->data[$i++][1] = html_print_input_text('remote_config', io_safe_output($config['remote_config']), '', 30, 100, true);
$table->data[$i++][1] = html_print_input_text(
'remote_config',
io_safe_output($config['remote_config']),
'',
30,
100,
true
);
$table->data[$i][0] = __('Phantomjs bin directory');
$table->data[$i++][1] = html_print_input_text('phantomjs_bin', io_safe_output($config['phantomjs_bin']), '', 30, 100, true);
$table->data[$i++][1] = html_print_input_text(
'phantomjs_bin',
io_safe_output(
$config['phantomjs_bin']
),
'',
30,
100,
true
);
$table->data[$i][0] = __('Auto login (hash) password');
$table->data[$i][1] = html_print_input_password('loginhash_pwd', io_output_password($config['loginhash_pwd']), '', 15, 15, true);
$table->data[$i++][1] .= ui_print_reveal_password('loginhash_pwd', true);
$table->data[$i][1] = html_print_input_password(
'loginhash_pwd',
io_output_password($config['loginhash_pwd']),
'',
15,
15,
true
);
$table->data[$i++][1] .= ui_print_reveal_password(
'loginhash_pwd',
true
);
$table->data[$i][0] = __('Time source');
$sources['system'] = __('System');
$sources['sql'] = __('Database');
$table->data[$i++][1] = html_print_select($sources, 'timesource', $config['timesource'], '', '', '', true);
$table->data[$i++][1] = html_print_select(
$sources,
'timesource',
$config['timesource'],
'',
'',
'',
true
);
$table->data[$i][0] = __('Automatic check for updates');
$table->data[$i++][1] = html_print_checkbox_switch('autoupdate', 1, $config['autoupdate'], true);
$table->data[$i++][1] = html_print_checkbox_switch(
'autoupdate',
1,
$config['autoupdate'],
true
);
echo "<div id='dialog' title='".__('Enforce https Information')."' style='display:none;'>";
echo "<p style='text-align: center;'>".__('If SSL is not properly configured you will lose access to ').get_product_name().__(' Console').'</p>';
echo '</div>';
$table->data[$i][0] = __('Enforce https');
$table->data[$i++][1] = html_print_checkbox_switch_extended('https', 1, $config['https'], false, '', '', true);
$table->data[$i++][1] = html_print_checkbox_switch_extended(
'https',
1,
$config['https'],
false,
'',
'',
true
);
$table->data[$i][0] = __('Use cert of SSL');
$table->data[$i++][1] = html_print_checkbox_switch_extended('use_cert', 1, $config['use_cert'], false, '', '', true);
$table->data[$i++][1] = html_print_checkbox_switch_extended(
'use_cert',
1,
$config['use_cert'],
false,
'',
'',
true
);
$table->rowstyle[$i] = 'display: none;';
$table->rowid[$i] = 'ssl-path-tr';
$table->data[$i][0] = __('Path of SSL Cert.');
$table->data[$i++][1] = html_print_input_text('cert_path', io_safe_output($config['cert_path']), '', 50, 255, true);
$table->data[$i++][1] = html_print_input_text(
'cert_path',
io_safe_output($config['cert_path']),
'',
50,
255,
true
);
$table->data[$i][0] = __('Attachment store');
$table->data[$i++][1] = html_print_input_text('attachment_store', io_safe_output($config['attachment_store']), '', 50, 255, true);
$table->data[$i++][1] = html_print_input_text(
'attachment_store',
io_safe_output($config['attachment_store']),
'',
50,
255,
true
);
$table->data[$i][0] = __('IP list with API access');
if (isset($_POST['list_ACL_IPs_for_API'])) {
$list_ACL_IPs_for_API = get_parameter_post('list_ACL_IPs_for_API');
} else {
$list_ACL_IPs_for_API = get_parameter_get('list_ACL_IPs_for_API', implode("\n", $config['list_ACL_IPs_for_API']));
$list_ACL_IPs_for_API = get_parameter_get(
'list_ACL_IPs_for_API',
implode("\n", $config['list_ACL_IPs_for_API'])
);
}
$table->data[$i++][1] = html_print_textarea('list_ACL_IPs_for_API', 2, 25, $list_ACL_IPs_for_API, 'style="height: 50px; width: 300px"', true);
$table->data[$i++][1] = html_print_textarea(
'list_ACL_IPs_for_API',
2,
25,
$list_ACL_IPs_for_API,
'style="height: 50px; width: 300px"',
true
);
$table->data[$i][0] = __('API password');
$table->data[$i][1] = html_print_input_password('api_password', io_output_password($config['api_password']), '', 25, 255, true);
$table->data[$i][1] = html_print_input_password(
'api_password',
io_output_password($config['api_password']),
'',
25,
255,
true
);
$table->data[$i++][1] .= ui_print_reveal_password('api_password', true);
$table->data[$i][0] = __('Enable GIS features');
$table->data[$i++][1] = html_print_checkbox_switch('activate_gis', 1, $config['activate_gis'], true);
$table->data[$i++][1] = html_print_checkbox_switch(
'activate_gis',
1,
$config['activate_gis'],
true
);
$table->data[$i][0] = __('Enable Netflow');
$rbt_disabled = false;
@ -167,7 +258,15 @@ if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
$rbt_disabled = true;
}
$table->data[$i++][1] = html_print_checkbox_switch_extended('activate_netflow', 1, $config['activate_netflow'], $rbt_disabled, '', '', true);
$table->data[$i++][1] = html_print_checkbox_switch_extended(
'activate_netflow',
1,
$config['activate_netflow'],
$rbt_disabled,
'',
'',
true
);
$table->data[$i][0] = __('Enable Network Traffic Analyzer');
$table->data[$i++][1] = html_print_switch(
@ -222,28 +321,106 @@ $table->data[$i][1] = html_print_input_text_extended(
'readonly',
true
);
$table->data[$i][1] .= '<a id="change_timezone">'.html_print_image('images/pencil.png', true, ['title' => __('Change timezone')]).'</a>';
$table->data[$i][1] .= '&nbsp;&nbsp;'.html_print_select($zone_name, 'zone', $zone_selected, 'show_timezone();', '', '', true);
$table->data[$i++][1] .= '&nbsp;&nbsp;'.html_print_select($timezone_n, 'timezone', $config['timezone'], '', '', '', true);
$table->data[$i][1] .= '<a id="change_timezone">'.html_print_image(
'images/pencil.png',
true,
['title' => __('Change timezone')]
).'</a>';
$table->data[$i][1] .= '&nbsp;&nbsp;'.html_print_select(
$zone_name,
'zone',
$zone_selected,
'show_timezone();',
'',
'',
true
);
$table->data[$i++][1] .= '&nbsp;&nbsp;'.html_print_select(
$timezone_n,
'timezone',
$config['timezone'],
'',
'',
'',
true
);
$sounds = get_sounds();
$table->data[$i][0] = __('Sound for Alert fired');
$table->data[$i][1] = html_print_select($sounds, 'sound_alert', $config['sound_alert'], 'replaySound(\'alert\');', '', '', true);
$table->data[$i][1] .= ' <a href="javascript: toggleButton(\'alert\');">'.html_print_image('images/control_play_col.png', true, ['id' => 'button_sound_alert', 'style' => 'vertical-align: middle;', 'width' => '16', 'title' => __('Play sound')]).'</a>';
$table->data[$i][1] = html_print_select(
$sounds,
'sound_alert',
$config['sound_alert'],
'replaySound(\'alert\');',
'',
'',
true
);
$table->data[$i][1] .= ' <a href="javascript: toggleButton(\'alert\');">'.html_print_image(
'images/control_play_col.png',
true,
[
'id' => 'button_sound_alert',
'style' => 'vertical-align: middle;',
'width' => '16',
'title' => __('Play sound'),
]
).'</a>';
$table->data[$i++][1] .= '<div id="layer_sound_alert"></div>';
$table->data[$i][0] = __('Sound for Monitor critical');
$table->data[$i][1] = html_print_select($sounds, 'sound_critical', $config['sound_critical'], 'replaySound(\'critical\');', '', '', true);
$table->data[$i][1] .= ' <a href="javascript: toggleButton(\'critical\');">'.html_print_image('images/control_play_col.png', true, ['id' => 'button_sound_critical', 'style' => 'vertical-align: middle;', 'width' => '16', 'title' => __('Play sound')]).'</a>';
$table->data[$i][1] = html_print_select(
$sounds,
'sound_critical',
$config['sound_critical'],
'replaySound(\'critical\');',
'',
'',
true
);
$table->data[$i][1] .= ' <a href="javascript: toggleButton(\'critical\');">'.html_print_image(
'images/control_play_col.png',
true,
[
'id' => 'button_sound_critical',
'style' => 'vertical-align: middle;',
'width' => '16',
'title' => __('Play sound'),
]
).'</a>';
$table->data[$i++][1] .= '<div id="layer_sound_critical"></div>';
$table->data[$i][0] = __('Sound for Monitor warning');
$table->data[$i][1] = html_print_select($sounds, 'sound_warning', $config['sound_warning'], 'replaySound(\'warning\');', '', '', true);
$table->data[$i][1] .= ' <a href="javascript: toggleButton(\'warning\');">'.html_print_image('images/control_play_col.png', true, ['id' => 'button_sound_warning', 'style' => 'vertical-align: middle;', 'width' => '16', 'title' => __('Play sound')]).'</a>';
$table->data[$i][1] = html_print_select(
$sounds,
'sound_warning',
$config['sound_warning'],
'replaySound(\'warning\');',
'',
'',
true
);
$table->data[$i][1] .= ' <a href="javascript: toggleButton(\'warning\');">'.html_print_image(
'images/control_play_col.png',
true,
[
'id' => 'button_sound_warning',
'style' => 'vertical-align: middle;',
'width' => '16',
'title' => __('Play sound'),
]
).'</a>';
$table->data[$i++][1] .= '<div id="layer_sound_warning"></div>';
$table->data[$i][0] = __('Public URL');
$table->data[$i++][1] = html_print_input_text('public_url', $config['public_url'], '', 40, 255, true);
$table->data[$i++][1] = html_print_input_text(
'public_url',
$config['public_url'],
'',
40,
255,
true
);
$table->data[$i][0] = __('Force use Public URL');
$table->data[$i++][1] = html_print_switch(
@ -253,25 +430,54 @@ $table->data[$i++][1] = html_print_switch(
]
);
echo "<div id='force_public_url_dialog' title='".__('Enforce public URL usage information')."' style='display:none;'>";
echo "<div id='force_public_url_dialog' title='".__(
'Enforce public URL usage information'
)."' style='display:none;'>";
echo "<p style='text-align: center;'>".__('If public URL is not properly configured you will lose access to ').get_product_name().__(' Console').'</p>';
echo '</div>';
$table->data[$i][0] = __('Public URL host exclusions');
$table->data[$i++][1] = html_print_textarea('public_url_exclusions', 2, 25, $config['public_url_exclusions'], 'style="height: 50px; width: 300px"', true);
$table->data[$i++][1] = html_print_textarea(
'public_url_exclusions',
2,
25,
$config['public_url_exclusions'],
'style="height: 50px; width: 300px"',
true
);
$table->data[$i][0] = __('Referer security');
$table->data[$i++][1] = html_print_checkbox_switch('referer_security', 1, $config['referer_security'], true);
$table->data[$i++][1] = html_print_checkbox_switch(
'referer_security',
1,
$config['referer_security'],
true
);
$table->data[$i][0] = __('Event storm protection');
$table->data[$i++][1] = html_print_checkbox_switch('event_storm_protection', 1, $config['event_storm_protection'], true);
$table->data[$i++][1] = html_print_checkbox_switch(
'event_storm_protection',
1,
$config['event_storm_protection'],
true
);
$table->data[$i][0] = __('Command Snapshot');
$table->data[$i++][1] = html_print_checkbox_switch('command_snapshot', 1, $config['command_snapshot'], true);
$table->data[$i++][1] = html_print_checkbox_switch(
'command_snapshot',
1,
$config['command_snapshot'],
true
);
$table->data[$i][0] = __('Change remote config encoding');
$table->data[$i++][1] = html_print_checkbox_switch('use_custom_encoding', 1, $config['use_custom_encoding'], true);
$table->data[$i++][1] = html_print_checkbox_switch(
'use_custom_encoding',
1,
$config['use_custom_encoding'],
true
);
$table->data[$i][0] = __('Server logs directory');
$table->data[$i++][1] = html_print_input_text(
@ -309,9 +515,16 @@ $table->data[$i++][1] = html_print_select(
true
);
$config['past_planned_downtimes'] = isset($config['past_planned_downtimes']) ? $config['past_planned_downtimes'] : 1;
$config['past_planned_downtimes'] = isset(
$config['past_planned_downtimes']
) ? $config['past_planned_downtimes'] : 1;
$table->data[$i][0] = __('Allow create planned downtimes in the past');
$table->data[$i++][1] = html_print_checkbox_switch('past_planned_downtimes', 1, $config['past_planned_downtimes'], true);
$table->data[$i++][1] = html_print_checkbox_switch(
'past_planned_downtimes',
1,
$config['past_planned_downtimes'],
true
);
$table->data[$i][0] = __('Limit for bulk operations');
$table->data[$i++][1] = html_print_input_text(
@ -324,22 +537,61 @@ $table->data[$i++][1] = html_print_input_text(
);
$table->data[$i][0] = __('Include agents manually disabled');
$table->data[$i++][1] = html_print_checkbox_switch('include_agents', 1, $config['include_agents'], true);
$table->data[$i++][1] = html_print_checkbox_switch(
'include_agents',
1,
$config['include_agents'],
true
);
$table->data[$i][0] = __('Set alias as name by default in agent creation');
$table->data[$i++][1] = html_print_checkbox_switch('alias_as_name', 1, $config['alias_as_name'], true);
$table->data[$i++][1] = html_print_checkbox_switch(
'alias_as_name',
1,
$config['alias_as_name'],
true
);
$table->data[$i][0] = __('Unique IP');
$table->data[$i++][1] = html_print_checkbox_switch('unique_ip', 1, $config['unique_ip'], true);
$table->data[$i++][1] = html_print_checkbox_switch(
'unique_ip',
1,
$config['unique_ip'],
true
);
$table->data[$i][0] = __('Enable console log').ui_print_help_tip(__('Log location').': pandora_console/log/console.log', true);
$table->data[$i++][1] = html_print_checkbox_switch('console_log_enabled', 1, $config['console_log_enabled'], true);
$table->data[$i][0] = __('Enable console log').ui_print_help_tip(
__('Log location').': pandora_console/log/console.log',
true
);
$table->data[$i++][1] = html_print_checkbox_switch(
'console_log_enabled',
1,
$config['console_log_enabled'],
true
);
$table->data[$i][0] = __('Enable audit log').ui_print_help_tip(__('Log location').': pandora_console/log/audit.log', true);
$table->data[$i++][1] = html_print_checkbox_switch('audit_log_enabled', 1, $config['audit_log_enabled'], true);
$table->data[$i][0] = __('Enable audit log').ui_print_help_tip(
__('Log location').': pandora_console/log/audit.log',
true
);
$table->data[$i++][1] = html_print_checkbox_switch(
'audit_log_enabled',
1,
$config['audit_log_enabled'],
true
);
$table->data[$i][0] = __('Module custom ID readonly').ui_print_help_tip(__('Useful for integrations'), true);
$table->data[$i++][1] = html_print_checkbox_switch('module_custom_id_ro', 1, $config['module_custom_id_ro'], true);
$table->data[$i][0] = __('Module custom ID readonly').ui_print_help_tip(
__('Useful for integrations'),
true
);
$table->data[$i++][1] = html_print_checkbox_switch(
'module_custom_id_ro',
1,
$config['module_custom_id_ro'],
true
);
echo '<form id="form_setup" method="post" action="index.php?sec=gsetup&sec2=godmode/setup/setup&amp;section=general&amp;pure='.$config['pure'].'">';
@ -350,7 +602,7 @@ echo '<legend>'.__('General options').'</legend>';
html_print_table($table);
$encryption = [
'ssl' => 'SSL/TLS',
'ssl' => 'SSL',
'sslv2' => 'SSLv2',
'sslv3' => 'SSLv3',
'tls' => 'STARTTLS',
@ -361,57 +613,127 @@ echo '</fieldset>';
echo '<fieldset>';
echo '<legend>'.__('Mail configuration').'</legend>';
$table_mail_conf->data[0][0] = __('From address');
$table_mail_conf->data[0][1] = html_print_input_text('email_from_dir', $config['email_from_dir'], '', 30, 100, true);
$table_mail_conf->data[0][0] = ui_print_warning_message(
__(
'Please notice that some providers like Gmail or Office365 need to setup/enable manually external connections using SMTP and you need to use STARTTLS on port 587.
$table_mail_conf->data[1][0] = __('From name');
$table_mail_conf->data[1][2] = html_print_input_text('email_from_name', $config['email_from_name'], '', 30, 100, true);
If you have manual settings in your pandora_server.conf, please note these settings will ignore this console setup.'
)
);
$table_mail_conf->data[2][0] = __('SMTP Server');
$table_mail_conf->data[2][1] = html_print_input_text('email_smtpServer', $config['email_smtpServer'], '', 30, 100, true);
$table_mail_conf->data[1][0] = __('From address');
$table_mail_conf->data[1][1] = html_print_input_text(
'email_from_dir',
$config['email_from_dir'],
'',
30,
100,
true
);
$table_mail_conf->data[3][0] = __('SMTP Port');
$table_mail_conf->data[3][1] = html_print_input_text('email_smtpPort', $config['email_smtpPort'], '', 30, 100, true);
$table_mail_conf->data[2][0] = __('From name');
$table_mail_conf->data[2][1] = html_print_input_text(
'email_from_name',
$config['email_from_name'],
'',
30,
100,
true
);
$table_mail_conf->data[4][0] = __('Encryption');
$table_mail_conf->data[4][1] = html_print_select($encryption, 'email_encryption', $config['email_encryption'], '', __('none'), 0, true);
$table_mail_conf->data[3][0] = __('SMTP Server');
$table_mail_conf->data[3][1] = html_print_input_text(
'email_smtpServer',
$config['email_smtpServer'],
'',
30,
100,
true
);
$table_mail_conf->data[5][0] = __('Email user');
$table_mail_conf->data[5][1] = html_print_input_text('email_username', $config['email_username'], '', 30, 100, true);
$table_mail_conf->data[4][0] = __('SMTP Port');
$table_mail_conf->data[4][1] = html_print_input_text(
'email_smtpPort',
$config['email_smtpPort'],
'',
30,
100,
true
);
$table_mail_conf->data[6][0] = __('Email password');
$table_mail_conf->data[6][1] = html_print_input_password('email_password', io_output_password($config['email_password']), '', 30, 100, true);
$table_mail_conf->data[6][1] .= ui_print_reveal_password('email_password', true);
$table_mail_conf->data[5][0] = __('Encryption');
$table_mail_conf->data[5][1] = html_print_select(
$encryption,
'email_encryption',
$config['email_encryption'],
'',
__('none'),
0,
true
);
$uniqid = uniqid();
$table_mail_conf->data[6][0] = __('Email user');
$table_mail_conf->data[6][1] = html_print_input_text(
'email_username',
$config['email_username'],
'',
30,
100,
true
);
$table_mail_conf->data[7][0] = html_print_button(__('Email test'), 'email_test_dialog', false, "show_email_test('".$uniqid."');", 'class="sub next"', true);
$table_mail_conf->data[7][0] = __('Email password');
$table_mail_conf->data[7][1] = html_print_input_password(
'email_password',
io_output_password(
$config['email_password']
),
'',
30,
100,
true
);
$table_mail_conf->data[7][1] .= ui_print_reveal_password(
'email_password',
true
);
print_email_test_modal_window($uniqid);
$uniqid = uniqid();
html_print_input_hidden('update_config', 1);
html_print_table($table_mail_conf);
$table_mail_conf->data[8][0] = html_print_button(
__('Email test'),
'email_test_dialog',
false,
"show_email_test('".$uniqid."');",
'class="sub next"',
true
);
print_email_test_modal_window($uniqid);
html_print_input_hidden('update_config', 1);
html_print_table($table_mail_conf);
echo '</fieldset>';
echo '</fieldset>';
echo '<fieldset>';
echo '<fieldset>';
echo '<div class="action-buttons" style="width: '.$table->width.'">';
html_print_submit_button(__('Update'), 'update_button', false, 'class="sub upd"');
echo '</div>';
echo '</form>';
echo '<div class="action-buttons" style="width: '.$table->width.'">';
html_print_submit_button(__('Update'), 'update_button', false, 'class="sub upd"');
echo '</div>';
echo '</form>';
/**
/**
* Print the modal window for the summary of each alerts group
*
* @param string $id Id.
*
* @return void
*/
function print_email_test_modal_window($id)
{
function print_email_test_modal_window($id)
{
// Email config table.
$table_mail_test = new stdClass();
$table_mail_test->width = '100%';
@ -421,15 +743,29 @@ function print_email_test_modal_window($id)
$table_mail_test->colspan[1][0] = 2;
$table_mail_test->data[0][0] = __('Address');
$table_mail_test->data[0][1] = html_print_input_text('email_test_address', '', '', 40, 100, true);
$table_mail_test->data[0][1] = html_print_input_text(
'email_test_address',
'',
'',
40,
100,
true
);
$table_mail_test->data[1][0] = html_print_button(__('Send'), 'email_test', false, '', 'class="sub next"', true).'&nbsp&nbsp<span id="email_test_sent_message" style="display:none;">Email sent</span><span id="email_test_failure_message" style="display:none;">Email could not been sent</span>';
$table_mail_test->data[1][0] = html_print_button(
__('Send'),
'email_test',
false,
'',
'class="sub next"',
true
).'&nbsp&nbsp<span id="email_test_sent_message" style="display:none;">Email sent</span><span id="email_test_failure_message" style="display:none;">Email could not been sent</span>';
echo '<div id="email_test_'.$id.'" title="'.__('Check mail configuration').'" style="display:none">'.html_print_table($table_mail_test, true).'</div>';
}
}
?>
?>
<script type="text/javascript">
function toggleButton(type) {
if ($("#button_sound_" + type).attr('src') == 'images/control_pause_col.png') {

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@ -19,12 +19,27 @@ require_once $config['homedir'].'/include/functions_network_components.php';
global $config;
if (is_ajax()) {
ob_clean();
set_error_handler(
function ($code, $string, $file, $line) {
throw new ErrorException($string, null, $code, $file, $line);
}
);
register_shutdown_function(
function () {
$error = error_get_last();
if (null !== $error) {
echo $error['message'];
}
}
);
try {
if ((bool) is_ajax() === true) {
$method = (string) get_parameter('method', '');
$action = (string) get_parameter('action', '');
$target_ip = (string) get_parameter('target_ip', '');
$target_port = (string) get_parameter('target_port', '');
$community = (string) io_safe_output((get_parameter('community', '')));
$snmp_version = (string) get_parameter('snmp_browser_version', '');
$snmp3_auth_user = io_safe_output(get_parameter('snmp3_browser_auth_user'));
@ -63,7 +78,8 @@ if (is_ajax()) {
$snmp3_privacy_method,
$snmp3_privacy_pass,
'null',
$server_to_exec
$server_to_exec,
$target_port
);
if (! is_array($snmp_tree)) {
echo $snmp_tree;
@ -91,7 +107,7 @@ if (is_ajax()) {
);
// Div for error/succes dialog.
$output .= '<div id="snmp_result_msg" style="display:none"></div>';
$output = '<div id="snmp_result_msg" style="display:none"></div>';
// Dialog error.
$output .= '<div id="dialog_error" style="display:none" title="'.__('SNMP modules').'">';
@ -167,6 +183,7 @@ if (is_ajax()) {
if ($method == 'snmp_browser_create_modules') {
// Get target ids from form.
$id_items = get_parameter('id_item2', null);
$id_target = null;
if (empty($id_items) === false) {
$id_target = explode(',', $id_items[0]);
}
@ -188,7 +205,12 @@ if (is_ajax()) {
$snmp_conf_values[$snmp_conf['name']] = $snmp_conf['value'];
}
$fail_modules = snmp_browser_create_modules_snmp($module_target, $snmp_conf_values, $id_target);
$fail_modules = snmp_browser_create_modules_snmp(
$module_target,
$snmp_conf_values,
$id_target,
$server_to_exec
);
// Return fail modules for error/success message.
echo json_encode($fail_modules);
@ -244,6 +266,8 @@ if (is_ajax()) {
];
echo json_encode($return);
exit;
}
}
} catch (\Exception $e) {
echo $e->getMessage();
}

View File

@ -1449,6 +1449,16 @@ switch ($action) {
}
switch ($type) {
case 'network_link':
$values['type'] = NETWORK_LINK;
$values['border_width'] = $line_width;
$values['border_color'] = $line_color;
$values['pos_x'] = $line_start_x;
$values['pos_y'] = $line_start_y;
$values['width'] = $line_end_x;
$values['height'] = $line_end_y;
break;
case 'line_item':
$values['type'] = LINE_ITEM;
$values['border_width'] = $line_width;

View File

@ -232,6 +232,17 @@ class AgentWizard extends HTML
*/
private $interfacesFound;
/**
* Some useful information about interfaces:
* `name` => [
* operstatus
* adminstatus
* ]
*
* @var array
*/
private $interfacesData;
/**
* X64 Interfaces
*
@ -260,6 +271,13 @@ class AgentWizard extends HTML
*/
private $moduleBlocks;
/**
* Extra arguments for SNMP call.
*
* @var string
*/
private $extraArguments = '';
/**
* Constructor
@ -913,16 +931,34 @@ class AgentWizard extends HTML
*/
public function performSNMPInterfaces($receivedOid)
{
// Path for get the IPs (ipv4).
$snmpIpDiscover = '.1.3.6.1.2.1.4.34.1.4.1.4';
$snmpIpIndexes = '.1.3.6.1.2.1.4.34.1.3.1.4';
$ipsResult = [];
// In this case we need the full information provided by snmpwalk.
$ipsResult = $this->snmpwalkValues($snmpIpDiscover, false, true);
$indexes = $this->snmpwalkValues($snmpIpIndexes, false, true);
$unicastIpReferences = [];
foreach ($indexes as $k => $v) {
$key = str_replace($snmpIpIndexes.'.', '', $k);
// Only catch the unicast records.
if ((preg_match('/unicast/', $ipsResult[$snmpIpDiscover.'.'.$key]) === 1)) {
$value = explode(': ', $v)[1];
$unicastIpReferences[$value] = $key;
}
}
// Create a list with the interfaces.
$interfaces = [];
foreach ($receivedOid as $keyOid => $nameOid) {
list($nameKey, $indexKey) = explode(
'.',
str_replace('IF-MIB::', '', $keyOid)
);
list($typeValue, $value) = explode(': ', $nameOid);
foreach ($receivedOid as $indexKey => $name) {
if ($indexKey[0] === '.') {
$indexKey = substr($indexKey, 1, strlen($indexKey));
}
// Set the name of interface.
$interfaces[$indexKey]['name'] = $value;
$interfaces[$indexKey]['name'] = $name;
// Get the description.
$interfaces[$indexKey]['descr'] = $this->snmpgetValue(
'.1.3.6.1.2.1.2.2.1.2.'.$indexKey
@ -933,40 +969,8 @@ class AgentWizard extends HTML
);
// Get unicast IP address.
$interfaces[$indexKey]['ip'] = '';
// Path for get the IPs (ipv4).
$snmpIpDiscover = '.1.3.6.1.2.1.4.34.1.4.1.4';
$ipsResult = [];
// In this case we need the full information provided by snmpwalk.
$snmpwalkIps = sprintf(
'snmpwalk -On -v%s -c %s %s %s',
$this->version,
$this->community,
$this->targetIp,
$snmpIpDiscover
);
exec($snmpwalkIps, $ipsResult);
foreach ($ipsResult as $ipResult) {
list($ipOidDirection, $ipOidValue) = explode(' = ', $ipResult);
// Only catch the unicast records.
if ((preg_match('/unicast/', $ipOidValue) === 1)) {
$tmpIpOidDirection = str_replace(
$snmpIpDiscover,
'',
$ipOidDirection
);
$snmpIpIndexDiscover = '.1.3.6.1.2.1.4.34.1.3.1.4';
$snmpIpIndexDiscover .= $tmpIpOidDirection;
$snmpgetIpIndex = $this->snmpgetValue($snmpIpIndexDiscover);
// If this Ip index number match with the current index key.
if ($snmpgetIpIndex === $indexKey) {
$interfaces[$indexKey]['ip'] .= substr(
$tmpIpOidDirection,
1
);
}
} else {
continue;
}
if (isset($unicastIpReferences[$indexKey]) === true) {
$interfaces[$indexKey]['ip'] = '';
}
}
@ -985,13 +989,15 @@ class AgentWizard extends HTML
public function performSNMPGeneral($receivedOid)
{
// Getting the Symbolic Name of the OID.
$symbolicName = explode('OID:', array_shift($receivedOid));
// Translate the Symbolic Name to numeric OID.
$output_oid = '';
exec('snmptranslate -On '.$symbolicName[1], $output_oid);
if (is_array($receivedOid) === false) {
// No PEN.
return;
}
// The PEN is hosted in the seventh position.
$tmpPEN = explode('.', $output_oid[0]);
$tmpPEN = explode('.', array_shift($receivedOid));
$pen = $tmpPEN[7];
// Then look in DB if the PEN is registered.
$penFound = db_get_value('manufacturer', 'tpen', 'pen', $pen);
if ($penFound === false) {
@ -1029,21 +1035,10 @@ class AgentWizard extends HTML
if ($this->wizardSection === 'snmp_interfaces_explorer') {
// Check if thereis x64 counters.
$snmp_tmp = '.1.3.6.1.2.1.31.1.1.1.6';
$check_x64 = get_snmpwalk(
$this->targetIp,
$this->version,
$this->community,
$this->authUserV3,
$this->securityLevelV3,
$this->authMethodV3,
$this->authPassV3,
$this->privacyMethodV3,
$this->privacyPassV3,
0,
$check_x64 = $this->snmpwalkValues(
$snmp_tmp,
$this->targetPort,
$this->server,
$this->extraArguments
false,
true
);
if ($check_x64) {
@ -1056,21 +1051,10 @@ class AgentWizard extends HTML
// Explore interface names.
$oidExplore = '.1.3.6.1.2.1.31.1.1.1.1';
$receivedOid = get_snmpwalk(
$this->targetIp,
$this->version,
$this->community,
$this->authUserV3,
$this->securityLevelV3,
$this->authMethodV3,
$this->authPassV3,
$this->privacyMethodV3,
$this->privacyPassV3,
0,
$receivedOid = $this->snmpwalkValues(
$oidExplore,
$this->targetPort,
$this->server,
$this->extraArguments
false,
true
);
} else {
// Get the device PEN.
@ -1078,21 +1062,10 @@ class AgentWizard extends HTML
}
// Doc Interfaces de red.
$receivedOid = get_snmpwalk(
$this->targetIp,
$this->version,
$this->community,
$this->authUserV3,
$this->securityLevelV3,
$this->authMethodV3,
$this->authPassV3,
$this->privacyMethodV3,
$this->privacyPassV3,
0,
$receivedOid = $this->snmpwalkValues(
$oidExplore,
$this->targetPort,
$this->server,
$this->extraArguments
false,
false
);
if (empty($receivedOid) || preg_grep('/no.*object/i', $receivedOid)) {
@ -1100,21 +1073,10 @@ class AgentWizard extends HTML
$oidExplore = '1.3.6.1.2.1.2.2.1.2';
// Doc Interfaces de red.
$receivedOid = get_snmpwalk(
$this->targetIp,
$this->version,
$this->community,
$this->authUserV3,
$this->securityLevelV3,
$this->authMethodV3,
$this->authPassV3,
$this->privacyMethodV3,
$this->privacyPassV3,
0,
$receivedOid = $this->snmpwalkValues(
$oidExplore,
$this->targetPort,
$this->server,
$this->extraArguments
false,
true
);
}
@ -1197,18 +1159,8 @@ class AgentWizard extends HTML
public function listModulesToCreate()
{
$data = get_parameter('data', '');
$data = json_decode(io_safe_output($data), true);
$data = array_reduce(
$data,
function ($carry, $item) {
$carry[$item['name']] = $item['value'];
return $carry;
},
[]
);
$candidateModules = $this->candidateModuleToCreate($data);
$this->sectionUrl = $this->baseUrl.'&wizard_section='.$this->wizardSection;
@ -2442,6 +2394,7 @@ class AgentWizard extends HTML
// Get current value.
$currentValue = $this->snmpgetValue($moduleData['value']);
// It unit of measure have data, attach to current value.
if (empty($moduleData['module_unit']) === false) {
$currentValue .= ' '.$moduleData['module_unit'];
@ -2486,13 +2439,13 @@ class AgentWizard extends HTML
'action' => $this->sectionUrl,
'id' => 'form-filter-interfaces',
'method' => 'POST',
'class' => 'modal flex flex-row',
'class' => 'modal flex flex-row searchbox',
'extra' => '',
];
// Inputs.
$inputs = [];
$inputs[] = [
// Inputs.
$inputs = [
[
'direct' => 1,
'class' => 'select-interfaces',
'block_content' => [
@ -2508,21 +2461,38 @@ class AgentWizard extends HTML
],
],
],
];
$inputs[] = [
'direct' => 1,
'block_content' => [
],
[
'label' => __('Search'),
'id' => 'txt-filter-search',
'class' => 'textbox',
'arguments' => [
'name' => 'filter-search',
'type' => 'text',
'class' => '',
'return' => true,
],
],
[
'label' => __('OperStatus UP'),
'arguments' => [
'name' => 'search-oper',
'type' => 'switch',
'id' => 'search-oper',
'onchange' => 'filterInterfaces()',
'value' => 0,
'return' => true,
],
],
[
'label' => __('AdminStatus UP'),
'arguments' => [
'name' => 'search-admin',
'type' => 'switch',
'id' => 'search-admin',
'onchange' => 'filterInterfaces()',
'value' => 0,
'return' => true,
],
],
];
@ -2577,6 +2547,7 @@ class AgentWizard extends HTML
// Get current value.
$currentValue = $this->snmpgetValue($moduleData['value']);
// Format current value with thousands and decimals.
if (is_numeric($currentValue) === true) {
$decimals = (is_float($currentValue) === true) ? 2 : 0;
@ -3023,6 +2994,12 @@ class AgentWizard extends HTML
$snmpwalkCombined = [];
foreach ($snmpwalkNames as $index => $name) {
if (isset($name) !== true
|| isset($snmpwalkValues[$index]) !== true
) {
continue;
}
$snmpwalkCombined[$index] = [
'name' => $name,
'value' => $snmpwalkValues[$index],
@ -3263,26 +3240,19 @@ class AgentWizard extends HTML
*/
private function snmpgetValue(string $oid, ?bool $full_output=false)
{
$output = get_snmpwalk(
$this->targetIp,
$this->version,
$this->community,
$this->authUserV3,
$this->securityLevelV3,
$this->authMethodV3,
$this->authPassV3,
$this->privacyMethodV3,
$this->privacyPassV3,
0,
$oid,
$this->targetPort,
$this->server,
$this->extraArguments,
(($full_output === false) ? '-Oa -On' : '-Oa')
);
if ($oid[0] !== '.') {
$oid = '.'.$oid;
}
$output = $this->snmpwalkValues($oid, false, true, true);
if (is_array($output) === true) {
foreach ($output as $k => $v) {
if ($k[0] !== '.') {
$k = '.'.$k;
}
if ($k == $oid) {
if ($full_output === true) {
return $k.' = '.$v;
}
@ -3291,6 +3261,7 @@ class AgentWizard extends HTML
return $value[1];
}
}
}
return false;
}
@ -3301,11 +3272,49 @@ class AgentWizard extends HTML
*
* @param string $oid Oid for get the values.
* @param boolean $full_output Array with full output.
* @param boolean $pure Return results as received by get_snmwalk.
* @param boolean $get If get operation, adjust key.
*
* @return array
*/
private function snmpwalkValues(string $oid, bool $full_output=false)
{
private function snmpwalkValues(
string $oid,
bool $full_output=false,
bool $pure=false,
bool $get=false
) {
static $__cached_walks;
if ($__cached_walks === null) {
$__cached_walks = [];
}
if ($oid[0] !== '.') {
$oid = '.'.$oid;
}
if ($get === true) {
// Request from snmpget. Cache is in tree.
$tree_oid = strrev($oid);
$tree_oid = strrev(
substr(
$tree_oid,
(strpos($tree_oid, '.') + 1),
strlen($tree_oid)
)
);
$key = $tree_oid.'-'.((int) $full_output).'-'.((int) $pure);
// Request entire sub-tree.
$oid = $tree_oid;
} else {
$key = $oid.'-'.((int) $full_output).'-'.((int) $pure);
}
if (isset($__cached_walks[$key]) === true) {
return $__cached_walks[$key];
}
$output = [];
$temporal = get_snmpwalk(
$this->targetIp,
@ -3325,6 +3334,11 @@ class AgentWizard extends HTML
(($full_output === false) ? '-Oa -On' : '-Oa')
);
if ($pure === true) {
$__cached_walks[$key] = $temporal;
return $temporal;
}
if (empty($temporal) === false) {
foreach ($temporal as $key => $oid_unit) {
if ($full_output === true) {
@ -3337,6 +3351,7 @@ class AgentWizard extends HTML
}
}
$__cached_walks[$key] = $output;
return $output;
}
@ -3586,6 +3601,40 @@ class AgentWizard extends HTML
}
/**
* Retrieve operstatus for given interface.
*
* @param string $interface_name Interface name.
*
* @return integer OperStatus.
*/
private function getOperStatus(string $interface_name)
{
if (is_array($this->interfacesData[$interface_name]) === true) {
return (int) $this->interfacesData[$interface_name]['operstatus'];
}
return 0;
}
/**
* Retrieve adminstatus for given interface.
*
* @param string $interface_name Interface name.
*
* @return integer AdminStatus.
*/
private function getAdminStatus(string $interface_name)
{
if (is_array($this->interfacesData[$interface_name]) === true) {
return (int) $this->interfacesData[$interface_name]['adminstatus'];
}
return 0;
}
/**
* Create the tables with toggle interface for show the modules availables.
*
@ -3607,6 +3656,8 @@ class AgentWizard extends HTML
) {
$output = '';
foreach ($blocks as $idBlock => $block) {
$md5IdBlock = hash('md5', $idBlock);
// Data with all components.
$blockData = $block['data'];
@ -3622,6 +3673,13 @@ class AgentWizard extends HTML
$blockComponentList .= $component['component_id'].',';
}
$is_up = false;
if ($this->getOperStatus($idBlock) === 1
&& $this->getAdminSTatus($idBlock) === 1
) {
$is_up = true;
}
$blockComponentList = chop($blockComponentList, ',');
// Title of Block.
if ($isInterface === true) {
@ -3632,15 +3690,16 @@ class AgentWizard extends HTML
);
$blockTitle .= '</b>';
} else {
$blockTitle = html_print_checkbox_switch_extended(
'interfaz_select_'.$idBlock,
1,
true,
false,
'',
'form="form-create-modules" class="interfaz_select"',
true,
''
$blockTitle = html_print_input(
[
'type' => 'switch',
'name' => 'interfaz_select_'.$idBlock,
'value' => $is_up,
'disabled' => false,
'attributes' => 'form="form-create-modules" class="interfaz_select" ',
'return' => true,
'id' => $md5IdBlock,
]
);
$blockTitle .= '<b>'.$block['name'];
$blockTitle .= '&nbsp;&nbsp;';
@ -3826,7 +3885,7 @@ class AgentWizard extends HTML
false,
false,
'',
'',
$md5IdBlock,
'',
'',
false,
@ -3866,7 +3925,7 @@ class AgentWizard extends HTML
false,
false,
'',
'',
$md5IdBlock,
'',
'',
false,
@ -3889,7 +3948,7 @@ class AgentWizard extends HTML
false,
false,
'',
'',
$md5IdBlock,
'',
'',
false,
@ -3932,7 +3991,7 @@ class AgentWizard extends HTML
false,
false,
'',
'',
$md5IdBlock,
'',
'',
false,
@ -3955,7 +4014,7 @@ class AgentWizard extends HTML
false,
false,
'',
'',
$md5IdBlock,
'',
'',
false,
@ -4037,7 +4096,7 @@ class AgentWizard extends HTML
'module-active-'.$uniqueId,
$module['module_enabled'],
true,
false,
$md5IdBlock,
'form="form-create-modules"'
);
@ -4046,7 +4105,7 @@ class AgentWizard extends HTML
'module-type-'.$uniqueId,
$module['type'],
true,
false,
$md5IdBlock,
'form="form-create-modules"'
);
@ -4055,7 +4114,7 @@ class AgentWizard extends HTML
'module-unit-'.$uniqueId,
$module['unit'],
true,
false,
$md5IdBlock,
'form="form-create-modules"'
);
@ -4064,7 +4123,7 @@ class AgentWizard extends HTML
'module-value-'.$uniqueId,
$module['value'],
true,
false,
$md5IdBlock,
'form="form-create-modules"'
);
@ -4073,7 +4132,7 @@ class AgentWizard extends HTML
'module-macros-'.$uniqueId,
base64_encode($module['macros']),
true,
false,
$md5IdBlock,
'form="form-create-modules"'
);
@ -4082,7 +4141,7 @@ class AgentWizard extends HTML
'module-name-oid-'.$uniqueId,
$module['name_oid'],
true,
false,
$md5IdBlock,
'form="form-create-modules"'
);
@ -4091,7 +4150,7 @@ class AgentWizard extends HTML
'module-scan_type-'.$uniqueId,
$module['scan_type'],
true,
false,
$md5IdBlock,
'form="form-create-modules"'
);
@ -4100,7 +4159,7 @@ class AgentWizard extends HTML
'module-execution_type-'.$uniqueId,
$module['execution_type'],
true,
false,
$md5IdBlock,
'form="form-create-modules"'
);
@ -4109,7 +4168,7 @@ class AgentWizard extends HTML
'module-query_class-'.$uniqueId,
$module['query_class'],
true,
false,
$md5IdBlock,
'form="form-create-modules"'
);
@ -4118,7 +4177,7 @@ class AgentWizard extends HTML
'module-query_key_field-'.$uniqueId,
$module['query_key_field'],
true,
false,
$md5IdBlock,
'form="form-create-modules"'
);
@ -4127,7 +4186,7 @@ class AgentWizard extends HTML
'module-scan_filters-'.$uniqueId,
$module['scan_filters'],
true,
false,
$md5IdBlock,
'form="form-create-modules"'
);
@ -4136,7 +4195,7 @@ class AgentWizard extends HTML
'module-query_filters-'.$uniqueId,
base64_encode($module['query_filters']),
true,
false,
$md5IdBlock,
'form="form-create-modules"'
);
@ -4147,7 +4206,7 @@ class AgentWizard extends HTML
'module-default_name-'.$uniqueId,
$module['name'],
true,
false,
$md5IdBlock,
'form="form-create-modules"'
);
@ -4155,7 +4214,7 @@ class AgentWizard extends HTML
'module-default_description-'.$uniqueId,
$module['description'],
true,
false,
$md5IdBlock,
'form="form-create-modules"'
);
}
@ -4167,6 +4226,10 @@ class AgentWizard extends HTML
$open = true;
$buttonSwitch = false;
$attr = 'operstatus="'.$this->getOperStatus($idBlock).'" ';
$attr .= 'adminstatus="';
$attr .= $this->getAdminStatus($idBlock).'" ';
$class = 'box-shadow white_table_graph interfaces_search';
$reverseImg = true;
if ($isPrincipal === true) {
@ -4176,22 +4239,25 @@ class AgentWizard extends HTML
$reverseImg = false;
}
$output .= ui_toggle(
$content,
$blockTitle,
'',
$idBlock,
$open,
true,
'',
'white-box-content',
$class,
'images/arrow_down_green.png',
'images/arrow_right_green.png',
false,
$reverseImg,
$buttonSwitch,
'form="form-create-modules"'
$output .= ui_print_toggle(
[
'content' => $content,
'name' => $blockTitle,
'title' => '',
'id' => $idBlock,
'hidden_default' => $open,
'return' => true,
'toggle_class' => '',
'container_class' => 'white-box-content',
'main_class' => $class,
'img_a' => 'images/arrow_down_green.png',
'img_b' => 'images/arrow_right_green.png',
'clean' => false,
'reverseImg' => $reverseImg,
'switch' => $buttonSwitch,
'attributes_switch' => 'form="form-create-modules"',
'toggl_attr' => $attr,
]
);
}
@ -4232,16 +4298,35 @@ class AgentWizard extends HTML
// Definition object.
$definition = [];
// Fulfill extra info.
$this->interfacesData[$data['name']] = [];
// IfOperStatus.
$adminStatusValue = 1;
if (empty($data) === false) {
$adminStatusValue = $this->snmpgetValue(
'1.3.6.1.2.1.2.2.1.7.'.$value
);
preg_match('/\((\d+?)\)/', $adminStatusValue, $match);
$adminStatusValue = (int) $match[1];
}
// IfOperStatus.
$operStatusValue = 1;
if (empty($data) === false) {
$operStatusValue = $this->snmpgetValue(
'1.3.6.1.2.1.2.2.1.8.'.$value
);
preg_match('/\((\d+?)\)/', $operStatusValue, $match);
$operStatusValue = (int) $match[1];
}
// Store aux data.
$this->interfacesData[$data['name']]['adminstatus'] = $adminStatusValue;
$this->interfacesData[$data['name']]['operstatus'] = $operStatusValue;
if ($adminStatusValue === 3) {
$min_warning = 3;
$max_warning = 4;
@ -5007,6 +5092,45 @@ class AgentWizard extends HTML
ob_start();
?>
<script type="text/javascript">
function filterInterfaces() {
var string = $('#text-filter-search').val().trim();
var filter_online = document.getElementById('search-admin').checked;
var filter_up = document.getElementById('search-oper').checked;
var regex = new RegExp(string, 'i');
var interfaces = $('.interfaces_search');
interfaces.each(function() {
if (string == ''
&& filter_up == false
&& filter_online == false
) {
$(this).removeClass('hidden');
return;
}
if (this.id.match(regex)) {
$(this).removeClass('hidden');
} else {
$(this).addClass('hidden');
}
if (filter_online == true) {
if ($(this).attr('adminstatus') != 1) {
$(this).addClass('hidden');
}
}
if (filter_up == true) {
if ($(this).attr('operstatus') != 1) {
$(this).addClass('hidden');
}
}
});
}
$(document).ready(function() {
// Meta.
var meta = "<?php echo is_metaconsole(); ?>";
@ -5020,20 +5144,7 @@ class AgentWizard extends HTML
// Filter search interfaces snmp.
$('#text-filter-search').keyup(function() {
var string = $('#text-filter-search').val();
var regex = new RegExp(string);
var interfaces = $('.interfaces_search');
interfaces.each(function() {
if (string == '') {
$(this).removeClass('hidden');
} else {
if (this.id.match(regex)) {
$(this).removeClass('hidden');
} else {
$(this).addClass('hidden');
}
}
});
filterInterfaces();
});
// Loading.
@ -5212,29 +5323,18 @@ class AgentWizard extends HTML
* Controls checkboxes for modules.
*/
function switchBlockControlInterfaces(e) {
var string = $('#text-filter-search').val();
if (string == '') {
if (e.checked) {
$(".interfaz_select").prop("checked", true);
} else {
$(".interfaz_select").prop("checked", false);
}
} else {
var regex = new RegExp(string);
var interfaces = $('.interfaces_search');
interfaces.each(function() {
if (this.id.match(regex)) {
$(this).removeClass('hidden');
if (e.checked) {
$("input[name='interfaz_select_" + this.id + "']")
.prop("checked", true);
} else {
$("input[name='interfaz_select_" + this.id + "']")
.prop("checked", false);
}
}
});
// Apply filters if not done yet.
//filterInterfaces();
// Select targets.
var interfaces = document.querySelectorAll(
'.interfaces_search:not(.hidden)'
);
// Apply selection.
for (let iface of interfaces) {
iface.querySelector('input[type="checkbox"]').checked = e.checked;
}
}
/**
@ -5243,23 +5343,47 @@ class AgentWizard extends HTML
function processListModules() {
confirmDialog({
title: "<?php echo __('Modules about to be created'); ?>",
hideOkButton: true,
message: function() {
var id = "div-" + uniqId();
var loading = "<?php echo __('Loading'); ?>" + "...";
var loading = "<?php echo __('Loading, this operation might take several minutes...'); ?>";
var datas = {};
let inputs = document.querySelectorAll("input,textarea");
for (let input of inputs) {
let id = input.className;
let chkbox =document.getElementById('interfaz_select_'+id);
if (chkbox != undefined
&& chkbox.checked == false
) {
// Skip disabled containers.
continue;
}
if (input.type != "checkbox") {
datas[input.name] = input.value;
}
if (input.type == "checkbox" && input.checked) {
datas[input.name] = input.value;
}
};
$.ajax({
method: "post",
url: "<?php echo ui_get_full_url('ajax.php', false, false, false); ?>",
data: {
page: "<?php echo $this->ajaxController; ?>",
method: "listModulesToCreate",
data: JSON.stringify(
$('#form-create-modules').serializeArray()
),
data: JSON.stringify(datas),
id_agente: "<?php echo $this->idAgent; ?>",
id: "<?php echo $this->idPolicy; ?>"
},
datatype: "html",
success: function(data) {
// Show hidden OK button
$('.sub.ok.submit-next').removeClass('invisible_important');
$('#' + id).empty().append(data);
},
error: function(e) {

View File

@ -20,7 +20,7 @@
/**
* Pandora build version and version
*/
$build_version = 'PC210201';
$build_version = 'PC210222';
$pandora_version = 'v7.0NG.752';
// Do not overwrite default timezone set if defined.
@ -40,18 +40,10 @@ if (!is_dir($config['homedir'])) {
}
// Help to debug problems. Override global PHP configuration
global $develop_bypass;
if ($develop_bypass != 1) {
// error_reporting(E_ALL);
if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
error_reporting(E_ALL & ~E_DEPRECATED & ~E_NOTICE);
} else {
error_reporting(E_ALL & ~E_NOTICE);
}
ini_set('display_errors', 0);
} else {
if ((int) $develop_bypass === 1) {
// Develop mode, show all notices and errors on Console (and log it)
if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
error_reporting(E_ALL & ~E_DEPRECATED);
@ -173,6 +165,10 @@ if (session_status() === PHP_SESSION_NONE) {
config_process_config();
config_prepare_session();
if ((bool) $config['console_log_enabled'] === true) {
error_reporting(E_ALL ^ E_NOTICE);
}
// Set a the system timezone default
if ((!isset($config['timezone'])) or ($config['timezone'] == '')) {
$config['timezone'] = 'Europe/Berlin';
@ -304,7 +300,7 @@ switch ($config['dbtype']) {
// ======================================================================
// Menu display mode.
if ($_SESSION['menu_type']) {
if (isset($_SESSION['meny_type']) === true && $_SESSION['menu_type']) {
$config['menu_type'] = $_SESSION['menu_type'];
} else {
$config['menu_type'] = 'classic';

View File

@ -232,6 +232,7 @@ define('DONUT_GRAPH', 17);
define('BARS_GRAPH', 18);
define('CLOCK', 19);
define('COLOR_CLOUD', 20);
define('NETWORK_LINK', 21);
// Some styles.
define('MIN_WIDTH', 300);
define('MIN_HEIGHT', 120);

View File

@ -2001,6 +2001,10 @@ function get_snmpwalk(
) {
global $config;
if (empty($ip_target) === true) {
return [];
}
// Note: quick_print is ignored
// Fix for snmp port
if (!empty($snmp_port)) {
@ -2012,7 +2016,6 @@ function get_snmpwalk(
$base_oid = escapeshellarg($base_oid);
}
if (empty($config['snmpwalk'])) {
switch (PHP_OS) {
case 'FreeBSD':
$snmpwalk_bin = '/usr/local/bin/snmpwalk';
@ -2023,11 +2026,12 @@ function get_snmpwalk(
break;
default:
if ($snmp_version == '1') {
$snmpwalk_bin = 'snmpwalk';
break;
}
} else {
$snmpwalk_bin = $config['snmpwalk'];
$snmpwalk_bin = 'snmpbulkwalk';
}
break;
}
switch (PHP_OS) {
@ -2035,6 +2039,7 @@ function get_snmpwalk(
case 'WINNT':
case 'Windows':
$error_redir_dir = 'NUL';
$snmpwalk_bin = 'snmpwalk';
break;
default:
@ -2042,6 +2047,14 @@ function get_snmpwalk(
break;
}
if (empty($config['snmpwalk']) === false) {
if ($snmp_version == '1') {
$snmpwalk_bin = $config['snmpwalk_fallback'];
} else {
$snmpwalk_bin = $config['snmpwalk'];
}
}
$output = [];
$rc = 0;
switch ($snmp_version) {
@ -4450,7 +4463,7 @@ function get_help_info($section_name)
{
global $config;
$user_language = get_user_language($id_user);
$user_language = get_user_language($config['id_user']);
$es = false;
$result = 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:';

View File

@ -1340,6 +1340,28 @@ function api_set_update_agent($id_agent, $thrash2, $other, $thrash3)
$disabled = $other['data'][11];
$description = $other['data'][12];
// Check parameters.
if ($idGroup == 0) {
$agent_update_error = __('The agent could not be modified. For security reasons, use a group other than 0.');
returnError('generic error', $agent_update_error);
return;
}
$server_name = db_get_value_sql('SELECT name FROM tserver WHERE BINARY name LIKE "'.$nameServer.'"');
if ($alias == '' && $alias_as_name === 0) {
returnError('alias_not_specified', 'No agent alias specified');
return;
} else if (db_get_value_sql('SELECT id_grupo FROM tgrupo WHERE id_grupo = '.$idGroup) === false) {
returnError('id_grupo_not_exist', 'The group doesn`t exist.');
return;
} else if (db_get_value_sql('SELECT id_os FROM tconfig_os WHERE id_os = '.$idOS) === false) {
returnError('id_os_not_exist', 'The OS doesn`t exist.');
return;
} else if ($server_name === false) {
returnError('server_not_exist', 'The '.get_product_name().' Server doesn`t exist.');
return;
}
if ($cascadeProtection == 1) {
if (($idParent != 0) && (db_get_value_sql(
'SELECT id_agente_modulo
@ -3187,7 +3209,7 @@ function api_set_create_network_module($id, $thrash1, $other, $thrash3)
$agent_by_alias = false;
if ($other['data'][30] === '1') {
if ($other['data'][31] === '1') {
$agent_by_alias = true;
}
@ -5242,6 +5264,8 @@ function api_get_module_value_all_agents($id, $thrash1, $other, $thrash2)
*/
function api_set_create_alert_template($name, $thrash1, $other, $thrash3)
{
global $config;
if (defined('METACONSOLE')) {
return;
}
@ -5257,64 +5281,93 @@ function api_set_create_alert_template($name, $thrash1, $other, $thrash3)
$template_name = $name;
$type = $other['data'][0];
$id_group = $other['data'][26];
if ($id_group == '') {
returnError(
'error_create_alert_template',
__('Error creating alert template. Id_group cannot be left blank.')
);
return;
}
if (users_can_manage_group_all('LM')) {
$groups = users_get_groups($config['id_user'], 'LM');
} else {
$groups = users_get_groups($config['id_user'], 'LM', false);
}
if ($groups[$id_group] === null) {
returnError(
'error_create_alert_template',
__('Error creating alert template. Invalid id_group or the user has not enough permission to make this action.')
);
return;
}
for ($i = 29; $i < 54; $i++) {
if ($other['data'][$i] === null) {
$other['data'][$i] = '';
}
}
$values = [
'description' => $other['data'][1],
'field1' => $other['data'][3],
'field2' => $other['data'][4],
'field3' => $other['data'][5],
'value' => $other['data'][6],
'matches_value' => $other['data'][7],
'max_value' => $other['data'][8],
'min_value' => $other['data'][9],
'time_threshold' => $other['data'][10],
'max_alerts' => $other['data'][11],
'min_alerts' => $other['data'][12],
'time_from' => $other['data'][13],
'time_to' => $other['data'][14],
'monday' => $other['data'][15],
'tuesday' => $other['data'][16],
'wednesday' => $other['data'][17],
'thursday' => $other['data'][18],
'friday' => $other['data'][19],
'saturday' => $other['data'][20],
'sunday' => $other['data'][21],
'recovery_notify' => $other['data'][22],
'field2_recovery' => $other['data'][23],
'field3_recovery' => $other['data'][24],
'priority' => $other['data'][25],
'id_group' => $other['data'][26],
'special_day' => $other['data'][27],
'min_alerts_reset_counter' => $other['data'][28],
'field1_recovery' => $other['data'][29],
'field4' => $other['data'][30],
'field5' => $other['data'][31],
'field6' => $other['data'][32],
'field7' => $other['data'][33],
'field8' => $other['data'][34],
'field9' => $other['data'][35],
'field10' => $other['data'][36],
'field11' => $other['data'][37],
'field12' => $other['data'][38],
'field13' => $other['data'][39],
'field14' => $other['data'][40],
'field15' => $other['data'][41],
'field4_recovery' => $other['data'][42],
'field5_recovery' => $other['data'][43],
'field6_recovery' => $other['data'][44],
'field7_recovery' => $other['data'][45],
'field8_recovery' => $other['data'][46],
'field9_recovery' => $other['data'][47],
'field10_recovery' => $other['data'][48],
'field11_recovery' => $other['data'][49],
'field12_recovery' => $other['data'][50],
'field13_recovery' => $other['data'][51],
'field14_recovery' => $other['data'][52],
'field15_recovery' => $other['data'][53],
];
if ($other['data'][2] != '') {
$values = [
'description' => $other['data'][1],
'id_alert_action' => $other['data'][2],
'field1' => $other['data'][3],
'field2' => $other['data'][4],
'field3' => $other['data'][5],
'value' => $other['data'][6],
'matches_value' => $other['data'][7],
'max_value' => $other['data'][8],
'min_value' => $other['data'][9],
'time_threshold' => $other['data'][10],
'max_alerts' => $other['data'][11],
'min_alerts' => $other['data'][12],
'time_from' => $other['data'][13],
'time_to' => $other['data'][14],
'monday' => $other['data'][15],
'tuesday' => $other['data'][16],
'wednesday' => $other['data'][17],
'thursday' => $other['data'][18],
'friday' => $other['data'][19],
'saturday' => $other['data'][20],
'sunday' => $other['data'][21],
'recovery_notify' => $other['data'][22],
'field2_recovery' => $other['data'][23],
'field3_recovery' => $other['data'][24],
'priority' => $other['data'][25],
'id_group' => $other['data'][26],
];
} else {
$values = [
'description' => $other['data'][1],
'field1' => $other['data'][3],
'field2' => $other['data'][4],
'field3' => $other['data'][5],
'value' => $other['data'][6],
'matches_value' => $other['data'][7],
'max_value' => $other['data'][8],
'min_value' => $other['data'][9],
'time_threshold' => $other['data'][10],
'max_alerts' => $other['data'][11],
'min_alerts' => $other['data'][12],
'time_from' => $other['data'][13],
'time_to' => $other['data'][14],
'monday' => $other['data'][15],
'tuesday' => $other['data'][16],
'wednesday' => $other['data'][17],
'thursday' => $other['data'][18],
'friday' => $other['data'][19],
'saturday' => $other['data'][20],
'sunday' => $other['data'][21],
'recovery_notify' => $other['data'][22],
'field2_recovery' => $other['data'][23],
'field3_recovery' => $other['data'][24],
'priority' => $other['data'][25],
'id_group' => $other['data'][26],
];
$values['id_alert_action'] = $other['data'][2];
}
$id_template = alerts_create_alert_template($template_name, $type, $values);
@ -5353,11 +5406,6 @@ function api_set_update_alert_template($id_template, $thrash1, $other, $thrash3)
return;
}
if (!check_acl($config['id_user'], 0, 'LM')) {
returnError('forbidden', 'string');
return;
}
if ($id_template == '') {
returnError(
'error_update_alert_template',
@ -5366,7 +5414,7 @@ function api_set_update_alert_template($id_template, $thrash1, $other, $thrash3)
return;
}
$result_template = alerts_get_alert_template_name($id_template);
$result_template = alerts_get_alert_template($id_template);
if (!$result_template) {
returnError(
@ -5376,6 +5424,27 @@ function api_set_update_alert_template($id_template, $thrash1, $other, $thrash3)
return;
}
if (users_can_manage_group_all('LM')) {
$groups = users_get_groups($config['id_user'], 'LM');
} else {
$groups = users_get_groups($config['id_user'], 'LM', false);
}
$id_group_org = $result_template['id_group'];
if ($other['data'][27] === null) {
$id_group_new = $id_group_org;
} else {
$id_group_new = $other['data'][27];
}
if ($groups[$id_group_org] === null || $groups[$id_group_new] === null) {
returnError(
'error_create_alert_template',
__('Error updating alert template. Invalid id_group or the user has not enough permission to make this action.')
);
return;
}
$fields_template = [
'name',
'type',
@ -5405,6 +5474,33 @@ function api_set_update_alert_template($id_template, $thrash1, $other, $thrash3)
'field3_recovery',
'priority',
'id_group',
'special_day',
'min_alerts_reset_counter',
'field1_recovery',
'field4',
'field5',
'field6',
'field7',
'field8',
'field9',
'field10',
'field11',
'field12',
'field13',
'field14',
'field15',
'field4_recovery',
'field5_recovery',
'field6_recovery',
'field7_recovery',
'field8_recovery',
'field9_recovery',
'field10_recovery',
'field11_recovery',
'field12_recovery',
'field13_recovery',
'field14_recovery',
'field15_recovery',
];
$cont = 0;
@ -5451,6 +5547,8 @@ function api_set_update_alert_template($id_template, $thrash1, $other, $thrash3)
*/
function api_set_delete_alert_template($id_template, $thrash1, $other, $thrash3)
{
global $config;
if (defined('METACONSOLE')) {
return;
}
@ -5463,6 +5561,28 @@ function api_set_delete_alert_template($id_template, $thrash1, $other, $thrash3)
return;
}
$result_template = alerts_get_alert_template($id_template);
if (!$result_template) {
returnError(
'error_update_alert_template',
__('Error deleting alert template. Id_template doesn\'t exist.')
);
return;
}
if (users_can_manage_group_all('LM')) {
$groups = users_get_groups($config['id_user'], 'LM');
} else {
$groups = users_get_groups($config['id_user'], 'LM', false);
}
$id_group = $result_template['id_group'];
if ($groups[$id_group] === null) {
returnError('forbidden', 'string');
return;
}
$result = alerts_delete_alert_template($id_template);
if ($result == 0) {
@ -13823,7 +13943,8 @@ function api_get_module_graph($id_module, $thrash2, $other, $thrash4)
'image_treshold' => $graph_threshold,
];
$graph_html = grafico_modulo_sparse($params);
// Format MIME RFC 2045 (line break 76 chars).
$graph_html = chunk_split(grafico_modulo_sparse($params));
if ($other['data'][1]) {
header('Content-type: text/html');

View File

@ -871,6 +871,14 @@ function config_update_config()
if (!config_update_value('row_limit_csv', get_parameter('row_limit_csv'))) {
$error_update[] = __('Row limit in csv log');
}
if (!config_update_value('snmpwalk', get_parameter('snmpwalk'))) {
$error_update[] = __('SNMP walk binary path');
}
if (!config_update_value('snmpwalk_fallback', get_parameter('snmpwalk_fallback'))) {
$error_update[] = __('SNMP walk binary path (fallback for v1)');
}
break;
case 'vis':
@ -1958,6 +1966,32 @@ function config_process_config()
config_update_value('row_limit_csv', 10000);
}
if (!isset($config['snmpwalk'])) {
switch (PHP_OS) {
case 'FreeBSD':
config_update_value('snmpwalk', '/usr/local/bin/snmpwalk');
break;
case 'NetBSD':
config_update_value('snmpwalk', '/usr/pkg/bin/snmpwalk');
break;
case 'WIN32':
case 'WINNT':
case 'Windows':
config_update_value('snmpwalk', 'snmpwalk');
break;
default:
config_update_value('snmpwalk', 'snmpbulkwalk');
break;
}
}
if (!isset($config['snmpwalk_fallback'])) {
config_update_value('snmpwalk_fallback', 'snmpwalk');
}
if (!isset($config['event_purge'])) {
config_update_value('event_purge', 15);
}
@ -2864,7 +2898,7 @@ function config_process_config()
}
if (!isset($config['legacy_vc'])) {
config_update_value('legacy_vc', 1);
config_update_value('legacy_vc', 0);
}
if (!isset($config['vc_default_cache_expiration'])) {

View File

@ -3718,6 +3718,14 @@ function events_get_response_target(
) {
global $config;
include_once $config['homedir'].'/vendor/autoload.php';
try {
$eventObjt = new PandoraFMS\Event($event_id);
} catch (Exception $e) {
$eventObjt = new PandoraFMS\Event();
}
// If server_id > 0, it's a metaconsole query.
$meta = $server_id > 0 || is_metaconsole();
$event_table = events_get_events_table($meta, $history);
@ -3915,9 +3923,69 @@ function events_get_response_target(
}
if (strpos($target, '_event_instruction_') !== false) {
// Fallback to module instructions if not defined in event.
$instructions = [];
foreach ([
'warning_instructions',
'critical_instructions',
'unknown_instructions',
] as $i) {
$instructions[$i] = $event[$i];
if (empty($instructions[$i]) === true
&& $eventObjt->module() !== null
) {
try {
$instructions[$i] = $eventObjt->module()->{$i}();
} catch (Exception $e) {
// Method not found.
$instructions[$i] = null;
}
}
}
$target = str_replace(
'_event_instruction_',
events_display_instructions($event['event_type'], $event, false),
events_display_instructions(
$event['event_type'],
$instructions,
false,
$eventObjt->toArray()
),
$target
);
}
if (strpos($target, '_data_') !== false
&& $eventObjt !== null
&& $eventObjt->module() !== null
) {
$target = str_replace(
'_data_',
$eventObjt->module()->lastValue(),
$target
);
} else {
$target = str_replace(
'_data_',
__('N/A'),
$target
);
}
if (strpos($target, '_moduledescription_') !== false
&& $eventObjt !== null
&& $eventObjt->module() !== null
) {
$target = str_replace(
'_moduledescription_',
io_safe_output($eventObjt->module()->descripcion()),
$target
);
} else {
$target = str_replace(
'_moduledescription_',
__('N/A'),
$target
);
}
@ -4404,7 +4472,14 @@ function events_page_details($event, $server='')
$data = [];
$data[0] = __('Instructions');
$data[1] = html_entity_decode(events_display_instructions($event['event_type'], $event, true));
$data[1] = html_entity_decode(
events_display_instructions(
$event['event_type'],
$event,
true,
$event
)
);
$table_details->data[] = $data;
$data = [];
@ -4535,13 +4610,50 @@ function events_display_status($status)
* instructions.
* @param boolean $italic Display N/A between italic html marks if
* instruction is not found.
* @param array $eventObj Event object.
*
* @return string Safe output.
*/
function events_display_instructions($event_type='', $inst=[], $italic=true)
function events_display_instructions($event_type='', $inst=[], $italic=true, $event=null)
{
if ($event_type === 'alert_fired') {
if ($event !== null) {
// Retrieve alert template type.
if ((bool) is_metaconsole() === true
&& $event['server_id'] > 0
) {
enterprise_include_once('include/functions_metaconsole.php');
$r = enterprise_hook(
'metaconsole_connect',
[
null,
$event['server_id'],
]
);
}
$event_type = db_get_value_sql(
sprintf(
'SELECT ta.type
FROM talert_templates ta
INNER JOIN talert_template_modules tam
ON ta.id=tam.id_alert_template
WHERE tam.id = %d',
$event['id_alert_am']
)
);
if ((bool) is_metaconsole() === true
&& $event['server_id'] > 0
) {
enterprise_hook('metaconsole_restore_db');
}
}
}
switch ($event_type) {
case 'going_unknown':
case 'unknown':
if ($inst['unknown_instructions'] != '') {
return str_replace("\n", '<br>', io_safe_output($inst['unknown_instructions']));
}
@ -4549,6 +4661,7 @@ function events_display_instructions($event_type='', $inst=[], $italic=true)
case 'going_up_warning':
case 'going_down_warning':
case 'warning':
if ($inst['warning_instructions'] != '') {
return str_replace("\n", '<br>', io_safe_output($inst['warning_instructions']));
}
@ -4556,6 +4669,7 @@ function events_display_instructions($event_type='', $inst=[], $italic=true)
case 'going_up_critical':
case 'going_down_critical':
case 'critical':
if ($inst['critical_instructions'] != '') {
return str_replace("\n", '<br>', io_safe_output($inst['critical_instructions']));
}
@ -7146,7 +7260,12 @@ function events_get_field_value_by_event_id(
if (strpos($value, '_event_instruction_') !== false) {
$value = str_replace(
'_event_instruction_',
events_display_instructions($event['event_type'], $event, false),
events_display_instructions(
$event['event_type'],
$event,
false,
$event
),
$value
);
}

View File

@ -536,6 +536,8 @@ function html_print_select_groups(
$include_groups[$nothing_value] = $nothing;
}
$json_exclusions = '';
$json_inclusions = '';
if (is_array($delete_groups) === true) {
$json_exclusions = json_encode($delete_groups);
}
@ -3586,7 +3588,7 @@ function html_print_checkbox_switch_extended(
if ($id == '') {
$output .= ' id="checkbox-'.$id_aux.'"';
} else {
$output .= ' '.$id.'"';
$output .= ' id="'.$id.'"';
}
if ($script != '') {
@ -4247,7 +4249,7 @@ function html_print_switch($attributes=[])
$attributes['style'] = '';
}
$disabled_class .= (bool) ($attributes['disabled']) ? ' p-slider-disabled' : '';
$disabled_class = (bool) ($attributes['disabled']) ? ' p-slider-disabled' : '';
return "<label class='p-switch' style='".$attributes['style']."'>
<input type='checkbox' ".$html_expand.">

View File

@ -227,7 +227,7 @@ function io_safe_output_array(&$item, $key=false, $utf8=true)
* @param string|array $value String or array of strings to be cleaned.
* @param boolean $utf8 Flag, set the output encoding in utf8, by default true.
*
* @return unknown_type
* @return string
*/
function io_safe_output($value, $utf8=true)
{

View File

@ -675,6 +675,8 @@ function modules_create_agent_module(
$time = 0;
if (empty($values['interval']) === false) {
$time = (time() - (int) $values['interval']);
} else {
$values['interval'] = null;
}
$result = db_process_sql_insert(

View File

@ -12864,7 +12864,7 @@ function reporting_get_stats_servers()
);
$tdata[1] = '<span class="big_data" id="total_events">'.html_print_image('images/spinner.gif', true).'</span>';
if ($system_events > 50000 && !enterprise_installed()) {
if (isset($system_events) && $system_events > 50000 && !enterprise_installed()) {
$tdata[2] = "<div id='monitoreventsmodal' class='publienterprise' title='Community version' style='text-align:left'><img data-title='Enterprise version' class='img_help forced_title' data-use_title_for_force_title='1' src='images/alert_enterprise.png'></div>";
} else {
$tdata[3] = '&nbsp;';

View File

@ -265,94 +265,43 @@ function snmp_browser_get_tree(
$snmp3_privacy_method='',
$snmp3_privacy_pass='',
$snmp3_context_engine_id=null,
$server_to_exec=0
$server_to_exec=0,
$target_port=''
) {
global $config;
if ($server_to_exec != 0) {
$output = get_snmpwalk(
// Ip_target.
$target_ip,
// Snmp_version.
$version,
// Snmp_community.
$community,
// Snmp3_auth_user.
$snmp3_auth_user,
// Snmp3_security_level.
$snmp3_security_level,
// Snmp3_auth_method.
$snmp3_auth_method,
// Snmp3_auth_pass.
$snmp3_auth_pass,
// Snmp3_privacy_method.
$snmp3_privacy_method,
// Snmp3_privacy_pass.
$snmp3_privacy_pass,
// Quick_print.
0,
// Base_oid.
$starting_oid,
'',
// Snmp_port.
$target_port,
// Server_to_exec.
$server_to_exec,
// Extra_arguments.
'',
// Format.
''
);
} else {
switch ($version) {
case '1':
$snmp_version = SNMP::VERSION_1;
break;
case '2':
$snmp_version = SNMP::VERSION_2C;
break;
case '2c':
$snmp_version = SNMP::VERSION_2C;
break;
case '3':
$snmp_version = SNMP::VERSION_3;
$community = $snmp3_auth_user;
break;
default:
$snmp_version = SNMP::VERSION_2C;
break;
}
$snmp_session = new SNMP($snmp_version, $target_ip, $community);
$snmp_session->oid_output_format = SNMP_OID_OUTPUT_MODULE;
// Set security if SNMP Version is 3.
if ($snmp_version == SNMP::VERSION_3) {
$snmp_session->setSecurity(
$snmp3_security_level,
$snmp3_auth_method,
$snmp3_auth_pass,
$snmp3_privacy_method,
$snmp3_privacy_pass,
'',
$snmp3_context_engine_id
);
}
$mibs_dir = $config['homedir'].'/attachment/mibs';
$_dir = opendir($mibs_dir);
// Future. Recomemended: Use a global config limit of MIBs loaded.
while (($mib_file = readdir($_dir)) !== false) {
if ($mib_file == '..' || $mib_file == '.') {
continue;
}
$rs = snmp_read_mib($mibs_dir.'/'.$mib_file);
if ($rs !== true) {
error_log('Failed while reading MIB file: '.$mib_file);
}
}
closedir($_dir);
$output = $snmp_session->walk($starting_oid);
if ($output == false) {
$output = $snmp_session->getError();
$snmp_session->close();
return $output;
}
$snmp_session->close();
}
// Build the tree if output comes filled.
if (empty($output) === false) {
@ -426,6 +375,7 @@ function snmp_browser_get_tree(
* @param string $snmp3_privacy_method Privicy method snmp3.
* @param string $snmp3_privacy_pass Pass Method snmp3.
* @param integer $server_to_exec Execute with other server.
* @param integer|null $target_port Target port.
*
* @return mixed OID data.
*/
@ -440,7 +390,8 @@ function snmp_browser_get_oid(
$snmp3_auth_pass='',
$snmp3_privacy_method='',
$snmp3_privacy_pass='',
$server_to_exec=0
$server_to_exec=0,
$target_port=''
) {
global $config;
@ -453,24 +404,40 @@ function snmp_browser_get_oid(
}
$output = get_snmpwalk(
// Ip_target.
$target_ip,
// Snmp_version.
$version,
// Snmp_community.
$community,
// Snmp3_auth_user.
$snmp3_auth_user,
// Snmp3_security_level.
$snmp3_security_level,
// Snmp3_auth_method.
$snmp3_auth_method,
// Snmp3_auth_pass.
$snmp3_auth_pass,
// Snmp3_privacy_method.
$snmp3_privacy_method,
// Snmp3_privacy_pass.
$snmp3_privacy_pass,
// Quick_print.
0,
// Base_oid.
$target_oid,
'',
// Snmp_port.
$target_port,
// Server_to_exec.
$server_to_exec,
// Extra_arguments.
'',
// Format.
'-On'
);
$oid_data['oid'] = $target_oid;
foreach ($output as $oid => $value) {
$oid = trim($oid);
$oid_data['numeric_oid'] = $oid;
@ -494,7 +461,8 @@ function snmp_browser_get_oid(
$snmptranslate_bin = $config['snmptranslate'];
}
if ($server_to_exec != 0) {
if ($server_to_exec != 0 && enterprise_installed()) {
$server_data = db_get_row('tserver', 'id_server', $server_to_exec);
$command_output = $snmptranslate_bin.' -m ALL -M +'.escapeshellarg($config['homedir'].'/attachment/mibs').' -Td '.escapeshellarg($oid);
if (empty($server_data['port'])) {
@ -574,7 +542,8 @@ function snmp_browser_print_oid(
) {
$output = '';
// OID information table
// OID information table.
$table = new StdClass();
$table->width = '100%';
$table->size = [];
$table->data = [];
@ -725,15 +694,33 @@ function snmp_browser_print_container(
$table->size = [];
$table->data = [];
$table->data[0][0] = '<strong>'.__('Target IP').'</strong> &nbsp;&nbsp;';
$table->data[0][0] .= html_print_input_text(
'target_ip',
get_parameter('target_ip', ''),
'',
25,
0,
true
$table->size[0] = '30%';
$table->data[0][0] = '<div class="mw500px"><strong>'.__('Target IP').'</strong> &nbsp;&nbsp;';
$table->data[0][0] .= html_print_input(
[
'type' => 'text',
'name' => 'target_ip',
'value' => get_parameter('target_ip', ''),
'required' => true,
'size' => 25,
'maxlength' => 0,
'return' => true,
]
);
$table->data[0][0] .= '&nbsp;&nbsp<strong>'.__('Port').'</strong>&nbsp;&nbsp;';
$table->data[0][0] .= html_print_input(
[
'type' => 'number',
'name' => 'target_port',
'id' => 'target_port',
'value' => get_parameter('target_port', 161),
'required' => true,
'return' => true,
]
);
$table->data[0][0] .= '</div>';
$table->data[0][1] = '<strong>'.__('Community').'</strong> &nbsp;&nbsp;';
$table->data[0][1] .= html_print_input_text(
'community',
@ -746,7 +733,7 @@ function snmp_browser_print_container(
$table->data[0][2] = '<strong>'.__('Starting OID').'</strong> &nbsp;&nbsp;';
$table->data[0][2] .= html_print_input_text(
'starting_oid',
get_parameter('starting_oid', '.1.3.6.1.2'),
get_parameter('starting_oid', '.1.3.6.1.2.1.2.2'),
'',
25,
0,
@ -805,12 +792,17 @@ function snmp_browser_print_container(
true
);
$table->data[1][2] = html_print_button(
__('Browse'),
'browse',
false,
'snmpBrowse()',
'class="sub search" style="margin-top:0px;"',
$table->data[1][2] = html_print_input(
[
'type' => 'submit',
'label' => __('Browse'),
'name' => 'browse',
'disabled' => false,
'script' => 'snmpBrowse()',
'attributes' => 'class="sub search" style="margin-top:0px;"',
'return' => true,
],
'div',
true
);
@ -1013,8 +1005,9 @@ function snmp_browser_print_container(
$output = '<div id="snmp_browser_container" style="'.$display.'">';
$output .= '<div style="text-align: left; width: '.$width.'; height: '.$height.';">';
$output .= '<div style="width: 100%">';
$output .= '<form onsubmit="snmpBrowse(); return false;">';
$output .= html_print_table($table, true);
$output .= '</div>';
$output .= '</form></div>';
if (isset($snmp_version) === false) {
$snmp_version = null;
@ -1118,22 +1111,71 @@ function snmp_browser_print_container(
* @param array $targets_oids Modules oids.
* @param array $values SNMP conf values.
* @param array|null $id_target (Optional) Id target where modules will be created.
* @return array $fail_modules
* @param string|null $server_to_exec Remote server to execute command.
*
* @return array Failed modules.
*/
function snmp_browser_create_modules_snmp(string $module_target, array $snmp_values, ?array $id_target)
{
function snmp_browser_create_modules_snmp(
string $module_target,
array $snmp_values,
?array $id_target,
?string $server_to_exec=null
) {
$target_ip = null;
$target_port = null;
$community = null;
$target_oid = null;
$snmp_version = null;
$snmp3_auth_user = null;
$snmp3_security_level = null;
$snmp3_auth_method = null;
$snmp3_auth_pass = null;
$snmp3_privacy_method = null;
$snmp3_privacy_pass = null;
if (is_array($snmp_values)) {
if (isset($snmp_values['snmp_browser_version']) === true) {
$snmp_version = $snmp_values['snmp_browser_version'];
}
if (isset($snmp_values['community']) === true) {
$community = $snmp_values['community'];
}
if (isset($snmp_values['target_ip']) === true) {
$target_ip = $snmp_values['target_ip'];
}
if (isset($snmp_values['target_port']) === true) {
$target_port = $snmp_values['target_port'];
}
if (isset($snmp_values['snmp3_browser_auth_user']) === true) {
$snmp3_auth_user = $snmp_values['snmp3_browser_auth_user'];
}
if (isset($snmp_values['snmp3_browser_security_level']) === true) {
$snmp3_security_level = $snmp_values['snmp3_browser_security_level'];
};
if (isset($snmp_values['snmp3_browser_auth_method']) === true) {
$snmp3_auth_method = $snmp_values['snmp3_browser_auth_method'];
}
if (isset($snmp_values['snmp3_browser_auth_pass']) === true) {
$snmp3_auth_pass = $snmp_values['snmp3_browser_auth_pass'];
}
if (isset($snmp_values['snmp3_privacy_method']) === true) {
$snmp3_privacy_method = $snmp_values['snmp3_privacy_method'];
};
if (isset($snmp_values['snmp3_browser_privacy_pass']) === true) {
$snmp3_privacy_pass = $snmp_values['snmp3_browser_privacy_pass'];
}
if (isset($snmp_values['oids']) === true) {
$targets_oids = $snmp_values['oids'];
}
}
$fail_modules = [];
@ -1148,9 +1190,16 @@ function snmp_browser_create_modules_snmp(string $module_target, array $snmp_val
$snmp3_auth_method,
$snmp3_auth_pass,
$snmp3_privacy_method,
$snmp3_privacy_pass
$snmp3_privacy_pass,
$server_to_exec,
$target_port
);
if (isset($oid['numeric_oid']) === false) {
$fail_modules[] = $target_oid;
continue;
}
if (empty($oid['description'])) {
$description = '';
} else {
@ -1241,7 +1290,7 @@ function snmp_browser_create_modules_snmp(string $module_target, array $snmp_val
'min' => 0,
'tcp_send' => $snmp_version,
'tcp_rcv' => '',
'tcp_port' => 0,
'tcp_port' => $target_port,
'snmp_oid' => $oid['numeric_oid'],
'snmp_community' => $community,
'id_module_group' => 3,
@ -1301,7 +1350,7 @@ function snmp_browser_create_modules_snmp(string $module_target, array $snmp_val
'min' => 0,
'tcp_send' => $snmp_version,
'tcp_rcv' => '',
'tcp_port' => 0,
'tcp_port' => $target_port,
'snmp_oid' => $oid['numeric_oid'],
'snmp_community' => $community,
'id_module_group' => 3,
@ -1354,7 +1403,7 @@ function snmp_browser_create_modules_snmp(string $module_target, array $snmp_val
}
}
if (is_array($ids)) {
if (isset($ids) === true && is_array($ids) === true) {
foreach ($ids as $id) {
// Id < 0 for error codes.
if (!$id || $id < 0) {
@ -1382,6 +1431,8 @@ function snmp_browser_create_modules_snmp(string $module_target, array $snmp_val
*/
function snmp_browser_print_create_module_massive($target='agent', $snmp_conf, $return=false)
{
global $config;
// String for labels.
switch ($target) {
case 'agent':
@ -1393,7 +1444,7 @@ function snmp_browser_print_create_module_massive($target='agent', $snmp_conf, $
break;
}
$output .= "<form target='_blank' id='create_module_massive' action='#' method='post'>";
$output = "<form target='_blank' id='create_module_massive' action='#' method='post'>";
$strict_user = db_get_value(
'strict_acl',
@ -1582,6 +1633,10 @@ function snmp_browser_print_create_policy()
{
$table = new stdClass();
$name = get_parameter('name');
$id_group = get_parameter('id_group');
$description = get_parameter('description');
$table->width = '100%';
$table->class = 'databox filters';
$table->style = [];
@ -1592,7 +1647,8 @@ function snmp_browser_print_create_policy()
$table->data[0][1] = html_print_input_text('name', $name, '', '60%', 150, true);
$table->data[1][0] = __('Group');
$table->data[1][1] = html_print_select_groups(
$table->data[1][1] = '<div class="flex flex-row"><div class="w90p">';
$table->data[1][1] .= html_print_select_groups(
false,
'AW',
false,
@ -1602,10 +1658,10 @@ function snmp_browser_print_create_policy()
'',
'',
true
);
).'</div>';
$table->data[1][1] .= ' <span id="group_preview">';
$table->data[1][1] .= ui_print_group_icon($id_group, true, 'groups_small', '', false);
$table->data[1][1] .= '</span>';
$table->data[1][1] .= '</span></div>';
$table->data[2][0] = __('Description');
$table->data[2][1] = html_print_textarea('description', 3, 30, $description, '', true);

View File

@ -2923,7 +2923,7 @@ function ui_progress(
$id = uniqid();
ui_require_css_file('progress');
$output .= '<span id="'.$id.'" class="progress_main" data-label="'.$text;
$output = '<span id="'.$id.'" class="progress_main" data-label="'.$text;
$output .= '" style="width: '.$width.'; height: '.$height.'em; border: 1px solid '.$color.'">';
$output .= '<span id="'.$id.'_progress" class="progress" style="width: '.$progress.'%; background: '.$color.'"></span>';
$output .= '</span>';
@ -3076,7 +3076,7 @@ function ui_progress_extend(
ui_require_css_file('progress');
// Main container.
$output .= '<div class="progress_main_noborder" ';
$output = '<div class="progress_main_noborder" ';
$output .= '" style="width:'.$data['width'].'%;';
$output .= ' height:'.$data['height'].'em;">';
@ -3419,6 +3419,7 @@ function ui_print_datatable(array $parameters)
$js .= $parameters['drawCallback'];
}
$columns = '';
for ($i = 1; $i <= (count($parameters['columns']) - 3); $i++) {
if ($i != (count($parameters['columns']) - 3)) {
$columns .= $i.',';
@ -3759,9 +3760,11 @@ function ui_print_event_priority(
* @param string $img_a Image (closed).
* @param string $img_b Image (opened).
* @param string $clean Do not encapsulate with class boxes, clean print.
* @param boolean $reverseImg Reverse image.
* @param boolean $swtich Use switch input instead image.
* @param string $attributes_switch Switch attributes (class...).
* @param boolean $reverseImg Reverse img.
* @param boolean $switch Use switch.
* @param string $attributes_switch Switch attributes.
* @param string $toggl_attr Main box extra attributes.
* @param boolean|null $switch_on Switch enabled disabled or depending on hidden_Default.
* @param string|null $switch_name Use custom switch input name or generate one.
*
* @return string HTML.
@ -3782,6 +3785,8 @@ function ui_toggle(
$reverseImg=false,
$switch=false,
$attributes_switch='',
$toggl_attr='',
$switch_on=null,
$switch_name=null
) {
// Generate unique Id.
@ -3824,7 +3829,7 @@ function ui_toggle(
}
// Link to toggle.
$output = '<div class="'.$main_class.'" id="'.$id.'">';
$output = '<div class="'.$main_class.'" id="'.$id.'" '.$toggl_attr.'>';
$output .= '<div class="'.$header_class.'" style="cursor: pointer;" id="tgl_ctrl_'.$uniqid.'">';
if ($reverseImg === false) {
if ($switch === true) {
@ -3838,7 +3843,7 @@ function ui_toggle(
'content' => html_print_checkbox_switch_extended(
$switch_name,
1,
($hidden_default === true) ? 0 : 1,
($switch_on === null) ? (($hidden_default === true) ? 0 : 1) : $switch_on,
false,
'',
$attributes_switch,
@ -3962,6 +3967,8 @@ function ui_toggle(
* - reverseImg
* - switch
* - attributes_switch
* - toggl_attr
* - switch_on
* - switch_name.
*
* @return string HTML code with toggle content.
@ -3984,6 +3991,8 @@ function ui_print_toggle($data)
(isset($data['reverseImg']) === true) ? $data['reverseImg'] : false,
(isset($data['switch']) === true) ? $data['switch'] : false,
(isset($data['attributes_switch']) === true) ? $data['attributes_switch'] : '',
(isset($data['toggl_attr']) === true) ? $data['toggl_attr'] : '',
(isset($data['switch_on']) === true) ? $data['switch_on'] : null,
(isset($data['switch_name']) === true) ? $data['switch_name'] : null
);
}
@ -5764,6 +5773,7 @@ function ui_print_module_string_value(
*/
function ui_print_tags_view($title='', $tags=[])
{
$tv = '';
if (!empty($title)) {
$tv .= '<div class="tag-wrapper">';
$tv .= '<h3>'.$title.'</h3>';
@ -6102,6 +6112,7 @@ function ui_print_comments($comments)
}
}
$last_comment = [];
foreach ($comments_array as $comm) {
// Show the comments more recent first.
if (is_array($comm)) {

View File

@ -304,6 +304,7 @@ function users_get_groups(
$search=''
) {
static $group_cache = [];
$filter = '';
// Added users_group_cache to avoid unnecessary proccess on massive calls...
static $users_group_cache = [];

View File

@ -3670,6 +3670,7 @@ function visual_map_print_visual_map(
$layout_data['label'] = visual_map_macro($layout_data['label'], $layout_data['id_agente_modulo']);
switch ($layout_data['type']) {
case NETWORK_LINK:
case LINE_ITEM:
visual_map_print_user_lines($layout_data, $proportion);
break;
@ -4397,6 +4398,9 @@ function visual_map_type_in_js($type)
case LINE_ITEM:
return 'line_item';
case NETWORK_LINK:
return 'network_link';
case COLOR_CLOUD:
return 'color_cloud';

View File

@ -1308,6 +1308,13 @@ function visual_map_editor_print_toolbox()
visual_map_print_button_editor('box_item', __('Box'), 'left', false, 'box_item_min', true);
visual_map_print_button_editor('line_item', __('Line'), 'left', false, 'line_item_min', true);
visual_map_print_button_editor('color_cloud', __('Color cloud'), 'left', false, 'color_cloud_min', true);
if (isset($config['legacy_vc']) === false
|| (bool) $config['legacy_vc'] === false
) {
// Applies only on modern VC.
visual_map_print_button_editor('network_link', __('Network link'), 'left', false, 'network_link_min', true);
}
if (defined('METACONSOLE')) {
echo '<a href="javascript:" class="tip"><img src="'.$config['homeurl_static'].'/images/tip.png" data-title="The data displayed in editor mode is not real" data-use_title_for_force_title="1"
class="forced_title" alt="The data displayed in editor mode is not real"></a>';

View File

@ -103,7 +103,7 @@ class gettext_reader {
* @param object Reader the StreamReader object
* @param boolean enable_cache Enable or disable caching of strings (default on)
*/
function gettext_reader($Reader, $enable_cache = true) {
function __construct($Reader, $enable_cache = true) {
$machine = php_uname("m");
$enabled64Bits = false;

View File

@ -1,3 +1,4 @@
/* globals $,jQuery */
// Load the SNMP tree via AJAX
function snmpBrowse() {
// Empty the SNMP tree
@ -15,6 +16,7 @@ function snmpBrowse() {
// Read the target IP and community
var target_ip = $("#text-target_ip").val();
var target_port = $("#target_port").val();
var community = $("#text-community").val();
var starting_oid = $("#text-starting_oid").val();
var snmp_version = $("#snmp_browser_version").val();
@ -25,13 +27,13 @@ function snmpBrowse() {
var snmp3_auth_pass = $("#password-snmp3_browser_auth_pass").val();
var snmp3_privacy_method = $("#snmp3_browser_privacy_method").val();
var snmp3_privacy_pass = $("#password-snmp3_browser_privacy_pass").val();
var server_to_exec = $("#server_to_exec").val();
var ajax_url = $("#hidden-ajax_url").val();
// Prepare the AJAX call
var params = {};
params["target_ip"] = target_ip;
params["target_port"] = target_port;
params["community"] = community;
params["starting_oid"] = starting_oid;
params["snmp_browser_version"] = snmp_version;
@ -52,7 +54,6 @@ function snmpBrowse() {
type: "POST",
url: (action = ajax_url),
async: true,
timeout: 120000,
success: function(data) {
// Hide the spinner
$("#spinner").css("display", "none");
@ -62,6 +63,19 @@ function snmpBrowse() {
// Manage click and select events.
snmp_browser_events_manage();
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
$("#spinner").css("display", "none");
$("#snmp_browser").html(
"<p>Status: " +
textStatus +
"</p><p>" +
"Error: " +
errorThrown +
"</p><p>" +
XMLHttpRequest.responseText +
"</p>"
);
}
});
}
@ -499,6 +513,7 @@ function checkSNMPVersion() {
function snmpBrowserWindow() {
// Keep elements in the form and the SNMP browser synced
$("#text-target_ip").val($("#text-ip_target").val());
$("#target_port").val($("#text-tcp_port").val());
$("#text-community").val($("#text-snmp_community").val());
$("#snmp_browser_version").val($("#snmp_version").val());
$("#text-snmp3_browser_auth_user").val($("#text-snmp3_auth_user").val());
@ -525,7 +540,7 @@ function snmpBrowserWindow() {
opacity: 0.5,
background: "black"
},
width: 920,
width: 1000,
height: 500
});
}
@ -561,6 +576,7 @@ function snmp_browser_create_modules(module_target, return_post = true) {
.get();
var target_ip = $("#text-target_ip").val();
var target_port = $("#target_port").val();
var community = $("#text-community").val();
var snmp_version = $("#snmp_browser_version").val();
var snmp3_auth_user = $("#text-snmp3_browser_auth_user").val();
@ -590,6 +606,7 @@ function snmp_browser_create_modules(module_target, return_post = true) {
var snmp_conf = {};
snmp_conf["target_ip"] = target_ip;
snmp_conf["target_port"] = target_port;
snmp_conf["community"] = community;
snmp_conf["oids"] = oids;
snmp_conf["snmp_browser_version"] = snmp_version;

View File

@ -87,7 +87,12 @@ function load_modal(settings) {
div.id = "div-modal-" + uniq;
div.style.display = "none";
if (document.getElementById("main") == null) {
// MC env.
document.getElementById("page").append(div);
} else {
document.getElementById("main").append(div);
}
var id_modal_target = "#div-modal-" + uniq;
@ -281,8 +286,6 @@ function load_modal(settings) {
data: formdata,
dataType: settings.onsubmit.dataType,
success: function(data) {
console.log("successsssssssssssss");
console.log(data);
if (settings.ajax_callback != undefined) {
if (settings.idMsgCallback != undefined) {
settings.ajax_callback(data, settings.idMsgCallback);
@ -379,6 +382,8 @@ function load_modal(settings) {
//$(".ui-dialog-titlebar-close").hide();
},
close: function() {
$(this).dialog("destroy");
if (id_modal_target != undefined) {
$(id_modal_target).remove();
}
@ -386,14 +391,12 @@ function load_modal(settings) {
if (settings.cleanup != undefined) {
settings.cleanup();
}
$(this).dialog("destroy");
},
beforeClose: settings.beforeClose()
});
},
error: function(data) {
// console.log(data);
console.error(data);
}
});
}
@ -403,6 +406,7 @@ function load_modal(settings) {
// eslint-disable-next-line no-unused-vars
function confirmDialog(settings) {
var randomStr = uniqId();
var hideOkButton = "";
if (settings.size == undefined) {
settings.size = 350;
@ -411,6 +415,10 @@ function confirmDialog(settings) {
if (settings.maxHeight == undefined) {
settings.maxHeight = 1000;
}
// You can hide the OK button.
if (settings.hideOkButton != undefined) {
hideOkButton = "invisible_important ";
}
if (typeof settings.message == "function") {
$("body").append(
@ -444,6 +452,7 @@ function confirmDialog(settings) {
{
text: "Ok",
class:
hideOkButton +
"ui-widget ui-state-default ui-corner-all ui-button-text-only sub ok submit-next",
click: function() {
$(this).dialog("close");

View File

@ -186,13 +186,44 @@ function createVisualConsole(
var item = e.item || {};
var meta = item.meta || {};
if ((meta.editMode || meta.lineMode) && !meta.isUpdating) {
if (meta.editMode && !meta.isUpdating) {
createOrUpdateVisualConsoleItem(
visualConsole,
asyncTaskManager,
baseUrl,
item
);
} else if (meta.lineMode && item.props.type == 21) {
load_modal({
url: baseUrl + "/ajax.php",
modal: {
title: "NetworkLink information",
ok: "Ok"
},
extradata: [
{
name: "from",
value: item.props.linkedStart
},
{
name: "to",
value: item.props.linkedEnd
}
],
onshow: {
page: "include/rest-api/index",
method: "networkLinkPopup"
}
});
// confirmDialog({
// title: "todo",
// message:
// "<pre>" +
// item.props.labelStart +
// "</pre><br><pre>" +
// item.props.labelEnd +
// "</pre>"
// });
}
});
// VC Item moved.
@ -203,7 +234,7 @@ function createVisualConsole(
y: e.newPosition.y,
type: e.item.props.type
};
if (e.item.props.type === 13) {
if (e.item.props.type === 13 || e.item.props.type === 21) {
var startIsLeft =
e.item.props.startPosition.x - e.item.props.endPosition.x <= 0;
var startIsTop =
@ -279,6 +310,7 @@ function createVisualConsole(
endX: e.endPosition.x,
endY: e.endPosition.y
};
var taskId = "visual-console-item-update-" + id;
// Persist the new position.
@ -290,18 +322,14 @@ function createVisualConsole(
id,
data,
function(error, data) {
// if (!error && !data) return;
if (error || !data) {
console.log(
"[ERROR]",
"[VISUAL-CONSOLE-CLIENT]",
"[API]",
error ? error.message : "Invalid response"
);
if (!error && !data) return;
// TODO: Move the element to its initial position.
try {
var decoded_data = JSON.parse(data);
visualConsole.updateElement(decoded_data);
} catch (error) {
console.error(error);
}
done();
}
);
@ -427,6 +455,7 @@ function createVisualConsole(
},
createItem: function(typeString) {
var type;
console.log(typeString);
switch (typeString) {
case "STATIC_GRAPH":
type = 0;
@ -479,6 +508,9 @@ function createVisualConsole(
case "COLOR_CLOUD":
type = 20;
break;
case "NETWORK_LINK":
type = 21;
break;
default:
type = 0;
}
@ -565,7 +597,7 @@ function createVisualConsole(
item.setMeta({ isUpdating: false });
var itemRetrieved = item.props;
if (itemRetrieved["type"] == 13) {
if (itemRetrieved["type"] == 13 || itemRetrieved["type"] == 21) {
var startIsLeft =
itemRetrieved["startPosition"]["x"] -
itemRetrieved["endPosition"]["x"] <=
@ -1179,6 +1211,9 @@ function createOrUpdateVisualConsoleItem(
case 20:
nameType = "Color Cloud";
break;
case 21:
nameType = "Network Link";
break;
default:
nameType = "Static graph";
@ -1259,7 +1294,8 @@ function createOrUpdateVisualConsoleItem(
tinyMCE != undefined &&
tinyMCE.editors.length > 0 &&
item.itemProps.type != 12 &&
item.itemProps.type != 13
item.itemProps.type != 13 &&
item.itemProps.type != 21
) {
// Content tiny.
var label = tinyMCE.activeEditor.getContent();

View File

@ -419,13 +419,126 @@ class Agent extends Entity
}
/**
* Return a list of interfaces.
*
* @param array $filter Filter interfaces by name in array.
*
* @return array Of interfaces and modules PandoraFMS\Modules.
*/
public function getInterfaces(array $filter=[])
{
$modules = $this->searchModules(
['nombre' => '%ifOperStatus%']
);
$interfaces = [];
foreach ($modules as $module) {
$matches = [];
if (preg_match(
'/^(.*?)_ifOperStatus$/',
$module->name(),
$matches
) > 0
) {
$interface = $matches[1];
}
if (empty($interface) === true) {
continue;
}
if (empty($filter) === false
&& in_array($interface, $filter) !== true
) {
continue;
}
$name_filters = [
'ifOperStatus' => ['nombre' => $interface.'_ifOperStatus'],
'ifInOctets' => ['nombre' => $interface.'_ifInOctets'],
'ifOutOctets' => ['nombre' => $interface.'_ifOutOctets'],
'ifHCInOctets' => ['nombre' => $interface.'_ifHCInOctets'],
'ifHCOutOctets' => ['nombre' => $interface.'_ifHCOutOctets'],
];
$ifOperStatus = $this->searchModules(
$name_filters['ifOperStatus']
);
$ifInOctets = $this->searchModules(
$name_filters['ifInOctets']
);
$ifOutOctets = $this->searchModules(
$name_filters['ifOutOctets']
);
$ifHCInOctets = $this->searchModules(
$name_filters['ifHCInOctets']
);
$ifHCOutOctets = $this->searchModules(
$name_filters['ifHCOutOctets']
);
$interfaces[$interface] = [
'ifOperStatus' => array_shift($ifOperStatus),
'ifInOctets' => array_shift($ifInOctets),
'ifOutOctets' => array_shift($ifOutOctets),
'ifHCInOctets' => array_shift($ifHCInOctets),
'ifHCOutOctets' => array_shift($ifHCOutOctets),
];
}
return $interfaces;
}
/**
* Retrieves status, in and out modules from given interface name.
*
* @param string $interface Interface name.
*
* @return array|null With status, in and out modules. Null if no iface.
*/
public function getInterfaceMetrics(string $interface):?array
{
$modules = $this->getInterfaces([$interface]);
if (empty($modules) === true) {
return null;
}
$modules = $modules[$interface];
$in = null;
$out = null;
$status = $modules['ifOperStatus'];
if (empty($modules['ifHCInOctets']) === false) {
$in = $modules['ifHCInOctets'];
} else if (empty($modules['ifInOctets']) === false) {
$in = $modules['ifInOctets'];
}
if (empty($modules['ifHCOutOctets']) === false) {
$out = $modules['ifHCOutOctets'];
} else if (empty($modules['ifOutOctets']) === false) {
$out = $modules['ifOutOctets'];
}
return [
'in' => $in,
'out' => $out,
'status' => $status,
];
}
/**
* Search for modules into this agent.
*
* @param array $filter Filters.
* @param integer $limit Limit search results.
*
* @return PandoraFMS\Module Module found.
* @return array Of PandoraFMS\Module Modules found.
*/
public function searchModules(array $filter, int $limit=0)
{
@ -452,7 +565,12 @@ class Agent extends Entity
return $results;
} else {
// Search in db.
return Module::search($filter, $limit);
$return = Module::search($filter, $limit);
if (is_array($return) === false) {
return [];
}
return $return;
}
}

View File

@ -57,6 +57,20 @@ abstract class Entity
*/
private $enterprise;
/**
* MC Node id.
*
* @var integer|null
*/
protected $nodeId = null;
/**
* Connected to external node.
*
* @var boolean
*/
private $connected = false;
/**
* Instances a new object using array definition.
@ -193,6 +207,53 @@ abstract class Entity
}
/**
* Connects to current nodeId target.
* If no nodeId is defined, then returns without doing anything.
*
* @return void
* @throws \Exception On error.
*/
public function connectNode()
{
if ($this->nodeId === null) {
return;
}
\enterprise_include_once('include/functions_metaconsole.php');
$r = \enterprise_hook(
'metaconsole_connect',
[
null,
$this->nodeId,
]
);
if ($r !== NOERR) {
throw new \Exception(
__('Cannot connect to node %d', $this->nodeId)
);
}
$this->connected = true;
}
/**
* Restore connection after connectNode.
*
* @return void
*/
public function restoreConnection()
{
if ($this->connected === true) {
\enterprise_include_once('include/functions_metaconsole.php');
\enterprise_hook('metaconsole_restore_db');
}
}
/**
* Saves current object definition to database.
*

View File

@ -33,40 +33,106 @@ global $config;
require_once $config['homedir'].'/include/functions_events.php';
/**
* PandoraFMS Group entity.
* PandoraFMS event entity.
*/
class Event extends Entity
{
/**
* List of available ajax methods.
* Agent related to this event.
*
* @var array
* @var \PandoraFMS\Agent
*/
private static $ajaxMethods = [];
private $linkedAgent;
/**
* Module related to this event.
*
* @var \PandoraFMS\Module
*/
private $linkedModule;
/**
* Builds a PandoraFMS\Group object from a group id.
* Builds a PandoraFMS\Event object from given event id.
*
* @param integer $id_group Group Id.
* @param integer $event_id Event Id.
*/
public function __construct(?int $id_group=null)
public function __construct(?int $event_id=null)
{
$table = 'tevento';
if ((bool) \is_metaconsole() === true) {
$table = 'tmetaconsole_event';
}
if ($id_group === 0) {
if ($event_id === 0) {
parent::__construct($table);
} else if (is_numeric($id_group) === true) {
parent::__construct($table, ['id_grupo' => $id_group]);
} else if (is_numeric($event_id) === true) {
parent::__construct($table, ['id_evento' => $event_id]);
} else {
// Empty skel.
parent::__construct($table);
}
try {
if ((bool) \is_metaconsole() === true
&& $this->server_id() !== null
) {
$this->nodeId = $this->server_id();
}
$this->connectNode();
if ($this->id_agente() !== null) {
$this->linkedAgent = new Agent((int) $this->id_agente());
}
if ($this->id_agentmodule() !== null) {
$this->linkedModule = new Module((int) $this->id_agentmodule());
}
} catch (\Exception $e) {
// Do not link items if failed to find them.
$this->restoreConnection();
}
// Restore if needed.
$this->restoreConnection();
}
/**
* Get/set linked agent.
*
* @param Agent|null $agent New agent to link.
*
* @return Agent|null Agent or null if set operation.
*/
public function agent(?Agent $agent=null) : ?Agent
{
if ($agent === null) {
return $this->linkedAgent;
}
$this->linkedAgent = $agent;
$this->id_agentmodule($agent->id_agentmodule());
}
/**
* Get/set linked agent.
*
* @param Module|null $module New module to link.
*
* @return Module|null module or null if set operation.
*/
public function module(?Module $module=null) : ?Module
{
if ($module === null) {
return $this->linkedModule;
}
$this->linkedModule = $module;
$this->id_agentmodule($module->id_agentmodule());
}
@ -83,7 +149,8 @@ class Event extends Entity
* @param boolean $return_sql Return sql or execute it.
* @param string $having Having.
*
* @return array|string|falsse Found events or SQL query or error.
* @return array|string|false Found events or SQL query or error.
* @throws \Exception On error.
*/
public static function search(
array $fields,
@ -121,10 +188,10 @@ class Event extends Entity
global $config;
if (isset($config['centralized_management']) === true
&& $config['centralized_management'] > 0
&& (bool) $config['centralized_management'] === true
) {
throw new \Exception(
get_class($this).' error, cannot be modified while centralized management environment.'
'error, cannot save in centralized management environment.'
);
}
@ -147,30 +214,4 @@ class Event extends Entity
}
/**
* Return error message to target.
*
* @param string $msg Error message.
*
* @return void
*/
public static function error(string $msg)
{
echo json_encode(['error' => $msg]);
}
/**
* Verifies target method is allowed to be called using AJAX call.
*
* @param string $method Method to be invoked via AJAX.
*
* @return boolean Available (true), or not (false).
*/
public static function ajaxMethod(string $method):bool
{
return in_array($method, self::$ajaxMethods) === true;
}
}

View File

@ -34,11 +34,17 @@ use PandoraFMS\Agent;
use PandoraFMS\ModuleType;
/**
* PandoraFMS agent entity.
* PandoraFMS module entity.
*/
class Module extends Entity
{
const INTERFACE_STATUS = 1;
const INTERFACE_INOCTETS = 2;
const INTERFACE_OUTOCTETS = 3;
const INTERFACE_HC_INOCTETS = 4;
const INTERFACE_HC_OUTOCTETS = 5;
/**
* Module status (From tagente_estado).
*
@ -85,8 +91,10 @@ class Module extends Entity
* @return PandoraFMS\Module found or null if not found.
* @throws \Exception On error.
*/
public static function search(array $params, ?int $limit=0)
{
public static function search(
array $params,
?int $limit=0
) {
if (empty($params) === true) {
return null;
}
@ -186,21 +194,40 @@ class Module extends Entity
*
* @param integer|null $id_agent_module Module id.
* @param boolean $link_agent Link agent object.
* @param integer|null $nodeId Target node (if metaconsole
* environment).
*
* @throws \Exception On error.
*/
public function __construct(
?int $id_agent_module=null,
bool $link_agent=false
bool $link_agent=false,
?int $nodeId=null
) {
if (is_numeric($id_agent_module) === true
&& $id_agent_module > 0
) {
if ($nodeId !== null) {
$this->nodeId = $nodeId;
}
try {
// Connect to node if needed.
$this->connectNode();
parent::__construct(
'tagente_modulo',
['id_agente_modulo' => $id_agent_module]
);
// Restore.
$this->restoreConnection();
} catch (\Exception $e) {
$this->restoreConnection();
// Forward exception.
throw $e;
}
if ($this->nombre() === 'delete_pending') {
return null;
}
@ -223,14 +250,22 @@ class Module extends Entity
}
try {
// Connect to node if needed.
$this->connectNode();
// Customize certain fields.
$this->status = new ModuleStatus($this->fields['id_agente_modulo']);
// Restore.
$this->restoreConnection();
} catch (\Exception $e) {
// Restore.
$this->restoreConnection();
$this->status = new Modulestatus();
}
// Customize certain fields.
$this->status = new ModuleStatus($this->fields['id_agente_modulo']);
$this->moduleType = new ModuleType($this->id_tipo_modulo());
// Include some enterprise dependencies.
@ -261,8 +296,15 @@ class Module extends Entity
{
if ($this->linkedAgent === null) {
try {
// Connect to node if needed.
$this->connectNode();
$this->linkedAgent = new Agent($this->id_agente());
// Connect to node if needed.
$this->restoreConnection();
} catch (\Exception $e) {
// Connect to node if needed.
$this->restoreConnection();
// Unexistent agent.
return null;
}
@ -753,6 +795,84 @@ class Module extends Entity
}
/**
* Return true if module represents an interface (operStatus, in/outOctets)
*
* @return integer > 0 if interface module, 0 if not.
*/
public function isInterfaceModule():int
{
if (strstr($this->name(), '_ifOperStatus') !== false) {
return self::INTERFACE_STATUS;
}
if (strstr($this->name(), '_ifInOctets') !== false) {
return self::INTERFACE_INOCTETS;
}
if (strstr($this->name(), '_ifOutOctets') !== false) {
return self::INTERFACE_OUTOCTETS;
}
if (strstr($this->name(), '_ifHCInOctets') !== false) {
return self::INTERFACE_HC_INOCTETS;
}
if (strstr($this->name(), '_ifHCOutOctets') !== false) {
return self::INTERFACE_HC_OUTOCTETS;
}
return 0;
}
/**
* Return interface name if module represents an interface module.
*
* @return string|null Interface name or null.
*/
public function getInterfaceName():?string
{
$label = null;
switch ($this->isInterfaceModule()) {
case self::INTERFACE_STATUS:
$label = '_ifOperStatus';
break;
case self::INTERFACE_INOCTETS:
$label = '_ifInOctets';
break;
case self::INTERFACE_OUTOCTETS:
$label = '_ifOutOctets';
break;
case self::INTERFACE_HC_INOCTETS:
$label = '_ifHCInOctets';
break;
case self::INTERFACE_HC_OUTOCTETS:
$label = '_ifHCOutOctets';
break;
default:
// Not an interface module.
return null;
}
if (preg_match(
'/^(.*?)'.$label.'$/',
$this->name(),
$matches
) > 0
) {
return $matches[1];
}
return null;
}
/**
* Transforms configuration data into an array.
*

View File

@ -219,7 +219,9 @@ function enable_session_handlers()
{
global $config;
if ($config['_using_pandora_sessionhandlers'] !== true) {
if (isset($config['_using_pandora_sessionhandlers']) !== true
|| $config['_using_pandora_sessionhandlers'] !== true
) {
if (session_status() !== PHP_SESSION_NONE) {
// Close previous version.
session_write_close();

View File

@ -9,6 +9,10 @@ if (!is_ajax()) {
require_once $config['homedir'].'/vendor/autoload.php';
// Require also some stuff from Pandora FMS.
enterprise_include('include/functions_metaconsole.php');
use Models\VisualConsole\Container as VisualConsole;
use Models\VisualConsole\View as Viewer;
use Models\VisualConsole\Item as Item;
@ -109,7 +113,7 @@ if ($getVisualConsole === true) {
$ratio
);
echo '['.implode($vcItems, ',').']';
echo '['.implode(',', $vcItems).']';
return;
} else if ($getVisualConsoleItem === true
|| $updateVisualConsoleItem === true
@ -121,6 +125,7 @@ if ($getVisualConsole === true) {
} catch (Throwable $e) {
// Bad params.
http_response_code(400);
hd($e);
return;
}
@ -245,7 +250,9 @@ if ($getVisualConsole === true) {
$item = VisualConsole::getItemFromDB($itemId);
$data = $item->toArray();
$data['id_layout'] = $visualConsoleId;
if ($data['type'] === LINE_ITEM) {
if ($data['type'] === LINE_ITEM
|| $data['type'] === NETWORK_LINK
) {
$data['endX'] = ($data['endX'] + 20);
$data['endY'] = ($data['endY'] + 20);
$data['startX'] = ($data['startX'] + 20);

View File

@ -366,6 +366,9 @@ final class Container extends Model
case COLOR_CLOUD:
return Items\ColorCloud::class;
case NETWORK_LINK:
return Items\NetworkLink::class;
default:
return Item::class;
}
@ -481,6 +484,7 @@ final class Container extends Model
$item = $class::fromDB($row);
} catch (\Throwable $e) {
// TODO: Log this?
error_log(obhd($e));
}
return $item;

View File

@ -196,6 +196,7 @@ class Item extends CachedModel
{
$decodedData = [
'id' => (int) $data['id'],
'colorStatus' => (string) COL_UNKNOWN,
'type' => (int) $data['type'],
'label' => static::extractLabel($data),
'labelPosition' => static::extractLabelPosition($data),
@ -1461,6 +1462,11 @@ class Item extends CachedModel
$result['linked_layout_node_id'] = $linked_layout_node_id;
}
if ($id_layout_linked > 0) {
// If VC linked, force link status to enabled.
$result['enable_link'] = 1;
}
$linked_layout_status_type = static::notEmptyStringOr(
static::issetInArray(
$data,
@ -2030,8 +2036,8 @@ class Item extends CachedModel
break;
default:
// Line not parent.
break;
// Lines could not be parents.
continue 2;
}
if (isset($data['agentAlias']) === true
@ -2204,7 +2210,7 @@ class Item extends CachedModel
*
* @return array Array all VCs.
*/
public function getAllVisualConsole(int $id):array
public static function getAllVisualConsole(int $id):array
{
// Extract all VC except own.
$result = db_get_all_rows_filter(
@ -2219,7 +2225,7 @@ class Item extends CachedModel
// Extract all VC for each node.
if (is_metaconsole() === true) {
enterprise_include_once('include/functions_metaconsole.php');
$meta_servers = metaconsole_get_servers();
$meta_servers = (array) metaconsole_get_servers();
foreach ($meta_servers as $server) {
if (metaconsole_load_external_db($server) !== NOERR) {
metaconsole_restore_db();
@ -2257,7 +2263,7 @@ class Item extends CachedModel
}
}
if ($result === false && $result === '') {
if ($result === false || $result === '') {
$result = [];
}
@ -2280,14 +2286,18 @@ class Item extends CachedModel
if ($fields === false) {
$fields = [];
} else {
$fields = \array_reduce(
$fields,
function ($carry, $item) {
$carry[$item['id']] = $item['name'];
return $carry;
},
[]
);
$rs = [];
foreach ($fields as $k => $v) {
if (isset($v['id']) === true && isset($v['name']) === true) {
// Modern environments use id-name format.
$rs[$v['id']] = $v;
} else {
// In MC environments is key-value.
$rs[$k] = $v;
}
}
$fields = $rs;
}
$getAllVisualConsoleValue = $values['linkedLayoutId'];

View File

@ -0,0 +1,958 @@
<?php
declare(strict_types=1);
namespace Models\VisualConsole\Items;
use Models\Model;
/**
* Model of a line item of the Visual Console.
*/
final class NetworkLink extends Model
{
/**
* Validate the received data structure to ensure if we can extract the
* values required to build the model.
*
* @param array $data Input data.
*
* @return void
* @throws \InvalidArgumentException If any input value is considered
* invalid.
*
* @overrides Model->validateData.
*/
protected function validateData(array $data): void
{
if (isset($data['id']) === false
|| \is_numeric($data['id']) === false
) {
throw new \InvalidArgumentException(
'the Id property is required and should be integer'
);
}
if (isset($data['type']) === false
|| \is_numeric($data['type']) === false
) {
throw new \InvalidArgumentException(
'the Id property is required and should be integer'
);
}
}
/**
* Returns a valid representation of the model.
*
* @param array $data Input data.
*
* @return array Data structure representing the model.
*
* @overrides Model->decode.
*/
protected function decode(array $data): array
{
return [
'id' => (int) $data['id'],
'type' => NETWORK_LINK,
'startX' => static::extractStartX($data),
'startY' => static::extractStartY($data),
'endX' => static::extractEndX($data),
'endY' => static::extractEndY($data),
'isOnTop' => static::extractIsOnTop($data),
'borderWidth' => static::extractBorderWidth($data),
'borderColor' => static::extractBorderColor($data),
'labelStart' => static::extractLabelStart($data),
'labelEnd' => static::extractLabelEnd($data),
'labelStartWidth' => static::extractlabelStartWidth($data),
'labelEndWidth' => static::extractlabelEndWidth($data),
'labelStartHeight' => static::extractlabelStartHeight($data),
'labelEndHeight' => static::extractlabelEndHeight($data),
'linkedStart' => static::extractlinkedStart($data),
'linkedEnd' => static::extractlinkedEnd($data),
];
}
/**
* Extract a x axis value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid x axis of the start position of the line.
*/
private static function extractStartX(array $data): int
{
return static::parseIntOr(
static::issetInArray($data, ['startX', 'pos_x']),
0
);
}
/**
* Extract a y axis value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid y axis of the start position of the line.
*/
private static function extractStartY(array $data): int
{
return static::parseIntOr(
static::issetInArray($data, ['startY', 'pos_y']),
0
);
}
/**
* Extract a x axis value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid x axis of the end position of the line.
*/
private static function extractEndX(array $data): int
{
return static::parseIntOr(
static::issetInArray($data, ['endX', 'width']),
0
);
}
/**
* Extract a y axis value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid y axis of the end position of the line.
*/
private static function extractEndY(array $data): int
{
return static::parseIntOr(
static::issetInArray($data, ['endY', 'height']),
0
);
}
/**
* Extract a conditional value which tells if the item has visual priority.
*
* @param array $data Unknown input data structure.
*
* @return boolean If the item is on top or not.
*/
private static function extractIsOnTop(array $data): bool
{
return static::parseBool(
static::issetInArray($data, ['isOnTop', 'show_on_top'])
);
}
/**
* Extract a border width value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid border width. 0 by default and minimum value.
*/
private static function extractBorderWidth(array $data): int
{
$borderWidth = static::parseIntOr(
static::issetInArray($data, ['borderWidth', 'border_width']),
0
);
return ($borderWidth >= 0) ? $borderWidth : 0;
}
/**
* Extract a border color value.
*
* @param array $data Unknown input data structure.
*
* @return mixed String representing the border color (not empty) or null.
*/
private static function extractBorderColor(array $data)
{
return static::notEmptyStringOr(
static::issetInArray($data, ['borderColor', 'border_color']),
null
);
}
/**
* Extract information to fullfil labels in NetworkLinks.
*
* @param string $ref Sub-data to extract from "label".
* @param array $data Unknown input data structure.
*
* @return mixed Reference from json encoded data stored in db.
*/
private static function extractExtra(?string $ref, array $data)
{
if ($data['label'] === null) {
return null;
}
$return = json_decode($data['label'], true);
if (json_last_error() === JSON_ERROR_NONE) {
if ($ref !== null) {
return $return[$ref];
}
return $return;
}
return null;
}
/**
* Extract label Start.
*
* @param array $data Unknown input data structure.
*
* @return mixed String representing label Start or null.
*/
private static function extractLabelStart(array $data)
{
return static::extractExtra(
'labelStart',
$data
);
}
/**
* Extract label End.
*
* @param array $data Unknown input data structure.
*
* @return mixed String representing label End or null.
*/
private static function extractLabelEnd(array $data)
{
return static::extractExtra(
'labelEnd',
$data
);
}
/**
* Extract label StartWidth.
*
* @param array $data Unknown input data structure.
*
* @return mixed Float representing label StartWidth or null.
*/
private static function extractlabelStartWidth(array $data)
{
return static::extractExtra(
'labelStartWidth',
$data
);
}
/**
* Extract label EndWidth.
*
* @param array $data Unknown input data structure.
*
* @return mixed Float representing label EndWidth or null.
*/
private static function extractlabelEndWidth(array $data)
{
return static::extractExtra(
'labelEndWidth',
$data
);
}
/**
* Extract label StartHeight.
*
* @param array $data Unknown input data structure.
*
* @return mixed Float representing label StartHeight or null.
*/
private static function extractlabelStartHeight(array $data)
{
return static::extractExtra(
'labelStartHeight',
$data
);
}
/**
* Extract label EndHeight.
*
* @param array $data Unknown input data structure.
*
* @return mixed Float representing label EndHeight or null.
*/
private static function extractlabelEndHeight(array $data)
{
return static::extractExtra(
'labelEndHeight',
$data
);
}
/**
* Extract label StartHeight.
*
* @param array $data Unknown input data structure.
*
* @return mixed Float representing label StartHeight or null.
*/
private static function extractlinkedStart(array $data)
{
return static::extractExtra(
'linkedStart',
$data
);
}
/**
* Extract label EndHeight.
*
* @param array $data Unknown input data structure.
*
* @return mixed Float representing label EndHeight or null.
*/
private static function extractlinkedEnd(array $data)
{
return static::extractExtra(
'linkedEnd',
$data
);
}
/**
* Obtain a vc item data structure from the database using a filter.
*
* @param array $filter Filter of the Visual Console Item.
* @param float $ratio Adjustment ratio factor.
*
* @return array The Visual Console line data structure stored into the DB.
* @throws \Exception When the data cannot be retrieved from the DB.
*
* @override Model::fetchDataFromDB.
*/
protected static function fetchDataFromDB(
array $filter,
?float $ratio=0
): array {
// Due to this DB call, this function cannot be unit tested without
// a proper mock.
$row = \db_get_row_filter('tlayout_data', $filter);
if ($row === false) {
throw new \Exception('error fetching the data from the DB');
}
if ($ratio != 0) {
$row['width'] = ($row['width'] * $ratio);
$row['height'] = ($row['height'] * $ratio);
$row['pos_x'] = ($row['pos_x'] * $ratio);
$row['pos_y'] = ($row['pos_y'] * $ratio);
}
$row['label'] = static::buildLabels($row);
return $row;
}
/**
* Calculates linked elements given line data.
*
* @param array $data Input data (item).
*
* @return array With start and end elements.
*/
private static function getLinkedItems(array $data)
{
$startX = $data['startX'];
$startY = $data['startY'];
$endX = $data['endX'];
$endY = $data['endY'];
$linked_start = static::extractlinkedStart($data);
$linked_end = static::extractlinkedEnd($data);
$start = false;
$end = false;
if ($linked_start !== null) {
$start = \db_get_row_filter(
'tlayout_data',
[
'id_layout' => $data['id_layout'],
'id' => $linked_start,
]
);
}
if ($linked_end !== null) {
$end = \db_get_row_filter(
'tlayout_data',
[
'id_layout' => $data['id_layout'],
'id' => $linked_end,
]
);
}
if (isset($data['width']) === true) {
// Row format.
$startX = $data['pos_x'];
$startY = $data['pos_y'];
$endX = $data['width'];
$endY = $data['height'];
}
if ($start === false) {
$start = \db_get_row_filter(
'tlayout_data',
[
'id_layout' => $data['id_layout'],
'pos_x' => '<'.$startX,
'pos_y' => '<'.$startY,
'pos_x`+`width' => '>'.$startX,
'pos_y`+`height' => '>'.$startY,
'type' => '!'.NETWORK_LINK,
'order' => [
[
'field' => 'show_on_top',
'order' => 'desc',
],
[
'field' => 'id',
'order' => 'desc',
],
],
]
);
}
if ($end === false) {
$end = \db_get_row_filter(
'tlayout_data',
[
'id_layout' => $data['id_layout'],
'pos_x' => '<'.$endX,
'pos_y' => '<'.$endY,
'pos_x`+`width' => '>'.$endX,
'pos_y`+`height' => '>'.$endY,
'type' => '!'.NETWORK_LINK,
'order' => [
[
'field' => 'show_on_top',
'order' => 'desc',
],
[
'field' => 'id',
'order' => 'desc',
],
],
]
);
}
return [
'start' => $start,
'end' => $end,
];
}
/**
* Builds a label depending on the information available.
*
* @param array $data Input data.
*
* @return string JSON encoded results to be stored in DB.
* @throws \Exception If cannot connect to node if needed.
*/
private static function buildLabels(array $data)
{
$links = self::getLinkedItems($data);
$labelStart = null;
$labelEnd = null;
$linkedStart = null;
$linkedEnd = null;
/*
* If start['id_agente_modulo'] its a network module (in/out/status)
* then:
*
* start => outOctets
*
* If end['id_agente_modulo'] its a network module (in/out/status)
* then:
* end => inOctets
*
*/
try {
if (isset($links['start']) === true) {
$linkedStart = $links['start']['id'];
if (is_numeric($links['start']['id_agente_modulo']) === true
&& $links['start']['id_agente_modulo'] > 0
) {
if (isset($links['start']['id_metaconsole']) === true
&& (bool) is_metaconsole() === true
) {
$cnn = \enterprise_hook(
'metaconsole_get_connection_by_id',
[ $links['start']['id_metaconsole'] ]
);
if (\enterprise_hook('metaconsole_connect', [$cnn]) !== NOERR) {
throw new \Exception(__('Failed to connect to node'));
}
}
$module = new \PandoraFMS\Module(
(int) $links['start']['id_agente_modulo']
);
if ((bool) $module->isInterfaceModule() === true) {
$interface_name = $module->getInterfaceName();
$interface = array_shift(
$module->agent()->getInterfaces(
[$interface_name]
)
);
$outOctets = 0;
$inOctets = 0;
$unitIn = '';
$unitOut = '';
if (isset($interface['ifOutOctets']) === true) {
$outOctets = $interface['ifOutOctets']->lastValue();
$unitOut = $interface['ifOutOctets']->unit();
} else if (isset($interface['ifHCOutOctets']) === true) {
$outOctets = $interface['ifHCOutOctets']->lastValue();
$unitOut = $interface['ifHCOutOctets']->unit();
}
if (isset($interface['ifInOctets']) === true) {
$inOctets = $interface['ifInOctets']->lastValue();
$unitIn = $interface['ifInOctets']->unit();
} else if (isset($interface['ifHCInOctets']) === true) {
$inOctets = $interface['ifHCInOctets']->lastValue();
$unitIn = $interface['ifHCInOctets']->unit();
}
if (empty($outOctets) === true) {
$outOctets = 0;
}
if (empty($inOctets) === true) {
$inOctets = 0;
}
$outOctets = sprintf('%0.3f %s', $outOctets, $unitOut);
$inOctets = sprintf('%0.3f %s', $inOctets, $unitIn);
$labelStart = $interface_name;
$labelStart .= ' (in): '.$inOctets;
$labelStart .= '<br>'.$interface_name;
$labelStart .= ' (out): '.$outOctets;
}
if (isset($links['start']['id_metaconsole']) === true
&& (bool) is_metaconsole() === true
) {
\enterprise_hook('metaconsole_restore_db');
}
}
}
} catch (\Exception $e) {
$labelStart = $e->getMessage();
}
try {
if (isset($links['end']) === true) {
$linkedEnd = $links['end']['id'];
if (is_numeric($links['end']['id_agente_modulo']) === true
&& $links['end']['id_agente_modulo'] > 0
) {
if (isset($links['end']['id_metaconsole']) === true
&& (bool) is_metaconsole() === true
) {
$cnn = \enterprise_hook(
'metaconsole_get_connection_by_id',
[$links['end']['id_metaconsole']]
);
if (\enterprise_hook('metaconsole_connect', [$cnn]) !== NOERR) {
throw new \Exception(__('Failed to connect to node'));
}
}
$module = new \PandoraFMS\Module(
(int) $links['end']['id_agente_modulo']
);
if ((bool) $module->isInterfaceModule() === true) {
$interface_name = $module->getInterfaceName();
$interface = array_shift(
$module->agent()->getInterfaces(
[$interface_name]
)
);
$outOctets = 0;
$inOctets = 0;
$unitIn = '';
$unitOut = '';
if (isset($interface['ifOutOctets']) === true) {
$outOctets = $interface['ifOutOctets']->lastValue();
$unitOut = $interface['ifOutOctets']->unit();
} else if (isset($interface['ifHCOutOctets']) === true) {
$outOctets = $interface['ifHCOutOctets']->lastValue();
$unitOut = $interface['ifHCOutOctets']->unit();
}
if (isset($interface['ifInOctets']) === true) {
$inOctets = $interface['ifInOctets']->lastValue();
$unitIn = $interface['ifInOctets']->unit();
} else if (isset($interface['ifHCInOctets']) === true) {
$inOctets = $interface['ifHCInOctets']->lastValue();
$unitIn = $interface['ifHCInOctets']->unit();
}
if (empty($outOctets) === true) {
$outOctets = 0;
}
if (empty($inOctets) === true) {
$inOctets = 0;
}
$outOctets = sprintf('%0.3f %s', $outOctets, $unitOut);
$inOctets = sprintf('%0.3f %s', $inOctets, $unitIn);
$labelEnd = $interface_name;
$labelEnd .= ' (in): '.$inOctets;
$labelEnd .= '<br>'.$interface_name;
$labelEnd .= ' (out): '.$outOctets;
}
if (isset($links['end']['id_metaconsole']) === true
&& (bool) is_metaconsole() === true
) {
\enterprise_hook('metaconsole_restore_db');
}
}
}
} catch (\Exception $e) {
$labelEnd = $e->getMessage();
}
return json_encode(
[
'labelStart' => io_safe_output($labelStart),
'labelEnd' => io_safe_output($labelEnd),
'linkedStart' => $linkedStart,
'linkedEnd' => $linkedEnd,
// 'labelStartWidth' => 105,
// 'labelStartHeight' => 105,
// 'labelEndWidth' => 105,
// 'labelEndHeight' => 105,
]
);
}
/**
* Return a valid representation of a record in database.
*
* @param array $data Input data.
*
* @return array Data structure representing a record in database.
*
* @overrides Model::encode.
*/
protected function encode(array $data): array
{
$result = [];
$result['type'] = NETWORK_LINK;
$id = static::getId($data);
if ($id) {
$result['id'] = $id;
}
$layoutId = static::getIdLayout($data);
if ($layoutId > 0) {
$result['id_layout'] = $layoutId;
}
$startX = static::parseIntOr(
static::issetInArray($data, ['pos_x', 'startX']),
null
);
if ($startX !== null) {
$result['pos_x'] = $startX;
}
$startY = static::parseIntOr(
static::issetInArray($data, ['pos_y', 'startY']),
null
);
if ($startY !== null) {
$result['pos_y'] = $startY;
}
$endX = static::parseIntOr(
static::issetInArray($data, ['width', 'endX']),
null
);
if ($endX !== null) {
$result['width'] = $endX;
}
$endY = static::parseIntOr(
static::issetInArray($data, ['height', 'endY']),
null
);
if ($endY !== null) {
$result['height'] = $endY;
}
$borderWidth = static::getBorderWidth($data);
if ($borderWidth !== null) {
if ($borderWidth < 1) {
$borderWidth = 1;
}
$result['border_width'] = $borderWidth;
}
$borderColor = static::extractBorderColor($data);
if ($borderColor !== null) {
$result['border_color'] = $borderColor;
}
// Build labels.
$result['label'] = static::buildLabels($data);
$showOnTop = static::issetInArray(
$data,
[
'isOnTop',
'show_on_top',
'showOnTop',
]
);
if ($showOnTop !== null) {
$result['show_on_top'] = static::parseBool($showOnTop);
}
return $result;
}
/**
* Extract item id.
*
* @param array $data Unknown input data structure.
*
* @return integer Item id. 0 by default.
*/
private static function getId(array $data): int
{
return static::parseIntOr(
static::issetInArray($data, ['id', 'itemId']),
0
);
}
/**
* Extract layout id.
*
* @param array $data Unknown input data structure.
*
* @return integer Item id. 0 by default.
*/
private static function getIdLayout(array $data): int
{
return static::parseIntOr(
static::issetInArray($data, ['id_layout', 'idLayout', 'layoutId']),
0
);
}
/**
* Extract a border width value.
*
* @param array $data Unknown input data structure.
*
* @return integer Valid border width.
*/
private static function getBorderWidth(array $data)
{
return static::parseIntOr(
static::issetInArray($data, ['border_width', 'borderWidth']),
null
);
}
/**
* Insert or update an item in the database
*
* @param array $data Unknown input data structure.
*
* @return integer The modeled element data structure stored into the DB.
*
* @overrides Model::save.
*/
public function save(array $data=[]): int
{
if (empty($data) === false) {
if (empty($data['id']) === true) {
// Insert.
$save = static::encode($data);
$result = \db_process_sql_insert('tlayout_data', $save);
if ($result !== false) {
$item = static::fromDB(['id' => $result]);
$item->setData($item->toArray());
}
} else {
// Update.
$dataModelEncode = $this->encode($this->toArray());
$dataEncode = $this->encode($data);
$save = array_merge($dataModelEncode, $dataEncode);
$result = \db_process_sql_update(
'tlayout_data',
$save,
['id' => $save['id']]
);
// Invalidate the item's cache.
if ($result !== false && $result > 0) {
$item = static::fromDB(['id' => $save['id']]);
// Update the model.
if (empty($item) === false) {
$this->setData($item->toArray());
}
}
}
}
return $result;
}
/**
* Delete a line in the database
*
* @param integer $itemId Identifier of the Item.
*
* @return boolean The modeled element data structure stored into the DB.
*
* @overrides Model::delete.
*/
public function delete(int $itemId): bool
{
$result = db_process_sql_delete(
'tlayout_data',
['id' => $itemId]
);
return (bool) $result;
}
/**
* Generates inputs for form (global, common).
*
* @param array $values Default values.
*
* @return array Of inputs.
*/
public static function getFormInputs(array $values): array
{
$inputs = [];
if ($values['tabSelected'] === 'specific') {
// Width.
if ($values['borderWidth'] === null) {
$values['borderWidth'] = 5;
}
if ($values['borderWidth'] < 1) {
$values['borderWidth'] = 1;
}
$inputs[] = [
'label' => __('Width'),
'arguments' => [
'name' => 'borderWidth',
'type' => 'number',
'value' => $values['borderWidth'],
'return' => true,
'min' => 1,
],
];
// Color.
$inputs[] = [
'label' => __('Color'),
'arguments' => [
'wrapper' => 'div',
'name' => 'borderColor',
'type' => 'color',
'value' => $values['borderColor'],
'return' => true,
],
];
// Show on top.
$inputs[] = [
'label' => __('Show on top'),
'arguments' => [
'name' => 'isOnTop',
'id' => 'isOnTop',
'type' => 'switch',
'value' => $values['isOnTop'],
],
];
}
return $inputs;
}
}

View File

@ -53,6 +53,7 @@ final class StaticGraph extends Item
static::issetInArray($data, ['lastValue']),
null
);
$return['colorStatus'] = $data['colorStatus'];
return $return;
}
@ -181,6 +182,35 @@ final class StaticGraph extends Item
false
);
$status = \visual_map_get_status_element($data);
// Magic numbers from the hell.
switch ($status) {
case 1:
case 4:
// Critical or critical alert (BAD).
$data['colorStatus'] = COL_CRITICAL;
break;
case 0:
// Normal (OK).
$data['colorStatus'] = COL_NORMAL;
break;
case 2:
case 10:
// Warning or warning alert.
$data['colorStatus'] = COL_WARNING;
break;
case 3:
// Unknown.
default:
// Default is Grey (Other).
$data['colorStatus'] = COL_UNKNOWN;
break;
}
// If the width or the height are equal to 0 we will extract them
// from the real image size.
$width = (int) $data['width'];

View File

@ -30,6 +30,8 @@
namespace Models\VisualConsole;
use Models\VisualConsole\Container as VisualConsole;
define('__DEBUG', 0);
global $config;
require_once $config['homedir'].'/include/class/HTML.class.php';
enterprise_include_once('include/functions_metaconsole.php');
@ -65,12 +67,14 @@ class View extends \HTML
'id' => 'tab-label',
'href' => $url.'&tabSelected=label',
'img' => 'label-settings.png',
],[
],
[
'name' => __('General settings'),
'id' => 'tab-general',
'href' => $url.'&tabSelected=general',
'img' => 'general-settings.png',
],[
],
[
'name' => __('Specific settings'),
'id' => 'tab-specific',
'href' => $url.'&tabSelected=specific',
@ -81,7 +85,9 @@ class View extends \HTML
$activetabs = 2;
if ($type === LABEL) {
$activetabs = 0;
} else if ($type === LINE_ITEM) {
} else if ($type === LINE_ITEM
|| $type === NETWORK_LINK
) {
$activetabs = 0;
$tabs = [
[
@ -99,7 +105,8 @@ class View extends \HTML
'id' => 'tab-general',
'href' => $url.'&tabSelected=general',
'img' => 'pencil.png',
],[
],
[
'name' => __('Specific settings'),
'id' => 'tab-specific',
'href' => $url.'&tabSelected=specific',
@ -242,7 +249,7 @@ class View extends \HTML
true
);
return $form.$jsforms;
return $form;
}
@ -306,7 +313,7 @@ class View extends \HTML
);
} else {
// Only Create, settings default values if not enter tab general.
if ($itemId === 0 && $type != LINE_ITEM) {
if ($itemId === 0 && $type != LINE_ITEM && $type != NETWORK_LINK) {
$class = VisualConsole::getItemClass((int) $type);
$data = $class::getDefaultGeneralValues($data);
}
@ -491,6 +498,17 @@ class View extends \HTML
$data['isLinkEnabled'] = true;
break;
case NETWORK_LINK:
$data['borderColor'] = \get_parameter('borderColor');
$data['borderWidth'] = \get_parameter('borderWidth');
$data['isOnTop'] = \get_parameter_switch('isOnTop');
// Insert line default position ball end.
if ($itemId === 0) {
$data['height'] = 100;
$data['width'] = 100;
}
break;
default:
// Not posible.
break;
@ -503,8 +521,12 @@ class View extends \HTML
// Save the new item.
$data['id_layout'] = $vCId;
$itemId = $class::save($data);
} catch (\Throwable $th) {
} catch (\Exception $e) {
// Bad params.
if (__DEBUG === 1) {
error_log($e->getMessage());
}
http_response_code(400);
return false;
}
@ -513,8 +535,12 @@ class View extends \HTML
try {
$item = VisualConsole::getItemFromDB($itemId);
$result = $item->toArray();
} catch (Throwable $e) {
} catch (\Exception $e) {
// Bad params.
if (__DEBUG === 1) {
error_log($e->getMessage());
}
http_response_code(400);
return false;
}
@ -522,8 +548,12 @@ class View extends \HTML
// UpdateVC.
try {
$item = VisualConsole::getItemFromDB($itemId);
} catch (Throwable $e) {
} catch (\Exception $e) {
// Bad params.
if (__DEBUG === 1) {
error_log($e->getMessage());
}
http_response_code(400);
return false;
}
@ -583,4 +613,214 @@ class View extends \HTML
}
/**
* Returns a popup for networkLink viewer.
*
* @return void
*/
public function networkLinkPopup()
{
global $config;
try {
include_once $config['homedir'].'/include/functions_graph.php';
$item_idFrom = get_parameter('from');
$item_idTo = get_parameter('to');
$itemFrom = db_get_row_filter(
'tlayout_data',
['id' => $item_idFrom]
);
$itemTo = db_get_row_filter(
'tlayout_data',
['id' => $item_idTo]
);
// Interface chart base configuration.
$params = [
'period' => SECONDS_6HOURS,
'width' => '90%',
'height' => 150,
'date' => time(),
'homeurl' => $config['homeurl'],
];
if ($config['type_interface_charts'] == 'line') {
$stacked = CUSTOM_GRAPH_LINE;
} else {
$stacked = CUSTOM_GRAPH_AREA;
}
$params_combined = [
'weight_list' => [],
'projection' => false,
'from_interface' => true,
'return' => 0,
'stacked' => $stacked,
];
// Interface FROM.
if (isset($itemFrom['id_metaconsole']) === true
&& (bool) is_metaconsole() === true
) {
$cnn = \enterprise_hook(
'metaconsole_get_connection_by_id',
[ $itemFrom['id_metaconsole'] ]
);
if (\enterprise_hook('metaconsole_connect', [$cnn]) !== NOERR) {
throw new \Exception(__('Failed to connect to node'));
}
$params['server_id'] = $itemFrom['id_metaconsole'];
} else {
$params['server_id'] = null;
}
$from = new \PandoraFMS\Module((int) $itemFrom['id_agente_modulo']);
if ((bool) $from->isInterfaceModule() === true) {
$interface_name = $from->getInterfaceName();
if ($interface_name !== null) {
$data = $from->agent()->getInterfaceMetrics(
$interface_name
);
echo '<h3 class="center">'.__('NetworkLink from').'</h3>';
echo '<div class="margin-top-10 interface-status from w90p centered flex-row-vcenter">';
ui_print_module_status($data['status']->lastStatus());
echo '<span style="margin-left: 1em;">';
echo __('Interface %s status', $interface_name);
echo '</span>';
echo '</div>';
$interface_traffic_modules = [
__('In') => $data['in']->id_agente_modulo(),
__('Out') => $data['out']->id_agente_modulo(),
];
$params['unit_name'] = array_fill(
0,
count($interface_traffic_modules),
$config['interface_unit']
);
$params_combined['labels'] = array_keys(
$interface_traffic_modules
);
$params_combined['modules_series'] = array_values(
$interface_traffic_modules
);
// Graph.
echo '<div id="stat-win-interface-graph from">';
if (isset($itemFrom['id_metaconsole']) === true
&& (bool) is_metaconsole() === true
) {
\enterprise_hook('metaconsole_restore_db');
}
\graphic_combined_module(
array_values($interface_traffic_modules),
$params,
$params_combined
);
echo '</div>';
}
} else {
if (isset($itemFrom['id_metaconsole']) === true
&& (bool) is_metaconsole() === true
) {
\enterprise_hook('metaconsole_restore_db');
}
}
// Interface TO.
if (isset($itemTo['id_metaconsole']) === true
&& (bool) is_metaconsole() === true
) {
$cnn = \enterprise_hook(
'metaconsole_get_connection_by_id',
[ $itemTo['id_metaconsole'] ]
);
if (\enterprise_hook('metaconsole_connect', [$cnn]) !== NOERR) {
throw new \Exception(__('Failed to connect to node'));
}
$params['server_id'] = $itemTo['id_metaconsole'];
} else {
$params['server_id'] = null;
}
$to = new \PandoraFMS\Module((int) $itemTo['id_agente_modulo']);
if ((bool) $to->isInterfaceModule() === true) {
$interface_name = $to->getInterfaceName();
if ($interface_name !== null) {
$data = $to->agent()->getInterfaceMetrics(
$interface_name
);
echo '<h3 class="center">'.__('NetworkLink to').'</h3>';
echo '<div class="interface-status from w90p centered flex-row-vcenter">';
ui_print_module_status($data['status']->lastStatus());
echo '<span style="margin-left: 1em;">';
echo __('Interface %s status', $interface_name);
echo '</span>';
echo '</div>';
$interface_traffic_modules = [
__('In') => $data['in']->id_agente_modulo(),
__('Out') => $data['out']->id_agente_modulo(),
];
$params['unit_name'] = array_fill(
0,
count($interface_traffic_modules),
$config['interface_unit']
);
$params_combined['labels'] = array_keys(
$interface_traffic_modules
);
$params_combined['modules_series'] = array_values(
$interface_traffic_modules
);
// Graph.
echo '<div id="stat-win-interface-graph to">';
if (isset($itemTo['id_metaconsole']) === true
&& (bool) is_metaconsole() === true
) {
\enterprise_hook('metaconsole_restore_db');
}
\graphic_combined_module(
array_values($interface_traffic_modules),
$params,
$params_combined
);
echo '</div>';
}
} else {
if (isset($itemTo['id_metaconsole']) === true
&& (bool) is_metaconsole() === true
) {
\enterprise_hook('metaconsole_restore_db');
}
}
} catch (\Exception $e) {
echo __('Failed to generate charts: %s', $e->getMessage());
}
}
}

View File

@ -60,7 +60,7 @@ class StringReader {
var $_pos;
var $_str;
function StringReader($str='') {
function __construct($str='') {
$this->_str = $str;
$this->_pos = 0;
//BUGFIX-HR: 2008-07-21 we have to detect, if we need mb_str* functions instead of normal functions !
@ -128,7 +128,7 @@ class FileReader {
var $_fd;
var $_length;
function FileReader($filename) {
function __construct($filename) {
if (file_exists($filename)) {
$this->_length=filesize($filename);
@ -184,8 +184,8 @@ class FileReader {
// Preloads entire file in memory first, then creates a StringReader
// over it (it assumes knowledge of StringReader internals)
class CachedFileReader extends StringReader {
function CachedFileReader($filename) {
parent::StringReader(); //BUGFIX-HR: 2008-07-21 missing parent constructor call
function __construct($filename) {
parent::__construct(); //BUGFIX-HR: 2008-07-21 missing parent constructor call
if (file_exists($filename)) {
$length=filesize($filename);

View File

@ -713,6 +713,9 @@ select:-internal-list-box {
.invisible {
display: none;
}
.invisible_important {
display: none !important;
}
.visible {
display: block;
@ -780,6 +783,9 @@ p.center {
.center {
text-align: center;
}
.centered {
margin: 0 auto;
}
.margin-top-10 {
margin-top: 10px;

View File

@ -234,7 +234,12 @@ input.service_min {
input.service_min[disabled] {
background: url(../../images/box.disabled.png) no-repeat center;
}
input.network_link_min {
background: url(../../images/network_link_item.png) no-repeat center;
}
input.network_link_min[disabled] {
background: url(../../images/network_link_item.disabled.png) no-repeat center;
}
input.group_item_min {
background: url(../../images/group_green.png) no-repeat center;
}

View File

@ -148,3 +148,20 @@ ul.wizard li > textarea {
.action_button_list li {
display: inline;
}
.searchbox ul {
justify-content: space-between;
}
.searchbox ul li:not(.textbox) {
flex-direction: row-reverse !important;
justify-content: flex-end !important;
}
.searchbox ul li.textbox label {
width: auto;
}
.searchbox ul li.textbox {
justify-content: space-evenly !important;
flex: 1 1 auto;
}

View File

@ -9,20 +9,10 @@
.visual-console-item {
position: absolute;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: initial;
-webkit-box-direction: initial;
-ms-flex-direction: initial;
flex-direction: initial;
justify-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
z-index: 1;
}
@ -31,19 +21,24 @@
z-index: 2;
}
.visual-console-item * {
overflow: visible;
}
.visual-console-item.is-editing {
border: 2px dashed #b2b2b2;
-webkit-transform: translateX(-2px) translateY(-2px);
transform: translateX(-2px) translateY(-2px);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.visual-console-item.is-editing:hover {
border-color: #82b92e;
}
.visual-console-item.is-editing.is-selected {
border: 2px dashed #2b2b2b;
cursor: move;
z-index: 10;
}
.visual-console-item.is-editing > .resize-draggable {
float: right;
@ -60,24 +55,11 @@
pointer-events: none;
}
@-webkit-keyframes spinner-loading {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(1turn);
transform: rotate(1turn);
}
}
@keyframes spinner-loading {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(1turn);
transform: rotate(1turn);
}
}
@ -90,14 +72,9 @@
border-bottom: 5px solid rgb(82, 85, 87);
border-left: 5px solid rgba(82, 85, 87, 0.2);
-webkit-animation-name: spinner-loading;
animation-name: spinner-loading;
-webkit-animation-duration: 0.8s;
animation-duration: 0.8s;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
}
@ -119,11 +96,7 @@
position: absolute;
width: 100%;
height: 100%;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
opacity: 0.7;
background: rgb(212, 215, 218);
@ -140,17 +113,9 @@
/*Forms*/
.div-input-group label {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
font-size: 12pt;
font-family: "lato-bolder", "Open Sans", sans-serif;
@ -173,7 +138,6 @@
font-family: "lato-bolder", "Open Sans", sans-serif;
font-weight: lighter;
padding: 0px 0px 2px 0px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
margin-right: 10px;
padding-left: 2px;
@ -192,14 +156,8 @@
}
.input-groups {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
}
@ -210,17 +168,9 @@
}
.div-ranges-input-group {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-align: start;
-ms-flex-align: start;
align-items: flex-start;
}
@ -231,17 +181,9 @@
.div-input-group,
.div-input-group div div {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
@ -259,20 +201,10 @@
}
.div-input-group-autocomplete-agent {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-align: start;
-ms-flex-align: start;
align-items: flex-start;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
height: 70px;
}
@ -336,33 +268,18 @@ p.error-p-validate {
}
.fa-spin {
-webkit-animation: fa-spin 2s infinite linear;
animation: fa-spin 2s infinite linear;
}
.fa-pulse {
-webkit-animation: fa-spin 1s infinite steps(8);
animation: fa-spin 1s infinite steps(8);
}
@-webkit-keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@ -417,18 +334,10 @@ p.error-p-validate {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
justify-items: center;
-ms-flex-line-pack: center;
align-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
@ -459,17 +368,14 @@ p.error-p-validate {
}
.visual-console-item .analogic-clock .hour-hand {
-webkit-animation: rotate-hour 43200s infinite linear;
animation: rotate-hour 43200s infinite linear;
}
.visual-console-item .analogic-clock .minute-hand {
-webkit-animation: rotate-minute 3600s infinite linear;
animation: rotate-minute 3600s infinite linear;
}
.visual-console-item .analogic-clock .second-hand {
-webkit-animation: rotate-second 60s infinite linear;
animation: rotate-second 60s infinite linear;
}
@ -480,18 +386,9 @@ p.error-p-validate {
#html-tabs .ui-tabs-anchor {
float: none;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
}
@ -526,21 +423,12 @@ li#li-position-item > label:not(:first-child) {
}
li#li-image-item label {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-pack: end;
-ms-flex-pack: end;
justify-content: flex-end;
}
li#li-image-item label img {
-webkit-box-flex: initial;
-ms-flex: initial;
flex: initial;
}
@ -570,8 +458,6 @@ li#li-image-item label img {
li#li-timeZone-item > label:not(:first-child),
.discovery.modal li#div-textarea-label > label {
-webkit-box-flex: inherit;
-ms-flex: inherit;
flex: inherit;
}
@ -585,12 +471,7 @@ li#li-timeZone-item > select:not(:first-child) {
/*style item group show statistic*/
.group-container {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
width: 100%;
height: 100%;
@ -601,48 +482,24 @@ li#li-timeZone-item > select:not(:first-child) {
background-color: #9d9ea0;
color: black;
font-weight: bold;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
}
.group-container .group-item-info {
width: 100%;
height: 70%;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
padding: 2%;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.group-container .group-item-info .group-item-info-container {
-webkit-box-flex: 1;
-ms-flex: 1 1 20%;
flex: 1 1 20%;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
border-radius: 2px;
max-height: 50px;
@ -650,31 +507,18 @@ li#li-timeZone-item > select:not(:first-child) {
}
.group-container .group-item-info .group-item-info-container .value-style {
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
color: #fff;
font-size: 100%;
padding: 5%;
width: 100%;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
}
.group-container .group-item-info .group-item-info-container .name-style {
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
background-color: white;
color: black;
@ -682,38 +526,18 @@ li#li-timeZone-item > select:not(:first-child) {
padding: 5%;
width: 100%;
height: 100%;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
}
div.label,
div.simple-value {
min-width: -webkit-fit-content;
min-width: -moz-fit-content;
min-width: fit-content;
min-height: -webkit-fit-content;
min-height: -moz-fit-content;
min-height: fit-content;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
}
@ -728,26 +552,14 @@ div.module-graph .parent_graph p table tr {
div.module-graph {
width: 100%;
height: 100%;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
}
div.module-graph .gauge_d3_class {
-webkit-box-flex: 1;
-ms-flex: 1 1 100px;
flex: 1 1 100px;
float: none !important;
overflow: inherit !important;
@ -758,6 +570,14 @@ div.module-graph .gauge_d3_class {
text-decoration: none;
}
.vc-item-nl-label {
border-radius: 5px;
background-color: #fff;
padding: 5px;
padding-left: 1em;
font-size: 14px;
}
/* Styles for the solid icons */
.fa {
@ -786,33 +606,18 @@ div.module-graph .gauge_d3_class {
}
.fa-spin {
-webkit-animation: fa-spin 2s infinite linear;
animation: fa-spin 2s infinite linear;
}
.fa-pulse {
-webkit-animation: fa-spin 1s infinite steps(8);
animation: fa-spin 1s infinite steps(8);
}
@-webkit-keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@ -862,21 +667,11 @@ div.module-graph .gauge_d3_class {
/* Digital clock */
.visual-console-item .digital-clock {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
justify-items: center;
-ms-flex-line-pack: center;
align-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
@ -908,17 +703,14 @@ div.module-graph .gauge_d3_class {
}
.visual-console-item .analogic-clock .hour-hand {
-webkit-animation: rotate-hour 43200s infinite linear;
animation: rotate-hour 43200s infinite linear;
}
.visual-console-item .analogic-clock .minute-hand {
-webkit-animation: rotate-minute 3600s infinite linear;
animation: rotate-minute 3600s infinite linear;
}
.visual-console-item .analogic-clock .second-hand {
-webkit-animation: rotate-second 60s infinite linear;
animation: rotate-second 60s infinite linear;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -380,9 +380,8 @@ if (! isset($config['id_user'])) {
'Invalid double auth login: '.$_SERVER['REMOTE_ADDR'],
$_SERVER['REMOTE_ADDR']
);
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}
exit('</html>');
@ -401,9 +400,8 @@ if (! isset($config['id_user'])) {
if (!$saml_user_id) {
$login_failed = true;
include_once 'general/login_page.php';
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}
exit('</html>');
@ -446,9 +444,8 @@ if (! isset($config['id_user'])) {
if ($blocked) {
include_once 'general/login_page.php';
db_pandora_audit('Password expired', 'Password expired: '.$nick, $nick);
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}
exit('</html>');
@ -481,9 +478,8 @@ if (! isset($config['id_user'])) {
'Password expired: '.$nick,
$nick
);
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}
exit('</html>');
@ -505,9 +501,8 @@ if (! isset($config['id_user'])) {
// Load the page to introduce the double auth code.
$login_screen = 'double_auth';
include_once 'general/login_page.php';
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}
exit('</html>');
@ -677,9 +672,8 @@ if (! isset($config['id_user'])) {
'Invalid login: '.$nick,
$nick
);
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}
exit('</html>');
@ -690,9 +684,8 @@ if (! isset($config['id_user'])) {
'Invalid login: '.$nick,
$nick
);
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}
exit('</html>');
@ -741,9 +734,8 @@ if (! isset($config['id_user'])) {
} else {
include_once 'general/login_page.php';
db_pandora_audit('Logon Failed (loginhash', '', 'system');
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}
exit('</html>');
@ -891,9 +883,8 @@ if (! isset($config['id_user'])) {
}
}
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}
exit('</html>');
@ -917,9 +908,8 @@ if (! isset($config['id_user'])) {
} else {
include_once 'general/login_page.php';
db_pandora_audit('Logon Failed (loginhash', '', 'system');
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}
exit('</html>');
@ -941,9 +931,8 @@ if (! isset($config['id_user'])) {
unset($_SESSION['id_usuario']);
unset($iduser);
include_once 'general/login_page.php';
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}
exit('</html>');
@ -960,9 +949,8 @@ if (! isset($config['id_user'])) {
unset($_SESSION['id_usuario']);
unset($iduser);
include_once 'general/login_page.php';
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}
exit('</html>');
@ -995,9 +983,8 @@ if (isset($_GET['bye'])) {
// Process logout.
include 'general/logoff.php';
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}
exit('</html>');
@ -1298,9 +1285,8 @@ if ($config['pure'] == 0) {
require_once 'include/functions_clippy.php';
clippy_start($sec2);
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}
db_print_database_debug();

View File

@ -129,7 +129,7 @@
<div style='height: 10px'>
<?php
$version = '7.0NG.752';
$build = '210201';
$build = '210222';
$banner = "v$version Build $build";
error_reporting(0);

View File

@ -60,7 +60,6 @@ if ($config['force_instant_logout'] === true) {
}
}
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}

View File

@ -287,9 +287,8 @@ $(document).ready (function () {
<?php
echo '</body>';
while (@ob_end_flush()) {
// Dumping...
continue;
while (ob_get_length() > 0) {
ob_end_flush();
}
echo '</html>';

View File

@ -139,7 +139,6 @@ function snmp_browser_show_add_module_massive(module_target = 'agent') {
var snmp_extradata = snmp_browser_create_modules(module_target);
// Load dinamically modal form.
load_modal({
target: $('#modal'),
form: 'snmp_browser_add_module_form',
extradata: [
{

View File

@ -280,6 +280,11 @@ if ($pure === false) {
__('Color cloud'),
'color_cloud_min link-create-item'
);
visual_map_print_button_editor_refactor(
'NETWORK_LINK',
__('Network link'),
'network_link_min link-create-item'
);
enterprise_include_once('include/functions_visual_map_editor.php');
enterprise_hook(
'enterprise_visual_map_editor_print_toolbox_refactor'

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_console
%define version 7.0NG.752
%define release 210201
%define release 210222
# User and Group under which Apache is running
%define httpd_name httpd

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_console
%define version 7.0NG.752
%define release 210201
%define release 210222
# User and Group under which Apache is running
%define httpd_name httpd

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_console
%define version 7.0NG.752
%define release 210201
%define release 210222
%define httpd_name httpd
# User and Group under which Apache is running
%define httpd_name apache2

View File

@ -109,10 +109,10 @@ INSERT INTO `tconfig` (`token`, `value`) VALUES
('custom_report_front_logo', 'images/pandora_logo_white.jpg'),
('custom_report_front_header', ''),
('custom_report_front_footer', ''),
('MR', 43),
('MR', 44),
('identification_reminder', 1),
('identification_reminder_timestamp', 0),
('current_package_enterprise', 751),
('current_package_enterprise', 752),
('post_process_custom_values', '{"0.00000038580247":"Seconds&#x20;to&#x20;months","0.00000165343915":"Seconds&#x20;to&#x20;weeks","0.00001157407407":"Seconds&#x20;to&#x20;days","0.01666666666667":"Seconds&#x20;to&#x20;minutes","0.00000000093132":"Bytes&#x20;to&#x20;Gigabytes","0.00000095367432":"Bytes&#x20;to&#x20;Megabytes","0.00097656250000":"Bytes&#x20;to&#x20;Kilobytes","0.00000001653439":"Timeticks&#x20;to&#x20;weeks","0.00000011574074":"Timeticks&#x20;to&#x20;days"}'),
('custom_docs_logo', 'default_docs.png'),
('custom_support_logo', 'default_support.png'),

View File

@ -1,5 +1,5 @@
package: pandorafms-server
Version: 7.0NG.752-210201
Version: 7.0NG.752-210222
Architecture: all
Priority: optional
Section: admin

View File

@ -14,7 +14,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
pandora_version="7.0NG.752-210201"
pandora_version="7.0NG.752-210222"
package_cpan=0
package_pandora=1

View File

@ -350,7 +350,7 @@ max_log_generation 1
max_queue_files 5000
# Use the XML file last modification time as timestamp.
# If set to 0, the timestamp attribute in XML data files will be ignored and the system time will be used instead.
# use_xml_timestamp 1

View File

@ -295,7 +295,7 @@ max_log_size 1048576
max_queue_files 250
# Use the XML file last modification time as timestamp.
# If set to 0, the timestamp attribute in XML data files will be ignored and the system time will be used instead.
# use_xml_timestamp 1

View File

@ -45,7 +45,7 @@ our @EXPORT = qw(
# version: Defines actual version of Pandora Server for this module only
my $pandora_version = "7.0NG.752";
my $pandora_build = "210201";
my $pandora_build = "210222";
our $VERSION = $pandora_version." ".$pandora_build;
# Setup hash

View File

@ -498,7 +498,9 @@ sub exec_network_module ($$$$) {
$module_data = pandora_ping_latency ($pa_config, $ip_target, $timeout, $retries);
if (defined($module_data)) {
$module_result = 1; # Unsuccessful
$module_result = 0; # Successful
} else {
$module_result = 1; # Unsuccessful: Cannot reach target.
}
}

View File

@ -34,7 +34,7 @@ our @ISA = qw(Exporter);
# version: Defines actual version of Pandora Server for this module only
my $pandora_version = "7.0NG.752";
my $pandora_build = "210201";
my $pandora_build = "210222";
our $VERSION = $pandora_version." ".$pandora_build;
our %EXPORT_TAGS = ( 'all' => [ qw() ] );
@ -959,7 +959,7 @@ sub print_error {
if (is_enabled($conf->{'as_server_plugin'})) {
print STDERR $msg . "\n";
print $value . "\n";
exit 1;
exit 0;
}
print_module($conf, {
@ -968,7 +968,7 @@ sub print_error {
value => $value,
desc => $msg,
});
exit 1;
exit 0;
}
################################################################################

View File

@ -219,7 +219,17 @@ sub sendmail {
}
my @sockets = $Sel->can_write($mailcfg{'timeout'});
return 0 if (!@sockets);
syswrite($sockets[0], $$data) || return 0;
eval {
local $SIG{__DIE__};
# Split log data in chunks if case write is
my $data_sent = 0;
while ($data_sent < length($$data)) {
$data_sent += syswrite($sockets[0], $$data, length($$data) - $data_sent, $data_sent) || die $!;
}
};
if ($@) {
print STDERR "[sendmail] error: $!\n";
}
}
1;
}

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_server
%define version 7.0NG.752
%define release 210201
%define release 210222
Summary: Pandora FMS Server
Name: %{name}

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_server
%define version 7.0NG.752
%define release 210201
%define release 210222
Summary: Pandora FMS Server
Name: %{name}

View File

@ -9,7 +9,7 @@
# **********************************************************************
PI_VERSION="7.0NG.752"
PI_BUILD="210201"
PI_BUILD="210222"
MODE=$1
if [ $# -gt 1 ]; then

View File

@ -35,7 +35,7 @@ use PandoraFMS::Config;
use PandoraFMS::DB;
# version: define current version
my $version = "7.0NG.752 PS210201";
my $version = "7.0NG.752 PS210222";
# Pandora server configuration
my %conf;

View File

@ -36,7 +36,7 @@ use Encode::Locale;
Encode::Locale::decode_argv;
# version: define current version
my $version = "7.0NG.752 PS210201";
my $version = "7.0NG.752 PS210222";
# save program name for logging
my $progname = basename($0);

View File

@ -47,5 +47,9 @@
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.3.1"
}
},
"browserslist": [
"> 1%",
"last 2 versions"
]
}

View File

@ -0,0 +1,5 @@
{
"trailingComma": "none",
"singleQuote": false,
"arrowParens": "avoid"
}

View File

@ -46,7 +46,8 @@ export const enum ItemType {
DONUT_GRAPH = 17,
BARS_GRAPH = 18,
CLOCK = 19,
COLOR_CLOUD = 20
COLOR_CLOUD = 20,
NETWORK_LINK = 21
}
// Base item properties. This interface should be extended by the item implementations.
@ -61,6 +62,7 @@ export interface ItemProps extends Position, Size {
parentId: number | null;
aclGroupId: number | null;
cacheExpiration: number | null;
colorStatus: string;
}
export interface ItemClickEvent {
@ -136,6 +138,7 @@ export function itemBasePropsDecoder(data: AnyObject): ItemProps | never {
parentId: parseIntOr(data.parentId, null),
aclGroupId: parseIntOr(data.aclGroupId, null),
cacheExpiration: parseIntOr(data.cacheExpiration, null),
colorStatus: notEmptyStringOr(data.colorStatus, "#CCC"),
...sizePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
...positionPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
};
@ -208,6 +211,9 @@ export function titleItem(id: number): string {
case ItemType.COLOR_CLOUD:
title = t("Color cloud");
break;
case ItemType.NETWORK_LINK:
title = t("Network link");
break;
default:
title = t("Item");
break;
@ -293,6 +299,14 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
* @param element Element to move inside its container.
*/
private initMovementListener(element: HTMLElement): void {
// Avoid line movement as 'block' force using circles.
if (
this.props.type == ItemType.LINE_ITEM ||
this.props.type == ItemType.NETWORK_LINK
) {
return;
}
this.removeMovement = addMovementListener(
element,
(x: Position["x"], y: Position["y"]) => {
@ -372,6 +386,12 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
* @param element Element to move inside its container.
*/
protected initResizementListener(element: HTMLElement): void {
if (
this.props.type == ItemType.LINE_ITEM ||
this.props.type == ItemType.NETWORK_LINK
) {
return;
}
this.removeResizement = addResizementListener(
element,
(width: Size["width"], height: Size["height"]) => {
@ -824,7 +844,7 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
if (
prevProps &&
(this.props.isLinkEnabled && prevProps.link !== this.props.link)
this.props.isLinkEnabled && prevProps.link !== this.props.link
) {
if (this.props.link !== null) {
this.elementRef.setAttribute("href", this.props.link);
@ -839,6 +859,7 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
this.elementRef.classList.remove("is-editing");
}
}
if (!prevMeta || prevMeta.isFetching !== this.meta.isFetching) {
if (this.meta.isFetching) {
this.elementRef.classList.add("is-fetching");
@ -999,8 +1020,13 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
*/
protected resizeElement(width: number, height: number): void {
// The most valuable size is the content size.
this.childElementRef.style.width = width > 0 ? `${width}px` : null;
this.childElementRef.style.height = height > 0 ? `${height}px` : null;
if (
this.props.type != ItemType.LINE_ITEM &&
this.props.type != ItemType.NETWORK_LINK
) {
this.childElementRef.style.width = width > 0 ? `${width}px` : "0";
this.childElementRef.style.height = height > 0 ? `${height}px` : "0";
}
if (this.props.label && this.props.label.length > 0) {
// Ugly table to show the label as its legacy counterpart.
@ -1011,11 +1037,11 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
switch (this.props.labelPosition) {
case "up":
case "down":
table.style.width = width > 0 ? `${width}px` : null;
table.style.width = width > 0 ? `${width}px` : "0";
break;
case "left":
case "right":
table.style.height = height > 0 ? `${height}px` : null;
table.style.height = height > 0 ? `${height}px` : "0";
break;
}
}
@ -1178,7 +1204,10 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
};
this.initMovementListener(this.elementRef);
if (this.props.type !== 13) {
if (
this.props.type !== ItemType.LINE_ITEM &&
this.props.type !== ItemType.NETWORK_LINK
) {
this.initResizementListener(this.elementRef);
}
}
@ -1194,7 +1223,7 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
};
this.stopMovementListener();
if (this.props.type !== 13) {
if (this.props.type !== ItemType.LINE_ITEM) {
this.stopResizementListener();
}
}

View File

@ -6,7 +6,8 @@ import {
notEmptyStringOr,
itemMetaDecoder,
t,
ellipsize
ellipsize,
debounce
} from "./lib";
import Item, {
ItemType,
@ -20,6 +21,7 @@ import Item, {
import StaticGraph, { staticGraphPropsDecoder } from "./items/StaticGraph";
import Icon, { iconPropsDecoder } from "./items/Icon";
import ColorCloud, { colorCloudPropsDecoder } from "./items/ColorCloud";
import NetworkLink, { networkLinkPropsDecoder } from "./items/NetworkLink";
import Group, { groupPropsDecoder } from "./items/Group";
import Clock, { clockPropsDecoder } from "./items/Clock";
import Box, { boxPropsDecoder } from "./items/Box";
@ -35,7 +37,6 @@ import DonutGraph, { donutGraphPropsDecoder } from "./items/DonutGraph";
import BarsGraph, { barsGraphPropsDecoder } from "./items/BarsGraph";
import ModuleGraph, { moduleGraphPropsDecoder } from "./items/ModuleGraph";
import Service, { servicePropsDecoder } from "./items/Service";
import { FormContainer } from "./Form";
// TODO: Document.
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
@ -82,6 +83,8 @@ function itemInstanceFrom(data: AnyObject) {
return new Clock(clockPropsDecoder(data), meta);
case ItemType.COLOR_CLOUD:
return new ColorCloud(colorCloudPropsDecoder(data), meta);
case ItemType.NETWORK_LINK:
return new NetworkLink(networkLinkPropsDecoder(data), meta);
default:
throw new TypeError("item not found");
}
@ -130,6 +133,8 @@ function decodeProps(data: AnyObject) {
return clockPropsDecoder(data);
case ItemType.COLOR_CLOUD:
return colorCloudPropsDecoder(data);
case ItemType.NETWORK_LINK:
return networkLinkPropsDecoder(data);
default:
throw new TypeError("decoder not found");
}
@ -206,6 +211,16 @@ export default class VisualConsole {
private relations: {
[key: string]: Line;
} = {};
// Dictionary which store the related items (by ID).
private lineLinks: {
[key: number]: { [key: number]: { [key: string]: number } };
} = {};
private lines: {
[key: number]: { [key: string]: number };
} = {};
// Event manager for click events.
private readonly clickEventManager = new TypedEvent<ItemClickEvent>();
// Event manager for double click events.
@ -266,6 +281,9 @@ export default class VisualConsole {
}
});
// Move lines conneted with this item.
this.updateLinesConnected(e.item.props, e.newPosition, false);
// console.log(`Moved element #${e.item.props.id}`, e);
};
@ -275,9 +293,36 @@ export default class VisualConsole {
*/
private handleElementMovementFinished: (e: ItemMovedEvent) => void = e => {
this.movedEventManager.emit(e);
// Move lines conneted with this item.
this.updateLinesConnected(e.item.props, e.newPosition, true);
// console.log(`Movement finished for element #${e.item.props.id}`, e);
};
/**
* Verifies if x,y are inside item coordinates.
* @param x Coordinate X
* @param y Coordinate Y
* @param item ItemProps instance.
*/
private coordinatesInItem(x: number, y: number, props: ItemProps) {
if (
props.type == ItemType.LINE_ITEM ||
props.type == ItemType.NETWORK_LINK
) {
return false;
}
if (
x > props.x &&
x < props.x + props.width &&
y > props.y &&
y < props.y + props.height
) {
return true;
}
return false;
}
/**
* React to a line movement.
* @param e Event object.
@ -285,7 +330,12 @@ export default class VisualConsole {
private handleLineElementMovementFinished: (
e: LineMovedEvent
) => void = e => {
// Update links.
this.refreshLink(e.item);
// Build line relationships between items and lines.
this.lineMovedEventManager.emit(e);
// console.log(`Movement finished for element #${e.item.props.id}`, e);
};
@ -373,6 +423,205 @@ export default class VisualConsole {
this.unSelectItems();
};
/**
* Refresh link for given line.
*
* @param line Line.
*/
protected refreshLink(l: Line) {
let line: number = l.props.id;
let itemAtStart = 0;
let itemAtEnd = 0;
try {
for (let i in this.elementsById) {
if (
this.coordinatesInItem(
l.props.startPosition.x,
l.props.startPosition.y,
this.elementsById[i].props
)
) {
// Start position at element i.
itemAtStart = parseInt(i);
}
if (
this.coordinatesInItem(
l.props.endPosition.x,
l.props.endPosition.y,
this.elementsById[i].props
)
) {
// Start position at element i.
itemAtEnd = parseInt(i);
}
}
if (this.lineLinks == null) {
this.lineLinks = {};
}
if (this.lines == null) {
this.lines = {};
}
if (itemAtStart == line) {
itemAtStart = 0;
}
if (itemAtEnd == line) {
itemAtEnd = 0;
}
// Initialize line if not registered.
if (this.lines[line] == null) {
this.lines[line] = {
start: itemAtStart,
end: itemAtEnd
};
}
// Register 'start' side of the line.
if (itemAtStart > 0) {
// Initialize.
if (this.lineLinks[itemAtStart] == null) {
this.lineLinks[itemAtStart] = {};
}
// Assign.
this.lineLinks[itemAtStart][line] = {
start: itemAtStart,
end: itemAtEnd
};
// Register line if not exists prviously.
} else {
// Clean previous line relationship.
if (this.lines[line]["start"] > 0) {
this.lineLinks[this.lines[line]["start"]][line]["start"] = 0;
this.lines[line]["start"] = 0;
}
}
if (itemAtEnd > 0) {
if (this.lineLinks[itemAtEnd] == null) {
this.lineLinks[itemAtEnd] = {};
}
this.lineLinks[itemAtEnd][line] = {
start: itemAtStart,
end: itemAtEnd
};
} else {
// Clean previous line relationship.
if (this.lines[line]["end"] > 0) {
this.lineLinks[this.lines[line]["end"]][line]["end"] = 0;
this.lines[line]["end"] = 0;
}
}
this.lines[line] = {
start: itemAtStart,
end: itemAtEnd
};
// Cleanup.
for (let i in this.lineLinks) {
if (this.lineLinks[i][line]) {
if (
this.lineLinks[i][line].start == 0 &&
this.lineLinks[i][line].end == 0
) {
// Object not connected to a line.
delete this.lineLinks[i][line];
if (Object.keys(this.lineLinks[i]).length === 0) {
delete this.lineLinks[i];
}
}
}
}
} catch (error) {
console.error(error);
}
}
/**
* Updates lines connected to this item.
*
* @param item Item moved.
* @param newPosition New location for item.
* @param oldPosition Old location for item.
* @param save Save to ajax or not.
*/
protected updateLinesConnected(item: ItemProps, to: Position, save: boolean) {
if (this.lineLinks[item.id] == null) {
return;
}
Object.keys(this.lineLinks[item.id]).forEach(i => {
let lineId = parseInt(i);
let line = this.elementsById[lineId] as Line;
if (line.props) {
let startX = line.props.startPosition.x;
let startY = line.props.startPosition.y;
let endX = line.props.endPosition.x;
let endY = line.props.endPosition.y;
if (item.id == this.lineLinks[item.id][lineId]["start"]) {
startX = to.x + item.width / 2;
startY = to.y + item.height / 2;
}
if (item.id == this.lineLinks[item.id][lineId]["end"]) {
endX = to.x + item.width / 2;
endY = to.y + item.height / 2;
}
// Update line movement.
this.updateElement({
...line.props,
startX: startX,
startY: startY,
endX: endX,
endY: endY
});
if (save) {
let debouncedLinePositionSave = debounce(
500,
(options: AnyObject) => {
this.lineMovedEventManager.emit({
item: options.line,
startPosition: {
x: options.startX,
y: options.startY
},
endPosition: {
x: options.endX,
y: options.endY
}
});
}
);
// Save line positon.
debouncedLinePositionSave({
line: line,
startX: startX,
startY: startY,
endX: endX,
endY: endY
});
}
}
});
// Update parents...
this.buildRelations(item.id, to.x + item.width / 2, to.y + item.height / 2);
}
public constructor(
container: HTMLElement,
props: AnyObject,
@ -397,6 +646,13 @@ export default class VisualConsole {
// Create lines.
this.buildRelations();
// Re-attach all connected lines if any.
this.elements.forEach(item => {
if (item instanceof Line) {
this.refreshLink(item);
}
});
this.containerRef.addEventListener("click", this.handleContainerClick);
}
@ -424,17 +680,18 @@ export default class VisualConsole {
// Item event handlers.
itemInstance.onRemove(context.handleElementRemove);
itemInstance.onSelectionChanged(context.handleElementSelectionChanged);
// TODO:Continue
itemInstance.onClick(context.handleElementClick);
itemInstance.onDblClick(context.handleElementDblClick);
itemInstance.onMoved(context.handleElementMovement);
itemInstance.onMovementFinished(context.handleElementMovementFinished);
// TODO:Continue
if (itemInstance instanceof Line) {
itemInstance.onLineMovementFinished(
context.handleLineElementMovementFinished
);
this.refreshLink(itemInstance);
} else {
itemInstance.onMoved(context.handleElementMovement);
itemInstance.onMovementFinished(context.handleElementMovementFinished);
itemInstance.onResized(context.handleElementResizement);
itemInstance.onResizeFinished(context.handleElementResizementFinished);
}
@ -443,7 +700,7 @@ export default class VisualConsole {
context.containerRef.append(itemInstance.elementRef);
return itemInstance;
} catch (error) {
console.log("Error creating a new element:", error.message);
console.error("Error creating a new element:", error.message);
}
return;
}
@ -480,7 +737,7 @@ export default class VisualConsole {
try {
this.elementsById[item.id].props = decodeProps(item);
} catch (error) {
console.log("Error updating an element:", error.message);
console.error("Error updating an element:", error.message);
}
}
}
@ -497,9 +754,11 @@ export default class VisualConsole {
public updateElement(item: AnyObject): void {
// Update item.
try {
this.elementsById[item.id].props = decodeProps(item);
this.elementsById[item.id].props = {
...decodeProps(item)
};
} catch (error) {
console.log("Error updating element:", error.message);
console.error("Error updating element:", error.message);
}
// Re-build relations.
@ -538,11 +797,13 @@ export default class VisualConsole {
public render(prevProps: VisualConsoleProps | null = null): void {
if (prevProps) {
if (prevProps.backgroundURL !== this.props.backgroundURL) {
if (this.props.backgroundURL)
this.containerRef.style.backgroundImage =
this.props.backgroundURL !== null
? `url(${this.props.backgroundURL})`
: null;
: "";
}
if (this.props.backgroundColor != null)
if (prevProps.backgroundColor !== this.props.backgroundColor) {
this.containerRef.style.backgroundColor = this.props.backgroundColor;
}
@ -550,11 +811,13 @@ export default class VisualConsole {
this.resizeElement(this.props.width, this.props.height);
}
} else {
if (this.props.backgroundURL)
this.containerRef.style.backgroundImage =
this.props.backgroundURL !== null
? `url(${this.props.backgroundURL})`
: null;
: "";
if (this.props.backgroundColor)
this.containerRef.style.backgroundColor = this.props.backgroundColor;
this.resizeElement(this.props.width, this.props.height);
}
@ -614,8 +877,11 @@ export default class VisualConsole {
/**
* Create line elements which connect the elements with their parents.
*
* When itemId is being moved, overwrite position of the 'parent' or 'child'
* endpoints of the line, using X and Y values.
*/
public buildRelations(): void {
public buildRelations(itemId?: number, x?: number, y?: number): void {
// Clear relations.
this.clearRelations();
// Add relations.
@ -623,7 +889,23 @@ export default class VisualConsole {
if (item.props.parentId !== null) {
const parent = this.elementsById[item.props.parentId];
const child = this.elementsById[item.props.id];
if (parent && child) this.addRelationLine(parent, child);
if (parent && child) {
if (itemId != undefined) {
if (item.props.parentId == itemId) {
// Update parent line position.
this.addRelationLine(parent, child, x, y);
} else if (item.props.id == itemId) {
// Update child line position.
this.addRelationLine(parent, child, undefined, undefined, x, y);
} else {
this.addRelationLine(parent, child);
}
} else {
// No movements default behaviour.
this.addRelationLine(parent, child);
}
}
}
});
}
@ -749,7 +1031,11 @@ export default class VisualConsole {
*/
private addRelationLine(
parent: Item<ItemProps>,
child: Item<ItemProps>
child: Item<ItemProps>,
parentX?: number,
parentY?: number,
childX?: number,
childY?: number
): Line {
const identifier = `${parent.props.id}|${child.props.id}`;
if (this.relations[identifier] != null) {
@ -757,9 +1043,27 @@ export default class VisualConsole {
}
// Get the items center.
const { x: startX, y: startY } = this.getVisualCenter(parent.props, parent);
const { x: endX, y: endY } = this.getVisualCenter(child.props, child);
let { x: startX, y: startY } = this.getVisualCenter(parent.props, parent);
let { x: endX, y: endY } = this.getVisualCenter(child.props, child);
// Overwrite positions if needed (while moving it!).
if (parentX != null) {
startX = parentX;
}
if (parentY != null) {
startY = parentY;
}
if (childX != null) {
endX = childX;
}
if (childY != null) {
endY = childY;
}
// Line inherits child element status.
const line = new Line(
linePropsDecoder({
id: 0,
@ -771,7 +1075,7 @@ export default class VisualConsole {
width: 0,
height: 0,
lineWidth: this.props.relationLineWidth,
color: "#CCCCCC"
color: notEmptyStringOr(child.props.colorStatus, "#CCC")
}),
itemMetaDecoder({
receivedAt: new Date()
@ -973,7 +1277,8 @@ export default class VisualConsole {
[ItemType.DONUT_GRAPH]: DonutGraph,
[ItemType.BARS_GRAPH]: BarsGraph,
[ItemType.CLOCK]: Clock,
[ItemType.COLOR_CLOUD]: ColorCloud
[ItemType.COLOR_CLOUD]: ColorCloud,
[ItemType.NETWORK_LINK]: NetworkLink
};
/**

View File

@ -8,9 +8,9 @@ import {
import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
import TypedEvent, { Listener, Disposable } from "../lib/TypedEvent";
interface LineProps extends ItemProps {
export interface LineProps extends ItemProps {
// Overrided properties.
readonly type: ItemType.LINE_ITEM;
type: number;
label: null;
isLinkEnabled: false;
parentId: null;
@ -20,6 +20,16 @@ interface LineProps extends ItemProps {
endPosition: Position;
lineWidth: number;
color: string | null;
viewportOffsetX: number;
viewportOffsetY: number;
labelEnd: string;
labelStart: string;
linkedEnd: number | null;
linkedStart: number | null;
labelEndWidth: number;
labelEndHeight: number;
labelStartWidth: number;
labelStartHeight: number;
}
/**
@ -54,7 +64,17 @@ export function linePropsDecoder(data: AnyObject): LineProps | never {
y: parseIntOr(data.endY, 0)
},
lineWidth: parseIntOr(data.lineWidth || data.borderWidth, 1),
color: notEmptyStringOr(data.borderColor || data.color, null)
color: notEmptyStringOr(data.borderColor || data.color, null),
viewportOffsetX: 0,
viewportOffsetY: 0,
labelEnd: notEmptyStringOr(data.labelEnd, ""),
labelEndWidth: parseIntOr(data.labelEndWidth, 0),
linkedEnd: data.linkedEnd,
linkedStart: data.linkedStart,
labelEndHeight: parseIntOr(data.labelEndHeight, 0),
labelStart: notEmptyStringOr(data.labelStart, ""),
labelStartWidth: parseIntOr(data.labelStartWidth, 0),
labelStartHeight: parseIntOr(data.labelStartHeight, 0)
};
/*
@ -82,20 +102,20 @@ export interface LineMovedEvent {
}
export default class Line extends Item<LineProps> {
private circleRadius = 8;
protected circleRadius = 8;
// To control if the line movement is enabled.
private moveMode: boolean = false;
protected moveMode: boolean = false;
// To control if the line is moving.
private isMoving: boolean = false;
protected isMoving: boolean = false;
// Event manager for moved events.
private readonly lineMovedEventManager = new TypedEvent<LineMovedEvent>();
public readonly lineMovedEventManager = new TypedEvent<LineMovedEvent>();
// List of references to clean the event listeners.
private readonly lineMovedEventDisposables: Disposable[] = [];
protected readonly lineMovedEventDisposables: Disposable[] = [];
// This function will only run the 2nd arg function after the time
// of the first arg have passed after its last execution.
private debouncedStartPositionMovementSave = debounce(
protected debouncedStartPositionMovementSave = debounce(
500, // ms.
(x: Position["x"], y: Position["y"]) => {
this.isMoving = false;
@ -110,13 +130,13 @@ export default class Line extends Item<LineProps> {
);
// This property will store the function
// to clean the movement listener.
private removeStartPositionMovement: Function | null = null;
protected removeStartPositionMovement: Function | null = null;
/**
* Start the movement funtionality for the start position.
* @param element Element to move inside its container.
*/
private initStartPositionMovementListener(
protected initStartPositionMovementListener(
element: HTMLElement,
container: HTMLElement
): void {
@ -124,8 +144,8 @@ export default class Line extends Item<LineProps> {
element,
(x: Position["x"], y: Position["y"]) => {
// Calculate the center of the circle.
x += this.circleRadius;
y += this.circleRadius;
x += this.circleRadius - this.props.viewportOffsetX / 2;
y += this.circleRadius - this.props.viewportOffsetY / 2;
const startPosition = { x, y };
@ -153,7 +173,7 @@ export default class Line extends Item<LineProps> {
// This function will only run the 2nd arg function after the time
// of the first arg have passed after its last execution.
private debouncedEndPositionMovementSave = debounce(
protected debouncedEndPositionMovementSave = debounce(
500, // ms.
(x: Position["x"], y: Position["y"]) => {
this.isMoving = false;
@ -168,13 +188,13 @@ export default class Line extends Item<LineProps> {
);
// This property will store the function
// to clean the movement listener.
private removeEndPositionMovement: Function | null = null;
protected removeEndPositionMovement: Function | null = null;
/**
* End the movement funtionality for the end position.
* @param element Element to move inside its container.
*/
private initEndPositionMovementListener(
protected initEndPositionMovementListener(
element: HTMLElement,
container: HTMLElement
): void {
@ -182,8 +202,8 @@ export default class Line extends Item<LineProps> {
element,
(x: Position["x"], y: Position["y"]) => {
// Calculate the center of the circle.
x += this.circleRadius;
y += this.circleRadius;
x += this.circleRadius - this.props.viewportOffsetX / 2;
y += this.circleRadius - this.props.viewportOffsetY / 2;
this.isMoving = true;
this.props = {
@ -231,6 +251,11 @@ export default class Line extends Item<LineProps> {
this.moveMode = meta.editMode;
this.init();
super.resizeElement(
Math.max(props.width, props.viewportOffsetX),
Math.max(props.height, props.viewportOffsetY)
);
}
/**
@ -272,27 +297,33 @@ export default class Line extends Item<LineProps> {
const element: HTMLDivElement = document.createElement("div");
element.className = "line";
const {
let {
x, // Box x
y, // Box y
width, // Box width
height, // Box height
lineWidth, // Line thickness
lineWidth, // Line thickness,
viewportOffsetX, // viewport width,
viewportOffsetY, // viewport heigth,
startPosition, // Line start position
endPosition, // Line end position
color // Line color
} = this.props;
const x1 = startPosition.x - x + lineWidth / 2;
const y1 = startPosition.y - y + lineWidth / 2;
const x2 = endPosition.x - x + lineWidth / 2;
const y2 = endPosition.y - y + lineWidth / 2;
width = width + viewportOffsetX;
height = height + viewportOffsetY;
const x1 = startPosition.x - x + lineWidth / 2 + viewportOffsetX / 2;
const y1 = startPosition.y - y + lineWidth / 2 + viewportOffsetY / 2;
const x2 = endPosition.x - x + lineWidth / 2 + viewportOffsetX / 2;
const y2 = endPosition.y - y + lineWidth / 2 + viewportOffsetY / 2;
// SVG container.
const svg = document.createElementNS(svgNS, "svg");
// Set SVG size.
svg.setAttribute("width", `${width + lineWidth}`);
svg.setAttribute("height", `${height + lineWidth}`);
const line = document.createElementNS(svgNS, "line");
line.setAttribute("x1", `${x1}`);
line.setAttribute("y1", `${y1}`);
@ -308,21 +339,26 @@ export default class Line extends Item<LineProps> {
}
protected updateDomElement(element: HTMLElement): void {
const {
let {
x, // Box x
y, // Box y
width, // Box width
height, // Box height
lineWidth, // Line thickness
viewportOffsetX, // viewport width,
viewportOffsetY, // viewport heigth,
startPosition, // Line start position
endPosition, // Line end position
color // Line color
} = this.props;
const x1 = startPosition.x - x + lineWidth / 2;
const y1 = startPosition.y - y + lineWidth / 2;
const x2 = endPosition.x - x + lineWidth / 2;
const y2 = endPosition.y - y + lineWidth / 2;
width = width + viewportOffsetX;
height = height + viewportOffsetY;
const x1 = startPosition.x - x + lineWidth / 2 + viewportOffsetX / 2;
const y1 = startPosition.y - y + lineWidth / 2 + viewportOffsetY / 2;
const x2 = endPosition.x - x + lineWidth / 2 + viewportOffsetX / 2;
const y2 = endPosition.y - y + lineWidth / 2 + viewportOffsetY / 2;
const svgs = element.getElementsByTagName("svg");
@ -352,9 +388,6 @@ export default class Line extends Item<LineProps> {
}
if (this.moveMode) {
const startIsLeft = startPosition.x - endPosition.x <= 0;
const startIsTop = startPosition.y - endPosition.y <= 0;
let startCircle: HTMLElement = document.createElement("div");
let endCircle: HTMLElement = document.createElement("div");
@ -384,12 +417,8 @@ export default class Line extends Item<LineProps> {
startCircle.style.borderRadius = "50%";
startCircle.style.backgroundColor = `${color}`;
startCircle.style.position = "absolute";
startCircle.style.left = startIsLeft
? `-${this.circleRadius}px`
: `${width + lineWidth - this.circleRadius}px`;
startCircle.style.top = startIsTop
? `-${this.circleRadius}px`
: `${height + lineWidth - this.circleRadius}px`;
startCircle.style.left = `${x1 - this.circleRadius}px`;
startCircle.style.top = `${y1 - this.circleRadius}px`;
endCircle.classList.add(
"visual-console-item-line-circle",
@ -400,12 +429,8 @@ export default class Line extends Item<LineProps> {
endCircle.style.borderRadius = "50%";
endCircle.style.backgroundColor = `${color}`;
endCircle.style.position = "absolute";
endCircle.style.left = startIsLeft
? `${width + lineWidth - 8}px`
: `-${this.circleRadius}px`;
endCircle.style.top = startIsTop
? `${height + lineWidth - this.circleRadius}px`
: `-${this.circleRadius}px`;
endCircle.style.left = `${x2 - this.circleRadius}px`;
endCircle.style.top = `${y2 - this.circleRadius}px`;
if (element.parentElement !== null) {
const circles = element.parentElement.getElementsByClassName(
@ -421,10 +446,14 @@ export default class Line extends Item<LineProps> {
}
// Init the movement listeners.
this.initStartPositionMovementListener(startCircle, this.elementRef
.parentElement as HTMLElement);
this.initEndPositionMovementListener(endCircle, this.elementRef
.parentElement as HTMLElement);
this.initStartPositionMovementListener(
startCircle,
this.elementRef.parentElement as HTMLElement
);
this.initEndPositionMovementListener(
endCircle,
this.elementRef.parentElement as HTMLElement
);
} else if (!this.moveMode) {
this.stopStartPositionMovementListener();
// Remove circles.

View File

@ -0,0 +1,314 @@
import { AnyObject, Position, ItemMeta } from "../lib/types";
import { debounce, notEmptyStringOr, parseIntOr } from "../lib";
import { ItemType } from "../Item";
import Line, { LineProps, linePropsDecoder } from "./Line";
const svgNS = "http://www.w3.org/2000/svg";
export interface NetworkLinkProps extends LineProps {
// Overrided properties.
type: number;
labelStart: string;
labelEnd: string;
}
/**
* Build a valid typed object from a raw object.
* This will allow us to ensure the type safety.
*
* @param data Raw object.
* @return An object representing the item props.
* @throws Will throw a TypeError if some property
* is missing from the raw object or have an invalid type.
*/
export function networkLinkPropsDecoder(
data: AnyObject
): NetworkLinkProps | never {
return {
...linePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
type: ItemType.NETWORK_LINK,
viewportOffsetX: 0,
viewportOffsetY: 0,
labelEnd: notEmptyStringOr(data.labelEnd, ""),
labelEndWidth: parseIntOr(data.labelEndWidth, 0),
labelEndHeight: parseIntOr(data.labelEndHeight, 0),
labelStart: notEmptyStringOr(data.labelStart, ""),
labelStartWidth: parseIntOr(data.labelStartWidth, 0),
labelStartHeight: parseIntOr(data.labelStartHeight, 0)
};
}
export default class NetworkLink extends Line {
/**
* @override
*/
public constructor(props: NetworkLinkProps, meta: ItemMeta) {
/*
* We need to override the constructor cause we need to obtain the
* box size and position from the start and finish points of the line.
*/
super(
{
...props
},
{
...meta
}
);
this.render();
}
/**
* @override
*/
protected debouncedStartPositionMovementSave = debounce(
50, // ms.
(x: Position["x"], y: Position["y"]) => {
this.isMoving = false;
const startPosition = { x, y };
// Re-Paint after move.
this.render();
// Emit the movement event.
this.lineMovedEventManager.emit({
item: this,
startPosition,
endPosition: this.props.endPosition
});
}
);
protected debouncedEndPositionMovementSave = debounce(
50, // ms.
(x: Position["x"], y: Position["y"]) => {
this.isMoving = false;
const endPosition = { x, y };
// Re-Paint after move.
this.render();
// Emit the movement event.
this.lineMovedEventManager.emit({
item: this,
endPosition,
startPosition: this.props.startPosition
});
}
);
protected updateDomElement(element: HTMLElement): void {
super.updateDomElement(element);
let {
x, // Box x
y, // Box y
lineWidth, // Line thickness
viewportOffsetX, // viewport width,
viewportOffsetY, // viewport heigth,
startPosition, // Line start position
endPosition, // Line end position
color, // Line color
labelEnd,
labelStart,
labelEndWidth,
labelEndHeight,
labelStartWidth,
labelStartHeight
} = this.props;
const svgs = element.getElementsByTagName("svg");
let line;
let svg;
if (svgs.length > 0) {
svg = svgs.item(0);
if (svg != null) {
// Set SVG size.
const lines = svg.getElementsByTagNameNS(svgNS, "line");
let groups = svg.getElementsByTagNameNS(svgNS, "g");
while (groups.length > 0) {
groups[0].remove();
}
if (lines.length > 0) {
line = lines.item(0);
}
}
} else {
// No line or svg, no more actions are required.
return;
}
if (svg == null || line == null) {
// No more actionas are required.
return;
}
// Font size and text adjustments.
const fontsize = 10;
const adjustment = 25;
const lineX1 = startPosition.x - x + lineWidth / 2 + viewportOffsetX / 2;
const lineY1 = startPosition.y - y + lineWidth / 2 + viewportOffsetY / 2;
const lineX2 = endPosition.x - x + lineWidth / 2 + viewportOffsetX / 2;
const lineY2 = endPosition.y - y + lineWidth / 2 + viewportOffsetY / 2;
let x1 = startPosition.x - x + lineWidth / 2 + viewportOffsetX / 2;
let y1 = startPosition.y - y + lineWidth / 2 + viewportOffsetY / 2;
let x2 = endPosition.x - x + lineWidth / 2 + viewportOffsetX / 2;
let y2 = endPosition.y - y + lineWidth / 2 + viewportOffsetY / 2;
// Calculate angle (rotation).
let rad = Math.atan2(lineY2 - lineY1, lineX2 - lineX1);
let g = (rad * 180) / Math.PI;
// Calculate effective 'text' box sizes.
const fontheight = 25;
if (labelStartWidth <= 0) {
let lines = labelStart.split("<br>");
labelStartWidth = 0;
lines.forEach(l => {
if (l.length > labelStartWidth) {
labelStartWidth = l.length * fontsize;
}
});
if (labelStartHeight <= 0) {
labelStartHeight = lines.length * fontheight;
}
}
if (labelEndWidth <= 0) {
let lines = labelEnd.split("<br>");
labelEndWidth = 0;
lines.forEach(l => {
if (l.length > labelEndWidth) {
labelEndWidth = l.length * fontsize;
}
});
if (labelEndHeight <= 0) {
labelEndHeight = lines.length * fontheight;
}
}
if (x1 < x2) {
// x1 on left of x2.
x1 += adjustment;
x2 -= adjustment + labelEndWidth;
}
if (x1 > x2) {
// x1 on right of x2.
x1 -= adjustment + labelStartWidth;
x2 += adjustment;
}
if (y1 < y2) {
// y1 on y2.
y1 += adjustment;
y2 -= adjustment + labelEndHeight;
}
if (y1 > y2) {
// y1 under y2.
y1 -= adjustment + labelStartHeight;
y2 += adjustment;
}
if (typeof color == "undefined") {
color = "#000";
}
// Clean.
if (element.parentElement !== null) {
const labels = element.parentElement.getElementsByClassName(
"vc-item-nl-label"
);
while (labels.length > 0) {
const label = labels.item(0);
if (label) label.remove();
}
const arrows = element.parentElement.getElementsByClassName(
"vc-item-nl-arrow"
);
while (arrows.length > 0) {
const arrow = arrows.item(0);
if (arrow) arrow.remove();
}
}
let arrowSize = lineWidth * 2;
let arrowPosX = lineX1 + (lineX2 - lineX1) / 2 - arrowSize;
let arrowPosY = lineY1 + (lineY2 - lineY1) / 2 - arrowSize;
let arrowStart: HTMLElement = document.createElement("div");
arrowStart.classList.add("vc-item-nl-arrow");
arrowStart.style.position = "absolute";
arrowStart.style.border = `${arrowSize}px solid transparent`;
arrowStart.style.borderBottom = `${arrowSize}px solid ${color}`;
arrowStart.style.left = `${arrowPosX}px`;
arrowStart.style.top = `${arrowPosY}px`;
arrowStart.style.transform = `rotate(${90 + g}deg)`;
let arrowEnd: HTMLElement = document.createElement("div");
arrowEnd.classList.add("vc-item-nl-arrow");
arrowEnd.style.position = "absolute";
arrowEnd.style.border = `${arrowSize}px solid transparent`;
arrowEnd.style.borderBottom = `${arrowSize}px solid ${color}`;
arrowEnd.style.left = `${arrowPosX}px`;
arrowEnd.style.top = `${arrowPosY}px`;
arrowEnd.style.transform = `rotate(${270 + g}deg)`;
if (element.parentElement !== null) {
element.parentElement.appendChild(arrowStart);
element.parentElement.appendChild(arrowEnd);
}
if (labelStart != "") {
let htmlLabelStart: HTMLElement = document.createElement("div");
try {
htmlLabelStart.innerHTML = labelStart;
htmlLabelStart.style.position = "absolute";
htmlLabelStart.style.left = `${x1}px`;
htmlLabelStart.style.top = `${y1}px`;
htmlLabelStart.style.width = `${labelStartWidth}px`;
htmlLabelStart.style.border = `2px solid ${color}`;
htmlLabelStart.classList.add("vc-item-nl-label", "label-start");
} catch (error) {
console.error(error);
}
if (element.parentElement !== null) {
element.parentElement.appendChild(htmlLabelStart);
}
}
if (labelEnd != "") {
let htmlLabelEnd: HTMLElement = document.createElement("div");
try {
htmlLabelEnd.innerHTML = labelEnd;
htmlLabelEnd.style.position = "absolute";
htmlLabelEnd.style.left = `${x2}px`;
htmlLabelEnd.style.top = `${y2}px`;
htmlLabelEnd.style.width = `${labelEndWidth}px`;
htmlLabelEnd.style.border = `2px solid ${color}`;
htmlLabelEnd.classList.add("vc-item-nl-label", "label-end");
} catch (error) {
console.error(error);
}
if (element.parentElement !== null) {
element.parentElement.appendChild(htmlLabelEnd);
}
}
}
}

View File

@ -71,6 +71,8 @@ export default class StaticGraph extends Item<StaticGraphProps> {
const imgSrc = this.props.statusImageSrc || this.props.imageSrc;
const element = document.createElement("div");
element.className = "static-graph";
element.setAttribute("ondragstart", "return false;");
element.setAttribute("draggable", "false");
element.style.backgroundImage = `url(${imgSrc})`;
element.style.backgroundRepeat = "no-repeat";
element.style.backgroundSize = "contain";

View File

@ -553,6 +553,10 @@ export function addMovementListener(
// Disable the drag temporarily.
element.draggable = false;
// Fix for Firefox browser.
element.setAttribute("ondragstart", "return false;");
element.setAttribute("draggable", "false");
// Store the difference between the cursor and
// the initial coordinates of the element.
const elementOffset = getOffset(element, container);

View File

@ -21,15 +21,24 @@
z-index: 2;
}
.visual-console-item * {
overflow: visible;
}
.visual-console-item.is-editing {
border: 2px dashed #b2b2b2;
transform: translateX(-2px) translateY(-2px);
user-select: none;
}
.visual-console-item.is-editing:hover {
border-color: #82b92e;
}
.visual-console-item.is-editing.is-selected {
border: 2px dashed #2b2b2b;
cursor: move;
z-index: 10;
}
.visual-console-item.is-editing > .resize-draggable {
float: right;
@ -560,3 +569,11 @@ div.module-graph .gauge_d3_class {
.textDecorationNone:hover {
text-decoration: none;
}
.vc-item-nl-label {
border-radius: 5px;
background-color: #fff;
padding: 5px;
padding-left: 1em;
font-size: 14px;
}

View File

@ -59,10 +59,11 @@ module.exports = {
loader: "postcss-loader",
options: {
plugins: () => [
// To improve the support for old browsers.
require("autoprefixer")({
browsers: ["> 1%", "last 2 versions"]
})
// Moved to package.json (?)
// // To improve the support for old browsers.
// require("autoprefixer")({
// browsers: ["> 1%", "last 2 versions"]
// })
]
}
}