diff --git a/extras/build_rpm_rhel7.sh b/extras/build_rpm_rhel7.sh new file mode 100755 index 0000000000..3684bd42e5 --- /dev/null +++ b/extras/build_rpm_rhel7.sh @@ -0,0 +1,26 @@ +#!/bin/bash +source build_vars.sh + +if [ ! -d $RPMHOME/RPMS ]; then + mkdir -p $RPMHOME/RPMS || exit 1 +fi + +echo "Creating RPM packages in $RPMHOME/RPMS" + +# Console +rpmbuild -ba $CODEHOME/pandora_console/pandora_console.rhel7.spec || exit 1 + +# Server +#rpmbuild -ba $CODEHOME/pandora_server/pandora_server.rhel7.spec || exit 1 + +# Unix agent +#rpmbuild -ba $CODEHOME/pandora_agents/unix/pandora_agent.rhel7.spec || exit 1 + +# Enterprise console +rpmbuild -ba $PANDHOME_ENT/pandora_console/enterprise/pandora_console_enterprise.rhel7.spec || exit 1 + +# Enterprise server +#rpmbuild -ba $PANDHOME_ENT/pandora_server/PandoraFMS-Enterprise/pandora_server_enterprise.rhel7.spec || exit 1 + +exit 0 + diff --git a/extras/docker/build_and_push.sh b/extras/docker/build_and_push.sh index 980087cfe5..91e6fa15e5 100755 --- a/extras/docker/build_and_push.sh +++ b/extras/docker/build_and_push.sh @@ -1,3 +1,3 @@ #!/bin/bash -docker build --rm=true --build-arg BRANCH="develop" --build-arg DB_PASS="pandora" -t pandorafms/pandorafms:7 . && \ +docker build --rm=true --pull --no-cache --build-arg BRANCH="develop" --build-arg DB_PASS="pandora" -t pandorafms/pandorafms:7 . && \ docker push pandorafms/pandorafms:7 diff --git a/extras/pandora_update_version.sh b/extras/pandora_update_version.sh index 90c4bf6519..edab1affeb 100755 --- a/extras/pandora_update_version.sh +++ b/extras/pandora_update_version.sh @@ -26,9 +26,11 @@ $CODEHOME/pandora_server/pandora_server.spec \ $PANDHOME_ENT/pandora_console/enterprise/pandora_console_enterprise.spec \ $PANDHOME_ENT/pandora_server/PandoraFMS-Enterprise/pandora_server_enterprise.spec \ $CODEHOME/pandora_console/pandora_console.redhat.spec \ +$CODEHOME/pandora_console/pandora_console.rhel7.spec \ $CODEHOME/pandora_agents/unix/pandora_agent.redhat.spec \ $CODEHOME/pandora_server/pandora_server.redhat.spec \ $PANDHOME_ENT/pandora_console/enterprise/pandora_console_enterprise.redhat.spec \ +$PANDHOME_ENT/pandora_console/enterprise/pandora_console_enterprise.rhel7.spec \ $PANDHOME_ENT/pandora_server/PandoraFMS-Enterprise/pandora_server_enterprise.redhat.spec" DEBIAN_FILES="$CODEHOME/pandora_console/DEBIAN \ $CODEHOME/pandora_server/DEBIAN \ @@ -54,7 +56,8 @@ AGENT_WIN_FILE="$CODEHOME/pandora_agents/win32/pandora.cc" AGENT_WIN_MPI_FILE="$CODEHOME/pandora_agents/win32/installer/pandora.mpi" AGENT_WIN_RC_FILE="$CODEHOME/pandora_agents/win32/versioninfo.rc" SATELLITE_FILE="$PANDHOME_ENT/satellite_server/satellite_server.pl" -PERL_PLUGIN_FILES="$PANDHOME_ENT/pandora_server/util/plugin/vmware-plugin.pl \ +PERL_PLUGIN_FILES="$PANDHOME_ENT/pandora_server/util/recon_script/vmware-plugin.pl \ +$PANDHOME_ENT/pandora_server/util/recon_script/pcm_client.pl \ $PANDHOME_ENT/pandora_plugins/NGINX/nginx_requests_queued.pl \ $PANDHOME_ENT/pandora_plugins/Sybase/sybase_plugin.pl \ $PANDHOME_ENT/pandora_plugins/SNMP/dynamic_snmp.pl \ @@ -171,8 +174,8 @@ echo "Updating Pandora Console version..." sed -i -e "s/\s*\$pandora_version\s*=.*/\$pandora_version = 'v$VERSION';/" "$CONSOLE_FILE" sed -i -e "s/\s*\$build_version\s*=.*/\$build_version = 'PC$BUILD';/" "$CONSOLE_FILE" echo "Updating Pandora Console installer version..." -sed -i -e "s/\s*\$version\s*=.*/\$version = '$VERSION';/" "$CONSOLE_INSTALL_FILE" -sed -i -e "s/\s*\$build\s*=.*/\$build = '$BUILD';/" "$CONSOLE_INSTALL_FILE" +sed -i -e "s/\(\s*\$version\s*=\s\).*/\1'$VERSION';/" "$CONSOLE_INSTALL_FILE" +sed -i -e "s/\(\s*\$build\s*=\s\).*/\1'$BUILD';/" "$CONSOLE_INSTALL_FILE" echo "Setting develop_bypass to 0..." sed -i -e "s/\s*if\s*(\s*[!]\s*isset\s*(\s*$develop_bypass\s*)\s*)\s*$develop_bypass\s*=.*/if ([!]isset($develop_bypass)) $develop_bypass = 0;/" "$CONSOLE_FILE" diff --git a/pandora_agents/pc/AIX/pandora_agent.conf b/pandora_agents/pc/AIX/pandora_agent.conf index bff05d8732..0ff67a62d3 100644 --- a/pandora_agents/pc/AIX/pandora_agent.conf +++ b/pandora_agents/pc/AIX/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731, AIX version +# Version 7.0NG.735, AIX version # Licensed under GPL license v2, # Copyright (c) 2003-2010 Artica Soluciones Tecnologicas # http://www.pandorafms.com diff --git a/pandora_agents/pc/DEBIAN/control b/pandora_agents/pc/DEBIAN/control index af1e09fc24..cdbcc99cfe 100644 --- a/pandora_agents/pc/DEBIAN/control +++ b/pandora_agents/pc/DEBIAN/control @@ -1,10 +1,10 @@ package: pandorafms-agent-unix -Version: 4.0.1 +Version: 7.0 Architecture: all Priority: optional Section: admin Installed-Size: 260 -Maintainer: Miguel de Dios -Homepage: http://pandorafms.org/ +Maintainer: ÁRTICA ST +Homepage: https://pandorafms.org/ Depends: coreutils, perl, unzip Description: Pandora FMS agents are based on native languages in every platform: scripts that can be written in any language. It’s possible to reproduce any agent in any programming language and can be extended without difficulty the existing ones in order to cover aspects not taken into account up to the moment. These scripts are formed by modules that each one gathers a "chunk" of information. Thus, every agent gathers several "chunks" of information; this one is organized in a data set and stored in a single file, called data file. diff --git a/pandora_agents/pc/FreeBSD/pandora_agent.conf b/pandora_agents/pc/FreeBSD/pandora_agent.conf index 938691a2af..c7c6fdd493 100644 --- a/pandora_agents/pc/FreeBSD/pandora_agent.conf +++ b/pandora_agents/pc/FreeBSD/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731, FreeBSD Version +# Version 7.0NG.735, FreeBSD Version # Licensed under GPL license v2, # Copyright (c) 2003-2010 Artica Soluciones Tecnologicas # http://www.pandorafms.com diff --git a/pandora_agents/pc/HP-UX/pandora_agent.conf b/pandora_agents/pc/HP-UX/pandora_agent.conf index d6f6d248c9..1a349583dc 100644 --- a/pandora_agents/pc/HP-UX/pandora_agent.conf +++ b/pandora_agents/pc/HP-UX/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731, HP-UX Version +# Version 7.0NG.735, HP-UX Version # Licensed under GPL license v2, # Copyright (c) 2003-2009 Artica Soluciones Tecnologicas # http://www.pandorafms.com diff --git a/pandora_agents/pc/Linux/pandora_agent.conf b/pandora_agents/pc/Linux/pandora_agent.conf index 0de221f790..dc172b7e2f 100644 --- a/pandora_agents/pc/Linux/pandora_agent.conf +++ b/pandora_agents/pc/Linux/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731, GNU/Linux +# Version 7.0NG.735, GNU/Linux # Licensed under GPL license v2, # Copyright (c) 2003-2009 Artica Soluciones Tecnologicas # http://www.pandorafms.com diff --git a/pandora_agents/pc/NT4/pandora_agent.conf b/pandora_agents/pc/NT4/pandora_agent.conf index cb90a522a3..3d76832397 100644 --- a/pandora_agents/pc/NT4/pandora_agent.conf +++ b/pandora_agents/pc/NT4/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731, GNU/Linux +# Version 7.0NG.735, GNU/Linux # Licensed under GPL license v2, # Copyright (c) 2003-2009 Artica Soluciones Tecnologicas # http://www.pandorafms.com diff --git a/pandora_agents/pc/SunOS/pandora_agent.conf b/pandora_agents/pc/SunOS/pandora_agent.conf index 1758206b7b..9b088eae51 100644 --- a/pandora_agents/pc/SunOS/pandora_agent.conf +++ b/pandora_agents/pc/SunOS/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731, Solaris Version +# Version 7.0NG.735, Solaris Version # Licensed under GPL license v2, # Copyright (c) 2003-2009 Artica Soluciones Tecnologicas # http://www.pandorafms.com diff --git a/pandora_agents/pc/Win32/pandora_agent.conf b/pandora_agents/pc/Win32/pandora_agent.conf index bc4a50047f..e2c442a520 100644 --- a/pandora_agents/pc/Win32/pandora_agent.conf +++ b/pandora_agents/pc/Win32/pandora_agent.conf @@ -1,6 +1,6 @@ # Base config file for Pandora FMS Windows Agent # (c) 2006-2010 Artica Soluciones Tecnologicas -# Version 7.0NG.731 +# Version 7.0NG.735 # This program is Free Software, you can redistribute it and/or modify it # under the terms of the GNU General Public Licence as published by the Free Software diff --git a/pandora_agents/shellscript/aix/pandora_agent.conf b/pandora_agents/shellscript/aix/pandora_agent.conf index 6ca5613d16..fea0cb56db 100644 --- a/pandora_agents/shellscript/aix/pandora_agent.conf +++ b/pandora_agents/shellscript/aix/pandora_agent.conf @@ -1,6 +1,6 @@ # Fichero de configuracion base de agentes de Pandora # Base config file for Pandora agents -# Version 7.0NG.731, AIX version +# Version 7.0NG.735, AIX version # General Parameters # ================== diff --git a/pandora_agents/shellscript/bsd-ipso/pandora_agent.conf b/pandora_agents/shellscript/bsd-ipso/pandora_agent.conf index b55b3033f6..f0ce5b2519 100644 --- a/pandora_agents/shellscript/bsd-ipso/pandora_agent.conf +++ b/pandora_agents/shellscript/bsd-ipso/pandora_agent.conf @@ -1,6 +1,6 @@ # Fichero de configuracion base de agentes de Pandora # Base config file for Pandora agents -# Version 7.0NG.731 +# Version 7.0NG.735 # FreeBSD/IPSO version # Licenced under GPL licence, 2003-2007 Sancho Lerena diff --git a/pandora_agents/shellscript/hp-ux/pandora_agent.conf b/pandora_agents/shellscript/hp-ux/pandora_agent.conf index 4a5a240381..20cdfeff99 100644 --- a/pandora_agents/shellscript/hp-ux/pandora_agent.conf +++ b/pandora_agents/shellscript/hp-ux/pandora_agent.conf @@ -1,6 +1,6 @@ # Fichero de configuracion base de agentes de Pandora # Base config file for Pandora agents -# Version 7.0NG.731, HPUX Version +# Version 7.0NG.735, HPUX Version # General Parameters # ================== diff --git a/pandora_agents/shellscript/linux/DEBIAN/control b/pandora_agents/shellscript/linux/DEBIAN/control index d17817f5b8..55a5168f93 100755 --- a/pandora_agents/shellscript/linux/DEBIAN/control +++ b/pandora_agents/shellscript/linux/DEBIAN/control @@ -1,10 +1,10 @@ package: pandorafms-agent -Version: 4.0 +Version: 7.0 Architecture: all Priority: optional Section: admin Installed-Size: 260 -Maintainer: Miguel de Dios +Maintainer: ÁRTICA ST Homepage: http://pandorafms.org/ Depends: coreutils, perl Description: Pandora FMS agents are based on native languages in every platform: scripts that can be written in any language. It’s possible to reproduce any agent in any programming language and can be extended without difficulty the existing ones in order to cover aspects not taken into account up to the moment. These scripts are formed by modules that each one gathers a "chunk" of information. Thus, every agent gathers several "chunks" of information; this one is organized in a data set and stored in a single file, called data file. diff --git a/pandora_agents/shellscript/linux/pandora_agent.conf b/pandora_agents/shellscript/linux/pandora_agent.conf index 8e2600567a..e8ba9653ce 100644 --- a/pandora_agents/shellscript/linux/pandora_agent.conf +++ b/pandora_agents/shellscript/linux/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731 +# Version 7.0NG.735 # Licensed under GPL license v2, # (c) 2003-2010 Artica Soluciones Tecnologicas # please visit http://pandora.sourceforge.net diff --git a/pandora_agents/shellscript/mac_osx/pandora_agent.conf b/pandora_agents/shellscript/mac_osx/pandora_agent.conf index 8dfed3e54d..29d13ff75c 100644 --- a/pandora_agents/shellscript/mac_osx/pandora_agent.conf +++ b/pandora_agents/shellscript/mac_osx/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731 +# Version 7.0NG.735 # Licensed under GPL license v2, # (c) 2003-2009 Artica Soluciones Tecnologicas # please visit http://pandora.sourceforge.net diff --git a/pandora_agents/shellscript/openWRT/pandora_agent.conf b/pandora_agents/shellscript/openWRT/pandora_agent.conf index ca04eca187..8ef8a6fdc1 100644 --- a/pandora_agents/shellscript/openWRT/pandora_agent.conf +++ b/pandora_agents/shellscript/openWRT/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731 +# Version 7.0NG.735 # Licensed under GPL license v2, # please visit http://pandora.sourceforge.net diff --git a/pandora_agents/shellscript/solaris/pandora_agent.conf b/pandora_agents/shellscript/solaris/pandora_agent.conf index 563805acdb..1ace947818 100644 --- a/pandora_agents/shellscript/solaris/pandora_agent.conf +++ b/pandora_agents/shellscript/solaris/pandora_agent.conf @@ -1,6 +1,6 @@ # Fichero de configuracion base de agentes de Pandora # Base config file for Pandora agents -# Version 7.0NG.731, Solaris version +# Version 7.0NG.735, Solaris version # General Parameters # ================== diff --git a/pandora_agents/unix/AIX/pandora_agent.conf b/pandora_agents/unix/AIX/pandora_agent.conf index 9d787783ff..c67f64d16c 100644 --- a/pandora_agents/unix/AIX/pandora_agent.conf +++ b/pandora_agents/unix/AIX/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731, AIX version +# Version 7.0NG.735, AIX version # Licensed under GPL license v2, # Copyright (c) 2003-2010 Artica Soluciones Tecnologicas # http://www.pandorafms.com diff --git a/pandora_agents/unix/DEBIAN/control b/pandora_agents/unix/DEBIAN/control index c9e01190e9..84194913b7 100644 --- a/pandora_agents/unix/DEBIAN/control +++ b/pandora_agents/unix/DEBIAN/control @@ -1,10 +1,10 @@ package: pandorafms-agent-unix -Version: 7.0NG.731-190215 +Version: 7.0NG.735-190605 Architecture: all Priority: optional Section: admin Installed-Size: 260 -Maintainer: Miguel de Dios +Maintainer: ÁRTICA ST Homepage: http://pandorafms.org/ Depends: coreutils, perl, unzip Description: Pandora FMS agents are based on native languages in every platform: scripts that can be written in any language. It’s possible to reproduce any agent in any programming language and can be extended without difficulty the existing ones in order to cover aspects not taken into account up to the moment. These scripts are formed by modules that each one gathers a "chunk" of information. Thus, every agent gathers several "chunks" of information; this one is organized in a data set and stored in a single file, called data file. diff --git a/pandora_agents/unix/DEBIAN/make_deb_package.sh b/pandora_agents/unix/DEBIAN/make_deb_package.sh index f50b4ee8dc..c5aa33342d 100644 --- a/pandora_agents/unix/DEBIAN/make_deb_package.sh +++ b/pandora_agents/unix/DEBIAN/make_deb_package.sh @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pandora_version="7.0NG.731-190215" +pandora_version="7.0NG.735-190605" echo "Test if you has the tools for to make the packages." whereis dpkg-deb | cut -d":" -f2 | grep dpkg-deb > /dev/null diff --git a/pandora_agents/unix/Darwin/pandora_agent.conf b/pandora_agents/unix/Darwin/pandora_agent.conf index 2164faaedc..d7ee481255 100644 --- a/pandora_agents/unix/Darwin/pandora_agent.conf +++ b/pandora_agents/unix/Darwin/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731, GNU/Linux +# Version 7.0NG.735, GNU/Linux # Licensed under GPL license v2, # Copyright (c) 2003-2012 Artica Soluciones Tecnologicas # http://www.pandorafms.com diff --git a/pandora_agents/unix/FreeBSD/pandora_agent.conf b/pandora_agents/unix/FreeBSD/pandora_agent.conf index 0c5a190f9b..b02b379470 100644 --- a/pandora_agents/unix/FreeBSD/pandora_agent.conf +++ b/pandora_agents/unix/FreeBSD/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731, FreeBSD Version +# Version 7.0NG.735, FreeBSD Version # Licensed under GPL license v2, # Copyright (c) 2003-2016 Artica Soluciones Tecnologicas # http://www.pandorafms.com diff --git a/pandora_agents/unix/HP-UX/pandora_agent.conf b/pandora_agents/unix/HP-UX/pandora_agent.conf index f039431f7a..57e35c0a03 100644 --- a/pandora_agents/unix/HP-UX/pandora_agent.conf +++ b/pandora_agents/unix/HP-UX/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731, HP-UX Version +# Version 7.0NG.735, HP-UX Version # Licensed under GPL license v2, # Copyright (c) 2003-2009 Artica Soluciones Tecnologicas # http://www.pandorafms.com diff --git a/pandora_agents/unix/Linux/pandora_agent.conf b/pandora_agents/unix/Linux/pandora_agent.conf index df03402446..db07876f12 100644 --- a/pandora_agents/unix/Linux/pandora_agent.conf +++ b/pandora_agents/unix/Linux/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731, GNU/Linux +# Version 7.0NG.735, GNU/Linux # Licensed under GPL license v2, # Copyright (c) 2003-2014 Artica Soluciones Tecnologicas # http://www.pandorafms.com diff --git a/pandora_agents/unix/NT4/pandora_agent.conf b/pandora_agents/unix/NT4/pandora_agent.conf index 12421565e8..8cda0f8fe0 100644 --- a/pandora_agents/unix/NT4/pandora_agent.conf +++ b/pandora_agents/unix/NT4/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731, GNU/Linux +# Version 7.0NG.735, GNU/Linux # Licensed under GPL license v2, # Copyright (c) 2003-2009 Artica Soluciones Tecnologicas # http://www.pandorafms.com diff --git a/pandora_agents/unix/NetBSD/pandora_agent.conf b/pandora_agents/unix/NetBSD/pandora_agent.conf index 6dd394db7a..629fe6a6fb 100644 --- a/pandora_agents/unix/NetBSD/pandora_agent.conf +++ b/pandora_agents/unix/NetBSD/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731, NetBSD Version +# Version 7.0NG.735, NetBSD Version # Licensed under GPL license v2, # Copyright (c) 2003-2010 Artica Soluciones Tecnologicas # http://www.pandorafms.com diff --git a/pandora_agents/unix/SunOS/pandora_agent.conf b/pandora_agents/unix/SunOS/pandora_agent.conf index 3d7294a56a..8ff3c52de5 100644 --- a/pandora_agents/unix/SunOS/pandora_agent.conf +++ b/pandora_agents/unix/SunOS/pandora_agent.conf @@ -1,5 +1,5 @@ # Base config file for Pandora FMS agents -# Version 7.0NG.731, Solaris Version +# Version 7.0NG.735, Solaris Version # Licensed under GPL license v2, # Copyright (c) 2003-2009 Artica Soluciones Tecnologicas # http://www.pandorafms.com diff --git a/pandora_agents/unix/pandora_agent b/pandora_agents/unix/pandora_agent index 187f94b41d..8fefec9ec8 100755 --- a/pandora_agents/unix/pandora_agent +++ b/pandora_agents/unix/pandora_agent @@ -41,8 +41,8 @@ my $Sem = undef; # Semaphore used to control the number of threads my $ThreadSem = undef; -use constant AGENT_VERSION => '7.0NG.731'; -use constant AGENT_BUILD => '190215'; +use constant AGENT_VERSION => '7.0NG.735'; +use constant AGENT_BUILD => '190605'; # Agent log default file size maximum and instances use constant DEFAULT_MAX_LOG_SIZE => 600000; @@ -536,6 +536,12 @@ sub parse_conf_modules($) { # Check for invalid modules next unless (($module->{'name'} ne '' && $module->{'func'} != 0) || $module->{'func'} == \&module_plugin); + # Skip disabled modules. + if (defined($module->{'disabled'}) && $module->{'disabled'} == 1) { + log_message('setup', 'Skipping disabled module "' . $module->{'name'} . '"'); + next; + } + # Set the intensive interval if ($module->{'is_intensive'} == 1) { $module->{'intensive_interval'} = $module->{'interval'}; @@ -662,6 +668,8 @@ sub parse_conf_modules($) { $module->{'ff_timeout'} = $1; } elsif ($line =~ /^\s*module_each_ff\s+(\S+)\s*$/) { $module->{'each_ff'} = $1; + } elsif ($line =~ /^\s*module_ff_type\s+(\d+)\s*$/) { + $module->{'ff_type'} = $1; # Macros } elsif ($line =~ /^\s*module_macro(\S+)\s+(.*)\s*$/) { $module->{'macros'}{$1} = $2; @@ -1073,6 +1081,10 @@ sub send_buffered_xml_files ($;$) { unlink ("$temporal_file/$xml_file"); } } + # Do not get stuck trying to send buffered XML files to a secondary server. + elsif ($flag_always == 2) { + last; + } } if (defined($flag_always) && ($flag_always == 2)){ swap_servers (); @@ -2101,45 +2113,28 @@ sub cron_next_execution { } # Get day of the week and month from cron config - my ($mday, $wday) = (split (/\s/, $cron))[2, 4]; + my ($wday) = (split (/\s/, $cron))[4]; + # Check the wday values to avoid infinite loop + my ($wday_down, $wday_up) = cron_get_interval($wday); + if ($wday_down ne "*" && ($wday_down > 6 || (defined($wday_up) && $wday_up > 6))) { + log_message('setup', "Invalid cron configuration $cron. Day of the week is out of limits."); + $wday = "*"; + } # Get current time and day of the week my $cur_time = time(); my $cur_wday = (localtime ($cur_time))[6]; - # Any day of the week - if ($wday eq '*') { - my $nex_time = cron_next_execution_date ($cron, $cur_time, $interval); - return $nex_time - time(); - } - # A range? - else { - $wday = cron_get_closest_in_range ($cur_wday, $wday); + my $nex_time = cron_next_execution_date ($cron, $cur_time, $interval); + + # Check the day + while (!cron_check_interval($wday, (localtime ($nex_time))[6])) { + # If it does not acomplish the day of the week, go to the next day. + $nex_time += 86400; + $nex_time = cron_next_execution_date ($cron, $nex_time, 0); } - # A specific day of the week - my $count = 0; - my $nex_time = $cur_time; - do { - $nex_time = cron_next_execution_date ($cron, $nex_time, $interval); - my $nex_time_wd = $nex_time; - my ($nex_mon, $nex_wday) = (localtime ($nex_time_wd))[4, 6]; - my $nex_mon_wd; - do { - # Check the day of the week - if ($nex_wday == $wday) { - return $nex_time_wd - time(); - } - - # Move to the next day of the month - $nex_time_wd += 86400; - ($nex_mon_wd, $nex_wday) = (localtime ($nex_time_wd))[4, 6]; - } while ($mday eq '*' && $nex_mon_wd == $nex_mon); - $count++; - } while ($count < 60); - - # Something went wrong, default to 5 minutes - return $interval; + return $nex_time - time(); } ############################################################################### @@ -2151,7 +2146,30 @@ sub cron_check_syntax ($) { return 0 if !defined ($cron); return ($cron =~ m/^(\d|\*|-)+ (\d|\*|-)+ (\d|\*|-)+ (\d|\*|-)+ (\d|\*|-)+$/); } +############################################################################### +# Check if a value is inside an interval. +############################################################################### +sub cron_check_interval { + my ($elem_cron, $elem_curr_time) = @_; + # Return 1 if wildcard. + return 1 if ($elem_cron eq "*"); + + my ($down, $up) = cron_get_interval($elem_cron); + # Check if it is not a range + if (!defined($up)) { + return ($down == $elem_curr_time) ? 1 : 0; + } + + # Check if it is on the range + if ($down < $up) { + return 0 if ($elem_curr_time < $down || $elem_curr_time > $up); + } else { + return 0 if ($elem_curr_time > $down || $elem_curr_time < $up); + } + + return 1; +} ############################################################################### # Get the next execution date for the given cron entry in seconds since epoch. ############################################################################### @@ -2189,8 +2207,7 @@ sub cron_next_execution_date { my @nex_time_array = @curr_time_array; # Update minutes - my ($min_down, undef) = cron_get_interval ($min); - $nex_time_array[0] = ($min_down eq '*') ? 0 : $min_down; + $nex_time_array[0] = cron_get_next_time_element($min); $nex_time = cron_valid_date(@nex_time_array, $cur_year); if ($nex_time >= $cur_time) { @@ -2224,8 +2241,7 @@ sub cron_next_execution_date { return $nex_time if cron_is_in_cron(\@cron_array, \@nex_time_array); #Update the hour if fails - my ($hour_down, undef) = cron_get_interval ($hour); - $nex_time_array[1] = ($hour_down eq '*') ? 0 : $hour_down; + $nex_time_array[1] = cron_get_next_time_element($hour); # When an overflow is passed check the hour update again $nex_time = cron_valid_date(@nex_time_array, $cur_year); @@ -2253,10 +2269,9 @@ sub cron_next_execution_date { return $nex_time if cron_is_in_cron(\@cron_array, \@nex_time_array); #Update the day if fails - my ($mday_down, undef) = cron_get_interval ($mday); - $nex_time_array[2] = ($mday_down eq '*') ? 1 : $mday_down; + $nex_time_array[2] = cron_get_next_time_element($mday, 1); - # When an overflow is passed check the day update in the next execution + # When an overflow is passed check the hour update in the next execution $nex_time = cron_valid_date(@nex_time_array, $cur_year); if ($nex_time >= $cur_time) { return $nex_time if cron_is_in_cron(\@cron_array, \@nex_time_array); @@ -2276,8 +2291,7 @@ sub cron_next_execution_date { return $nex_time if cron_is_in_cron(\@cron_array, \@nex_time_array); #Update the month if fails - my ($mon_down, undef) = cron_get_interval ($mon); - $nex_time_array[3] = ($mon_down eq '*') ? 0 : $mon_down; + $nex_time_array[3] = cron_get_next_time_element($mon); # When an overflow is passed check the month update in the next execution $nex_time = cron_valid_date(@nex_time_array, $cur_year); @@ -2308,23 +2322,30 @@ sub cron_is_in_cron { #If there is no elements means that is in cron return 1 unless (defined($elem_cron) || defined($elem_curr_time)); - # Go to last element if current is a wild card - if ($elem_cron ne '*') { - my ($down, $up) = cron_get_interval($elem_cron); - # Check if there is no a range - return 0 if (!defined($up) && ($down != $elem_curr_time)); - # Check if there is on the range - if (defined($up)) { - if ($down < $up) { - return 0 if ($elem_curr_time < $down || $elem_curr_time > $up); - } else { - return 0 if ($elem_curr_time > $down || $elem_curr_time < $up); - } - } - } + # Check the element interval + return 0 unless (cron_check_interval($elem_cron, $elem_curr_time)); + return cron_is_in_cron(\@deref_elems_cron, \@deref_elems_curr_time); } +################################################################################ +#Get the next tentative time for a cron value or interval in case of overflow. +#Floor data is the minimum localtime data for a position. Ex: +#Ex: +# * should returns floor data. +# 5 should returns 5. +# 10-55 should returns 10. +# 55-10 should retunrs floor data. +################################################################################ +sub cron_get_next_time_element { + # Default floor data is 0 + my ($curr_element, $floor_data) = @_; + $floor_data = 0 unless defined($floor_data); + my ($elem_down, $elem_up) = cron_get_interval ($curr_element); + return ($elem_down eq '*' || (defined($elem_up) && $elem_down > $elem_up)) + ? $floor_data + : $elem_down; +} ############################################################################### # Returns the interval of a cron element. If there is not a range, # returns an array with the first element in the first place of array @@ -2416,12 +2437,11 @@ sub check_module_cron { return 1 unless ($is_first); # Check if current timestamp is a valid cron date - my $next_execution = cron_next_execution_date( + my $next_execution = cron_next_execution( $module->{'cron'}, - $now - $interval, - $interval + 0 ); - return 1 if ($next_execution == $now); + return 1 if (time() + $next_execution == $now); return 0; } @@ -2532,6 +2552,7 @@ sub write_module_xml ($@) { $Xml .= " " . $module->{'min_ff_event_critical'} . "\n" if (defined ($module->{'min_ff_event_critical'})); $Xml .= " " . $module->{'ff_timeout'} . "\n" if (defined ($module->{'ff_timeout'})); $Xml .= " " . $module->{'each_ff'} . "\n" if (defined ($module->{'each_ff'})); + $Xml .= " " . $module->{'ff_type'} . "\n" if (defined ($module->{'ff_type'})); # Data list if ($#data > 0) { diff --git a/pandora_agents/unix/pandora_agent.redhat.spec b/pandora_agents/unix/pandora_agent.redhat.spec index 16bf75ef2f..0ca9923632 100644 --- a/pandora_agents/unix/pandora_agent.redhat.spec +++ b/pandora_agents/unix/pandora_agent.redhat.spec @@ -2,8 +2,8 @@ #Pandora FMS Linux Agent # %define name pandorafms_agent_unix -%define version 7.0NG.731 -%define release 190215 +%define version 7.0NG.735 +%define release 190605 Summary: Pandora FMS Linux agent, PERL version Name: %{name} diff --git a/pandora_agents/unix/pandora_agent.spec b/pandora_agents/unix/pandora_agent.spec index 1dd06bf43e..a4fc651f2d 100644 --- a/pandora_agents/unix/pandora_agent.spec +++ b/pandora_agents/unix/pandora_agent.spec @@ -2,8 +2,8 @@ #Pandora FMS Linux Agent # %define name pandorafms_agent_unix -%define version 7.0NG.731 -%define release 190215 +%define version 7.0NG.735 +%define release 190605 Summary: Pandora FMS Linux agent, PERL version Name: %{name} diff --git a/pandora_agents/unix/pandora_agent_installer b/pandora_agents/unix/pandora_agent_installer index 340a0c2712..ff2c1c7d80 100755 --- a/pandora_agents/unix/pandora_agent_installer +++ b/pandora_agents/unix/pandora_agent_installer @@ -9,8 +9,8 @@ # Please see http://www.pandorafms.org. This code is licensed under GPL 2.0 license. # ********************************************************************** -PI_VERSION="7.0NG.731" -PI_BUILD="190215" +PI_VERSION="7.0NG.735" +PI_BUILD="190605" OS_NAME=`uname -s` FORCE=0 diff --git a/pandora_agents/unix/plugins/inventory b/pandora_agents/unix/plugins/inventory index a6d9a8bc83..6ef6233d23 100755 --- a/pandora_agents/unix/plugins/inventory +++ b/pandora_agents/unix/plugins/inventory @@ -4,23 +4,44 @@ # Copyright (c) 2009 Artica Soluciones Tecnologicas S.L. # # inventory Generate a hardware/software inventory. -# +# # Sample usage: ./inventory [cpu] [ram] [video] [nic] [hd] [cdrom] [software] [init_services] [filesystem] [process] [users] # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# GNU General Public License for more details. # ############################################################################### use strict; use constant TSTAMP_FILE => '/tmp/pandora_inventory.tstamp'; +use Scalar::Util qw(looks_like_number); +use Data::Dumper; +# Set environment language to English +$ENV{"LANG"} = "en_US"; + +# Check AIX system +my $AIX=0; +my $system = `uname -a | awk '{print $1}'`; +if ($system =~ 'AIX') { + $AIX=1; +} + +sub is_enabled { + my $value = shift; + if ((defined ($value)) && looks_like_number($value) && ($value > 0)){ + # return true + return 1; + } + #return false + return 0; +} # Operation mode (LSHW or HWINFO) my $Mode; @@ -31,12 +52,12 @@ my $Separator; sub get_module_data ($$$$) { my ($name, $hwinfo, $keys, $modules) = @_; my %module; - - # Store keys + $Separator='\s+\*\-'; + # Store keys foreach my $key (@{$keys}) { push (@{$module{'_keys'}}, $key); } - + # Parse module data while (my $line = shift (@{$hwinfo})) { if ($line =~ /$Separator/) { @@ -46,7 +67,7 @@ sub get_module_data ($$$$) { foreach my $key (@{$keys}) { if ($line =~ /$key:\s+(.+)/) { $module{$key} = $1; - # Replace semicolon by comma to avoid parse errors + # Replace semicolon by comma to avoid parse errors $module{$key} =~ s/;/,/g; } } @@ -58,12 +79,65 @@ sub get_module_data ($$$$) { push (@{$modules->{$name}}, \%module); } +sub test_contain ($$) { + my ($value, $array)=@_; + if ( grep( /$value/, @{$array} ) ) { + return 1; + } +} +sub get_module_data_aix_ram_cpu ($$$$) { + my ($name, $hwinfo, $keys, $modules) = @_; + my %module; + # Store keys + foreach my $key (@{$keys}) { + push (@{$module{'_keys'}}, $key); + } + # Parse module data + foreach my $line (@{$hwinfo}) { + foreach my $key (@{$keys}) { + if ($line =~ /$key:\s+(.+)/) { + $module{$key} = $1; + $module{$key} =~ s/,/ /g; + } + } + } + + # No data found + #my @data = keys (%module); + #return unless ($#data >= 0); + + push (@{$modules->{$name}}, \%module); +} +sub get_module_data_aix ($$$$) { + my ($name,$hwinfo,$regex,$modules) = @_; + my %module; + foreach my $line (@{$hwinfo}) { + $line =~ s/\s{2,}/;/g; + $line =~ s/\+ //g; + $line =~ s/\* //g; + } + foreach my $line (@{$hwinfo}) { + if ($line =~ /$regex/){ + my ($var1, $var2, $var3) = split /;/, $line; + my %module; + $module{'device'} = $var1; + $module{'serial'} = $var2; + $module{'description'}=$var3; + $module{'_keys'} = ['device','serial','description']; + push (@{$modules->{$name}}, \%module); + } + } +} # Get a list of information file system in machine sub get_file_system($$) { my ($name, $modules) = @_; - - my @fileSystems = `df -hP | tail -n +2`; #remove the titles of columns + my @fileSystems; + if (is_enabled $AIX){ + @fileSystems = `df -gP | tail -n +2`; + } else { + @fileSystems = `df -hP | tail -n +2`; #remove the titles of columns + } foreach my $row (@fileSystems) { next unless ($row =~ /^(\S+)\s+\S+\s+(\S+)\s+(\S+)\s+\S+\s+(\S+)/); @@ -73,94 +147,110 @@ sub get_file_system($$) { $module{'used'} = $2; $module{'avail'} = $3; $module{'mount'} = $4; - $module{'_keys'} = ['filesystem', 'used','avail', 'mount']; - push (@{$modules->{$name}}, \%module); - } + $module{'_keys'} = ['filesystem', 'used','avail', 'mount']; + push (@{$modules->{$name}}, \%module); + } } # Get a list of services init in machine sub get_servicies_init_machine($$) { my ($name, $modules) = @_; - my $runlevel = `who -r | awk '{print \$2}'`; + my $runlevel; + if (is_enabled $AIX) { + $runlevel = `who -r | awk '{print \$3}'`; + } else { + $runlevel = `who -r | awk '{print \$2}'`; + } #ini trim($runlevel) $runlevel =~ s/^\s*//; #ltrim $runlevel =~ s/\s*$//; #rtrim #end trim($runlevel) - my $script = ""; - + my $script; + if (-e "/etc/rc" . $runlevel .".d/") { - $script = "ls /etc/rc" . $runlevel .".d/ -l | grep \"^l.*\" | awk \"{print \\\$NF}\" | sed -e \"s/\\.\\.\\///g\" | sed -e \"s/.*init\\.d\\///g\""; + $script = "ls -l /etc/rc" . $runlevel .".d/ | grep \"^l.*\" | awk \"{print \\\$NF}\" | sed -e \"s/\\.\\.\\///g\" | sed -e \"s/.*init\\.d\\///g\""; } else { - $script = "ls /etc/rc.d/rc" . $runlevel .".d/ -l | grep \"^l.*\" | grep \" S.* \" | awk \"{print \\\$NF}\" | sed -e \"s/\\.\\.\\///g\" | sed -e \"s/.*init\\.d\\///g\""; - + $script = "ls -l /etc/rc.d/rc" . $runlevel .".d/ | grep \"^l.*\" | grep \" S.* \" | awk \"{print \\\$NF}\" | sed -e \"s/\\.\\.\\///g\" | sed -e \"s/.*init\\.d\\///g\""; } - + my @services = `$script`; foreach my $row (@services) { - my %module; - $row =~ s/\n//; - $module{'service'} = $row; - $module{'_keys'} = ['service']; - push (@{$modules->{$name}}, \%module); + $row =~ s/\n//; + $module{'service'} = $row; + $module{'_keys'} = ['service']; + push (@{$modules->{$name}}, \%module); } } # Get a list of running processes sub get_processes ($$) { my ($name, $modules) = @_; + my $script; + if (is_enabled $AIX) { + $script = "ps -eo args | tail -n +2"; + } else { + $script = "ps -eo command | tail -n +2"; + } - my $script = "ps -eo command"; - - my @services = `$script`; - foreach my $row (@services) { - my %module; - # Remove carriage returns - $row =~ s/[\n\l\f]//g; - # Replace semicolon by comma to avoid parse errors - $row =~ s/;/,/g; - $module{'service'} = $row; - $module{'_keys'} = ['service']; - push (@{$modules->{$name}}, \%module); - } + my @services = `$script`; + foreach my $row (@services) { + my %module; + # Remove carriage returns + $row =~ s/[\n\l\f]//g; + # Replace semicolon by comma to avoid parse errors + $row =~ s/;/,/g; + $module{'service'} = $row; + $module{'_keys'} = ['service']; + push (@{$modules->{$name}}, \%module); + } } # Get a list of valid users in the system sub get_users ($$) { - my ($name, $modules) = @_; - - my $script = "cat /etc/passwd"; + my ($name, $modules) = @_; + my $script = "cat /etc/passwd"; my $user = ""; my $estado = ""; - my @services = `$script`; - foreach my $row (@services) { - my %module; + my @services = `$script`; + foreach my $row (@services) { + my %module; - next unless ($row =~ /^([A-Za-z0-9\-\_]*)/); - - $user = $1; - $script = `passwd -S $user`; - if ( $script =~ /^(\S+)\sP./){ - $module{'user'} = $user; - $module{'_keys'} = ['user']; - push (@{$modules->{$name}}, \%module); + next unless ($row =~ /^([A-Za-z0-9\-\_]*)/); + if (is_enabled $AIX) { + $user = $1; + $script = `lsuser $user`; + if ( $script =~ /^(\S+)\sid./){ + $module{'user'} = $user; + $module{'_keys'} = ['user']; + push (@{$modules->{$name}}, \%module); + } + } else { + $user = $1; + $script = `passwd -S $user`; + if ( $script =~ /^(\S+)\sP./){ + $module{'user'} = $user; + $module{'_keys'} = ['user']; + push (@{$modules->{$name}}, \%module); } } + + } } # Show Kernel Information sub get_kernel_info ($$) { - my ($name, $modules) = @_; - my $script = `uname -a | tr -d \";\"`; - my %module; + my ($name, $modules) = @_; + my $script = `uname -a | tr -d \";\"`; + my %module; - $module{'Kernel'} = $script; - $module{'_keys'} = ['Kernel']; - push (@{$modules->{$name}}, \%module); + $module{'Kernel'} = $script; + $module{'_keys'} = ['Kernel']; + push (@{$modules->{$name}}, \%module); } @@ -171,11 +261,13 @@ sub get_software_module_data ($$) { # Guess the current distribution my $distrib_id = ""; - if ( -e "/etc/SuSE-release"){ + if (is_enabled $AIX) { + $distrib_id = "AIX"; + }elsif ( -e "/etc/SuSE-release"){ $distrib_id = "SUSE"; - } elsif ( -e "/etc/redhat-release"){ + }elsif ( -e "/etc/redhat-release"){ $distrib_id = "REDHAT"; - } else { + }else { $distrib_id = "DEBIAN"; } @@ -183,7 +275,9 @@ sub get_software_module_data ($$) { my @soft; if ($distrib_id eq 'DEBIAN') { @soft = `dpkg -l | grep ii`; - } else { + }elsif ($distrib_id eq 'AIX') { + @soft = `lslpp -Lcq | awk -F: '{print "ii "\$1" "\$3" "\$8}'`; + }else { # Sometimes rpm return data splitted in two lines, and with dupes. Thats bad for our inventory system @soft = `rpm -q -a --qf "ii %{NAME} %{VERSION} %{SUMMARY}\n" | grep "^ii" | sort -u`; } @@ -197,7 +291,7 @@ sub get_software_module_data ($$) { $module{'program'} = $1; $module{'version'} = $2; $module{'description'} = $3; - # Replace semicolon by comma to avoid parse errors + # Replace semicolon by comma to avoid parse errors $module{'program'} =~ s/;/,/g; $module{'version'} =~ s/;/,/g; $module{'description'} =~ s/;/,/g; @@ -211,67 +305,95 @@ sub get_software_module_data ($$) { #Get the list of interfaces with the ip assigned sub get_ips ($$) { my ($name, $modules) = @_; + my @interfaces; + my $ifconfig; + if (is_enabled $AIX) { + $ifconfig = `ifconfig -a`; + } else { + $ifconfig = `ifconfig`; + } - my $ifconfig = `ifconfig`; - - my @ifconfig_array = split("\n", $ifconfig); - - for(my $i = 0; $i<$#ifconfig_array; $i++) { - - #Check for an interface - if ($ifconfig_array[$i] =~ /Link/) { - my %info; - - my @line_split = split(" ", $ifconfig_array[$i]); - - #Get interface name - $info{'interface'} = $line_split[0]; - #Get IP address - my $line = $ifconfig_array[$i+1]; - - $line =~ s/\s+//g; + my @ifconfig_array = split("\n", $ifconfig); - @line_split = split(":", $line); - - if($line_split[1] =~ /(\d+\.\d+\.\d+\.\d+).+/) { - $info{'ip'} = $1; - } - - $info{'_keys'} = ['interface', 'ip']; - push (@{$modules->{$name}}, \%info); - - } + foreach (@ifconfig_array){ + if ($_=~/(.*)flags/){ + my $match; + ($match)=$_=~/^(.*?)\: flags/; + $match=~s/://; + push @interfaces,$match; + } + } + foreach (@interfaces) { + my $ifconfig_item=`ifconfig $_`; + my $interface=$_; + my @ip_array = split("\n", $ifconfig_item); + foreach (@ip_array) { + if ($_=~/(?<=inet )(.*)(?= netmask)/){ + my $ip; + ($ip)=$_=~/inet (.*) netmask/; + my %info; + $info{'interface'} = $interface; + $info{'ip'} = $ip; + $info{'_keys'} = ['interface','ip']; + push (@{$modules->{$name}}, \%info); + } + } } } #Get route table sub get_route_table ($$) { - my ($name, $modules) = @_; - - my $route_table = `route`; - - my @table_split = split("\n", $route_table); - - for (my $i=2; $i<=$#table_split; $i++) { - - my @split = split(" ", $table_split[$i]); - - my %info; - - $info{'destination'} = $split[0]; - $info{'gateway'} = $split[1]; - $info{'mask'} = $split[2]; - $info{'flags'} = $split[3]; - $info{'metric'} = $split[4]; - $info{'ref'} = $split[5]; - $info{'use'} = $split[6]; - $info{'interface'} = $split[7]; - - $info{'_keys'} = ['destination', 'gateway', 'mask', 'flags', 'metric', 'use', 'interface']; - - push (@{$modules->{$name}}, \%info); - } + my ($name, $modules) = @_; + my $route_table; + my @table_split; + if (is_enabled $AIX) { + $route_table = `netstat -rn`; + @table_split = split("\n", $route_table); + my $length=scalar @table_split; + for (my $i=4; $i<=$length-4; $i++) { + + my @split = split(" ", $table_split[$i]); + + my %info; + + $info{'destination'} = $split[0]; + $info{'gateway'} = $split[1]; + $info{'mask'} = $split[2]; + $info{'flags'} = $split[3]; + $info{'metric'} = $split[4]; + $info{'ref'} = $split[5]; + $info{'use'} = $split[6]; + $info{'interface'} = $split[7]; + + $info{'_keys'} = ['destination', 'gateway', 'mask', 'flags', 'metric', 'use', 'interface']; + + push (@{$modules->{$name}}, \%info); + } + } else { + $route_table = `route`; + my @table_split = split("\n", $route_table); + + for (my $i=2; $i<=$#table_split; $i++) { + + my @split = split(" ", $table_split[$i]); + + my %info; + + $info{'destination'} = $split[0]; + $info{'gateway'} = $split[1]; + $info{'mask'} = $split[2]; + $info{'flags'} = $split[3]; + $info{'metric'} = $split[4]; + $info{'ref'} = $split[5]; + $info{'use'} = $split[6]; + $info{'interface'} = $split[7]; + + $info{'_keys'} = ['destination', 'gateway', 'mask', 'flags', 'metric', 'use', 'interface']; + + push (@{$modules->{$name}}, \%info); + } + } } # Print module data sub print_module ($$) { @@ -309,14 +431,18 @@ my $enable_all = 0; $interval = $ARGV[0]; if ($#ARGV == 0){ - $enable_all = 1; + $enable_all = 1; +} +if ($interval!=/[:alpha:]/){ + splice @ARGV,0,1; } -foreach my $module (@ARGV) { +foreach my $module (@ARGV) { if ($module eq "all"){ - $enable_all = 1; - } - $enabled{$module} = 1; + $enable_all = 1; + }else { + $enabled{$module} = 1; + } } # Check execution interval @@ -333,76 +459,107 @@ close (FILE); # Retrieve hardware information $Mode = 'LSHW'; $Separator = '\s+\*\-'; -my @hwinfo = `lshw 2>/dev/null`; -if ($? != 0) { - $Mode = 'HWINFO'; - $Separator = 'Hardware Class:'; - @hwinfo = `hwinfo --cpu --memory --gfxcard --netcard --cdrom --disk 2>/dev/null`; +my @hwinfo; +if (is_enabled $AIX) { + $Separator = '^\s*$'; + @hwinfo=`prtconf 2>/dev/null`; +} else { + @hwinfo = `lshw 2>/dev/null`; + if ($? != 0) { + $Mode = 'HWINFO'; + $Separator = 'Hardware Class:'; + @hwinfo = `hwinfo --cpu --memory --gfxcard --netcard --cdrom --disk 2>/dev/null`; + } } -# Parse hardware information my %modules; -while (my $line = shift (@hwinfo)) { + + if (is_enabled $AIX) { + #CPU + # VIDEO + ### Not avilable in AIX ### + # NIC + ### Not relevant in AIX ### + if ((test_contain('ent',\@hwinfo)) && ($enable_all == 1 || $enabled{'nic'} == 1)) { + get_module_data_aix ('NIC',\@hwinfo,'^ent',\%modules); + } + if ((test_contain('hdisk',\@hwinfo)) && ($enable_all == 1 || $enabled{'hd'} == 1)) { + get_module_data_aix ('HD',\@hwinfo,'^hdisk',\%modules); + } + + foreach my $line (@hwinfo) { + chomp ($line); + #CPU + if (($line =~ /^Memory Size:/) && ($enable_all == 1 || $enabled{'ram'} == 1)) { + get_module_data_aix_ram_cpu ('RAM', \@hwinfo, ['Memory Size','Good Memory Size'], \%modules); + } + + if (($line =~ /^System Model/) && ($enable_all == 1 || $enabled{'cpu'} == 1)) { + get_module_data_aix_ram_cpu ('CPU', \@hwinfo, ['System Model', 'Processor Implementation Mode', 'Number Of Processors'], \%modules); + } + } +} else { + # Parse hardware information + while (my $line= shift (@hwinfo)) { chomp ($line); + # CPU + if (($line =~ /\*\-cpu/ || $line =~ /Hardware Class: cpu/) && ($enable_all == 1 || $enabled{'cpu'} == 1)) { + if ($Mode eq 'LSHW') { + get_module_data ('CPU', \@hwinfo, ['product', 'vendor', 'capacity'], \%modules); + } else { + get_module_data ('CPU', \@hwinfo, ['Model', 'Vendor', 'Clock'], \%modules); + } + } - # CPU - if (($line =~ /\*\-cpu/ || $line =~ /Hardware Class: cpu/) && ($enable_all == 1 || $enabled{'cpu'} == 1)) { - if ($Mode eq 'LSHW') { - get_module_data ('CPU', \@hwinfo, ['product', 'vendor', 'capacity'], \%modules); - } else { - get_module_data ('CPU', \@hwinfo, ['Model', 'Vendor', 'Clock'], \%modules); - } - } + # RAM + if (($line =~ /\*\-bank/ || $line =~ /\*\-memory/ || $line =~ /Hardware Class: memory/) && ($enable_all == 1 || $enabled{'ram'} == 1)) { + if ($Mode eq 'LSHW') { + get_module_data ('RAM', \@hwinfo, ['description', 'size'], \%modules); + } else { + get_module_data ('RAM', \@hwinfo, ['Model', 'Memory Size'], \%modules); + } + } - # RAM - if (($line =~ /\*\-bank/ || $line =~ /Hardware Class: memory/) && ($enable_all == 1 || $enabled{'ram'} == 1)) { - if ($Mode eq 'LSHW') { - get_module_data ('RAM', \@hwinfo, ['description', 'size'], \%modules); - } else { - get_module_data ('RAM', \@hwinfo, ['Model', 'Memory Size'], \%modules); - } - } + # VIDEO + if (($line =~ /\*\-display/ || $line =~ /Hardware Class: graphics card/) && ($enable_all == 1 || $enabled{'video'} == 1)) { + if ($Mode eq 'LSHW') { + get_module_data ('VIDEO', \@hwinfo, ['product', 'description', 'vendor'], \%modules); + } else { + # Spaces before Device and Vendor are intentional to avoid matching SubDevice and SubVendor + get_module_data ('VIDEO', \@hwinfo, ['Model', ' Device', ' Vendor'], \%modules); + } + } - # VIDEO - if (($line =~ /\*\-display/ || $line =~ /Hardware Class: graphics card/) && ($enable_all == 1 || $enabled{'video'} == 1)) { - if ($Mode eq 'LSHW') { - get_module_data ('VIDEO', \@hwinfo, ['product', 'description', 'vendor'], \%modules); - } else { - # Spaces before Device and Vendor are intentional to avoid matching SubDevice and SubVendor - get_module_data ('VIDEO', \@hwinfo, ['Model', ' Device', ' Vendor'], \%modules); - } - } + # NIC + if (($line =~ /\*\-network/ || $line =~ /Hardware Class: network/) && ($enable_all == 1 || $enabled{'nic'} == 1)) { + if ($Mode eq 'LSHW') { + get_module_data ('NIC', \@hwinfo, ['product', 'description', 'vendor', 'serial'], \%modules); + } else { + # Spaces before Device and Vendor are intentional to avoid matching SubDevice and SubVendor + get_module_data ('NIC', \@hwinfo, ['Model', ' Device', ' Vendor', 'HW Address'], \%modules); + } + } - # NIC - if (($line =~ /\*\-network/ || $line =~ /Hardware Class: network/) && ($enable_all == 1 || $enabled{'nic'} == 1)) { - if ($Mode eq 'LSHW') { - get_module_data ('NIC', \@hwinfo, ['product', 'description', 'vendor', 'serial'], \%modules); - } else { - # Spaces before Device and Vendor are intentional to avoid matching SubDevice and SubVendor - get_module_data ('NIC', \@hwinfo, ['Model', ' Device', ' Vendor', 'HW Address'], \%modules); - } - } - - # CDROM - if (($line =~ /\*\-cdrom/ || $line =~ /Hardware Class: cdrom/) && ($enable_all == 1 || $enabled{'cdrom'} == 1)) { - if ($Mode eq 'LSHW') { - get_module_data ('CDROM', \@hwinfo, ['product', 'description', 'vendor'], \%modules); - } else { - # Spaces before Device and Vendor are intentional to avoid matching SubDevice and SubVendor - get_module_data ('CDROM', \@hwinfo, ['Model', ' Device', ' Vendor'], \%modules); - } - } + # CDROM + if (($line =~ /\*\-cdrom/ || $line =~ /Hardware Class: cdrom/) && ($enable_all == 1 || $enabled{'cdrom'} == 1)) { + if ($Mode eq 'LSHW') { + get_module_data ('CDROM', \@hwinfo, ['product', 'description', 'vendor'], \%modules); + } else { + # Spaces before Device and Vendor are intentional to avoid matching SubDevice and SubVendor + get_module_data ('CDROM', \@hwinfo, ['Model', ' Device', ' Vendor'], \%modules); + } + } - # HD - if (($line =~ /\*\-disk/ || $line =~ /Hardware Class: disk/) && ($enable_all == 1 || $enabled{'hd'} == 1)) { - if ($Mode eq 'LSHW') { - get_module_data ('HD', \@hwinfo, ['product', 'description', 'size'], \%modules); - } else { - get_module_data ('HD', \@hwinfo, ['Model', 'Serial ID', 'Size'], \%modules); - } - } + # HD + if (($line =~ /\*\-disk/ || $line =~ /Hardware Class: disk/) && ($enable_all == 1 || $enabled{'hd'} == 1)) { + if ($Mode eq 'LSHW') { + get_module_data ('HD', \@hwinfo, ['product', 'description', 'size'], \%modules); + } else { + get_module_data ('HD', \@hwinfo, ['Model', 'Serial ID', 'Size'], \%modules); + } + } + } } - # Software if ($enable_all == 1 || $enabled{'software'} == 1) { get_software_module_data ('Software', \%modules); @@ -410,12 +567,12 @@ if ($enable_all == 1 || $enabled{'software'} == 1) { #init_services if ($enable_all == 1 || $enabled{'init_services'} == 1) { - get_servicies_init_machine ('Init services', \%modules); + get_servicies_init_machine ('Init_services', \%modules); } #filesystem if ($enable_all == 1 || $enabled{'filesystem'} == 1) { - get_file_system('File system', \%modules); + get_file_system('Filesystem', \%modules); } #processes @@ -442,7 +599,6 @@ if ($enable_all == 1 || $enabled{'route'} == 1) { if ($enable_all == 1 || $enabled{'kernel'} == 1){ get_kernel_info ('Kernel', \%modules); } - # Print module data print "\n"; while (my ($name, $module) = each (%modules)) { diff --git a/pandora_agents/win32/bin/pandora_agent.conf b/pandora_agents/win32/bin/pandora_agent.conf index aab9a2f315..518cd3df0e 100644 --- a/pandora_agents/win32/bin/pandora_agent.conf +++ b/pandora_agents/win32/bin/pandora_agent.conf @@ -1,6 +1,6 @@ # Base config file for Pandora FMS Windows Agent # (c) 2006-2017 Artica Soluciones Tecnologicas -# Version 7.0NG.731 +# Version 7.0NG.735 # This program is Free Software, you can redistribute it and/or modify it # under the terms of the GNU General Public Licence as published by the Free Software @@ -44,6 +44,8 @@ remote_config 0 #agent_name_cmd cscript.exe //B "%ProgramFiles%\Pandora_Agent\util\agentname.vbs" agent_name_cmd __rand__ +# Agent alias. Name should be unique rather than alias. Hostname by default +# agent_alias $Alias$ #Parent agent_name #parent_agent_name caprica diff --git a/pandora_agents/win32/installer/pandora.mpi b/pandora_agents/win32/installer/pandora.mpi index b7dff2f2ec..a195ab96ee 100644 --- a/pandora_agents/win32/installer/pandora.mpi +++ b/pandora_agents/win32/installer/pandora.mpi @@ -3,7 +3,7 @@ AllowLanguageSelection {Yes} AppName -{Pandora FMS Windows Agent v7.0NG.731} +{Pandora FMS Windows Agent v7.0NG.735} ApplicationID {17E3D2CF-CA02-406B-8A80-9D31C17BD08F} @@ -186,7 +186,7 @@ UpgradeApplicationID {} Version -{190215} +{190605} ViewReadme {Yes} diff --git a/pandora_agents/win32/misc/cron.cc b/pandora_agents/win32/misc/cron.cc index 2d3e5e0440..409a43f726 100644 --- a/pandora_agents/win32/misc/cron.cc +++ b/pandora_agents/win32/misc/cron.cc @@ -214,7 +214,7 @@ int Cron::getResetValue (int position) { int default_value = 0; // Days start in 1 if (position == 2) default_value = 1; - return isWildCard(position) + return (isWildCard(position) || !isNormalInterval(position)) ? default_value : this->params[position][CRDOWN]; } diff --git a/pandora_agents/win32/modules/pandora_module.cc b/pandora_agents/win32/modules/pandora_module.cc index eac38c8fa1..e7c751d367 100644 --- a/pandora_agents/win32/modules/pandora_module.cc +++ b/pandora_agents/win32/modules/pandora_module.cc @@ -78,6 +78,7 @@ Pandora_Module::Pandora_Module (string name) { this->warning_inverse = ""; this->quiet = ""; this->module_ff_interval = ""; + this->module_ff_type = ""; this->module_alert_template = ""; this->module_crontab = ""; } @@ -733,6 +734,13 @@ Pandora_Module::getXml () { module_xml += this->module_ff_interval; module_xml += "\n"; } + + /* Module FF type */ + if (this->module_ff_type != "") { + module_xml += "\t"; + module_xml += this->module_ff_type; + module_xml += "\n"; + } /* Module Alert template */ if (this->module_alert_template != "") { @@ -1028,6 +1036,16 @@ Pandora_Module::setModuleFFInterval (string value) { this->module_ff_interval = value; } +/** + * Set the module FF type for the module. + * + * @param value module FF type value to set. + */ +void +Pandora_Module::setModuleFFType (string value) { + this->module_ff_type = value; +} + /** * Set the module Alert template for the module. * diff --git a/pandora_agents/win32/modules/pandora_module.h b/pandora_agents/win32/modules/pandora_module.h index 9fb29e1183..c766766950 100644 --- a/pandora_agents/win32/modules/pandora_module.h +++ b/pandora_agents/win32/modules/pandora_module.h @@ -176,6 +176,7 @@ namespace Pandora_Modules { string unit, custom_id, str_warning, str_critical; string module_group, warning_inverse, critical_inverse, quiet; string module_ff_interval, module_alert_template, module_crontab; + string module_ff_type; string critical_instructions, warning_instructions, unknown_instructions, tags; protected: @@ -277,6 +278,7 @@ namespace Pandora_Modules { void setWarningInverse (string value); void setQuiet (string value); void setModuleFFInterval (string value); + void setModuleFFType (string value); void setModuleAlertTemplate (string value); void setModuleCrontab (string value); diff --git a/pandora_agents/win32/modules/pandora_module_factory.cc b/pandora_agents/win32/modules/pandora_module_factory.cc index 658ff724fd..a4d9553c20 100644 --- a/pandora_agents/win32/modules/pandora_module_factory.cc +++ b/pandora_agents/win32/modules/pandora_module_factory.cc @@ -119,6 +119,7 @@ using namespace Pandora_Strutils; #define TOKEN_WARNING_INVERSE ("module_warning_inverse ") #define TOKEN_QUIET ("module_quiet ") #define TOKEN_MODULE_FF_INTERVAL ("module_ff_interval ") +#define TOKEN_MODULE_FF_TYPE ("module_ff_type ") #define TOKEN_MACRO ("module_macro") #define TOKEN_NATIVE_ENCODING ("module_native_encoding") #define TOKEN_ALERT_TEMPLATE ("module_alert_template") @@ -176,7 +177,7 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { string module_unit, module_group, module_custom_id, module_str_warning, module_str_critical; string module_critical_instructions, module_warning_instructions, module_unknown_instructions, module_tags; string module_critical_inverse, module_warning_inverse, module_quiet, module_ff_interval; - string module_native_encoding, module_alert_template; + string module_native_encoding, module_alert_template, module_ff_type; string macro; Pandora_Module *module; bool numeric; @@ -254,6 +255,7 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { module_warning_inverse = ""; module_quiet = ""; module_ff_interval = ""; + module_ff_type = ""; module_native_encoding = ""; module_alert_template = ""; module_user_session = ""; @@ -507,6 +509,10 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { if (module_ff_interval == "") { module_ff_interval = parseLine (line, TOKEN_MODULE_FF_INTERVAL); } + + if (module_ff_type == "") { + module_ff_type = parseLine (line, TOKEN_MODULE_FF_TYPE); + } if (module_alert_template == "") { module_alert_template = parseLine (line, TOKEN_ALERT_TEMPLATE); @@ -1087,6 +1093,13 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { } } + if (module_ff_type != "") { + pos_macro = module_ff_type.find(macro_name); + if (pos_macro != string::npos){ + module_ff_type.replace(pos_macro, macro_name.size(), macro_value); + } + } + if (module_alert_template != "") { pos_macro = module_alert_template.find(macro_name); if (pos_macro != string::npos){ @@ -1104,6 +1117,12 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { } } + /* Skip disabled modules */ + if (module_disabled == "1") { + pandoraLog ("Skipping disabled module \"%s\"", module_name.c_str ()); + return NULL; + } + /* Create module objects */ if (module_exec != "") { module = new Pandora_Module_Exec (module_name, @@ -1447,6 +1466,10 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { if (module_ff_interval != "") { module->setModuleFFInterval (module_ff_interval); } + + if (module_ff_type != "") { + module->setModuleFFType (module_ff_type); + } if (module_alert_template != "") { module->setModuleAlertTemplate (module_alert_template); diff --git a/pandora_agents/win32/pandora.cc b/pandora_agents/win32/pandora.cc index 48aba959cb..54994bfa82 100644 --- a/pandora_agents/win32/pandora.cc +++ b/pandora_agents/win32/pandora.cc @@ -30,7 +30,7 @@ using namespace Pandora; using namespace Pandora_Strutils; #define PATH_SIZE _MAX_PATH+1 -#define PANDORA_VERSION ("7.0NG.731(Build 190215)") +#define PANDORA_VERSION ("7.0NG.735(Build 190605)") string pandora_path; string pandora_dir; diff --git a/pandora_agents/win32/versioninfo.rc b/pandora_agents/win32/versioninfo.rc index 2b58063706..fd912eae71 100644 --- a/pandora_agents/win32/versioninfo.rc +++ b/pandora_agents/win32/versioninfo.rc @@ -11,7 +11,7 @@ BEGIN VALUE "LegalCopyright", "Artica ST" VALUE "OriginalFilename", "PandoraAgent.exe" VALUE "ProductName", "Pandora FMS Windows Agent" - VALUE "ProductVersion", "(7.0NG.731(Build 190215))" + VALUE "ProductVersion", "(7.0NG.735(Build 190605))" VALUE "FileVersion", "1.0.0.0" END END diff --git a/pandora_console/DEBIAN/control b/pandora_console/DEBIAN/control index 12ecde5daf..00e162ac2f 100644 --- a/pandora_console/DEBIAN/control +++ b/pandora_console/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-console -Version: 7.0NG.731-190215 +Version: 7.0NG.735-190605 Architecture: all Priority: optional Section: admin diff --git a/pandora_console/DEBIAN/make_deb_package.sh b/pandora_console/DEBIAN/make_deb_package.sh index 0171643ae5..0e4d3c1331 100644 --- a/pandora_console/DEBIAN/make_deb_package.sh +++ b/pandora_console/DEBIAN/make_deb_package.sh @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pandora_version="7.0NG.731-190215" +pandora_version="7.0NG.735-190605" package_pear=0 package_pandora=1 @@ -149,7 +149,7 @@ if [ $package_pear -eq 1 ] then echo "Make the package \"php-xml-rpc\"." cd temp_package - dh-make-pear --maintainer "Miguel de Dios " XML_RPC + dh-make-pear --maintainer "ÁRTICA ST " XML_RPC cd php-xml-rpc-* dpkg-buildpackage -rfakeroot cd .. diff --git a/pandora_console/composer.json b/pandora_console/composer.json index acc6a3e352..208e2d3d14 100644 --- a/pandora_console/composer.json +++ b/pandora_console/composer.json @@ -10,5 +10,16 @@ "require": { "mpdf/mpdf": "^7.1", "swiftmailer/swiftmailer": "^6.0" + }, + "autoload": { + "psr-4": { + "Models\\": "include/rest-api/models", + "Enterprise\\Models\\": "enterprise/include/rest-api/models" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } } } diff --git a/pandora_console/extensions/agents_alerts.php b/pandora_console/extensions/agents_alerts.php index 46272504f6..54e0ec6b12 100755 --- a/pandora_console/extensions/agents_alerts.php +++ b/pandora_console/extensions/agents_alerts.php @@ -138,8 +138,15 @@ function mainAgentsAlerts() $onheader['combo_refr'] = $comborefr; } - // Header - ui_print_page_header(__('Agents/Alerts'), 'images/op_alerts.png', false, '', false, $updated_time); + // Header. + ui_print_page_header( + __('Agents/Alerts'), + 'images/op_alerts.png', + false, + 'agents_alerts_view', + false, + $updated_time + ); // Old style table, we need a lot of special formatting,don't use table function // Prepare old-style table @@ -291,7 +298,7 @@ function mainAgentsAlerts() $table2->data[2][0] = __('Threshold'); $table2->data[2][1] = html_print_input_text('module_action_threshold', '0', '', 5, 7, true); - $table2->data[2][1] .= ' '.__('seconds').ui_print_help_icon('action_threshold', true); + $table2->data[2][1] .= ' '.__('seconds'); $content2 = '
'; $content2 .= html_print_table($table2, true); @@ -378,7 +385,8 @@ function mainAgentsAlerts() 'alerts_agents' ); - echo ''; + echo '
'; + echo ''; echo "'; if ($hor_offset > 0) { @@ -421,9 +429,10 @@ function mainAgentsAlerts() continue; } - echo ''; + echo ''; } + echo ''; if (($hor_offset + $block) < $ntemplates) { $new_hor_offset = ($hor_offset + $block); echo "
".__('Agents').' / '.__('Alert templates').''.io_safe_output($tname).html_print_image('images/information_alerts.png', true, ['title' => io_safe_output($tname), 'style' => 'margin-left:5px' ]).''.io_safe_output($tname).'
@@ -455,7 +464,7 @@ function mainAgentsAlerts() $cellstyle = 'background:'.COL_ALERTFIRED.';'; } - echo ' '; + echo ' '; $uniqid = uniqid(); echo '
'; @@ -478,6 +487,23 @@ function mainAgentsAlerts() } echo '
'; + + ui_pagination( + $nagents, + false, + 0, + 0, + false, + 'offset', + true, + 'pagination-bottom', + '', + [ + 'count' => '', + 'offset' => 'offset_param', + ], + 'alerts_agents' + ); } } @@ -487,7 +513,7 @@ function mainAgentsAlerts() function print_alerts_summary_modal_window($id, $alerts) { $table->width = '98%'; - $table->class = 'databox'; + $table->class = 'info_table'; $table->data = []; $table->head[0] = __('Module'); diff --git a/pandora_console/extensions/agents_modules.php b/pandora_console/extensions/agents_modules.php index 798f4e140e..b5860068d8 100644 --- a/pandora_console/extensions/agents_modules.php +++ b/pandora_console/extensions/agents_modules.php @@ -181,8 +181,15 @@ function mainAgentsModules() // Old style table, we need a lot of special formatting,don't use table function // Prepare old-style table if ($config['pure'] == 0) { - // Header - ui_print_page_header(__('Agents/Modules'), 'images/module_mc.png', false, '', false, $updated_time); + // Header. + ui_print_page_header( + __('Agents/Modules'), + 'images/module_mc.png', + false, + 'agents_module_view', + false, + $updated_time + ); echo ''; echo ''; echo "'; @@ -661,7 +668,7 @@ $ignored_params['refresh'] = ''; else { var agentes_id = $("#id_agents2").val(); - var id_agentes = $.get("full_agents_id"); + var id_agentes = getQueryParam("full_agents_id"); if (agentes_id === null && id_agentes !== null) { id_agentes = id_agentes.split(";") id_agentes.forEach(function(element) { @@ -799,7 +806,7 @@ $ignored_params['refresh'] = ''; $("#module").append (option); }); - var id_modules = $.get("full_modules_selected"); + var id_modules = getQueryParam("full_modules_selected"); if(id_modules !== null) { id_modules = id_modules.split(";"); id_modules.forEach(function(element) { @@ -812,20 +819,18 @@ $ignored_params['refresh'] = ''; ); } - (function($) { - $.get = function(key) { - key = key.replace(/[[]/, '['); - key = key.replace(/[]]/, ']'); - var pattern = "[?&]" + key + "=([^&#]*)"; - var regex = new RegExp(pattern); - var url = unescape(window.location.href); - var results = regex.exec(url); - if (results === null) { - return null; - } else { - return results[1]; - } - } - })(jQuery); + function getQueryParam (key) { + key = key.replace(/[[]/, '['); + key = key.replace(/[]]/, ']'); + var pattern = "[?&]" + key + "=([^&#]*)"; + var regex = new RegExp(pattern); + var url = unescape(window.location.href); + var results = regex.exec(url); + if (results === null) { + return null; + } else { + return results[1]; + } + } - \ No newline at end of file + diff --git a/pandora_console/extensions/db_status.php b/pandora_console/extensions/db_status.php index 435474dc53..2d8669f83f 100755 --- a/pandora_console/extensions/db_status.php +++ b/pandora_console/extensions/db_status.php @@ -25,7 +25,7 @@ function extension_db_status() __('DB Schema check'), 'images/extensions.png', false, - '', + 'db_status_tab', true, '' ); diff --git a/pandora_console/extensions/dbmanager.php b/pandora_console/extensions/dbmanager.php index 2aface6996..546ee463fa 100644 --- a/pandora_console/extensions/dbmanager.php +++ b/pandora_console/extensions/dbmanager.php @@ -148,7 +148,7 @@ function dbmgr_extension_main() echo "
"; $table = new stdClass(); $table->width = '100%'; - $table->class = 'databox data'; + $table->class = 'info_table'; $table->head = array_keys($result[0]); $table->data = $result; diff --git a/pandora_console/extensions/files_repo/files_repo_list.php b/pandora_console/extensions/files_repo/files_repo_list.php index 1d01cd1418..80de4563ae 100644 --- a/pandora_console/extensions/files_repo/files_repo_list.php +++ b/pandora_console/extensions/files_repo/files_repo_list.php @@ -45,11 +45,9 @@ if (!empty($files)) { $table = new stdClass(); $table->width = '100%'; - $table->class = 'databox data'; + $table->class = 'info_table'; $table->style = []; $table->style[1] = 'max-width: 200px;'; - $table->style[2] = 'text-align: center;'; - $table->style[3] = 'text-align: center;'; $table->style[4] = 'text-align: center;'; $table->head = []; $table->head[0] = __('Name'); @@ -81,6 +79,7 @@ if (!empty($files)) { // Last modification // Public URL $data[4] = ''; + $table->cellclass[][4] = 'action_buttons'; if (!empty($file['hash'])) { $public_url = ui_get_full_url(EXTENSIONS_DIR.'/files_repo/files_repo_get_file.php?file='.$file['hash']); $message = __('Copy to clipboard').': Ctrl+C -> Enter'; @@ -92,7 +91,7 @@ if (!empty($files)) { } $data[4] .= ""; - $data[4] .= html_print_image('images/download.png', true, ['title' => __('Download')]); + $data[4] .= html_print_image('images/download.png', true, ['title' => __('Download'), 'style' => 'padding:3px' ]); // Download image $data[4] .= ''; diff --git a/pandora_console/extensions/module_groups.php b/pandora_console/extensions/module_groups.php index 1a505538ed..9e750be932 100644 --- a/pandora_console/extensions/module_groups.php +++ b/pandora_console/extensions/module_groups.php @@ -192,7 +192,14 @@ function mainModuleGroups() $array_data[$value['id_grupo']][$value['id_mg']] = $value; } - ui_print_page_header(__('Combined table of agent group and module group'), 'images/module_group.png', false, '', false, ''); + ui_print_page_header( + __('Combined table of agent group and module group'), + 'images/module_group.png', + false, + 'module_groups_view', + false, + '' + ); echo "
".$fullscreen['text'].'
"; diff --git a/pandora_console/extensions/realtime_graphs.php b/pandora_console/extensions/realtime_graphs.php index 09d66abf0c..cea09fe4d5 100644 --- a/pandora_console/extensions/realtime_graphs.php +++ b/pandora_console/extensions/realtime_graphs.php @@ -29,7 +29,14 @@ function pandora_realtime_graphs() $hide_header = get_parameter('hide_header', 0); if (!$hide_header) { - ui_print_page_header(__('Realtime graphs'), 'images/extensions.png', false, '', false, $onheader); + ui_print_page_header( + __('Realtime graphs'), + 'images/extensions.png', + false, + 'real_time_view', + false, + $onheader + ); } $chart[time()]['graph'] = '0'; diff --git a/pandora_console/extensions/resource_registration.php b/pandora_console/extensions/resource_registration.php index 92d106d153..c43e2a97f2 100755 --- a/pandora_console/extensions/resource_registration.php +++ b/pandora_console/extensions/resource_registration.php @@ -998,20 +998,23 @@ function process_upload_xml($xml) { $hook_enterprise = enterprise_include('extensions/resource_registration/functions.php'); - // Extract component + // Extract component. process_upload_xml_component($xml); $group_filter = get_parameter('group'); - // Extract visual map + // Extract visual map. process_upload_xml_visualmap($xml, $group_filter); - // Extract policies + // Extract policies. if ($hook_enterprise === true) { - process_upload_xml_policy($xml, $group_filter); + $centralized_management = !is_central_policies_on_node(); + if ($centralized_management) { + process_upload_xml_policy($xml, $group_filter); + } } - // Extract reports + // Extract reports. process_upload_xml_report($xml, $group_filter); } @@ -1038,6 +1041,11 @@ function resource_registration_extension_main() return; } + $centralized_management = !is_central_policies_on_node(); + if (!$centralized_management) { + ui_print_warning_message(__('This node is configured with centralized mode. Go to metaconsole to create a policy.')); + } + echo '
'; echo __('This extension makes registering resource templates easier.').' '.__('Here you can upload a resource template in .ptr format.').' '.__('Please refer to our documentation for more information on how to obtain and use %s resources.', get_product_name()).' '.'

'.__("You can get more resurces in our Public Resource Library"); echo '
'; diff --git a/pandora_console/extensions/users_connected.php b/pandora_console/extensions/users_connected.php index 562d757a20..e26b0dab1e 100644 --- a/pandora_console/extensions/users_connected.php +++ b/pandora_console/extensions/users_connected.php @@ -66,10 +66,10 @@ function users_extension_main_god($god=true) $rows = []; echo "
".__('No other users connected').'
'; } else { - $table->cellpadding = 4; - $table->cellspacing = 4; + $table->cellpadding = 0; + $table->cellspacing = 0; $table->width = '100%'; - $table->class = 'databox data'; + $table->class = 'info_table'; $table->size = []; $table->data = []; $table->head = []; diff --git a/pandora_console/extras/delete_files/.gitignore b/pandora_console/extras/delete_files/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pandora_console/extras/delete_files/delete_files.txt b/pandora_console/extras/delete_files/delete_files.txt new file mode 100644 index 0000000000..82ce1527aa --- /dev/null +++ b/pandora_console/extras/delete_files/delete_files.txt @@ -0,0 +1,3 @@ +/general/login_identification_wizard.php +/general/login_required.php +/godmode/update_manager/update_manager.messages.php \ No newline at end of file diff --git a/pandora_console/extras/mr/25.sql b/pandora_console/extras/mr/25.sql new file mode 100644 index 0000000000..0809bc486e --- /dev/null +++ b/pandora_console/extras/mr/25.sql @@ -0,0 +1,147 @@ +START TRANSACTION; + +UPDATE `twidget` SET `unique_name`='example' WHERE `class_name` LIKE 'WelcomeWidget'; + +INSERT INTO `tconfig` (`token`, `value`) VALUES ('status_monitor_fields', 'policy,agent,data_type,module_name,server_type,interval,status,graph,warn,data,timestamp'); + +ALTER TABLE `trecon_task` ADD COLUMN `wmi_enabled` tinyint(1) unsigned DEFAULT '0'; +ALTER TABLE `trecon_task` ADD COLUMN `auth_strings` text; +ALTER TABLE `trecon_task` ADD COLUMN `autoconfiguration_enabled` tinyint(1) unsigned default '0'; + + +INSERT INTO `trecon_script` (`name`,`description`,`script`,`macros`) VALUES ('Discovery.Application.VMware', 'Discovery Application script to monitor VMware technologies (ESXi, VCenter, VSphere)', '/usr/share/pandora_server/util/recon_scripts/vmware-plugin.pl', '{"1":{"macro":"_field1_","desc":"Configuration file","help":"","value":"","hide":""}}'); +INSERT INTO `trecon_script` (`name`,`description`,`script`,`macros`) VALUES ('Discovery.Cloud', 'Discovery Cloud script to monitor Cloud technologies (AWS.EC2, AWS.S3, AWS.RDS, RDS,ȊWS.EKS)', '/usr/share/pandora_server/util/recon_scripts/pcm_client.pl', '{"1":{"macro":"_field1_","desc":"Configuration file","help":"","value":"","hide":""}}'); + +CREATE TABLE IF NOT EXISTS `tevent_extended` ( + `id` serial PRIMARY KEY, + `id_evento` bigint(20) unsigned NOT NULL, + `external_id` bigint(20) unsigned, + `utimestamp` bigint(20) NOT NULL default '0', + `description` text, + FOREIGN KEY `tevent_ext_fk`(`id_evento`) REFERENCES `tevento`(`id_evento`) + ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `tnotification_source` ( + `id` serial, + `description` VARCHAR(255) DEFAULT NULL, + `icon` text, + `max_postpone_time` int(11) DEFAULT NULL, + `enabled` int(1) DEFAULT NULL, + `user_editable` int(1) DEFAULT NULL, + `also_mail` int(1) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `tnotification_source` +-- +INSERT INTO `tnotification_source`(`description`, `icon`, `max_postpone_time`, `enabled`, `user_editable`, `also_mail`) VALUES + ("System status", "icono_info_mr.png", 86400, 1, 1, 0), + ("Message", "icono_info_mr.png", 86400, 1, 1, 0), + ("Pending task", "icono_info_mr.png", 86400, 1, 1, 0), + ("Advertisement", "icono_info_mr.png", 86400, 1, 1, 0), + ("Official communication", "icono_info_mr.png", 86400, 1, 1, 0), + ("Sugerence", "icono_info_mr.png", 86400, 1, 1, 0); + +-- ----------------------------------------------------- +-- Table `tmensajes` +-- ----------------------------------------------------- +ALTER TABLE `tmensajes` ADD COLUMN `url` TEXT; +ALTER TABLE `tmensajes` ADD COLUMN `response_mode` VARCHAR(200) DEFAULT NULL; +ALTER TABLE `tmensajes` ADD COLUMN `citicity` INT(10) UNSIGNED DEFAULT '0'; +ALTER TABLE `tmensajes` ADD COLUMN `id_source` BIGINT(20) UNSIGNED NOT NULL; +ALTER TABLE `tmensajes` ADD COLUMN `subtype` VARCHAR(255) DEFAULT ''; +ALTER TABLE `tmensajes` ADD INDEX (`id_source`); +UPDATE `tmensajes` SET `id_source`=(SELECT `id` FROM `tnotification_source` WHERE `description` = "Message"); +ALTER TABLE `tmensajes` ADD CONSTRAINT `tsource_fk` FOREIGN KEY (`id_source`) REFERENCES `tnotification_source` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; + + +CREATE TABLE IF NOT EXISTS `tnotification_user` ( + `id_mensaje` INT(10) UNSIGNED NOT NULL, + `id_user` VARCHAR(60) NOT NULL, + `utimestamp_read` BIGINT(20), + `utimestamp_erased` BIGINT(20), + `postpone` INT, + PRIMARY KEY (`id_mensaje`,`id_user`), + FOREIGN KEY (`id_mensaje`) REFERENCES `tmensajes`(`id_mensaje`) + ON UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY (`id_user`) REFERENCES `tusuario`(`id_user`) + ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tnotification_group` ( + `id_mensaje` INT(10) UNSIGNED NOT NULL, + `id_group` mediumint(4) UNSIGNED NOT NULL, + PRIMARY KEY (`id_mensaje`,`id_group`), + FOREIGN KEY (`id_mensaje`) REFERENCES `tmensajes`(`id_mensaje`) + ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tnotification_source_user` ( + `id_source` BIGINT(20) UNSIGNED NOT NULL, + `id_user` VARCHAR(60), + `enabled` INT(1) DEFAULT NULL, + `also_mail` INT(1) DEFAULT NULL, + PRIMARY KEY (`id_source`,`id_user`), + FOREIGN KEY (`id_source`) REFERENCES `tnotification_source`(`id`) + ON UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY (`id_user`) REFERENCES `tusuario`(`id_user`) + ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tnotification_source_group` ( + `id_source` BIGINT(20) UNSIGNED NOT NULL, + `id_group` mediumint(4) unsigned NOT NULL, + PRIMARY KEY (`id_source`,`id_group`), + INDEX (`id_group`), + FOREIGN KEY (`id_source`) REFERENCES `tnotification_source`(`id`) + ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tnotification_source_group_user`( + `id_source` BIGINT(20) UNSIGNED NOT NULL, + `id_group` mediumint(4) unsigned NOT NULL, + `id_user` VARCHAR(60), + `enabled` INT(1) DEFAULT NULL, + `also_mail` INT(1) DEFAULT NULL, + PRIMARY KEY (`id_source`,`id_user`), + FOREIGN KEY (`id_source`) REFERENCES `tnotification_source`(`id`) + ON UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY (`id_user`) REFERENCES `tusuario`(`id_user`) + ON UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY (`id_group`) REFERENCES `tnotification_source_group`(`id_group`) + ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +INSERT INTO `talert_commands` (`name`, `command`, `description`, `internal`, `fields_descriptions`, `fields_values`) VALUES ('Generate Notification','Internal type','This command allows you to send an internal notification to any user or group.',1,'[\"Destination user\",\"Destination group\",\"Title\",\"Message\",\"Link\",\"Criticity\",\"\",\"\",\"\",\"\",\"\"]','[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]'); + +INSERT INTO `tnotification_source_user` (`id_source`, `id_user`, `enabled`, `also_mail`) VALUES ((SELECT `id` FROM `tnotification_source` WHERE `description`="System status"), "admin", 1, 0); +INSERT INTO `tnotification_source_group` SELECT `id`,0 FROM `tnotification_source` WHERE `description`="Message"; +INSERT INTO `tnotification_user` (`id_mensaje`, `id_user`) SELECT `id_mensaje`, `id_usuario_destino` FROM `tmensajes` WHERE `id_usuario_destino` != ''; + +INSERT INTO tlog_graph_models (`title`,`regexp`,`fields`,`average`) VALUES ('Apache accesses per client and status', +'(.*?)\ -.*1.1"\ (\d+)\ \d+', +'host,status', 1); + +INSERT INTO tlog_graph_models (`title`,`regexp`,`fields`,`average`) VALUES ('Apache time per requester and html code', +'(.*?)\ -.*1.1"\ (\d+)\ (\d+)', +'origin,respose,_time_', 1); + +INSERT INTO tlog_graph_models (`title`,`regexp`,`fields`,`average`) VALUES ('Count output', +'.*', +'Coincidences', 0); + +INSERT INTO tlog_graph_models (`title`,`regexp`,`fields`,`average`) VALUES ('Events replicated to metaconsole', +'.* (.*?) .* (\d+) events replicated to metaconsole', +'server,_events_', 0); + +INSERT INTO tlog_graph_models (`title`,`regexp`,`fields`,`average`) VALUES ('Pages with warnings', +'PHP Warning:.*in (.*?) on', +'page', 0); + +INSERT INTO tlog_graph_models (`title`,`regexp`,`fields`,`average`) VALUES ('Users login', +'Starting Session \d+\ of user (.*)', +'user', 0); + +COMMIT; diff --git a/pandora_console/extras/mr/26.sql b/pandora_console/extras/mr/26.sql new file mode 100644 index 0000000000..591edd6499 --- /dev/null +++ b/pandora_console/extras/mr/26.sql @@ -0,0 +1,24 @@ +START TRANSACTION; + +CREATE TABLE IF NOT EXISTS `tnetwork_matrix` ( + `id` int(10) unsigned NOT NULL auto_increment, + `source` varchar(60) default '', + `destination` varchar(60) default '', + `utimestamp` bigint(20) default 0, + `bytes` int(18) unsigned default 0, + `pkts` int(18) unsigned default 0, + PRIMARY KEY (`id`), + UNIQUE (`source`, `destination`, `utimestamp`) +) ENGINE = InnoDB DEFAULT CHARSET=utf8 ; + +ALTER TABLE `treport_content` ADD COLUMN `show_extended_events` tinyint(1) default '0'; + +UPDATE `treport_content` SET type="netflow_summary" WHERE type="netflow_pie" OR type="netflow_statistics"; + +UPDATE `tnetflow_filter` SET aggregate="dstip" WHERE aggregate NOT IN ("dstip", "srcip", "dstport", "srcport"); + +ALTER TABLE tagent_custom_fields ADD COLUMN `combo_values` VARCHAR(255) DEFAULT ''; + +ALTER TABLE `trecon_task` ADD COLUMN `summary` text; + +COMMIT; diff --git a/pandora_console/extras/mr/27.sql b/pandora_console/extras/mr/27.sql new file mode 100644 index 0000000000..697be21a93 --- /dev/null +++ b/pandora_console/extras/mr/27.sql @@ -0,0 +1,54 @@ +START TRANSACTION; + +ALTER TABLE `tnetflow_filter` DROP COLUMN `output`; + +ALTER TABLE `tagente_modulo` ADD COLUMN `ff_type` tinyint(1) unsigned default '0'; +ALTER TABLE `tnetwork_component` ADD COLUMN `ff_type` tinyint(1) unsigned default '0'; +ALTER TABLE `tlocal_component` ADD COLUMN `ff_type` tinyint(1) unsigned default '0'; +ALTER TABLE `tpolicy_modules` ADD COLUMN `ff_type` tinyint(1) unsigned default '0'; + +ALTER TABLE `tagente_estado` ADD COLUMN `ff_normal` int(4) unsigned default '0'; +ALTER TABLE `tagente_estado` ADD COLUMN `ff_warning` int(4) unsigned default '0'; +ALTER TABLE `tagente_estado` ADD COLUMN `ff_critical` int(4) unsigned default '0'; + +UPDATE tuser_task SET parameters = 'a:5:{i:0;a:6:{s:11:\"description\";s:28:\"Report pending to be created\";s:5:\"table\";s:7:\"treport\";s:8:\"field_id\";s:9:\"id_report\";s:10:\"field_name\";s:4:\"name\";s:4:\"type\";s:3:\"int\";s:9:\"acl_group\";s:8:\"id_group\";}i:1;a:2:{s:11:\"description\";s:46:\"Send to email addresses (separated by a comma)\";s:4:\"type\";s:4:\"text\";}i:2;a:2:{s:11:\"description\";s:7:\"Subject\";s:8:\"optional\";i:1;}i:3;a:3:{s:11:\"description\";s:7:\"Message\";s:4:\"type\";s:4:\"text\";s:8:\"optional\";i:1;}i:4;a:2:{s:11:\"description\";s:11:\"Report Type\";s:4:\"type\";s:11:\"report_type\";}}' where function_name = "cron_task_generate_report"; + +ALTER TABLE `treport_content` ADD COLUMN `total_time` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `time_failed` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `time_in_ok_status` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `time_in_unknown_status` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `time_of_not_initialized_module` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `time_of_downtime` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `total_checks` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `checks_failed` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `checks_in_ok_status` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `unknown_checks` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `agent_max_value` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `agent_min_value` TINYINT(1) DEFAULT '1'; + +ALTER TABLE `treport_content_template` ADD COLUMN `total_time` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `time_failed` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `time_in_ok_status` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `time_in_unknown_status` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `time_of_not_initialized_module` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `time_of_downtime` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `total_checks` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `checks_failed` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `checks_in_ok_status` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `unknown_checks` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `agent_max_value` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `agent_min_value` TINYINT(1) DEFAULT '1'; + +ALTER TABLE `trecon_script` ADD COLUMN `type` int NOT NULL default 0; +ALTER TABLE `trecon_task` ADD COLUMN `type` int NOT NULL default 0; + +UPDATE `trecon_script` SET `type` = 1 WHERE `name`="Discovery.Application.VMware"; +UPDATE `trecon_script` SET `type` = 2 WHERE `name`="Discovery.Cloud"; +UPDATE `trecon_script` SET `type` = 3 WHERE `name` LIKE "IPAM%Recon"; +UPDATE `trecon_script` SET `type` = 4 WHERE `name` LIKE "IPMI%Recon"; + +UPDATE `trecon_task` SET `type`=3 WHERE `description`="Discovery.Application.VMware"; +UPDATE `trecon_task` SET `type`=2 WHERE `description`="Discovery.Cloud"; +UPDATE `trecon_task` SET `type`=7 WHERE `description`="Discovery.Cloud.RDS"; + +COMMIT; diff --git a/pandora_console/extras/mr/28.sql b/pandora_console/extras/mr/28.sql new file mode 100644 index 0000000000..bab07bead8 --- /dev/null +++ b/pandora_console/extras/mr/28.sql @@ -0,0 +1,45 @@ +START TRANSACTION; + +ALTER TABLE `treport_content` ADD COLUMN `current_month` TINYINT(1) DEFAULT '1'; + +ALTER TABLE `treport_content_template` ADD COLUMN `current_month` TINYINT(1) DEFAULT '1'; + +ALTER TABLE `talert_commands` ADD COLUMN `fields_hidden` text; + +ALTER TABLE `talert_templates` MODIFY COLUMN `type` ENUM('regex','max_min','max','min','equal','not_equal','warning','critical','onchange','unknown','always','not_normal'); + +DELETE FROM `tevent_response` WHERE `name` LIKE 'Create Integria IMS incident from event'; +INSERT INTO `tnews` (`id_news`, `author`, `subject`, `text`, `timestamp`) VALUES (NULL,'admin','Welcome to Pandora FMS Console', '&lt;p style="text-align: center; font-size: 13px;"&gt;Hello, congratulations, if you've arrived here you already have an operational monitoring console. Remember that our forums and online documentation are available 24x7 to get you out of any trouble. You can replace this message with a personalized one at Admin tools -&amp;gt; Site news.&lt;/p&gt; ',NOW()); + + +INSERT INTO `tnotification_source_user` (`id_source`, `id_user`, `enabled`, `also_mail`) VALUES ((SELECT `id` FROM `tnotification_source` WHERE `description`="Official communication"), "admin", 1, 0); +UPDATE `tnotification_source` SET `enabled`=1 WHERE `description` = 'System status' OR `description` = 'Official communication'; +UPDATE `tnotification_source` SET `icon`="icono_logo_pandora.png" WHERE `description` = 'Official communication'; + +-- --------------------------------------------------------------------- +-- Table `tvisual_console_items_cache` +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS `tvisual_console_elements_cache` ( + `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + `vc_id` INTEGER UNSIGNED NOT NULL, + `vc_item_id` INTEGER UNSIGNED NOT NULL, + `user_id` VARCHAR(60) DEFAULT NULL, + `data` TEXT NOT NULL, + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `expiration` INTEGER UNSIGNED NOT NULL COMMENT 'Seconds to expire', + PRIMARY KEY(`id`), + FOREIGN KEY(`vc_id`) REFERENCES `tlayout`(`id`) + ON DELETE CASCADE, + FOREIGN KEY(`vc_item_id`) REFERENCES `tlayout_data`(`id`) + ON DELETE CASCADE, + FOREIGN KEY (`user_id`) REFERENCES `tusuario`(`id_user`) + ON DELETE CASCADE ON UPDATE CASCADE +) engine=InnoDB DEFAULT CHARSET=utf8; + +ALTER TABLE `tlayout_data` ADD COLUMN `cache_expiration` INTEGER UNSIGNED NOT NULL DEFAULT 0; + +ALTER TABLE `tusuario` ADD COLUMN `ehorus_user_level_user` VARCHAR(60); +ALTER TABLE `tusuario` ADD COLUMN `ehorus_user_level_pass` VARCHAR(45); +ALTER TABLE `tusuario` ADD COLUMN `ehorus_user_level_enabled` TINYINT(1) DEFAULT '1'; + +COMMIT; diff --git a/pandora_console/extras/pandora_diag.php b/pandora_console/extras/pandora_diag.php index 4a0b32de81..c5420c26bd 100644 --- a/pandora_console/extras/pandora_diag.php +++ b/pandora_console/extras/pandora_diag.php @@ -106,7 +106,9 @@ function get_value_sum($arr) { foreach ($arr as $clave) { foreach ($clave as $valor) { - $result += $valor; + if (is_numeric($valor) === true) { + $result += $valor; + } } } @@ -120,7 +122,7 @@ function execution_time() if ($times[0]['datos'] > ($times[1]['datos'] * 1.2)) { return "Warning Status   The execution time could be degrading. For a more extensive information of this data consult the Execution Time graph"; } else { - return "Normal Status   The execution time is correct. For a more extensive information of this data consult the Execution Time graph"; + return "Normal Status   The execution time is correct. For more information about this data, check the Execution Time graph"; } } @@ -138,7 +140,7 @@ function get_status_logs($path) { $status_server_log = ''; $size_server_log = get_logs_size($path); - if ($size_server_log <= 10240) { + if ($size_server_log <= 1048576) { $status_server_log = "Normal Status   You have less than 10 MB of logs"; } else { $status_server_log = "Warning Status   You have more than 10 MB of logs"; @@ -155,9 +157,9 @@ function percentage_modules_per_agent() $total_modules = db_get_value_sql('SELECT count(*) FROM tagente_modulo'); $average_modules_per_agent = ($total_modules / $total_agents); if ($average_modules_per_agent <= 40) { - $status_average_modules = "Normal Status   The average of modules per agent is less than 40 percent"; + $status_average_modules = "Normal Status   The average of modules per agent is less than 40"; } else { - $status_average_modules = "Warning Status  The average of modules per agent is more than 40 percent. You can have performance problems"; + $status_average_modules = "Warning Status  The average of modules per agent is more than 40. You can have performance problems"; } return $status_average_modules; @@ -171,9 +173,9 @@ function license_capacity() $status_license_capacity = ''; $current_count = db_get_value_sql('SELECT count(*) FROM tagente'); if ($current_count > ($license_limit * 90 / 100)) { - $status_license_capacity = "Warning Status   The license capacity is more than 90 percent"; + $status_license_capacity = "Warning Status   License capacity exceeds 90 percent"; } else { - $status_license_capacity = "Normal Status   The license capacity is less than 90 percent"; + $status_license_capacity = "Normal Status   License capacity is less than 90 percent"; } return $status_license_capacity; @@ -200,9 +202,9 @@ function interval_average_of_network_modules() $average_time = ((int) $total_module_interval_time / $total_network_modules); if ($average_time < 180) { - $status_average_modules = "Warning Status   The system has a lot of load and a very fine configuration is required"; + $status_average_modules = "Warning Status   The system is overloaded (average time $average_time) and a very fine configuration is required"; } else { - $status_average_modules = "Normal Status   The system has an acceptable charge"; + $status_average_modules = "Normal Status   The system is not overloaded (average time $average_time) "; } if ($average_time == 0) { @@ -219,9 +221,9 @@ $attachment_total_files = count(glob($config['homedir'].'/attachment/{*.*}', GLO function files_attachment_folder($total_files) { if ($total_files <= 700) { - $status_total_files = "Normal Status   The attachment folder has less than 700 files."; + $status_total_files = "Normal Status   The attached folder contains less than 700 files."; } else { - $status_total_files = "Warning Status   The attachment folder has more than 700 files."; + $status_total_files = "Warning Status   The attached folder contains more than 700 files."; } return $status_total_files; @@ -234,9 +236,9 @@ $tagente_datos_size = db_get_value_sql('SELECT COUNT(*) FROM tagente_datos'); function status_tagente_datos($tagente_datos_size) { if ($tagente_datos_size <= 3000000) { - $tagente_datos_size = "Normal Status   The tagente_datos table has an acceptable amount of data."; + $tagente_datos_size = "Normal Status   The tagente_datos table contains an acceptable amount of data."; } else { - $tagente_datos_size = "Warning Status   The tagente_datos table has too much data. A historical database is recommended."; + $tagente_datos_size = "Warning Status   The tagente_datos table contains too much data. A historical database is recommended."; } return $tagente_datos_size; @@ -272,6 +274,7 @@ if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') { } $path_server_logs = '/log/pandora/pandora_server.log'; +$path_err_logs = '/log/pandora/pandora_server.error'; $path_console_logs = '/www/html/pandora_console/pandora_console.log'; $innodb_log_file_size_min_rec_value = '64M'; $innodb_log_buffer_size_min_rec_value = '16M'; @@ -292,16 +295,16 @@ $key_buffer_size_min_rec_value = 256; $read_buffer_size_min_rec_value = 32; $read_rnd_buffer_size_min_rec_value = 32; $query_cache_min_res_unit_min_rec_value = 2; -$innodb_file_per_table_min_rec_value = 0; +$innodb_file_per_table_min_rec_value = 1; function status_fragmentation_tables($tables_fragmentation_max_rec_value, $tables_fragmentation) { $status_tables_frag = ''; if ($tables_fragmentation > $tables_fragmentation_max_rec_value) { - $status_tables_frag = "Warning Status   The fragmentation tables is higher than recommended. You should defragment them."; + $status_tables_frag = "Warning Status   Table fragmentation is higher than recommended. They should be defragmented."; } else { - $status_tables_frag = "Normal Status   The fragmentation tables is correct."; + $status_tables_frag = "Normal Status   Table fragmentation is correct."; } return $status_tables_frag; @@ -317,9 +320,9 @@ if ($console_mode == 1) { echo "\nPandora FMS PHP diagnostic tool v3.2 (c) Artica ST 2009-2010 \n"; if ($argc == 1 || in_array($argv[1], ['--help', '-help', '-h', '-?'])) { - echo "\nThis command line script gives information about Pandora FMS database. -This program only can be executed from console, and need a parameter, the -full path to Pandora FMS 'config.php' file. + echo "\nThis command line script contains information about Pandora FMS database. + This program can only be executed from the console, and it needs a parameter, the + full path to Pandora FMS 'config.php' file. Usage: php pandora_diag.php path_to_pandora_console @@ -342,15 +345,21 @@ full path to Pandora FMS 'config.php' file. include '../include/config.php'; } - // Not from console, this is a web session - if ((!isset($config['id_user'])) or (!check_acl($config['id_user'], 0, 'PM'))) { + // Not from console, this is a web session. + if ((!isset($config['id_user'])) || (!check_acl($config['id_user'], 0, 'PM'))) { echo "

You don't have privileges to use diagnostic tool

"; echo '

Please login with an administrator account before try to use this tool

'; exit; } - // Header - ui_print_page_header(__('Pandora FMS Diagnostic tool'), '', false, '', true); + // Header. + ui_print_page_header( + __('Pandora FMS Diagnostic tool'), + '', + false, + 'diagnostic_tool_tab', + true + ); echo "
"; echo "'; @@ -412,11 +421,7 @@ render_info_data( render_info_data('SELECT COUNT(*) FROM tagente_modulo', 'Total modules'); render_info_data('SELECT COUNT(*) FROM tgrupo', 'Total groups'); render_info_data('SELECT COUNT(*) FROM tagente_datos', 'Total module data records'); - // render_info_data ("SELECT COUNT(*) FROM tagente_datos_string","Total module string data records"); - // render_info_data ("SELECT COUNT(*) FROM tagente_datos_log4x","Total module log4x data records"); render_info_data('SELECT COUNT(*) FROM tagent_access', 'Total agent access record'); - // render_info ("tagente_estado"); - // render_info ("talert_template_modules"); render_info_data('SELECT COUNT(*) FROM tevento', 'Total events'); if ($config['enterprise_installed']) { @@ -679,7 +684,7 @@ render_info_data( $read_rnd_buffer_size = (db_get_value_sql('SELECT @@read_rnd_buffer_size') / 1024); $query_cache_min_res_unit = (db_get_value_sql('SELECT @@query_cache_min_res_unit') / 1024); $innodb_file_per_table = db_get_value_sql('SELECT @@innodb_file_per_table'); - echo "'; + echo "'; render_row(status_values($innodb_log_file_size_min_rec_value, $innodb_log_file_size), 'InnoDB log file size ', 'InnoDB log file size '); render_row(status_values($innodb_log_buffer_size_min_rec_value, $innodb_log_buffer_size), 'InnoDB log buffer size ', 'InnoDB log buffer size '); @@ -700,22 +705,24 @@ render_info_data( render_row(status_values($read_rnd_buffer_size_min_rec_value, $read_rnd_buffer_size), 'Read rnd-buffer size ', 'Read rnd-buffer size '); render_row(status_values($query_cache_min_res_unit_min_rec_value, $query_cache_min_res_unit), 'Query cache min-res-unit ', 'Query cache min-res-unit '); render_row(status_values($innodb_file_per_table_min_rec_value, $innodb_file_per_table), 'InnoDB file per table ', 'InnoDB file per table '); - echo "'; + echo "'; render_row($tables_fragmentation_max_rec_value.'%', 'Tables fragmentation (maximum recommended value)'); render_row(number_format($tables_fragmentation, 2).'%', 'Tables fragmentation (current value)'); - render_row(status_fragmentation_tables($tables_fragmentation_max_rec_value, $tables_fragmentation), 'Status fragmentation tables'); + render_row(status_fragmentation_tables($tables_fragmentation_max_rec_value, $tables_fragmentation), 'Table fragmentation status'); - echo "'; + echo "'; - render_row(number_format((get_logs_size($path_server_logs) / 1024), 2).'M', 'Size server logs (current value)'); + render_row(number_format((get_logs_size($path_server_logs) / 1048576), 3).'M', 'Size server logs (current value)'); render_row(get_status_logs($path_server_logs), 'Status server logs'); - render_row(number_format((get_logs_size($path_console_logs) / 1024), 2).'M', 'Size console logs (current value)'); + render_row(number_format((get_logs_size($path_err_logs) / 1048576), 3).'M', 'Size error logs (current value)'); + render_row(get_status_logs($path_err_logs), 'Status error logs'); + render_row(number_format((get_logs_size($path_console_logs) / 1048576), 3).'M', 'Size console logs (current value)'); render_row(get_status_logs($path_console_logs), 'Status console logs'); - echo "'; + echo "'; render_row(html_print_textarea('keys[customer_key]', 10, 255, $settings->customer_key, 'style="height:40px; width:450px;"', true), 'Customer key'); render_row($license['expiry_date'], 'Expires'); @@ -733,14 +740,14 @@ render_info_data( echo "'; - render_row($attachment_total_files, 'Total files in the attachment folder'); + render_row($attachment_total_files, 'Total files in the attached folder'); render_row(files_attachment_folder($attachment_total_files), 'Status of the attachment folder'); echo "'; - render_row($tagente_datos_size, 'Total data in the tagente_datos table'); - render_row(status_tagente_datos($tagente_datos_size), 'Status of the tagente_datos table'); - render_row(execution_time(), 'Degradation of the execution time when executing a count'); + render_row($tagente_datos_size, 'Total data in tagente_datos table'); + render_row(status_tagente_datos($tagente_datos_size), 'Tangente_datos table status'); + render_row(execution_time(), 'Execution time degradation when executing a count'); echo "'; @@ -783,6 +790,6 @@ render_info_data( echo "
"; echo ''.__( - '(*) Please check your Pandora Server setup and be sure that database maintenance daemon is running. It\' very important to -keep up-to-date database to get the best performance and results in Pandora' + '(*) Please check your Pandora Server setup and make sure that the database maintenance daemon is running. It\' is very important to + keep the database up-to-date to get the best performance and results in Pandora' ).'


'; diff --git a/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql b/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql index bedb9927cd..2c9ff7e7de 100644 --- a/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql +++ b/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql @@ -58,6 +58,7 @@ CREATE TABLE IF NOT EXISTS `tlocal_component` ( ALTER TABLE `tlocal_component` ADD COLUMN `dynamic_next` bigint(20) NOT NULL default '0'; ALTER TABLE `tlocal_component` ADD COLUMN `dynamic_two_tailed` tinyint(1) unsigned default '0'; +ALTER TABLE `tlocal_component` ADD COLUMN `ff_type` tinyint(1) unsigned default '0'; -- ----------------------------------------------------- -- Table `tpolicy_modules` @@ -136,6 +137,7 @@ CREATE TABLE IF NOT EXISTS `tpolicy_modules` ( ALTER TABLE `tpolicy_modules` ADD COLUMN `dynamic_next` bigint(20) NOT NULL default '0'; ALTER TABLE `tpolicy_modules` ADD COLUMN `dynamic_two_tailed` tinyint(1) unsigned default '0'; +ALTER TABLE `tpolicy_modules` ADD COLUMN `ff_type` tinyint(1) unsigned default '0'; -- --------------------------------------------------------------------- -- Table `tpolicies` @@ -759,11 +761,41 @@ CREATE TABLE IF NOT EXISTS `treport_content_template` ( PRIMARY KEY(`id_rc`) ) ENGINE = InnoDB DEFAULT CHARSET=utf8; +-- ---------------------------------------------------------------------- +-- Table `tnews` +-- ---------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS `tnews` ( + `id_news` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + `author` varchar(255) NOT NULL DEFAULT '', + `subject` varchar(255) NOT NULL DEFAULT '', + `text` TEXT NOT NULL, + `timestamp` DATETIME NOT NULL DEFAULT 0, + `id_group` int(10) NOT NULL default 0, + `modal` tinyint(1) DEFAULT 0, + `expire` tinyint(1) DEFAULT 0, + `expire_timestamp` DATETIME NOT NULL DEFAULT 0, + PRIMARY KEY(`id_news`) +) ENGINE = InnoDB DEFAULT CHARSET=utf8; + + ALTER TABLE treport_content_template ADD COLUMN `historical_db` tinyint(1) NOT NULL DEFAULT '0'; ALTER TABLE treport_content_template ADD COLUMN `lapse_calc` tinyint(1) default '0'; ALTER TABLE treport_content_template ADD COLUMN `lapse` int(11) default '300'; ALTER TABLE treport_content_template ADD COLUMN `visual_format` tinyint(1) default '0'; ALTER TABLE treport_content_template ADD COLUMN `hide_no_data` tinyint(1) default '0'; +ALTER TABLE `treport_content_template` ADD COLUMN `total_time` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `time_failed` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `time_in_ok_status` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `time_in_unknown_status` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `time_of_not_initialized_module` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `time_of_downtime` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `total_checks` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `checks_failed` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `checks_in_ok_status` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `unknown_checks` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `agent_max_value` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `agent_min_value` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content_template` ADD COLUMN `current_month` TINYINT(1) DEFAULT '1'; -- ----------------------------------------------------- -- Table `treport_content_sla_com_temp` (treport_content_sla_combined_template) @@ -1150,6 +1182,9 @@ ALTER TABLE tagente_estado MODIFY `status_changes` tinyint(4) unsigned default 0 ALTER TABLE tagente_estado CHANGE `last_known_status` `known_status` tinyint(4) default 0; ALTER TABLE tagente_estado ADD COLUMN `last_known_status` tinyint(4) default 0; ALTER TABLE tagente_estado ADD COLUMN last_unknown_update bigint(20) NOT NULL default 0; +ALTER TABLE `tagente_estado` ADD COLUMN `ff_normal` int(4) unsigned default '0'; +ALTER TABLE `tagente_estado` ADD COLUMN `ff_warning` int(4) unsigned default '0'; +ALTER TABLE `tagente_estado` ADD COLUMN `ff_critical` int(4) unsigned default '0'; -- --------------------------------------------------------------------- -- Table `talert_actions` @@ -1180,6 +1215,7 @@ ALTER TABLE talert_actions ADD COLUMN `field15_recovery` TEXT NOT NULL DEFAULT " UPDATE `talert_commands` SET `fields_descriptions` = '[\"Integria IMS API path\",\"Integria IMS API pass\",\"Integria IMS user\",\"Integria IMS user pass\",\"Ticket title\",\"Ticket group ID\",\"Ticket priority\",\"Email copy\",\"Ticket owner\",\"Ticket description\"]', `fields_values` = '[\"\",\"\",\"\",\"\",\"\",\"\",\"10,Maintenance;0,Informative;1,Low;2,Medium;3,Serious;4,Very Serious\",\"\",\"\",\"\"]' WHERE `id` = 11 AND `name` = 'Integria IMS Ticket'; UPDATE `talert_commands` SET `description` = 'This alert send an email using internal Pandora FMS Server SMTP capabilities (defined in each server, using: _field1_ as destination email address, and _field2_ as subject for message. _field3_ as text of message. _field4_ as content type (text/plain or html/text).', `fields_descriptions` = '[\"Destination address\",\"Subject\",\"Text\",\"Content Type\",\"\",\"\",\"\",\"\",\"\",\"\"]', `fields_values` = '[\"\",\"\",\"_html_editor_\",\"_content_type_\",\"\",\"\",\"\",\"\",\"\",\"\"]' WHERE id=1; ALTER TABLE `talert_commands` ADD COLUMN `id_group` mediumint(8) unsigned NULL default 0; +ALTER TABLE `talert_commands` ADD COLUMN `fields_hidden` text; UPDATE `talert_actions` SET `field4` = 'text/html', `field4_recovery` = 'text/html' WHERE id = 1; @@ -1199,13 +1235,14 @@ ALTER TABLE titem MODIFY `source_data` int(10) unsigned; 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', 24); +INSERT INTO `tconfig` (`token`, `value`) VALUES ('MR', 28); 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', '731'); +INSERT INTO `tconfig` (`token`, `value`) VALUES ('current_package_enterprise', '735'); +INSERT INTO `tconfig` (`token`, `value`) VALUES ('status_monitor_fields', 'policy,agent,data_type,module_name,server_type,interval,status,graph,warn,data,timestamp'); -- --------------------------------------------------------------------- -- Table `tconfig_os` @@ -1251,6 +1288,11 @@ alter table tusuario add autorefresh_white_list text not null default ''; ALTER TABLE tusuario ADD COLUMN `time_autorefresh` int(5) unsigned NOT NULL default '30'; ALTER TABLE `tusuario` DROP COLUMN `flash_chart`; ALTER TABLE `tusuario` ADD COLUMN `default_custom_view` int(10) unsigned NULL default '0'; +ALTER TABLE `tusuario` ADD COLUMN `ehorus_user_level_user` VARCHAR(60); +ALTER TABLE `tusuario` ADD COLUMN `ehorus_user_level_pass` VARCHAR(45); +ALTER TABLE `tusuario` ADD COLUMN `ehorus_user_level_enabled` TINYINT(1); + + -- --------------------------------------------------------------------- -- Table `tagente_modulo` @@ -1259,6 +1301,10 @@ ALTER TABLE tagente_modulo ADD COLUMN `dynamic_next` bigint(20) NOT NULL default ALTER TABLE tagente_modulo ADD COLUMN `dynamic_two_tailed` tinyint(1) unsigned default '0'; ALTER TABLE tagente_modulo ADD COLUMN `parent_module_id` int(10) unsigned NOT NULL default 0; ALTER TABLE `tagente_modulo` ADD COLUMN `cps` int NOT NULL default 0; +ALTER TABLE `tagente_modulo` ADD COLUMN `ff_type` tinyint(1) unsigned default '0'; +ALTER TABLE `tagente_modulo` ADD COLUMN `ff_normal` int(4) unsigned default '0'; +ALTER TABLE `tagente_modulo` ADD COLUMN `ff_warning` int(4) unsigned default '0'; +ALTER TABLE `tagente_modulo` ADD COLUMN `ff_critical` int(4) unsigned default '0'; -- --------------------------------------------------------------------- -- Table `tagente_datos` @@ -1278,6 +1324,7 @@ ALTER TABLE tnetwork_component ADD COLUMN `dynamic_max` int(4) default '0'; ALTER TABLE tnetwork_component ADD COLUMN `dynamic_min` int(4) default '0'; ALTER TABLE tnetwork_component ADD COLUMN `dynamic_next` bigint(20) NOT NULL default '0'; ALTER TABLE tnetwork_component ADD COLUMN `dynamic_two_tailed` tinyint(1) unsigned default '0'; +ALTER TABLE `tnetwork_component` ADD COLUMN `ff_type` tinyint(1) unsigned default '0'; -- --------------------------------------------------------------------- -- Table `tagente` @@ -1328,6 +1375,7 @@ ALTER TABLE `tlayout_data` ADD COLUMN `linked_layout_status_type` ENUM ('default ALTER TABLE `tlayout_data` ADD COLUMN `linked_layout_status_as_service_warning` FLOAT(20, 3) NOT NULL default 0; ALTER TABLE `tlayout_data` ADD COLUMN `linked_layout_status_as_service_critical` FLOAT(20, 3) NOT NULL default 0; ALTER TABLE `tlayout_data` ADD COLUMN `linked_layout_node_id` INT(10) NOT NULL default 0; +ALTER TABLE `tlayout_data` ADD COLUMN `cache_expiration` INTEGER UNSIGNED NOT NULL DEFAULT 0; -- --------------------------------------------------------------------- -- Table `tagent_custom_fields` @@ -1354,6 +1402,7 @@ ALTER TABLE tgraph ADD COLUMN `fullscale` tinyint(1) UNSIGNED NOT NULL default ' -- Table `tnetflow_filter` -- --------------------------------------------------------------------- ALTER TABLE tnetflow_filter ADD COLUMN `router_ip` TEXT NOT NULL DEFAULT ""; +UPDATE `tnetflow_filter` SET aggregate="dstip" WHERE aggregate NOT IN ("dstip", "srcip", "dstport", "srcport"); -- --------------------------------------------------------------------- -- Table `treport_custom_sql` @@ -1368,13 +1417,27 @@ UPDATE treport_custom_sql SET `sql` = 'select t1.alias as agent_n -- ---------------------------------------------------------------------- -- Table `treport_content` -- --------------------------------------------------------------------- - ALTER TABLE treport_content ADD COLUMN `historical_db` tinyint(1) NOT NULL DEFAULT '0'; ALTER TABLE treport_content ADD COLUMN `lapse_calc` tinyint(1) default '0'; ALTER TABLE treport_content ADD COLUMN `lapse` int(11) default '300'; ALTER TABLE treport_content ADD COLUMN `visual_format` tinyint(1) default '0'; ALTER TABLE treport_content ADD COLUMN `hide_no_data` tinyint(1) default '0'; ALTER TABLE treport_content ADD COLUMN `recursion` tinyint(1) default NULL; +ALTER TABLE treport_content ADD COLUMN `show_extended_events` tinyint(1) default '0'; +UPDATE `treport_content` SET type="netflow_summary" WHERE type="netflow_pie" OR type="netflow_statistics"; +ALTER TABLE `treport_content` ADD COLUMN `total_time` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `time_failed` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `time_in_ok_status` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `time_in_unknown_status` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `time_of_not_initialized_module` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `time_of_downtime` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `total_checks` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `checks_failed` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `checks_in_ok_status` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `unknown_checks` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `agent_max_value` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `agent_min_value` TINYINT(1) DEFAULT '1'; +ALTER TABLE `treport_content` ADD COLUMN `current_month` TINYINT(1) DEFAULT '1'; -- --------------------------------------------------------------------- -- Table `tmodule_relationship` @@ -1406,12 +1469,17 @@ ALTER TABLE twidget_dashboard MODIFY options LONGTEXT NOT NULL default ""; ALTER TABLE trecon_task ADD `alias_as_name` int(2) unsigned default '0'; ALTER TABLE trecon_task ADD `snmp_enabled` int(2) unsigned default '0'; ALTER TABLE trecon_task ADD `vlan_enabled` int(2) unsigned default '0'; +ALTER TABLE trecon_task ADD `wmi_enabled` tinyint(1) unsigned DEFAULT '0'; +ALTER TABLE trecon_task ADD `auth_strings` text; +ALTER TABLE trecon_task ADD `autoconfiguration_enabled` tinyint(1) unsigned default '0'; +ALTER TABLE trecon_task ADD `summary` text; -- --------------------------------------------------------------------- -- Table `twidget` AND Table `twidget_dashboard` -- --------------------------------------------------------------------- UPDATE twidget_dashboard SET id_widget = (SELECT id FROM twidget WHERE unique_name = 'graph_module_histogram') WHERE id_widget = (SELECT id FROM twidget WHERE unique_name = 'graph_availability'); DELETE FROM twidget WHERE unique_name = 'graph_availability'; +UPDATE `twidget` SET `unique_name`='example' WHERE `class_name` LIKE 'WelcomeWidget'; -- --------------------------------------------------------------------- -- Table `tbackup` (Extension table. Modify only if exists) @@ -1816,7 +1884,30 @@ CREATE TABLE IF NOT EXISTS `tlog_graph_models` ( INSERT INTO tlog_graph_models VALUES (1, 'Apache log model', '^.*?\s+.*".*?\s(\/.*?)\?.*1.1"\s+(.*?)\s+(.*?)\s+', 'pagina, html_err_code, _tiempo_', 1); - + +INSERT INTO tlog_graph_models VALUES (2, 'Apache accesses per client and status', +'(.*?)\ -.*1.1"\ (\d+)\ \d+', +'host,status', 1); + +INSERT INTO tlog_graph_models VALUES (3, 'Apache time per requester and html code', +'(.*?)\ -.*1.1"\ (\d+)\ (\d+)', +'origin,respose,_time_', 1); + +INSERT INTO tlog_graph_models VALUES (4, 'Count output', +'.*', +'Coincidences', 0); + +INSERT INTO tlog_graph_models VALUES (5, 'Events replicated to metaconsole', +'.* (.*?) .* (\d+) events replicated to metaconsole', +'server,_events_', 0); + +INSERT INTO tlog_graph_models VALUES (6, 'Pages with warnings', +'PHP Warning:.*in (.*?) on', +'page', 0); + +INSERT INTO tlog_graph_models VALUES (7, 'Users login', +'Starting Session \d+\ of user (.*)', +'user', 0); -- ----------------------------------------------------- -- Add column in table `treport` -- ----------------------------------------------------- @@ -1856,15 +1947,248 @@ ALTER TABLE `tevento` ADD COLUMN `data` double(22,5) default NULL; ALTER TABLE `tevento` ADD COLUMN `module_status` int(4) NOT NULL default '0'; +-- --------------------------------------------------------------------- +-- Table `tevent_extended` +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS `tevent_extended` ( + `id` serial PRIMARY KEY, + `id_evento` bigint(20) unsigned NOT NULL, + `external_id` bigint(20) unsigned, + `utimestamp` bigint(20) NOT NULL default '0', + `description` text, + FOREIGN KEY `tevent_ext_fk`(`id_evento`) REFERENCES `tevento`(`id_evento`) + ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + -- ----------------------------------------------------- -- Table `tgis_map_layer_groups` -- ----------------------------------------------------- -CREATE TABLE IF NOT EXISTS `tgis_map_layer_groups` ( - `layer_id` INT NOT NULL, - `group_id` MEDIUMINT(4) UNSIGNED NOT NULL, - `agent_id` INT(10) UNSIGNED NOT NULL COMMENT 'Used to link the position to the group', - PRIMARY KEY (`layer_id`, `group_id`), - FOREIGN KEY (`layer_id`) REFERENCES `tgis_map_layer` (`id_tmap_layer`) ON DELETE CASCADE, - FOREIGN KEY (`group_id`) REFERENCES `tgrupo` (`id_grupo`) ON DELETE CASCADE, - FOREIGN KEY (`agent_id`) REFERENCES `tagente` (`id_agente`) ON DELETE CASCADE +CREATE TABLE `tgis_map_layer_groups` ( + `layer_id` int(11) NOT NULL, + `group_id` mediumint(4) unsigned NOT NULL, + `agent_id` int(10) unsigned NOT NULL COMMENT 'Used to link the position to the group', + PRIMARY KEY (`layer_id`,`group_id`), + KEY `group_id` (`group_id`), + KEY `agent_id` (`agent_id`), + CONSTRAINT `tgis_map_layer_groups_ibfk_1` FOREIGN KEY (`layer_id`) REFERENCES `tgis_map_layer` (`id_tmap_layer`) ON DELETE CASCADE, + CONSTRAINT `tgis_map_layer_groups_ibfk_2` FOREIGN KEY (`group_id`) REFERENCES `tgrupo` (`id_grupo`) ON DELETE CASCADE, + CONSTRAINT `tgis_map_layer_groups_ibfk_3` FOREIGN KEY (`agent_id`) REFERENCES `tagente` (`id_agente`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- ----------------------------------------------------- +-- Table `tnetwork_matrix` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `tnetwork_matrix` ( + `id` int(10) unsigned NOT NULL auto_increment, + `source` varchar(60) default '', + `destination` varchar(60) default '', + `utimestamp` bigint(20) default 0, + `bytes` int(18) unsigned default 0, + `pkts` int(18) unsigned default 0, + PRIMARY KEY (`id`), + UNIQUE (`source`, `destination`, `utimestamp`) +) ENGINE = InnoDB DEFAULT CHARSET=utf8 ; + +-- --------------------------------------------------------------------- +-- Table `user_task` +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS `tuser_task` ( + `id` int(20) unsigned NOT NULL auto_increment, + `function_name` varchar(80) NOT NULL default '', + `parameters` text NOT NULL default '', + `name` varchar(60) NOT NULL default '', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- --------------------------------------------------------------------- +-- Table `user_task_scheduled` +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS `tuser_task_scheduled` ( + `id` int(20) unsigned NOT NULL auto_increment, + `id_usuario` varchar(60) NOT NULL default '0', + `id_user_task` int(20) unsigned NOT NULL default '0', + `args` TEXT NOT NULL, + `scheduled` enum('no','hourly','daily','weekly','monthly','yearly','custom') default 'no', + `last_run` int(20) unsigned default '0', + `custom_data` int(10) NULL default '0', + `flag_delete` tinyint(1) UNSIGNED NOT NULL default 0, + `id_grupo` int(10) unsigned NOT NULL default 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- ----------------------------------------------------- +-- Table `tnotification_source` +-- ----------------------------------------------------- +CREATE TABLE `tnotification_source` ( + `id` serial, + `description` VARCHAR(255) DEFAULT NULL, + `icon` text, + `max_postpone_time` int(11) DEFAULT NULL, + `enabled` int(1) DEFAULT NULL, + `user_editable` int(1) DEFAULT NULL, + `also_mail` int(1) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `tnotification_source` +-- +INSERT INTO `tnotification_source`(`description`, `icon`, `max_postpone_time`, `enabled`, `user_editable`, `also_mail`) VALUES + ("System status", "icono_info_mr.png", 86400, 1, 1, 0), + ("Message", "icono_info_mr.png", 86400, 1, 1, 0), + ("Pending task", "icono_info_mr.png", 86400, 1, 1, 0), + ("Advertisement", "icono_info_mr.png", 86400, 1, 1, 0), + ("Official communication", "icono_logo_pandora.png", 86400, 1, 1, 0), + ("Sugerence", "icono_info_mr.png", 86400, 1, 1, 0); + +-- ----------------------------------------------------- +-- Table `tmensajes` +-- ----------------------------------------------------- +ALTER TABLE `tmensajes` ADD COLUMN `url` TEXT; +ALTER TABLE `tmensajes` ADD COLUMN `response_mode` VARCHAR(200) DEFAULT NULL; +ALTER TABLE `tmensajes` ADD COLUMN `citicity` INT(10) UNSIGNED DEFAULT '0'; +ALTER TABLE `tmensajes` ADD COLUMN `id_source` BIGINT(20) UNSIGNED NOT NULL; +ALTER TABLE `tmensajes` ADD COLUMN `subtype` VARCHAR(255) DEFAULT ''; +ALTER TABLE `tmensajes` ADD CONSTRAINT `tsource_fk` FOREIGN KEY (`id_source`) REFERENCES `tnotification_source` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; + + +-- ---------------------------------------------------------------------- +-- Table `tnotification_user` +-- ---------------------------------------------------------------------- +CREATE TABLE `tnotification_user` ( + `id_mensaje` INT(10) UNSIGNED NOT NULL, + `id_user` VARCHAR(60) NOT NULL, + `utimestamp_read` BIGINT(20), + `utimestamp_erased` BIGINT(20), + `postpone` INT, + PRIMARY KEY (`id_mensaje`,`id_user`), + FOREIGN KEY (`id_mensaje`) REFERENCES `tmensajes`(`id_mensaje`) + ON UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY (`id_user`) REFERENCES `tusuario`(`id_user`) + ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- ---------------------------------------------------------------------- +-- Table `tnotification_group` +-- ---------------------------------------------------------------------- +CREATE TABLE `tnotification_group` ( + `id_mensaje` INT(10) UNSIGNED NOT NULL, + `id_group` mediumint(4) UNSIGNED NOT NULL, + PRIMARY KEY (`id_mensaje`,`id_group`), + FOREIGN KEY (`id_mensaje`) REFERENCES `tmensajes`(`id_mensaje`) + ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- ---------------------------------------------------------------------- +-- Table `tnotification_source_user` +-- ---------------------------------------------------------------------- +CREATE TABLE `tnotification_source_user` ( + `id_source` BIGINT(20) UNSIGNED NOT NULL, + `id_user` VARCHAR(60), + `enabled` INT(1) DEFAULT NULL, + `also_mail` INT(1) DEFAULT NULL, + PRIMARY KEY (`id_source`,`id_user`), + FOREIGN KEY (`id_source`) REFERENCES `tnotification_source`(`id`) + ON UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY (`id_user`) REFERENCES `tusuario`(`id_user`) + ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- ---------------------------------------------------------------------- +-- Table `tnotification_source_group` +-- ---------------------------------------------------------------------- +CREATE TABLE `tnotification_source_group` ( + `id_source` BIGINT(20) UNSIGNED NOT NULL, + `id_group` mediumint(4) unsigned NOT NULL, + PRIMARY KEY (`id_source`,`id_group`), + INDEX (`id_group`), + FOREIGN KEY (`id_source`) REFERENCES `tnotification_source`(`id`) + ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- ---------------------------------------------------------------------- +-- Table `tnotification_source_user` +-- ---------------------------------------------------------------------- +CREATE TABLE `tnotification_source_group_user` ( + `id_source` BIGINT(20) UNSIGNED NOT NULL, + `id_group` mediumint(4) unsigned NOT NULL, + `id_user` VARCHAR(60), + `enabled` INT(1) DEFAULT NULL, + `also_mail` INT(1) DEFAULT NULL, + PRIMARY KEY (`id_source`,`id_user`), + FOREIGN KEY (`id_source`) REFERENCES `tnotification_source`(`id`) + ON UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY (`id_user`) REFERENCES `tusuario`(`id_user`) + ON UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY (`id_group`) REFERENCES `tnotification_source_group`(`id_group`) + ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- ---------------------------------------------------------------------- +-- Add alert command 'Generate notification' +-- ---------------------------------------------------------------------- +INSERT INTO `talert_commands` (`name`, `command`, `description`, `internal`, `fields_descriptions`, `fields_values`) VALUES ('Generate Notification','Internal type','This command allows you to send an internal notification to any user or group.',1,'[\"Destination user\",\"Destination group\",\"Title\",\"Message\",\"Link\",\"Criticity\",\"\",\"\",\"\",\"\",\"\"]','[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]'); + +-- ---------------------------------------------------------------------- +-- Update message references and pre-configure notifications +-- ---------------------------------------------------------------------- +INSERT INTO `tnotification_source_user` (`id_source`, `id_user`, `enabled`, `also_mail`) VALUES ((SELECT `id` FROM `tnotification_source` WHERE `description`="System status"), "admin", 1, 0); +INSERT INTO `tnotification_source_group` SELECT `id`,0 FROM `tnotification_source` WHERE `description`="Message"; +INSERT INTO `tnotification_user` (`id_mensaje`, `id_user`) SELECT `id_mensaje`, `id_usuario_destino` FROM `tmensajes` WHERE `id_usuario_destino` != ''; +INSERT INTO `tnotification_source_user` (`id_source`, `id_user`, `enabled`, `also_mail`) VALUES ((SELECT `id` FROM `tnotification_source` WHERE `description`="Official communication"), "admin", 1, 0); +UPDATE `tnotification_source` SET `enabled`=1 WHERE `description` = 'System status' OR `description` = 'Official communication'; + +-- ---------------------------------------------------------------------- +-- Add custom internal recon scripts +-- ---------------------------------------------------------------------- +INSERT INTO `trecon_script` (`name`,`description`,`script`,`macros`) VALUES ('Discovery.Application.VMware', 'Discovery Application script to monitor VMware technologies (ESXi, VCenter, VSphere)', '/usr/share/pandora_server/util/recon_scripts/vmware-plugin.pl', '{"1":{"macro":"_field1_","desc":"Configuration file","help":"","value":"","hide":""}}'); +INSERT INTO `trecon_script` (`name`,`description`,`script`,`macros`) VALUES ('Discovery.Cloud', 'Discovery Cloud script to monitor Cloud technologies (AWS.EC2, AWS.S3, AWS.RDS, RDS,ȊWS.EKS)', '/usr/share/pandora_server/util/recon_scripts/pcm_client.pl', '{"1":{"macro":"_field1_","desc":"Configuration file","help":"","value":"","hide":""}}'); +-- ---------------------------------------------------------------------- +-- Add column in table `tagent_custom_fields` +-- ---------------------------------------------------------------------- +ALTER TABLE tagent_custom_fields ADD COLUMN `combo_values` VARCHAR(255) DEFAULT ''; + +-- ---------------------------------------------------------------------- +-- Add column in table `tnetflow_filter` +-- ---------------------------------------------------------------------- +ALTER TABLE `tnetflow_filter` DROP COLUMN `output`; + + +-- ---------------------------------------------------------------------- +-- Update table `tuser_task` +-- ---------------------------------------------------------------------- +UPDATE tuser_task set parameters = 'a:5:{i:0;a:6:{s:11:\"description\";s:28:\"Report pending to be created\";s:5:\"table\";s:7:\"treport\";s:8:\"field_id\";s:9:\"id_report\";s:10:\"field_name\";s:4:\"name\";s:4:\"type\";s:3:\"int\";s:9:\"acl_group\";s:8:\"id_group\";}i:1;a:2:{s:11:\"description\";s:46:\"Send to email addresses (separated by a comma)\";s:4:\"type\";s:4:\"text\";}i:2;a:2:{s:11:\"description\";s:7:\"Subject\";s:8:\"optional\";i:1;}i:3;a:3:{s:11:\"description\";s:7:\"Message\";s:4:\"type\";s:4:\"text\";s:8:\"optional\";i:1;}i:4;a:2:{s:11:\"description\";s:11:\"Report Type\";s:4:\"type\";s:11:\"report_type\";}}' where function_name = "cron_task_generate_report"; + +-- ---------------------------------------------------------------------- +-- ADD message in table 'tnews' +-- ---------------------------------------------------------------------- + +INSERT INTO `tnews` (`id_news`, `author`, `subject`, `text`, `timestamp`) VALUES (NULL,'admin','Welcome to Pandora FMS Console', '&lt;p style="text-align: center; font-size: 13px;"&gt;Hello, congratulations, if you've arrived here you already have an operational monitoring console. Remember that our forums and online documentation are available 24x7 to get you out of any trouble. You can replace this message with a personalized one at Admin tools -&amp;gt; Site news.&lt;/p&gt; ',NOW()); + +-- ---------------------------------------------------------------------- +-- Alter table `talert_templates` +-- ---------------------------------------------------------------------- + + ALTER TABLE `talert_templates` MODIFY COLUMN `type` ENUM('regex','max_min','max','min','equal','not_equal','warning','critical','onchange','unknown','always','not_normal'); + +-- --------------------------------------------------------------------- +-- Table `tvisual_console_items_cache` +-- --------------------------------------------------------------------- +CREATE TABLE `tvisual_console_elements_cache` ( + `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + `vc_id` INTEGER UNSIGNED NOT NULL, + `vc_item_id` INTEGER UNSIGNED NOT NULL, + `user_id` VARCHAR(60) DEFAULT NULL, + `data` TEXT NOT NULL, + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `expiration` INTEGER UNSIGNED NOT NULL COMMENT 'Seconds to expire', + PRIMARY KEY(`id`), + FOREIGN KEY(`vc_id`) REFERENCES `tlayout`(`id`) + ON DELETE CASCADE, + FOREIGN KEY(`vc_item_id`) REFERENCES `tlayout_data`(`id`) + ON DELETE CASCADE, + FOREIGN KEY (`user_id`) REFERENCES `tusuario`(`id_user`) + ON DELETE CASCADE + ON UPDATE CASCADE +) engine=InnoDB DEFAULT CHARSET=utf8; + diff --git a/pandora_console/general/firts_task/collections.php b/pandora_console/general/firts_task/collections.php index 269de3ba12..8e27ce6ee3 100755 --- a/pandora_console/general/firts_task/collections.php +++ b/pandora_console/general/firts_task/collections.php @@ -22,7 +22,7 @@ ui_require_css_file('firts_task'); __('Collections')]); ?>
-

+

true, 'message' => __('There are no custom __('Custom Fields')]); ?>

-

+

true, 'message' => __('There are no custom __('Custom Graphs')]); ?>

-

+

__('Fields Manager')]); ?>

-

+

__('Incidents')]); ?>

-

+

__('Visual Console')]); ?>

-

+

__('Network Map')]); ?>

-

+

__('Planned Downtime')]); ?>

-

+

- true, 'message' => __('There are no recon task defined yet.') ]); ?> + true, 'message' => __('There are no discovery tasks defined yet.') ]); ?>

- __('Recon server')]); ?> + __('Discovery server')]); ?>
-

+

ICMP (pings), SNMP (detecting the topology of networks and their interfaces), and other customized @@ -33,8 +33,8 @@ ui_require_css_file('firts_task'); ); ?>

- - + +
diff --git a/pandora_console/general/firts_task/service_list.php b/pandora_console/general/firts_task/service_list.php index f3971ca786..424bc60400 100755 --- a/pandora_console/general/firts_task/service_list.php +++ b/pandora_console/general/firts_task/service_list.php @@ -25,7 +25,7 @@ ui_require_css_file('firts_task'); __('Services')]); ?>
-

+

__('SNMP Filter')]); ?>

-

+

__('Tags')]); ?>

-

+

__('Transactions')]); ?>

-

+

'; +echo ''; require_once $config['homedir'].'/include/functions_update_manager.php'; @@ -40,9 +43,7 @@ if ($current_package == 0) { echo sprintf(__('%s %s - Build %s - MR %s', get_product_name(), $pandora_version, $build_package_version, $config['MR'])); -echo '
'; -echo ''.__('Page generated at').' '.date($config['date_format']); -echo '
® '.get_copyright_notice().''; +echo ' '; if (isset($config['debug'])) { $cache_info = []; diff --git a/pandora_console/general/header.php b/pandora_console/general/header.php index 846f20677b..a093596b2b 100644 --- a/pandora_console/general/header.php +++ b/pandora_console/general/header.php @@ -1,8 +1,7 @@ '; +} else { + echo '

'; +} ?> -
".__('Pandora status info').'
".__('MySQL Performance metrics').'
".__('MySQL Performance metrics').' '.ui_print_help_icon('performance_metrics_tab', true).'
".__('Tables fragmentation in the PandoraFMS database').'
".__('Tables fragmentation in the Pandora FMS database').'
".__(' PandoraFMS logs dates').'
".__(' Pandora FMS logs dates').'
".__(' PandoraFMS Licence Information').'
".__(' Pandora FMS Licence Information').'
".__(' Status of the attachment folder').'
".__(' Information from the tagente_datos table').'
".__(' Pandora FMS server threads').'
- - - - - -
- - + '.notifications_print_ball( + $notifications_numbers['notifications'], + $notifications_numbers['last_id'] + ).''; - if (!defined('PANDORA_ENTERPRISE')) { - $logo_title = get_product_name().' Opensource'; - $custom_logo = 'images/custom_logo/pandora_logo_head_3.png'; - } else { - if (file_exists(ENTERPRISE_DIR.'/'.$custom_logo)) { - $custom_logo = ENTERPRISE_DIR.'/'.$custom_logo; - } - - $logo_title = get_product_name().' Enterprise'; - } - - echo html_print_image( - $custom_logo, - true, - [ - 'alt' => $logo_title, - 'border' => '0', - ] - ); - ?> - - - id = 'header_table'; - $table->class = 'none'; - $table->cellpadding = 0; - $table->cellspacing = 0; - $table->head = []; - $table->data = []; - $table->style[0] = $table->style['clippy'] = $table->style[1] = $table->style[3] = $table->style[4] = $table->style[5] = $table->style[6] = $table->style[8] = $table->style[9] = $table->style['qr'] = 'width: 22px; text-align:center; height: 22px; padding-right: 9px;padding-left: 9px;'; - $table->style[7] = 'width: 20px; padding-right: 9px;'; - $table->style['searchbar'] = 'width: 180px; min-width: 180px;'; - $table->style[11] = 'padding-left: 10px; padding-right: 5px;width: 16px;'; - $table->width = '100%'; - $table->styleTable = 'margin: auto; margin-top: 0px;'; - $table->rowclass[0] = ''; - - $acl_head_search = true; - if ($config['acl_enterprise'] == 1 && !users_is_admin()) { - $acl_head_search = db_get_sql( - "SELECT sec FROM tusuario - INNER JOIN tusuario_perfil ON tusuario.id_user = tusuario_perfil.id_usuario - INNER JOIN tprofile_view ON tprofile_view.id_profile = tusuario_perfil.id_perfil - WHERE tusuario.id_user = '".$config['id_user']."' AND (sec = '*' OR sec = 'head_search')" - ); + // ======= Servers List =============================================== + $servers_list = '
'; + $servers = []; + $servers['all'] = (int) db_get_value('COUNT(id_server)', 'tserver'); + if ($servers['all'] != 0) { + $servers['up'] = (int) servers_check_status(); + $servers['down'] = ($servers['all'] - $servers['up']); + if ($servers['up'] == 0) { + // All Servers down or no servers at all. + $servers_check_img = html_print_image('images/header_down_gray.png', true, ['alt' => 'cross', 'class' => 'bot', 'title' => __('All systems').': '.__('Down')]); + } else if ($servers['down'] != 0) { + // Some servers down. + $servers_check_img = html_print_image('images/header_warning_gray.png', true, ['alt' => 'error', 'class' => 'bot', 'title' => $servers['down'].' '.__('servers down')]); + } else { + // All servers up. + $servers_check_img = html_print_image('images/header_ready_gray.png', true, ['alt' => 'ok', 'class' => 'bot', 'title' => __('All systems').': '.__('Ready')]); } - if ($acl_head_search) { - $table->data[0][11] = ui_print_help_tip(__('Blank characters are used as AND conditions'), true); + unset($servers); + // Since this is the header, we don't like to trickle down variables. + $servers_check_img_link = ''; + $servers_check_img_link .= $servers_check_img; + $servers_check_img_link .= ''; + }; + $servers_list .= $servers_check_img_link.'
'; - // Search bar - $search_bar = '
'; - if (!isset($config['search_keywords'])) { + + + // ======= Alerts =============================================== + $check_minor_release_available = false; + $pandora_management = check_acl($config['id_user'], 0, 'PM'); + + $check_minor_release_available = db_check_minor_relase_available(); + + if ($check_minor_release_available) { + if (users_is_admin($config['id_user'])) { + if ($config['language'] == 'es') { + set_pandora_error_for_header('Hay una o mas revisiones menores en espera para ser actualizadas. '.__('Sobre actualización de revisión menor').'', 'Revisión/es menor/es disponible/s'); + } else { + set_pandora_error_for_header('There are one or more minor releases waiting for update. '.__('About minor release update').'', 'minor release/s available'); + } + } + } + + + // Chat messages. + $header_chat = "'; + + + // Search. + $acl_head_search = true; + if ($config['acl_enterprise'] == 1 && !users_is_admin()) { + $acl_head_search = db_get_sql( + "SELECT sec FROM tusuario + INNER JOIN tusuario_perfil ON tusuario.id_user = tusuario_perfil.id_usuario + INNER JOIN tprofile_view ON tprofile_view.id_profile = tusuario_perfil.id_perfil + WHERE tusuario.id_user = '".$config['id_user']."' AND (sec = '*' OR sec = 'head_search')" + ); + } + + if ($acl_head_search) { + // Search bar. + $search_bar = ''; + if (!isset($config['search_keywords'])) { + $search_bar .= ''; + } else { + if (strlen($config['search_keywords']) == 0) { $search_bar .= ''; } else { - if (strlen($config['search_keywords']) == 0) { - $search_bar .= ''; - } else { - $search_bar .= ''; - } + $search_bar .= ''; } + } - $search_bar .= ''; + + // $search_bar .= 'onClick="javascript: document.quicksearch.submit()"'; + $search_bar .= ""; + $search_bar .= '
'; + + $header_searchbar = ''; + } + + + // ======= Autorefresh code ============================= + $autorefresh_txt = ''; + $autorefresh_additional = ''; + + $ignored_params = [ + 'agent_config' => false, + 'code' => false, + ]; + + if (!isset($_GET['sec2'])) { + $_GET['sec2'] = ''; + } + + if ($_GET['sec'] == 'main' || !isset($_GET['sec'])) { + // home screen chosen by the user + $home_page = ''; + if (isset($config['id_user'])) { + $user_info = users_get_user_by_id($config['id_user']); + $home_page = io_safe_output($user_info['section']); + $home_url = $user_info['data_section']; + } + + if ($home_page != '') { + switch ($home_page) { + case 'Event list': + $_GET['sec2'] = 'operation/events/events'; + break; + + case 'Group view': + $_GET['sec2'] = 'operation/agentes/group_view'; + break; + + case 'Alert detail': + $_GET['sec2'] = 'operation/agentes/alerts_status'; + break; + + case 'Tactical view': + $_GET['sec2'] = 'operation/agentes/tactical'; + break; + + case 'Default': + $_GET['sec2'] = 'general/logon_ok'; + break; + + case 'Dashboard': + $_GET['sec2'] = 'enterprise/dashboard/main_dashboard'; + break; + + case 'Visual console': + $_GET['sec2'] = 'operation/visual_console/render_view'; + break; + + case 'Other': + $home_url = io_safe_output($home_url); + $url_array = parse_url($home_url); + parse_str($url_array['query'], $res); + foreach ($res as $key => $param) { + $_GET[$key] = $param; + } + break; } + } + } - $search_bar .= 'onfocus="javascript: if (fieldKeyWordEmpty) $(\'#keywords\').val(\'\');" - onkeyup="javascript: fieldKeyWordEmpty = false;" - style="margin-top:5px;" class="search_input" />'; + if (!isset($_GET['refr'])) { + $_GET['refr'] = null; + } - // $search_bar .= 'onClick="javascript: document.quicksearch.submit()"'; - $search_bar .= ""; - $search_bar .= ''; + $select = db_process_sql( + "SELECT autorefresh_white_list,time_autorefresh + FROM tusuario + WHERE id_user = '".$config['id_user']."'" + ); - $table->data[0]['searchbar'] = $search_bar; + $autorefresh_list = json_decode( + $select[0]['autorefresh_white_list'] + ); + + if ($autorefresh_list !== null + && array_search($_GET['sec2'], $autorefresh_list) !== false + ) { + $do_refresh = true; + if ($_GET['sec2'] == 'operation/agentes/pandora_networkmap') { + if ((!isset($_GET['tab'])) || ($_GET['tab'] != 'view')) { + $do_refresh = false; + } } - // Servers check - $servers = []; - $servers['all'] = (int) db_get_value('COUNT(id_server)', 'tserver'); - $servers['up'] = (int) servers_check_status(); - $servers['down'] = ($servers['all'] - $servers['up']); - if ($servers['up'] == 0) { - // All Servers down or no servers at all - $servers_check_img = html_print_image('images/header_down.png', true, ['alt' => 'cross', 'class' => 'bot', 'title' => __('All systems').': '.__('Down')]); - } else if ($servers['down'] != 0) { - // Some servers down - $servers_check_img = html_print_image('images/header_warning.png', true, ['alt' => 'error', 'class' => 'bot', 'title' => $servers['down'].' '.__('servers down')]); - } else { - // All servers up - $servers_check_img = html_print_image('images/header_ready.png', true, ['alt' => 'ok', 'class' => 'bot', 'title' => __('All systems').': '.__('Ready')]); - } - - unset($servers); - // Since this is the header, we don't like to trickle down variables. - $servers_link_open = ''; - $servers_link_close = ''; - - if ($config['show_qr_code_header'] == 0) { - $show_qr_code_header = 'display: none;'; - } else { - $show_qr_code_header = 'display: inline;'; - } - - $table->data[0]['qr'] = ''; + ); - echo "'; - ?> - - data[0]['clippy'] = ''.html_print_image( - 'images/clippy_icon.png', - true, - [ - 'id' => 'clippy', - 'class' => 'clippy', - 'alt' => __('%s assistant', get_product_name()), - 'title' => __( - '%s assistant', - get_product_name() - ), - ] - ).''; + if ((isset($select[0]['time_autorefresh']) === true) + && $select[0]['time_autorefresh'] !== 0 + && $config['refr'] === null + ) { + $config['refr'] = $select[0]['time_autorefresh']; + $autorefresh_txt .= ' ('; + $autorefresh_txt .= date( + 'i:s', + $config['refr'] + ); + $autorefresh_txt .= ')'; + } else if ($_GET['refr']) { + $autorefresh_txt .= ' ('; + $autorefresh_txt .= date('i:s', $config['refr']); + $autorefresh_txt .= ')'; } + $ignored_params['refr'] = ''; + $values = get_refresh_time_array(); - $table->data[0][0] = $servers_link_open.$servers_check_img.$servers_link_close; - - - - - // ======= Autorefresh code ============================= - $autorefresh_txt = ''; - $autorefresh_additional = ''; - - $ignored_params = [ - 'agent_config' => false, - 'code' => false, - ]; - - if (!isset($_GET['sec2'])) { - $_GET['sec2'] = ''; + $autorefresh_additional = ''; + unset($values); + if ($home_page != '') { + $autorefresh_link_open_img = ''; + } else { + $autorefresh_link_open_img = ''; } - if (!isset($_GET['refr'])) { - $_GET['refr'] = null; - } - - $select = db_process_sql("SELECT autorefresh_white_list,time_autorefresh FROM tusuario WHERE id_user = '".$config['id_user']."'"); - $autorefresh_list = json_decode($select[0]['autorefresh_white_list']); - - if ($autorefresh_list !== null && array_search($_GET['sec2'], $autorefresh_list) !== false) { - $do_refresh = true; - if ($_GET['sec2'] == 'operation/agentes/pandora_networkmap') { - if ((!isset($_GET['tab'])) || ($_GET['tab'] != 'view')) { - $do_refresh = false; - } - } - - if ($do_refresh) { - $autorefresh_img = html_print_image('images/header_refresh.png', true, ['class' => 'bot', 'alt' => 'lightning', 'title' => __('Configure autorefresh')]); - - if ($_GET['refr']) { - $autorefresh_txt .= ' ('.date('i:s', $config['refr']).')'; - } - - $ignored_params['refr'] = ''; - $values = get_refresh_time_array(); - $autorefresh_additional = ''; - unset($values); - - $autorefresh_link_open_img = ''; - - if ($_GET['refr']) { - $autorefresh_link_open_txt = ''; - } else { - $autorefresh_link_open_txt = ''; - } - - $autorefresh_link_close = ''; + if ($_GET['refr'] + || ((isset($select[0]['time_autorefresh']) === true) + && $select[0]['time_autorefresh'] !== 0) + ) { + if ($home_page != '') { + $autorefresh_link_open_txt = ''; } else { - $autorefresh_img = html_print_image('images/header_refresh_disabled.png', true, ['class' => 'bot autorefresh_disabled', 'alt' => 'lightning', 'title' => __('Disabled autorefresh')]); - - $ignored_params['refr'] = false; - - $autorefresh_link_open_img = ''; - $autorefresh_link_open_txt = ''; - $autorefresh_link_close = ''; + $autorefresh_link_open_txt = ''; } } else { - $autorefresh_img = html_print_image('images/header_refresh_disabled.png', true, ['class' => 'bot autorefresh_disabled', 'alt' => 'lightning', 'title' => __('Disabled autorefresh')]); - - $ignored_params['refr'] = false; - - $autorefresh_link_open_img = ''; - $autorefresh_link_open_txt = ''; - $autorefresh_link_close = ''; + $autorefresh_link_open_txt = ''; } - $table->data[0][1] = $autorefresh_link_open_img.$autorefresh_img.$autorefresh_link_close; - $table->data[0][2] = $autorefresh_link_open_txt.$autorefresh_txt.$autorefresh_link_close.$autorefresh_additional; - // ====================================================== - $check_minor_release_available = false; - $pandora_management = check_acl($config['id_user'], 0, 'PM'); + $autorefresh_link_close = ''; + $display_counter = 'display:block'; + } else { + $autorefresh_img = html_print_image('images/header_refresh_disabled_gray.png', true, ['class' => 'bot autorefresh_disabled', 'alt' => 'lightning', 'title' => __('Disabled autorefresh')]); - $check_minor_release_available = db_check_minor_relase_available(); + $ignored_params['refr'] = false; - if ($check_minor_release_available) { - if (users_is_admin($config['id_user'])) { - if ($config['language'] == 'es') { - set_pandora_error_for_header('Hay una o mas revisiones menores en espera para ser actualizadas. '.__('Sobre actualización de revisión menor').'', 'Revisión/es menor/es disponible/s'); - } else { - set_pandora_error_for_header('There are one or more minor releases waiting for update. '.__('About minor release update').'', 'minor release/s available'); - } - } - } + $autorefresh_link_open_img = ''; + $autorefresh_link_open_txt = ''; + $autorefresh_link_close = ''; - echo ''; - - if ($config['alert_cnt'] > 0) { - $maintenance_link = 'javascript:'; - $maintenance_title = __('System alerts detected - Please fix as soon as possible'); - $maintenance_class = $maintenance_id = 'show_systemalert_dialog white'; - - $maintenance_link_open_txt = ''; - $maintenance_link_open_img = ''; - $maintenance_link_close = ''; - if (!$pandora_management) { - $maintenance_img = ''; - } else { - $maintenance_img = $maintenance_link_open_img.html_print_image( - 'images/header_yellow.png', - true, - [ - 'title' => __( - 'You have %d warning(s)', - $config['alert_cnt'] - ), - 'id' => 'yougotalert', - 'class' => 'bot', - ] - ).$maintenance_link_close; - } - } else { - if (!$pandora_management) { - $maintenance_img = ''; - } else { - $maintenance_img = html_print_image('images/header_ready.png', true, ['title' => __('There are not warnings'), 'id' => 'yougotalert', 'class' => 'bot']); - } - } - - $table->data[0][3] = $maintenance_img; - - // Main help icon - if (!$config['disable_help']) { - $table->data[0][4] = ''.html_print_image( - 'images/header_help.png', - true, - [ - 'title' => __('Main help'), - 'id' => 'helpmodal', - 'class' => 'modalpopup', - ] - ).''; - } - - // Logout - $table->data[0][5] = ''; - $table->data[0][5] .= html_print_image('images/header_logout.png', true, ['alt' => __('Logout'), 'class' => 'bot', 'title' => __('Logout')]); - $table->data[0][5] .= ''; - - // User - if (is_user_admin($config['id_user']) == 1) { - $table->data[0][6] = html_print_image('images/header_user_admin.png', true, ['title' => __('Edit my user'), 'class' => 'bot', 'alt' => 'user']); - } else { - $table->data[0][6] = html_print_image('images/header_user.png', true, ['title' => __('Edit my user'), 'class' => 'bot', 'alt' => 'user']); - } - - $table->data[0][6] = ''.$table->data[0][6].''; - - $table->data[0][7] = ' ('.$config['id_user'].')'; - - // Chat messages - $table->data[0][8] = "'; - - // Messages - $msg_cnt = messages_get_count($config['id_user']); - if ($msg_cnt > 0) { - echo ''; - - $table->data[0][9] = ''; - $table->data[0][9] .= html_print_image('images/header_email.png', true, ['title' => __('You have %d unread message(s)', $msg_cnt), 'id' => 'yougotmail', 'class' => 'bot', 'style' => 'width:24px;']); - $table->data[0][9] .= ''; - } - - - - html_print_table($table); - - unset($table); - ?> -
+ $ignored_params['refr'] = false; + + $autorefresh_link_open_img = ''; + $autorefresh_link_open_txt = ''; + $autorefresh_link_close = ''; + + $display_counter = 'display:none'; + } + + $header_autorefresh = '
'; + $header_autorefresh .= $autorefresh_link_open_img; + $header_autorefresh .= $autorefresh_img; + $header_autorefresh .= $autorefresh_link_close; + $header_autorefresh .= '
'; + + $header_autorefresh_counter = '
'; + $header_autorefresh_counter .= $autorefresh_link_open_txt; + $header_autorefresh_counter .= $autorefresh_txt; + $header_autorefresh_counter .= $autorefresh_link_close; + $header_autorefresh_counter .= $autorefresh_additional; + $header_autorefresh_counter .= '
'; + + + // Support. + if (defined('PANDORA_ENTERPRISE')) { + $header_support_link = 'https://support.artica.es/'; + } else { + $header_support_link = 'https://pandorafms.com/forums/'; + } + + $header_support = ''; + + // Documentation. + $header_docu = ''; + + + // User. + if (is_user_admin($config['id_user']) == 1) { + $header_user = html_print_image( + 'images/header_user_admin_green.png', + true, + [ + 'title' => __('Edit my user'), + 'class' => 'bot', + 'alt' => 'user', + ] + ); + } else { + $header_user = html_print_image( + 'images/header_user_green.png', + true, + [ + 'title' => __('Edit my user'), + 'class' => 'bot', + 'alt' => 'user', + ] + ); + } + + $header_user = ''; + + // Logout. + $header_logout = ''; + + echo '
'.$config['custom_title_header'].''.$config['custom_subtitle_header'].'
+
'.$header_searchbar.'
+
'.$header_chat, $header_autorefresh, $header_autorefresh_counter, $header_discovery, $servers_list, $header_support, $header_docu, $header_user, $header_logout.'
'; + ?> + + + + + + + + + - - - diff --git a/pandora_console/general/login_page.php b/pandora_console/general/login_page.php index 198b5c3fc9..86dccfa53a 100755 --- a/pandora_console/general/login_page.php +++ b/pandora_console/general/login_page.php @@ -82,42 +82,30 @@ if (!empty($page) && !empty($sec)) { } $login_body_style = ''; -// Overrides the default background with the defined by the user +// Overrides the default background with the defined by the user. if (!empty($config['login_background'])) { $background_url = 'images/backgrounds/'.$config['login_background']; - $login_body_style = "style=\"background-image: url('$background_url');\""; + $login_body_style = "style=\"background:linear-gradient(74deg, #02020255 36%, transparent 36%), url('".$background_url."');\""; } -// Get the custom icons +// Get the custom icons. $docs_logo = ui_get_docs_logo(); $support_logo = ui_get_support_logo(); echo '
'; echo '
'; - echo '
'; -if (file_exists(ENTERPRISE_DIR.'/load_enterprise.php')) { - if (isset($config['custom_logo'])) { - echo 'monitoring_console'; - } else { - echo 'monitoring_console'; - } -} else { - echo 'monitoring_console'; -} - - echo '
'; - echo '
'; + } + + +} diff --git a/pandora_console/godmode/wizards/index.php b/pandora_console/godmode/wizards/index.php new file mode 100755 index 0000000000..d825d5121d --- /dev/null +++ b/pandora_console/godmode/wizards/index.php @@ -0,0 +1,7 @@ +load(); diff --git a/pandora_console/images/arrow_down_green.png b/pandora_console/images/arrow_down_green.png new file mode 100644 index 0000000000..edc1cff1b8 Binary files /dev/null and b/pandora_console/images/arrow_down_green.png differ diff --git a/pandora_console/images/arrow_down_white.png b/pandora_console/images/arrow_down_white.png new file mode 100644 index 0000000000..7b28df71f9 Binary files /dev/null and b/pandora_console/images/arrow_down_white.png differ diff --git a/pandora_console/images/arrow_right_green.png b/pandora_console/images/arrow_right_green.png new file mode 100644 index 0000000000..a772cd6cf4 Binary files /dev/null and b/pandora_console/images/arrow_right_green.png differ diff --git a/pandora_console/images/arrow_up_green.png b/pandora_console/images/arrow_up_green.png new file mode 100644 index 0000000000..c197c2333c Binary files /dev/null and b/pandora_console/images/arrow_up_green.png differ diff --git a/pandora_console/images/arrow_up_white.png b/pandora_console/images/arrow_up_white.png new file mode 100644 index 0000000000..2fbd55b69a Binary files /dev/null and b/pandora_console/images/arrow_up_white.png differ diff --git a/pandora_console/images/back_login.png b/pandora_console/images/back_login.png new file mode 100644 index 0000000000..870226192e Binary files /dev/null and b/pandora_console/images/back_login.png differ diff --git a/pandora_console/images/back_login_hover.png b/pandora_console/images/back_login_hover.png new file mode 100644 index 0000000000..d518b9cfe6 Binary files /dev/null and b/pandora_console/images/back_login_hover.png differ diff --git a/pandora_console/images/backgrounds/background_pandora_console_keys.jpg b/pandora_console/images/backgrounds/background_pandora_console_keys.jpg index b919de4ed8..d1775d40f2 100644 Binary files a/pandora_console/images/backgrounds/background_pandora_console_keys.jpg and b/pandora_console/images/backgrounds/background_pandora_console_keys.jpg differ diff --git a/pandora_console/images/backgrounds/background_pandora_console_keys_2.jpg b/pandora_console/images/backgrounds/background_pandora_console_keys_2.jpg new file mode 100644 index 0000000000..b919de4ed8 Binary files /dev/null and b/pandora_console/images/backgrounds/background_pandora_console_keys_2.jpg differ diff --git a/pandora_console/images/builder.menu_gray.png b/pandora_console/images/builder.menu_gray.png new file mode 100644 index 0000000000..bee9c472ba Binary files /dev/null and b/pandora_console/images/builder.menu_gray.png differ diff --git a/pandora_console/images/builder.menu_white.png b/pandora_console/images/builder.menu_white.png new file mode 100644 index 0000000000..f08ba661e9 Binary files /dev/null and b/pandora_console/images/builder.menu_white.png differ diff --git a/pandora_console/images/button_classic_menu.png b/pandora_console/images/button_classic_menu.png new file mode 100644 index 0000000000..c84ab30c21 Binary files /dev/null and b/pandora_console/images/button_classic_menu.png differ diff --git a/pandora_console/images/button_collapse_menu.png b/pandora_console/images/button_collapse_menu.png new file mode 100644 index 0000000000..17b91bab38 Binary files /dev/null and b/pandora_console/images/button_collapse_menu.png differ diff --git a/pandora_console/images/candado_login.png b/pandora_console/images/candado_login.png index 149f2ef12c..3c51ef775e 100644 Binary files a/pandora_console/images/candado_login.png and b/pandora_console/images/candado_login.png differ diff --git a/pandora_console/images/clippy_icon_gray.png b/pandora_console/images/clippy_icon_gray.png new file mode 100644 index 0000000000..e7ac2b967a Binary files /dev/null and b/pandora_console/images/clippy_icon_gray.png differ diff --git a/pandora_console/images/custom_logo/pandora_logo_green_collapsed.png b/pandora_console/images/custom_logo/pandora_logo_green_collapsed.png new file mode 100644 index 0000000000..73f77dec8f Binary files /dev/null and b/pandora_console/images/custom_logo/pandora_logo_green_collapsed.png differ diff --git a/pandora_console/images/custom_logo/pandora_logo_head_3.png b/pandora_console/images/custom_logo/pandora_logo_head_3.png index 5bce825279..c39d604af8 100644 Binary files a/pandora_console/images/custom_logo/pandora_logo_head_3.png and b/pandora_console/images/custom_logo/pandora_logo_head_3.png differ diff --git a/pandora_console/images/custom_logo/pandora_logo_head_4.png b/pandora_console/images/custom_logo/pandora_logo_head_4.png index 275871dca6..8bf5fbb1d3 100644 Binary files a/pandora_console/images/custom_logo/pandora_logo_head_4.png and b/pandora_console/images/custom_logo/pandora_logo_head_4.png differ diff --git a/pandora_console/images/custom_logo/pandora_logo_head_5.png b/pandora_console/images/custom_logo/pandora_logo_head_5.png new file mode 100644 index 0000000000..275871dca6 Binary files /dev/null and b/pandora_console/images/custom_logo/pandora_logo_head_5.png differ diff --git a/pandora_console/images/custom_logo/pandora_logo_head_6.png b/pandora_console/images/custom_logo/pandora_logo_head_6.png new file mode 100644 index 0000000000..5bce825279 Binary files /dev/null and b/pandora_console/images/custom_logo/pandora_logo_head_6.png differ diff --git a/pandora_console/images/custom_logo_login/pandora_logo.png b/pandora_console/images/custom_logo_login/pandora_logo.png index 67aeb1bf84..c84a02fb6a 100644 Binary files a/pandora_console/images/custom_logo_login/pandora_logo.png and b/pandora_console/images/custom_logo_login/pandora_logo.png differ diff --git a/pandora_console/images/custom_logo_login/pandora_logo_2.png b/pandora_console/images/custom_logo_login/pandora_logo_2.png new file mode 100644 index 0000000000..67aeb1bf84 Binary files /dev/null and b/pandora_console/images/custom_logo_login/pandora_logo_2.png differ diff --git a/pandora_console/images/darrowleft_green.png b/pandora_console/images/darrowleft_green.png new file mode 100644 index 0000000000..6262dd7e2d Binary files /dev/null and b/pandora_console/images/darrowleft_green.png differ diff --git a/pandora_console/images/darrowright_green.png b/pandora_console/images/darrowright_green.png new file mode 100644 index 0000000000..ccac0d6690 Binary files /dev/null and b/pandora_console/images/darrowright_green.png differ diff --git a/pandora_console/images/discovery-100.png b/pandora_console/images/discovery-100.png new file mode 100644 index 0000000000..7ec755e7eb Binary files /dev/null and b/pandora_console/images/discovery-100.png differ diff --git a/pandora_console/images/discovery_green-100.png b/pandora_console/images/discovery_green-100.png new file mode 100644 index 0000000000..bcda80e4dd Binary files /dev/null and b/pandora_console/images/discovery_green-100.png differ diff --git a/pandora_console/images/extensions.menu_gray.png b/pandora_console/images/extensions.menu_gray.png new file mode 100644 index 0000000000..7e7c768645 Binary files /dev/null and b/pandora_console/images/extensions.menu_gray.png differ diff --git a/pandora_console/images/extensions.menu_white.png b/pandora_console/images/extensions.menu_white.png new file mode 100644 index 0000000000..7618eb6c23 Binary files /dev/null and b/pandora_console/images/extensions.menu_white.png differ diff --git a/pandora_console/images/firts_task/icono_aws.png b/pandora_console/images/firts_task/icono_aws.png new file mode 100644 index 0000000000..c5f0c3a547 Binary files /dev/null and b/pandora_console/images/firts_task/icono_aws.png differ diff --git a/pandora_console/images/gm_alerts.menu_gray.png b/pandora_console/images/gm_alerts.menu_gray.png new file mode 100644 index 0000000000..3973619787 Binary files /dev/null and b/pandora_console/images/gm_alerts.menu_gray.png differ diff --git a/pandora_console/images/gm_alerts.menu_white.png b/pandora_console/images/gm_alerts.menu_white.png new file mode 100644 index 0000000000..6eae2f3b31 Binary files /dev/null and b/pandora_console/images/gm_alerts.menu_white.png differ diff --git a/pandora_console/images/gm_configuration.menu_gray.png b/pandora_console/images/gm_configuration.menu_gray.png new file mode 100644 index 0000000000..1d69e0f85b Binary files /dev/null and b/pandora_console/images/gm_configuration.menu_gray.png differ diff --git a/pandora_console/images/gm_configuration.menu_white.png b/pandora_console/images/gm_configuration.menu_white.png new file mode 100644 index 0000000000..a82ece6578 Binary files /dev/null and b/pandora_console/images/gm_configuration.menu_white.png differ diff --git a/pandora_console/images/gm_discovery.menu.png b/pandora_console/images/gm_discovery.menu.png new file mode 100644 index 0000000000..5c0296b562 Binary files /dev/null and b/pandora_console/images/gm_discovery.menu.png differ diff --git a/pandora_console/images/gm_discovery.menu_white.png b/pandora_console/images/gm_discovery.menu_white.png new file mode 100644 index 0000000000..80d0913c90 Binary files /dev/null and b/pandora_console/images/gm_discovery.menu_white.png differ diff --git a/pandora_console/images/gm_discovery_green.menu.png b/pandora_console/images/gm_discovery_green.menu.png new file mode 100644 index 0000000000..f4a387c201 Binary files /dev/null and b/pandora_console/images/gm_discovery_green.menu.png differ diff --git a/pandora_console/images/gm_events.menu_gray.png b/pandora_console/images/gm_events.menu_gray.png new file mode 100644 index 0000000000..09bcd60c8f Binary files /dev/null and b/pandora_console/images/gm_events.menu_gray.png differ diff --git a/pandora_console/images/gm_events.menu_white.png b/pandora_console/images/gm_events.menu_white.png new file mode 100644 index 0000000000..43e8c157c8 Binary files /dev/null and b/pandora_console/images/gm_events.menu_white.png differ diff --git a/pandora_console/images/gm_resources.menu_gray.png b/pandora_console/images/gm_resources.menu_gray.png new file mode 100644 index 0000000000..7915645c47 Binary files /dev/null and b/pandora_console/images/gm_resources.menu_gray.png differ diff --git a/pandora_console/images/gm_resources.menu_white.png b/pandora_console/images/gm_resources.menu_white.png new file mode 100644 index 0000000000..130b63ce3d Binary files /dev/null and b/pandora_console/images/gm_resources.menu_white.png differ diff --git a/pandora_console/images/gm_servers.menu_gray.png b/pandora_console/images/gm_servers.menu_gray.png new file mode 100644 index 0000000000..c32c8e06c2 Binary files /dev/null and b/pandora_console/images/gm_servers.menu_gray.png differ diff --git a/pandora_console/images/gm_servers.menu_white.png b/pandora_console/images/gm_servers.menu_white.png new file mode 100644 index 0000000000..c2604ad7da Binary files /dev/null and b/pandora_console/images/gm_servers.menu_white.png differ diff --git a/pandora_console/images/gm_setup.menu_gray.png b/pandora_console/images/gm_setup.menu_gray.png new file mode 100644 index 0000000000..14e6cf1031 Binary files /dev/null and b/pandora_console/images/gm_setup.menu_gray.png differ diff --git a/pandora_console/images/gm_setup.menu_white.png b/pandora_console/images/gm_setup.menu_white.png new file mode 100644 index 0000000000..79ee9cd95f Binary files /dev/null and b/pandora_console/images/gm_setup.menu_white.png differ diff --git a/pandora_console/images/gm_users.menu_gray.png b/pandora_console/images/gm_users.menu_gray.png new file mode 100644 index 0000000000..94261dcdbc Binary files /dev/null and b/pandora_console/images/gm_users.menu_gray.png differ diff --git a/pandora_console/images/gm_users.menu_white.png b/pandora_console/images/gm_users.menu_white.png new file mode 100644 index 0000000000..83a8134a9b Binary files /dev/null and b/pandora_console/images/gm_users.menu_white.png differ diff --git a/pandora_console/images/go_first_g.png b/pandora_console/images/go_first_g.png new file mode 100644 index 0000000000..dcb0fe41b8 Binary files /dev/null and b/pandora_console/images/go_first_g.png differ diff --git a/pandora_console/images/go_last_g.png b/pandora_console/images/go_last_g.png new file mode 100644 index 0000000000..ce49963baa Binary files /dev/null and b/pandora_console/images/go_last_g.png differ diff --git a/pandora_console/images/go_next_g.png b/pandora_console/images/go_next_g.png new file mode 100644 index 0000000000..08601a2a3e Binary files /dev/null and b/pandora_console/images/go_next_g.png differ diff --git a/pandora_console/images/go_previous_g.png b/pandora_console/images/go_previous_g.png new file mode 100644 index 0000000000..84bbe0492e Binary files /dev/null and b/pandora_console/images/go_previous_g.png differ diff --git a/pandora_console/images/header_alert_gray.png b/pandora_console/images/header_alert_gray.png new file mode 100644 index 0000000000..13a2172a92 Binary files /dev/null and b/pandora_console/images/header_alert_gray.png differ diff --git a/pandora_console/images/header_chat_gray.png b/pandora_console/images/header_chat_gray.png new file mode 100644 index 0000000000..54ebc23bdc Binary files /dev/null and b/pandora_console/images/header_chat_gray.png differ diff --git a/pandora_console/images/header_docu.png b/pandora_console/images/header_docu.png new file mode 100644 index 0000000000..2a1c193bed Binary files /dev/null and b/pandora_console/images/header_docu.png differ diff --git a/pandora_console/images/header_down_gray.png b/pandora_console/images/header_down_gray.png new file mode 100644 index 0000000000..68b302c3ea Binary files /dev/null and b/pandora_console/images/header_down_gray.png differ diff --git a/pandora_console/images/header_email.png b/pandora_console/images/header_email.png index 0d45c72d46..c5d41054a2 100644 Binary files a/pandora_console/images/header_email.png and b/pandora_console/images/header_email.png differ diff --git a/pandora_console/images/header_email_old.png b/pandora_console/images/header_email_old.png new file mode 100644 index 0000000000..0d45c72d46 Binary files /dev/null and b/pandora_console/images/header_email_old.png differ diff --git a/pandora_console/images/header_help_gray.png b/pandora_console/images/header_help_gray.png new file mode 100644 index 0000000000..faa7815a32 Binary files /dev/null and b/pandora_console/images/header_help_gray.png differ diff --git a/pandora_console/images/header_logout_gray.png b/pandora_console/images/header_logout_gray.png new file mode 100644 index 0000000000..e139a329a1 Binary files /dev/null and b/pandora_console/images/header_logout_gray.png differ diff --git a/pandora_console/images/header_ready_gray.png b/pandora_console/images/header_ready_gray.png new file mode 100644 index 0000000000..a1fd9adfb3 Binary files /dev/null and b/pandora_console/images/header_ready_gray.png differ diff --git a/pandora_console/images/header_refresh_disabled_gray.png b/pandora_console/images/header_refresh_disabled_gray.png new file mode 100644 index 0000000000..abe7de6bea Binary files /dev/null and b/pandora_console/images/header_refresh_disabled_gray.png differ diff --git a/pandora_console/images/header_refresh_gray.png b/pandora_console/images/header_refresh_gray.png new file mode 100644 index 0000000000..35c8893b01 Binary files /dev/null and b/pandora_console/images/header_refresh_gray.png differ diff --git a/pandora_console/images/header_support.png b/pandora_console/images/header_support.png new file mode 100644 index 0000000000..75823214b6 Binary files /dev/null and b/pandora_console/images/header_support.png differ diff --git a/pandora_console/images/header_user_admin_green.png b/pandora_console/images/header_user_admin_green.png new file mode 100644 index 0000000000..5179d6b263 Binary files /dev/null and b/pandora_console/images/header_user_admin_green.png differ diff --git a/pandora_console/images/header_user_green.png b/pandora_console/images/header_user_green.png new file mode 100644 index 0000000000..4a2eae96e5 Binary files /dev/null and b/pandora_console/images/header_user_green.png differ diff --git a/pandora_console/images/header_warning_gray.png b/pandora_console/images/header_warning_gray.png new file mode 100644 index 0000000000..c09319fef4 Binary files /dev/null and b/pandora_console/images/header_warning_gray.png differ diff --git a/pandora_console/images/help_g.png b/pandora_console/images/help_g.png new file mode 100644 index 0000000000..60aae95a80 Binary files /dev/null and b/pandora_console/images/help_g.png differ diff --git a/pandora_console/images/help_green.png b/pandora_console/images/help_green.png new file mode 100644 index 0000000000..0d02332988 Binary files /dev/null and b/pandora_console/images/help_green.png differ diff --git a/pandora_console/images/icon_error_db.png b/pandora_console/images/icon_error_db.png new file mode 100644 index 0000000000..1aad380c2f Binary files /dev/null and b/pandora_console/images/icon_error_db.png differ diff --git a/pandora_console/images/icon_error_mr.png b/pandora_console/images/icon_error_mr.png new file mode 100644 index 0000000000..d1e33eed42 Binary files /dev/null and b/pandora_console/images/icon_error_mr.png differ diff --git a/pandora_console/images/icon_info_mr.png b/pandora_console/images/icon_info_mr.png new file mode 100644 index 0000000000..4c0abb0585 Binary files /dev/null and b/pandora_console/images/icon_info_mr.png differ diff --git a/pandora_console/images/icon_success_db.png b/pandora_console/images/icon_success_db.png new file mode 100644 index 0000000000..38511ca06e Binary files /dev/null and b/pandora_console/images/icon_success_db.png differ diff --git a/pandora_console/images/icon_success_mr.png b/pandora_console/images/icon_success_mr.png new file mode 100644 index 0000000000..39c72ea9a1 Binary files /dev/null and b/pandora_console/images/icon_success_mr.png differ diff --git a/pandora_console/images/icon_warning_db.png b/pandora_console/images/icon_warning_db.png new file mode 100644 index 0000000000..f89a7f51b0 Binary files /dev/null and b/pandora_console/images/icon_warning_db.png differ diff --git a/pandora_console/images/imagen-no-acceso.jpg b/pandora_console/images/imagen-no-acceso.jpg new file mode 100644 index 0000000000..93b9256edb Binary files /dev/null and b/pandora_console/images/imagen-no-acceso.jpg differ diff --git a/pandora_console/images/input_zoom_gray.png b/pandora_console/images/input_zoom_gray.png new file mode 100644 index 0000000000..002e397e8a Binary files /dev/null and b/pandora_console/images/input_zoom_gray.png differ diff --git a/pandora_console/images/links.menu_gray.png b/pandora_console/images/links.menu_gray.png new file mode 100644 index 0000000000..7520e0f056 Binary files /dev/null and b/pandora_console/images/links.menu_gray.png differ diff --git a/pandora_console/images/links.menu_white.png b/pandora_console/images/links.menu_white.png new file mode 100644 index 0000000000..71af1a2cd2 Binary files /dev/null and b/pandora_console/images/links.menu_white.png differ diff --git a/pandora_console/images/mysqlerr.png b/pandora_console/images/mysqlerr.png new file mode 100644 index 0000000000..7f6e0ffbc3 Binary files /dev/null and b/pandora_console/images/mysqlerr.png differ diff --git a/pandora_console/images/op_events.menu_gray.png b/pandora_console/images/op_events.menu_gray.png new file mode 100644 index 0000000000..84ab4bebf2 Binary files /dev/null and b/pandora_console/images/op_events.menu_gray.png differ diff --git a/pandora_console/images/op_events.menu_white.png b/pandora_console/images/op_events.menu_white.png new file mode 100644 index 0000000000..b2cadf90ea Binary files /dev/null and b/pandora_console/images/op_events.menu_white.png differ diff --git a/pandora_console/images/op_monitoring.menu_gray.png b/pandora_console/images/op_monitoring.menu_gray.png new file mode 100644 index 0000000000..5456d64b1d Binary files /dev/null and b/pandora_console/images/op_monitoring.menu_gray.png differ diff --git a/pandora_console/images/op_monitoring.menu_white.png b/pandora_console/images/op_monitoring.menu_white.png new file mode 100644 index 0000000000..8ed3c1a0a4 Binary files /dev/null and b/pandora_console/images/op_monitoring.menu_white.png differ diff --git a/pandora_console/images/op_network.menu_gray.png b/pandora_console/images/op_network.menu_gray.png new file mode 100644 index 0000000000..4d76055f8a Binary files /dev/null and b/pandora_console/images/op_network.menu_gray.png differ diff --git a/pandora_console/images/op_network.menu_white.png b/pandora_console/images/op_network.menu_white.png new file mode 100644 index 0000000000..cf778daeb5 Binary files /dev/null and b/pandora_console/images/op_network.menu_white.png differ diff --git a/pandora_console/images/op_reporting.menu_gray.png b/pandora_console/images/op_reporting.menu_gray.png new file mode 100644 index 0000000000..3e99cf9064 Binary files /dev/null and b/pandora_console/images/op_reporting.menu_gray.png differ diff --git a/pandora_console/images/op_reporting.menu_white.png b/pandora_console/images/op_reporting.menu_white.png new file mode 100644 index 0000000000..a764bc3a7a Binary files /dev/null and b/pandora_console/images/op_reporting.menu_white.png differ diff --git a/pandora_console/images/op_workspace.menu_gray.png b/pandora_console/images/op_workspace.menu_gray.png new file mode 100644 index 0000000000..4689daeaed Binary files /dev/null and b/pandora_console/images/op_workspace.menu_gray.png differ diff --git a/pandora_console/images/op_workspace.menu_white.png b/pandora_console/images/op_workspace.menu_white.png new file mode 100644 index 0000000000..fec51f589e Binary files /dev/null and b/pandora_console/images/op_workspace.menu_white.png differ diff --git a/pandora_console/images/people_1.png b/pandora_console/images/people_1.png old mode 100755 new mode 100644 index 19ad0f4e6a..aa1dd32f32 Binary files a/pandora_console/images/people_1.png and b/pandora_console/images/people_1.png differ diff --git a/pandora_console/images/people_1_old.png b/pandora_console/images/people_1_old.png new file mode 100755 index 0000000000..19ad0f4e6a Binary files /dev/null and b/pandora_console/images/people_1_old.png differ diff --git a/pandora_console/images/people_2.png b/pandora_console/images/people_2.png old mode 100755 new mode 100644 index dd38b8d758..14ba3aaaeb Binary files a/pandora_console/images/people_2.png and b/pandora_console/images/people_2.png differ diff --git a/pandora_console/images/people_2_old.png b/pandora_console/images/people_2_old.png new file mode 100755 index 0000000000..dd38b8d758 Binary files /dev/null and b/pandora_console/images/people_2_old.png differ diff --git a/pandora_console/images/qrcode_icon_gray.png b/pandora_console/images/qrcode_icon_gray.png new file mode 100644 index 0000000000..c2408753f0 Binary files /dev/null and b/pandora_console/images/qrcode_icon_gray.png differ diff --git a/pandora_console/images/saml_login.png b/pandora_console/images/saml_login.png new file mode 100644 index 0000000000..414b590d84 Binary files /dev/null and b/pandora_console/images/saml_login.png differ diff --git a/pandora_console/images/saml_login_hover.png b/pandora_console/images/saml_login_hover.png new file mode 100644 index 0000000000..7f76c0e5ad Binary files /dev/null and b/pandora_console/images/saml_login_hover.png differ diff --git a/pandora_console/images/sort_down_black.png b/pandora_console/images/sort_down_black.png new file mode 100644 index 0000000000..13ade460fc Binary files /dev/null and b/pandora_console/images/sort_down_black.png differ diff --git a/pandora_console/images/sort_down_green.png b/pandora_console/images/sort_down_green.png new file mode 100644 index 0000000000..dc6086912d Binary files /dev/null and b/pandora_console/images/sort_down_green.png differ diff --git a/pandora_console/images/sort_up_black.png b/pandora_console/images/sort_up_black.png new file mode 100644 index 0000000000..238d89520f Binary files /dev/null and b/pandora_console/images/sort_up_black.png differ diff --git a/pandora_console/images/sort_up_green.png b/pandora_console/images/sort_up_green.png new file mode 100644 index 0000000000..5c57937f40 Binary files /dev/null and b/pandora_console/images/sort_up_green.png differ diff --git a/pandora_console/images/status_sets/default/module_alertsfired_rounded.png b/pandora_console/images/status_sets/default/module_alertsfired_rounded.png new file mode 100644 index 0000000000..7a9b5ae0cd Binary files /dev/null and b/pandora_console/images/status_sets/default/module_alertsfired_rounded.png differ diff --git a/pandora_console/images/status_sets/default/module_critical_rounded.png b/pandora_console/images/status_sets/default/module_critical_rounded.png new file mode 100644 index 0000000000..7fceda18da Binary files /dev/null and b/pandora_console/images/status_sets/default/module_critical_rounded.png differ diff --git a/pandora_console/images/status_sets/default/module_no_data_rounded.png b/pandora_console/images/status_sets/default/module_no_data_rounded.png new file mode 100644 index 0000000000..fd5e433ece Binary files /dev/null and b/pandora_console/images/status_sets/default/module_no_data_rounded.png differ diff --git a/pandora_console/images/status_sets/default/module_ok_rounded.png b/pandora_console/images/status_sets/default/module_ok_rounded.png new file mode 100644 index 0000000000..d47f2ef4ff Binary files /dev/null and b/pandora_console/images/status_sets/default/module_ok_rounded.png differ diff --git a/pandora_console/images/status_sets/default/module_unknown_rounded.png b/pandora_console/images/status_sets/default/module_unknown_rounded.png new file mode 100644 index 0000000000..2ec6d98f39 Binary files /dev/null and b/pandora_console/images/status_sets/default/module_unknown_rounded.png differ diff --git a/pandora_console/images/status_sets/default/module_warning_rounded.png b/pandora_console/images/status_sets/default/module_warning_rounded.png new file mode 100644 index 0000000000..c28924178d Binary files /dev/null and b/pandora_console/images/status_sets/default/module_warning_rounded.png differ diff --git a/pandora_console/images/status_sets/default/severity_critical_rounded.png b/pandora_console/images/status_sets/default/severity_critical_rounded.png new file mode 100644 index 0000000000..7fceda18da Binary files /dev/null and b/pandora_console/images/status_sets/default/severity_critical_rounded.png differ diff --git a/pandora_console/images/status_sets/default/severity_informational_rounded.png b/pandora_console/images/status_sets/default/severity_informational_rounded.png new file mode 100644 index 0000000000..fd5e433ece Binary files /dev/null and b/pandora_console/images/status_sets/default/severity_informational_rounded.png differ diff --git a/pandora_console/images/status_sets/default/severity_maintenance_rounded.png b/pandora_console/images/status_sets/default/severity_maintenance_rounded.png new file mode 100644 index 0000000000..2ec6d98f39 Binary files /dev/null and b/pandora_console/images/status_sets/default/severity_maintenance_rounded.png differ diff --git a/pandora_console/images/status_sets/default/severity_major_rounded.png b/pandora_console/images/status_sets/default/severity_major_rounded.png new file mode 100644 index 0000000000..cc6523e28e Binary files /dev/null and b/pandora_console/images/status_sets/default/severity_major_rounded.png differ diff --git a/pandora_console/images/status_sets/default/severity_minor_rounded.png b/pandora_console/images/status_sets/default/severity_minor_rounded.png new file mode 100644 index 0000000000..fd3ea3d2d9 Binary files /dev/null and b/pandora_console/images/status_sets/default/severity_minor_rounded.png differ diff --git a/pandora_console/images/status_sets/default/severity_normal_rounded.png b/pandora_console/images/status_sets/default/severity_normal_rounded.png new file mode 100644 index 0000000000..d47f2ef4ff Binary files /dev/null and b/pandora_console/images/status_sets/default/severity_normal_rounded.png differ diff --git a/pandora_console/images/status_sets/default/severity_warning_rounded.png b/pandora_console/images/status_sets/default/severity_warning_rounded.png new file mode 100644 index 0000000000..c28924178d Binary files /dev/null and b/pandora_console/images/status_sets/default/severity_warning_rounded.png differ diff --git a/pandora_console/images/timestamp.png b/pandora_console/images/timestamp.png new file mode 100644 index 0000000000..1750c4acbd Binary files /dev/null and b/pandora_console/images/timestamp.png differ diff --git a/pandora_console/images/tip_help.png b/pandora_console/images/tip_help.png new file mode 100644 index 0000000000..f2704b34ac Binary files /dev/null and b/pandora_console/images/tip_help.png differ diff --git a/pandora_console/images/to_top_menu.png b/pandora_console/images/to_top_menu.png new file mode 100644 index 0000000000..ebc693cf39 Binary files /dev/null and b/pandora_console/images/to_top_menu.png differ diff --git a/pandora_console/images/to_top_menu_hover.png b/pandora_console/images/to_top_menu_hover.png new file mode 100644 index 0000000000..452f7450dd Binary files /dev/null and b/pandora_console/images/to_top_menu_hover.png differ diff --git a/pandora_console/images/tree_events.png b/pandora_console/images/tree_events.png new file mode 100644 index 0000000000..7628d6a80d Binary files /dev/null and b/pandora_console/images/tree_events.png differ diff --git a/pandora_console/images/tree_service_map.png b/pandora_console/images/tree_service_map.png new file mode 100644 index 0000000000..16005f1c98 Binary files /dev/null and b/pandora_console/images/tree_service_map.png differ diff --git a/pandora_console/images/um_messages.menu_gray.png b/pandora_console/images/um_messages.menu_gray.png new file mode 100644 index 0000000000..b76bf8d6b4 Binary files /dev/null and b/pandora_console/images/um_messages.menu_gray.png differ diff --git a/pandora_console/images/um_messages.menu_white.png b/pandora_console/images/um_messages.menu_white.png new file mode 100644 index 0000000000..5c4a899c24 Binary files /dev/null and b/pandora_console/images/um_messages.menu_white.png differ diff --git a/pandora_console/images/update_manager_background.jpg b/pandora_console/images/update_manager_background.jpg new file mode 100644 index 0000000000..121e476860 Binary files /dev/null and b/pandora_console/images/update_manager_background.jpg differ diff --git a/pandora_console/images/update_manager_button.png b/pandora_console/images/update_manager_button.png new file mode 100644 index 0000000000..b18b218d78 Binary files /dev/null and b/pandora_console/images/update_manager_button.png differ diff --git a/pandora_console/images/user_email.png b/pandora_console/images/user_email.png new file mode 100644 index 0000000000..095b012a5c Binary files /dev/null and b/pandora_console/images/user_email.png differ diff --git a/pandora_console/images/user_login.png b/pandora_console/images/user_login.png new file mode 100644 index 0000000000..4821ba6d52 Binary files /dev/null and b/pandora_console/images/user_login.png differ diff --git a/pandora_console/images/user_login_hover.png b/pandora_console/images/user_login_hover.png new file mode 100644 index 0000000000..14705007e5 Binary files /dev/null and b/pandora_console/images/user_login_hover.png differ diff --git a/pandora_console/images/user_name.png b/pandora_console/images/user_name.png new file mode 100644 index 0000000000..20f823f40e Binary files /dev/null and b/pandora_console/images/user_name.png differ diff --git a/pandora_console/images/user_password.png b/pandora_console/images/user_password.png new file mode 100644 index 0000000000..8e81afd75e Binary files /dev/null and b/pandora_console/images/user_password.png differ diff --git a/pandora_console/images/user_phone.png b/pandora_console/images/user_phone.png new file mode 100644 index 0000000000..050559ed8d Binary files /dev/null and b/pandora_console/images/user_phone.png differ diff --git a/pandora_console/images/usuario_login.png b/pandora_console/images/usuario_login.png index cd333a1f46..78e65a607d 100644 Binary files a/pandora_console/images/usuario_login.png and b/pandora_console/images/usuario_login.png differ diff --git a/pandora_console/images/welcome_image.png b/pandora_console/images/welcome_image.png new file mode 100644 index 0000000000..b9b745ba33 Binary files /dev/null and b/pandora_console/images/welcome_image.png differ diff --git a/pandora_console/images/wizard/customnetscan.png b/pandora_console/images/wizard/customnetscan.png new file mode 100644 index 0000000000..edc036fa39 Binary files /dev/null and b/pandora_console/images/wizard/customnetscan.png differ diff --git a/pandora_console/images/wizard/hostdevices.png b/pandora_console/images/wizard/hostdevices.png new file mode 100644 index 0000000000..bc60d6125c Binary files /dev/null and b/pandora_console/images/wizard/hostdevices.png differ diff --git a/pandora_console/images/wizard/managenetscanscripts.png b/pandora_console/images/wizard/managenetscanscripts.png new file mode 100644 index 0000000000..4694ec1e7a Binary files /dev/null and b/pandora_console/images/wizard/managenetscanscripts.png differ diff --git a/pandora_console/images/wizard/netscan.png b/pandora_console/images/wizard/netscan.png new file mode 100644 index 0000000000..c90f4ddc5d Binary files /dev/null and b/pandora_console/images/wizard/netscan.png differ diff --git a/pandora_console/images/wizard/netscan_green.png b/pandora_console/images/wizard/netscan_green.png new file mode 100644 index 0000000000..faeae9b042 Binary files /dev/null and b/pandora_console/images/wizard/netscan_green.png differ diff --git a/pandora_console/images/wizard/tasklist.png b/pandora_console/images/wizard/tasklist.png new file mode 100644 index 0000000000..3250311b69 Binary files /dev/null and b/pandora_console/images/wizard/tasklist.png differ diff --git a/pandora_console/images/wizard/verde/hostdevices.png b/pandora_console/images/wizard/verde/hostdevices.png new file mode 100644 index 0000000000..8b8fa022ec Binary files /dev/null and b/pandora_console/images/wizard/verde/hostdevices.png differ diff --git a/pandora_console/images/wizard/verde/tasklist.png b/pandora_console/images/wizard/verde/tasklist.png new file mode 100644 index 0000000000..4c6669e89d Binary files /dev/null and b/pandora_console/images/wizard/verde/tasklist.png differ diff --git a/pandora_console/include/ajax/alert_list.ajax.php b/pandora_console/include/ajax/alert_list.ajax.php index fef3f3c97c..b8c3705046 100644 --- a/pandora_console/include/ajax/alert_list.ajax.php +++ b/pandora_console/include/ajax/alert_list.ajax.php @@ -153,24 +153,48 @@ if ($show_update_action_menu) { $id_alert = (int) get_parameter('id_alert'); $module_name = modules_get_agentmodule_name($id_agent_module); - $agent_alias = modules_get_agentmodule_agent_alias($id_agent); + + $agent_alias = modules_get_agentmodule_agent_alias($id_agent_module); $id_action = (int) get_parameter('id_action'); $actions = alerts_get_alert_agent_module_actions($id_alert); - $action_opction = db_get_row('talert_template_module_actions', 'id_alert_template_module', $id_alert); + $action_opction = db_get_row( + 'talert_template_module_actions', + 'id_alert_template_module', + $id_alert + ); $data .= '
'; $data .= ''; - $data .= html_print_input_hidden('update_action', 1, true); - $data .= html_print_input_hidden('id_module_action_ajax', $id_module_action, true); + $data .= html_print_input_hidden( + 'update_action', + 1, + true + ); + $data .= html_print_input_hidden( + 'id_module_action_ajax', + $id_module_action, + true + ); if (! $id_agente) { $data .= ''; $data .= ''; $data .= ''; $data .= ''; } @@ -180,7 +204,14 @@ if ($show_update_action_menu) { $data .= __('Module'); $data .= ''; $data .= ''; $data .= ''; $data .= ''; @@ -188,29 +219,72 @@ if ($show_update_action_menu) { $data .= __('Action'); $data .= ''; $data .= ''; $data .= ''; $data .= ''; $data .= ''; $data .= ''; $data .= ''; $data .= ''; $data .= ''; $data .= ''; $data .= ''; $data .= '
'; - $data .= __('Agent'); + $data .= __('Agent').' '.ui_print_help_icon( + 'alert_scalate', + true, + ui_get_full_url(false, false, false, false) + ); $data .= ''; - $data .= ui_print_truncate_text($agent_alias, 'agent_small', false, true, true, '[…]'); + $data .= ui_print_truncate_text( + $agent_alias, + 'agent_small', + false, + true, + true, + '[…]' + ); $data .= '
'; - $data .= ui_print_truncate_text($module_name, 'module_small', false, true, true, '[…]'); + $data .= ui_print_truncate_text( + $module_name, + 'module_small', + false, + true, + true, + '[…]' + ); $data .= '
'; - $data .= html_print_select($actions, 'action_select_ajax', $id_action, '', __('None'), 0, true, false, true, '', false, 'width:150px'); + $data .= html_print_select( + $actions, + 'action_select_ajax', + $id_action, + '', + __('None'), + 0, + true, + false, + true, + '', + false, + 'width:150px' + ); $data .= '
'; - $data .= __('Number of alerts match from').' '.ui_print_help_icon('alert-matches', true, ui_get_full_url(false, false, false, false)); + $data .= __('Number of alerts match from'); $data .= ''; - $data .= html_print_input_text('fires_min_ajax', $action_opction['fires_min'], '', 4, 10, true); + $data .= html_print_input_text( + 'fires_min_ajax', + $action_opction['fires_min'], + '', + 4, + 10, + true + ); $data .= ' '.__('to').' '; - $data .= html_print_input_text('fires_max_ajax', $action_opction['fires_max'], '', 4, 10, true); + $data .= html_print_input_text( + 'fires_max_ajax', + $action_opction['fires_max'], + '', + 4, + 10, + true + ); $data .= '
'; - $data .= __('Threshold').' '.ui_print_help_icon('action_threshold', true, ui_get_full_url(false, false, false, false)); + $data .= __('Threshold'); $data .= ''; - $data .= html_print_input_text('module_action_threshold_ajax', $action_opction['module_action_threshold'], '', 4, 10, true); + $data .= html_print_input_text( + 'module_action_threshold_ajax', + $action_opction['module_action_threshold'], + '', + 4, + 10, + true + ); $data .= '
'; - $data .= html_print_submit_button(__('Update'), 'updbutton', false, ['class' => 'sub next', 'style' => 'float:right'], true); + $data .= html_print_submit_button( + __('Update'), + 'updbutton', + false, + [ + 'class' => 'sub next', + 'style' => 'float:right', + ], + true + ); $data .= '
'; echo $data; return; diff --git a/pandora_console/include/ajax/custom_fields.php b/pandora_console/include/ajax/custom_fields.php index 0cb9626e7f..9baacdcdc2 100644 --- a/pandora_console/include/ajax/custom_fields.php +++ b/pandora_console/include/ajax/custom_fields.php @@ -1,17 +1,33 @@ $value) { - $values_insert[] = '('.$value['id_server'].', '.$value['id_agente'].", '".$value['description']."', ".$value['status'].')'; + $values_insert[] = '('.$value['id_server'].', '.$value['id_agente'].", '".$value['description']."', '".$value['critical_count']."', '".$value['warning_count']."', '".$value['unknown_count']."', '".$value['notinit_count']."', '".$value['normal_count']."', '".$value['total_count']."', ".$value['status'].')'; } $values_insert_implode = implode(',', $values_insert); $query_insert = 'INSERT INTO temp_custom_fields VALUES '.$values_insert_implode; db_process_sql($query_insert); - // search table for alias, custom field data, server_name, direction + // Search table for alias, custom field data, server_name, direction. $search_query = ''; if ($search['value'] != '') { $search_query = ' AND (tma.alias LIKE "%'.$search['value'].'%"'; @@ -95,7 +134,61 @@ if (check_login()) { $search_query .= ' OR temp.name_custom_fields LIKE "%'.$search['value'].'%" ) '; } - // query all fields result + // Search for status module. + $status_agent_search = ''; + if (isset($id_status) === true && is_array($id_status) === true) { + if (in_array(-1, $id_status) === false) { + if (in_array(AGENT_MODULE_STATUS_NOT_NORMAL, $id_status) === false) { + $status_agent_search = ' AND temp.status IN ('.implode(',', $id_status).')'; + } else { + // Not normal statuses. + $status_agent_search = ' AND temp.status IN (1,2,3,4,5)'; + } + } + } + + // Search for status module. + $status_module_search = ''; + if (isset($module_status) === true && is_array($module_status) === true) { + if (in_array(-1, $module_status) === false) { + if (in_array(AGENT_MODULE_STATUS_NOT_NORMAL, $module_status) === false) { + if (count($module_status) > 0) { + $status_module_search = ' AND ( '; + foreach ($module_status as $key => $value) { + $status_module_search .= ($key != 0) ? ' OR (' : ' ('; + switch ($value) { + default: + case AGENT_STATUS_NORMAL: + $status_module_search .= ' temp.normal_count > 0) '; + break; + case AGENT_STATUS_CRITICAL: + $status_module_search .= ' temp.critical_count > 0) '; + break; + + case AGENT_STATUS_WARNING: + $status_module_search .= ' temp.warning_count > 0) '; + break; + + case AGENT_STATUS_UNKNOWN: + $status_module_search .= ' temp.unknown_count > 0) '; + break; + + case AGENT_STATUS_NOT_INIT: + $status_module_search .= ' temp.notinit_count > 0) '; + break; + } + } + + $status_module_search .= ' ) '; + } + } else { + // Not normal. + $status_module_search = ' AND ( temp.critical_count > 0 OR temp.warning_count > 0 OR temp.unknown_count > 0 AND temp.notinit_count > 0 )'; + } + } + } + + // Query all fields result. $query = sprintf( 'SELECT tma.id_agente, @@ -112,10 +205,14 @@ if (check_login()) { AND temp.id_server = tma.id_tmetaconsole_setup WHERE tma.disabled = 0 %s + %s + %s %s LIMIT %d OFFSET %d ', $search_query, + $status_agent_search, + $status_module_search, $order_by, $length, $start @@ -123,23 +220,27 @@ if (check_login()) { $result = db_get_all_rows_sql($query); - // query count + // Query count. $query_count = sprintf( 'SELECT COUNT(tma.id_agente) AS `count` - FROM tmetaconsole_agent tma - INNER JOIN temp_custom_fields temp - ON temp.id_agent = tma.id_tagente - AND temp.id_server = tma.id_tmetaconsole_setup - WHERE tma.disabled = 0 - %s - ', - $search_query + FROM tmetaconsole_agent tma + INNER JOIN temp_custom_fields temp + ON temp.id_agent = tma.id_tagente + AND temp.id_server = tma.id_tmetaconsole_setup + WHERE tma.disabled = 0 + %s + %s + %s + ', + $search_query, + $status_agent_search, + $status_module_search ); $count = db_get_sql($query_count); - // for link nodes. + // For link nodes. $array_nodes = metaconsole_get_connections(); if (isset($array_nodes) && is_array($array_nodes)) { $hash_array_nodes = []; @@ -158,20 +259,20 @@ if (check_login()) { $user_rot13 = str_rot13($config['id_user']); $hashdata = $user.$pwd; $hashdata = md5($hashdata); - $url_hash = '&'.'loginhash=auto&'.'loginhash_data='.$hashdata.'&'.'loginhash_user='.$user_rot13; + $url_hash = '&loginhash=auto&loginhash_data='.$hashdata.'&loginhash_user='.$user_rot13; $hash_array_nodes[$server['id']]['hashurl'] = $url_hash; $hash_array_nodes[$server['id']]['server_url'] = $server['server_url']; } } - // prepare rows for table dinamic + // Prepare rows for table dinamic. $data = []; foreach ($result as $values) { $image_status = agents_get_image_status($values['status']); - // link nodes - $agent_link = ''; + // Link nodes. + $agent_link = ''; $agent_alias = ui_print_truncate_text( $values['alias'], @@ -225,7 +326,7 @@ if (check_login()) { $name_where = " AND tam.nombre LIKE '%".$module_search."%'"; } - // filter by status module + // Filter by status module. $and_module_status = ''; if (is_array($module_status)) { if (!in_array(-1, $module_status)) { @@ -260,7 +361,7 @@ if (check_login()) { $and_module_status .= ' ) '; } } else { - // not normal + // Not normal. $and_module_status = 'AND tae.estado <> 0 AND tae.estado <> 300 '; } } @@ -314,7 +415,12 @@ if (check_login()) { && $value['id_tipo_modulo'] != 23 && $value['id_tipo_modulo'] != 33 ) { - $table_modules->data[$key][1] = remove_right_zeros(number_format($value['datos'], $config['graph_precision'])); + $table_modules->data[$key][1] = remove_right_zeros( + number_format( + $value['datos'], + $config['graph_precision'] + ) + ); } else { $table_modules->data[$key][1] = $value['datos']; } @@ -329,7 +435,10 @@ if (check_login()) { ); $table_modules->data[$key][3] = $value['current_interval']; - $table_modules->data[$key][4] = ui_print_timestamp($value['utimestamp'], true); + $table_modules->data[$key][4] = ui_print_timestamp( + $value['utimestamp'], + true + ); switch ($value['estado']) { case 0: case 300: @@ -398,7 +507,7 @@ if (check_login()) { } } - // status agents from tagente + // Status agents from tagente. $sql_info_agents = 'SELECT * fROM tagente WHERE id_agente ='.$id_agent; $info_agents = db_get_row_sql($sql_info_agents); $status_agent = agents_get_status_from_counts($info_agents); @@ -463,7 +572,13 @@ if (check_login()) { false ); - $table->data[0][3] = html_print_submit_button(__('Load filter'), 'load_filter', false, 'class="sub upd"', true); + $table->data[0][3] = html_print_submit_button( + __('Load filter'), + 'load_filter', + false, + 'class="sub upd"', + true + ); echo "
"; html_print_table($table); @@ -474,7 +589,12 @@ if (check_login()) { } if ($append_tab_filter) { - $filters = json_decode(io_safe_output(get_parameter('filters', '')), true); + $filters = json_decode( + io_safe_output( + get_parameter('filters', '') + ), + true + ); $table = new StdClass; $table->id = 'save_filter_form'; @@ -485,7 +605,14 @@ if (check_login()) { if ($filters['id'] == 'extended_create_filter') { echo "
"; $table->data[0][0] = __('Filter name'); - $table->data[0][1] = html_print_input_text('id_name', '', '', 15, 255, true); + $table->data[0][1] = html_print_input_text( + 'id_name', + '', + '', + 15, + 255, + true + ); $table->data[1][0] = __('Group'); $table->data[1][1] = html_print_select_groups( @@ -510,7 +637,13 @@ if (check_login()) { ); $table->rowspan[0][2] = 2; - $table->data[0][2] = html_print_submit_button(__('Create filter'), 'create_filter', false, 'class="sub upd"', true); + $table->data[0][2] = html_print_submit_button( + __('Create filter'), + 'create_filter', + false, + 'class="sub upd"', + true + ); } else { echo "
"; echo "
"; @@ -552,8 +685,20 @@ if (check_login()) { false ); - $table->data[0][2] = html_print_submit_button(__('Delete filter'), 'delete_filter', false, 'class="sub upd"', true); - $table->data[1][2] = html_print_submit_button(__('Update filter'), 'update_filter', false, 'class="sub upd"', true); + $table->data[0][2] = html_print_submit_button( + __('Delete filter'), + 'delete_filter', + false, + 'class="sub upd"', + true + ); + $table->data[1][2] = html_print_submit_button( + __('Update filter'), + 'update_filter', + false, + 'class="sub upd"', + true + ); } html_print_table($table); @@ -561,17 +706,20 @@ if (check_login()) { } if ($create_filter_cf) { - // initialize result + // Initialize result. $result_array = []; $result_array['error'] = 0; $result_array['msg'] = ''; - // initialize vars - $filters = json_decode(io_safe_output(get_parameter('filters', '')), true); + // Initialize vars. + $filters = json_decode( + io_safe_output(get_parameter('filters', '')), + true + ); $name_filter = get_parameter('name_filter', ''); $group_search = get_parameter('group_search', 0); - // check that the name is not empty + // Check that the name is not empty. if ($name_filter == '') { $result_array['error'] = 1; $result_array['msg'] = ui_print_error_message( @@ -596,7 +744,7 @@ if (check_login()) { return; } - // check custom field is not empty + // Check custom field is not empty. if ($filters['id_custom_fields'] == '') { $result_array['error'] = 1; $result_array['msg'] = ui_print_error_message( @@ -608,13 +756,15 @@ if (check_login()) { return; } - // insert + // Insert. $values = []; $values['name'] = $name_filter; $values['group_search'] = $group_search; $values['id_group'] = $filters['group']; $values['id_custom_field'] = $filters['id_custom_fields']; - $values['id_custom_fields_data'] = json_encode($filters['id_custom_fields_data']); + $values['id_custom_fields_data'] = json_encode( + $filters['id_custom_fields_data'] + ); $values['id_status'] = json_encode($filters['id_status']); $values['module_search'] = $filters['module_search']; $values['module_status'] = json_encode($filters['module_status']); @@ -622,7 +772,7 @@ if (check_login()) { $insert = db_process_sql_insert('tagent_custom_fields_filter', $values); - // check error insert + // Check error insert. if ($insert) { $result_array['error'] = 0; $result_array['msg'] = ui_print_success_message( @@ -644,17 +794,17 @@ if (check_login()) { } if ($update_filter_cf) { - // initialize result + // Initialize result. $result_array = []; $result_array['error'] = 0; $result_array['msg'] = ''; - // initialize vars + // Initialize vars. $filters = json_decode(io_safe_output(get_parameter('filters', '')), true); $id_filter = get_parameter('id_filter', ''); $group_search = get_parameter('group_search', 0); - // check selected filter + // Check selected filter. if ($id_filter == -1) { $result_array['error'] = 1; $result_array['msg'] = ui_print_error_message( @@ -666,11 +816,11 @@ if (check_login()) { return; } - // array condition update + // Array condition update. $condition = []; $condition['id'] = $id_filter; - // check selected custom fields + // Check selected custom fields. if ($filters['id_custom_fields'] == '') { $result_array['error'] = 1; $result_array['msg'] = ui_print_error_message( @@ -682,7 +832,7 @@ if (check_login()) { return; } - // array values update + // Array values update. $values = []; $values['id_group'] = $filters['group']; $values['group_search'] = $group_search; @@ -693,10 +843,10 @@ if (check_login()) { $values['module_status'] = json_encode($filters['module_status']); $values['recursion'] = $filters['recursion']; - // update + // Update. $update = db_process_sql_update('tagent_custom_fields_filter', $values, $condition); - // check error insert + // Check error insert. if ($update) { $result_array['error'] = 0; $result_array['msg'] = ui_print_success_message( @@ -718,16 +868,16 @@ if (check_login()) { } if ($delete_filter_cf) { - // Initialize result + // Initialize result. $result_array = []; $result_array['error'] = 0; $result_array['msg'] = ''; - // Initialize vars + // Initialize vars. $filters = json_decode(io_safe_output(get_parameter('filters', '')), true); $id_filter = get_parameter('id_filter', ''); - // Check selected filter + // Check selected filter. if ($id_filter == -1) { $result_array['error'] = 1; $result_array['msg'] = ui_print_error_message( @@ -739,14 +889,14 @@ if (check_login()) { return; } - // Array condition update + // Array condition update. $condition = []; $condition['id'] = $id_filter; - // Delete + // Delete. $delete = db_process_sql_delete('tagent_custom_fields_filter', $condition); - // Check error insert + // Check error insert. if ($delete) { $result_array['error'] = 0; $result_array['msg'] = ui_print_success_message( diff --git a/pandora_console/include/ajax/events.php b/pandora_console/include/ajax/events.php index 5f6f62568b..b58a3c2386 100644 --- a/pandora_console/include/ajax/events.php +++ b/pandora_console/include/ajax/events.php @@ -1,16 +1,31 @@ > '; switch ($event_response['type']) { case 'command': - - if ($massive) { echo "
"; - echo $prompt.sprintf("(Event #$event_id) ".__('Executing command: %s', $command)); + echo $prompt.sprintf( + '(Event #'.$event_id.') '.__( + 'Executing command: %s', + $command + ) + ); echo '

'; - echo "'; + echo "'; echo "
"; if ($end) { echo "
'; } } else { @@ -242,7 +283,11 @@ if ($dialogue_event_response) { case 'url': $command = str_replace('localhost', $_SERVER['SERVER_NAME'], $command); - echo ""; + echo ""; + break; + + default: + // Ignore. break; } } @@ -319,10 +364,10 @@ if ($get_extended_event) { $readonly = true; } - // Clean url from events and store in array + // Clean url from events and store in array. $event['clean_tags'] = events_clean_tags($event['tags']); - // If the event is not found, we abort + // If the event is not found, we abort. if (empty($event)) { ui_print_error_message('Event not found'); return false; @@ -341,42 +386,62 @@ if ($get_extended_event) { $event['timestamp_last'] = $timestamp_last; $event['event_rep'] = $event_rep; - // Check ACLs + // Check ACLs. if (is_user_admin($config['id_user'])) { - // Do nothing if you're admin, you get full access + // Do nothing if you're admin, you get full access. + $__ignored_line = 0; } else if ($config['id_user'] == $event['owner_user']) { - // Do nothing if you're the owner user, you get access + // Do nothing if you're the owner user, you get access. + $__ignored_line = 0; } else if ($event['id_grupo'] == 0) { - // If the event has access to all groups, you get access + // If the event has access to all groups, you get access. + $__ignored_line = 0; } else { - // Get your groups + // Get your groups. $groups = users_get_groups($config['id_user'], 'ER'); if (in_array($event['id_grupo'], array_keys($groups))) { - // If the event group is among the groups of the user, you get access + // If event group is among the groups of the user, you get access. + $__ignored_line = 0; } else { - // If all the access types fail, abort + // If all the access types fail, abort. echo 'Access denied'; return false; } } - // Print group_rep in a hidden field to recover it from javascript + // Print group_rep in a hidden field to recover it from javascript. html_print_input_hidden('group_rep', (int) $group_rep); if ($event === false) { return; } - // Tabs - $tabs = "
    "; - $tabs .= "
  • ".html_print_image('images/lightning_go.png', true)."".__('General').'
  • '; - $tabs .= "
  • ".html_print_image('images/zoom.png', true)."".__('Details').'
  • '; - $tabs .= "
  • ".html_print_image('images/custom_field_col.png', true)."".__('Agent fields').'
  • '; - $tabs .= "
  • ".html_print_image('images/pencil.png', true)."".__('Comments').'
  • '; + // Tabs. + $tabs = "'; - // Get criticity image + // Get criticity image. switch ($event['criticity']) { default: case 0: - $img_sev = 'images/status_sets/default/severity_maintenance.png'; + $img_sev = 'images/status_sets/default/severity_maintenance_rounded.png'; break; case 1: - $img_sev = 'images/status_sets/default/severity_informational.png'; + $img_sev = 'images/status_sets/default/severity_informational_rounded.png'; break; case 2: - $img_sev = 'images/status_sets/default/severity_normal.png'; + $img_sev = 'images/status_sets/default/severity_normal_rounded.png'; break; case 3: - $img_sev = 'images/status_sets/default/severity_warning.png'; + $img_sev = 'images/status_sets/default/severity_warning_rounded.png'; break; case 4: - $img_sev = 'images/status_sets/default/severity_critical.png'; + $img_sev = 'images/status_sets/default/severity_critical_rounded.png'; break; case 5: - $img_sev = 'images/status_sets/default/severity_minor.png'; + $img_sev = 'images/status_sets/default/severity_minor_rounded.png'; break; case 6: - $img_sev = 'images/status_sets/default/severity_major.png'; + $img_sev = 'images/status_sets/default/severity_major_rounded.png'; break; } if (!$readonly - && ((tags_checks_event_acl($config['id_user'], $event['id_grupo'], 'EM', $event['clean_tags'], $childrens_ids)) || (tags_checks_event_acl($config['id_user'], $event['id_grupo'], 'EW', $event['clean_tags'], $childrens_ids))) + && ((tags_checks_event_acl( + $config['id_user'], + $event['id_grupo'], + 'EM', + $event['clean_tags'], + $childrens_ids + )) || (tags_checks_event_acl( + $config['id_user'], + $event['id_grupo'], + 'EW', + $event['clean_tags'], + $childrens_ids + ))) ) { $responses = events_page_responses($event, $childrens_ids); } else { @@ -427,7 +504,7 @@ if ($get_extended_event) { } $console_url = ''; - // If metaconsole switch to node to get details and custom fields + // If metaconsole switch to node to get details and custom fields. if ($meta) { $server = metaconsole_get_connection_by_id($server_id); metaconsole_connect($server); @@ -437,7 +514,12 @@ if ($get_extended_event) { $details = events_page_details($event, $server); - // Juanma (09/05/2014) Fix: Needs to reconnect to node, in previous funct node connection was lost + if (events_has_extended_info($event['id_evento']) === true) { + $related = events_page_related($event, $server); + } + + // Juanma (09/05/2014) Fix: Needs to reconnect to node, in previous funct + // node connection was lost. if ($meta) { $server = metaconsole_get_connection_by_id($server_id); metaconsole_connect($server); @@ -464,7 +546,7 @@ if ($get_extended_event) { $loading = ''; - $out = '
    '.$tabs.$notifications.$loading.$general.$details.$custom_fields.$comments.$responses.$custom_data.html_print_input_hidden('id_event', $event['id_evento']).'
    '; + $out = '
    '.$tabs.$notifications.$loading.$general.$details.$related.$custom_fields.$comments.$responses.$custom_data.html_print_input_hidden('id_event', $event['id_evento']).'
    '; $js = ''; + $js .= '});'; + + if (events_has_extended_info($event['id_evento']) === true) { + $js .= ' + $("#link_related").click(function (){ + $.post ({ + url : "ajax.php", + data : { + page: "include/ajax/events_extended", + get_extended_info: 1, + id_event: '.$event['id_evento'].' + }, + dataType : "html", + success: function (data) { + $("#related_data").html(data); + } + }); + });'; + } + + $js .= ''; echo $out.$js; } @@ -543,6 +651,10 @@ if ($get_events_details) { $img = ui_get_full_url('images/hourglass.png', false, false, false); $title = __('Event in process'); break; + + default: + // Ignore. + break; } $out .= ''; @@ -594,7 +706,8 @@ if ($table_events) { $id_agente = (int) get_parameter('id_agente', 0); $all_events_24h = (int) get_parameter('all_events_24h', 0); - // Fix: for tag functionality groups have to be all user_groups (propagate ACL funct!) + // Fix: for tag functionality groups have to be all user_groups + // (propagate ACL funct!). $groups = users_get_groups($config['id_user']); $tags_condition = tags_get_acl_tags( @@ -604,15 +717,21 @@ if ($table_events) { 'event_condition', 'AND' ); - echo '
    '; - echo ''; - echo html_print_checkbox('all_events_24h', $all_events_24h, $all_events_24h, true, false, '', true); + echo '
    '; + echo ''; + echo html_print_switch( + [ + 'name' => 'all_events_24h', + 'value' => $all_events_24h, + 'id' => 'checkbox-all_events_24h', + ] + ); echo '
    '; $date_subtract_day = (time() - (24 * 60 * 60)); if ($all_events_24h) { events_print_event_table( - "utimestamp > $date_subtract_day", + 'utimestamp > '.$date_subtract_day, 200, '100%', false, @@ -621,7 +740,7 @@ if ($table_events) { ); } else { events_print_event_table( - "estado <> 1 $tags_condition", + 'estado <> 1 '.$tags_condition, 200, '100%', false, @@ -707,3 +826,67 @@ if ($graphic_event_group) { echo $prueba; return; } + +if ($get_table_response_command) { + global $config; + + $response_id = get_parameter('event_response_id'); + $params_string = db_get_value( + 'params', + 'tevent_response', + 'id', + $response_id + ); + + $params = explode(',', $params_string); + + $table = new stdClass; + $table->id = 'events_responses_table_command'; + $table->width = '90%'; + $table->styleTable = 'text-align:center; margin: 0 auto;'; + + $table->style = []; + $table->style[0] = 'text-align:center;'; + $table->style[1] = 'text-align:center;'; + + $table->head = []; + $table->head[0] = __('Parameters'); + $table->head[0] .= ui_print_help_tip( + __('These commands will apply to all selected events'), + true + ); + $table->head[1] = __('Value'); + + if (isset($params) === true + && is_array($params) === true + ) { + foreach ($params as $key => $value) { + $table->data[$key][0] = $value; + $table->data[$key][1] = html_print_input_text( + $value.'-'.$key, + '', + '', + 50, + 255, + true, + false, + false, + '', + 'response_command_input' + ); + } + } + + echo ''; + echo html_print_table($table, true); + echo ''; + echo html_print_submit_button( + __('Execute'), + 'enter_command', + false, + 'class="sub next" style="float:right; margin-top:15px; margin-right:25px;"', + true + ); + + return; +} diff --git a/pandora_console/include/ajax/events_extended.php b/pandora_console/include/ajax/events_extended.php new file mode 100644 index 0000000000..1fb3e94c63 --- /dev/null +++ b/pandora_console/include/ajax/events_extended.php @@ -0,0 +1,102 @@ +width = '100%'; + $table->data = []; + $table->head = []; + $table->cellspacing = 2; + $table->cellpadding = 2; + $table->class = 'table_modal_alternate'; + + $output = []; + $output[] = ''.__('Timestamp').''; + $output[] = ''.__('Description').''; + $table->data[] = $output; + + foreach ($extended_info as $data) { + $output = []; + $output[] = date('Y/m/d H:i:s', $data['utimestamp']); + $output[] = io_safe_output($data['description']); + $table->data[] = $output; + } + + html_print_table($table); +} diff --git a/pandora_console/include/ajax/module.php b/pandora_console/include/ajax/module.php index 6e93f12165..76dc24e145 100755 --- a/pandora_console/include/ajax/module.php +++ b/pandora_console/include/ajax/module.php @@ -1,17 +1,33 @@ 'tmodule_group.name', @@ -549,6 +566,7 @@ if (check_login()) { case 'type': switch ($sort) { case 'up': + default: $selectTypeUp = $selected; $order[] = [ 'field' => 'tagente_modulo.id_modulo', @@ -583,6 +601,10 @@ if (check_login()) { 'order' => 'DESC', ]; break; + + default: + // Ignore. + break; } break; @@ -603,6 +625,10 @@ if (check_login()) { 'order' => '', ]; break; + + default: + // Ignore. + break; } break; @@ -623,20 +649,24 @@ if (check_login()) { 'order' => 'DESC', ]; break; + + default: + // Ignore. + break; } break; default: - $selectTypeUp = ''; - $selectTypeDown = ''; + $selectTypeUp = false; + $selectTypeDown = false; $selectNameUp = $selected; - $selectNameDown = ''; - $selectStatusUp = ''; - $selectStatusDown = ''; - $selectDataUp = ''; - $selectDataDown = ''; - $selectLastContactUp = ''; - $selectLastContactDown = ''; + $selectNameDown = false; + $selectStatusUp = false; + $selectStatusDown = false; + $selectDataUp = false; + $selectDataDown = false; + $selectLastContactUp = false; + $selectLastContactDown = false; $order[] = [ 'field' => 'tagente_modulo.nombre', @@ -645,7 +675,8 @@ if (check_login()) { break; } - // Fix: for tag functionality groups have to be all user_groups (propagate ACL funct!) + // Fix: for tag functionality groups have to be all user_groups + // (propagate ACL funct!). $groups = users_get_groups($config['id_user'], $access); $tags_join = ''; @@ -669,7 +700,7 @@ if (check_login()) { $status_filter_sql = '1 = 1'; if ($status_filter_monitor == AGENT_MODULE_STATUS_NOT_NORMAL) { - // Not normal + // Not normal. $status_filter_sql = ' tagente_estado.estado <> 0'; } else if ($status_filter_monitor != -1) { $status_filter_sql = 'tagente_estado.estado = '.$status_filter_monitor; @@ -693,7 +724,7 @@ if (check_login()) { } // Count monitors/modules - // Build the order sql + // Build the order sql. $first = true; foreach ($order as $ord) { if ($first) { @@ -756,11 +787,23 @@ if (check_login()) { $modules = []; } + // Urls to sort the table. + $url_up_type = $url.'&sort_field=type&sort=up&refr=&filter_monitors=1&status_filter_monitor='.$status_filter_monitor.' &status_text_monitor='.$status_text_monitor.'&status_module_group= '.$status_module_group; + $url_down_type = $url.'&sort_field=type&sort=down&refr=&filter_monitors=1&status_filter_monitor='.$status_filter_monitor.' &status_text_monitor='.$status_text_monitor.'&status_module_group= '.$status_module_group; + $url_up_name = $url.'&sort_field=name&sort=up&refr=&filter_monitors=1&status_filter_monitor='.$status_filter_monitor.' &status_text_monitor='.$status_text_monitor.'&status_module_group= '.$status_module_group; + $url_down_name = $url.'&sort_field=name&sort=down&refr=&filter_monitors=1&status_filter_monitor='.$status_filter_monitor.' &status_text_monitor='.$status_text_monitor.'&status_module_group= '.$status_module_group; + $url_up_status = $url.'&sort_field=status&sort=up&refr=&filter_monitors=1&status_filter_monitor='.$status_filter_monitor.' &status_text_monitor='.$status_text_monitor.'&status_module_group= '.$status_module_group; + $url_down_status = $url.'&sort_field=status&sort=down&refr=&filter_monitors=1&status_filter_monitor='.$status_filter_monitor.' &status_text_monitor='.$status_text_monitor.'&status_module_group= '.$status_module_group; + $url_up_last = $url.'&sort_field=last_contact&sort=up&refr=&filter_monitors=1&status_filter_monitor='.$status_filter_monitor.' &status_text_monitor='.$status_text_monitor.'&status_module_group= '.$status_module_group; + $url_down_last = $url.'&sort_field=last_contact&sort=down&refr=&filter_monitors=1&status_filter_monitor='.$status_filter_monitor.' &status_text_monitor='.$status_text_monitor.'&status_module_group= '.$status_module_group; + + $table = new stdClass(); $table->width = '100%'; - $table->cellpadding = 4; - $table->cellspacing = 4; - $table->class = 'databox data'; + $table->styleTable = 'border: 0;border-radius: 0;'; + $table->cellpadding = 0; + $table->cellspacing = 0; + $table->class = 'info_table'; $table->head = []; $table->data = []; @@ -773,17 +816,14 @@ if (check_login()) { $table->head[1] = "".__('P.').''; } - $table->head[2] = __('Type').' '.''.html_print_image('images/sort_up.png', true, ['style' => $selectTypeUp, 'alt' => 'up']).''.''.html_print_image('images/sort_down.png', true, ['style' => $selectTypeDown, 'alt' => 'down']).''; - $table->head[3] = __('Module name').' '.''.html_print_image('images/sort_up.png', true, ['style' => $selectNameUp, 'alt' => 'up']).''.''.html_print_image('images/sort_down.png', true, ['style' => $selectNameDown, 'alt' => 'down']).''; + $table->head[2] = __('Type').ui_get_sorting_arrows($url_up_type, $url_down_type, $selectTypeUp, $selectTypeDown); + $table->head[3] = __('Module name').ui_get_sorting_arrows($url_up_name, $url_down_name, $selectNameUp, $selectNameDown); $table->head[4] = __('Description'); - $table->head[5] = __('Status').' '.''.html_print_image('images/sort_up.png', true, ['style' => $selectStatusUp, 'alt' => 'up']).''.''.html_print_image('images/sort_down.png', true, ['style' => $selectStatusDown, 'alt' => 'down']).''; + $table->head[5] = __('Status').ui_get_sorting_arrows($url_up_status, $url_down_status, $selectStatusUp, $selectStatusDown); $table->head[6] = __('Thresholds'); $table->head[7] = __('Data'); $table->head[8] = __('Graph'); - $table->headstyle[8] = 'min-width: 60px'; - $table->head[9] = __('Last contact').' '.''.html_print_image('images/sort_up.png', true, ['style' => $selectLastContactUp, 'alt' => 'up']).''.''.html_print_image('images/sort_down.png', true, ['style' => $selectLastContactDown, 'alt' => 'down']).''; - - + $table->head[9] = __('Last contact').ui_get_sorting_arrows($url_up_last, $url_down_last, $selectLastContactUp, $selectLastContactDown); $table->align = [ 'left', 'left', @@ -796,6 +836,12 @@ if (check_login()) { 'left', ]; + $table->headstyle[2] = 'min-width: 60px'; + $table->headstyle[3] = 'min-width: 100px'; + $table->headstyle[5] = 'min-width: 60px'; + $table->headstyle[8] = 'min-width: 85px'; + $table->headstyle[9] = 'min-width: 100px'; + $last_modulegroup = 0; $rowIndex = 0; @@ -896,7 +942,7 @@ if (check_login()) { $data[2] = servers_show_type($module['id_modulo']).' '; if (check_acl($config['id_user'], $id_grupo, 'AW')) { - $data[2] .= ''.html_print_image('images/config.png', true, ['alt' => '0', 'border' => '', 'title' => __('Edit')]).''; + $data[2] .= ''.html_print_image('images/config.png', true, ['alt' => '0', 'border' => '', 'title' => __('Edit'), 'class' => 'action_button_img']).''; } @@ -927,12 +973,12 @@ if (check_login()) { } } - // Adds tag context information + // Adds tag context information. if (tags_get_modules_tag_count($module['id_agente_modulo']) > 0) { $data[3] .= ' '.html_print_image('images/tag_red.png', true, ['id' => 'tag-details-'.$module['id_agente_modulo'], 'class' => 'img_help']).' '; } - // Adds relations context information + // Adds relations context information. if (modules_relation_exists($module['id_agente_modulo'])) { $data[3] .= ' '.html_print_image('images/link2.png', true, ['id' => 'relations-details-'.$module['id_agente_modulo'], 'class' => 'img_help']).' '; } @@ -955,7 +1001,7 @@ if (check_login()) { $title ); - $data[5] = ui_print_status_image($status, $title, true); + $data[5] = ui_print_module_status($module['estado'], $title, true, false, true); if (!$show_context_help_first_time) { $show_context_help_first_time = true; @@ -964,122 +1010,85 @@ if (check_login()) { } } - if ($module['id_tipo_modulo'] == 24) { - // log4x - switch ($module['datos']) { - case 10: - $salida = 'TRACE'; - $style = 'font-weight:bold; color:darkgreen;'; - break; + if (is_numeric($module['datos']) && !modules_is_string_type($module['id_tipo_modulo'])) { + if ($config['render_proc']) { + switch ($module['id_tipo_modulo']) { + case 2: + case 6: + case 9: + case 18: + case 21: + case 31: + if ($module['datos'] >= 1) { + $salida = $config['render_proc_ok']; + } else { + $salida = $config['render_proc_fail']; + } + break; - case 20: - $salida = 'DEBUG'; - $style = 'font-weight:bold; color:darkgreen;'; - break; - - case 30: - $salida = 'INFO'; - $style = 'font-weight:bold; color:darkgreen;'; - break; - - case 40: - $salida = 'WARN'; - $style = 'font-weight:bold; color:darkorange;'; - break; - - case 50: - $salida = 'ERROR'; - $style = 'font-weight:bold; color:red;'; - break; - - case 60: - $salida = 'FATAL'; - $style = 'font-weight:bold; color:red;'; - break; - } - - $salida = "$salida"; - } else { - if (is_numeric($module['datos']) && !modules_is_string_type($module['id_tipo_modulo'])) { - if ($config['render_proc']) { - switch ($module['id_tipo_modulo']) { - case 2: - case 6: - case 9: - case 18: - case 21: - case 31: - if ($module['datos'] >= 1) { - $salida = $config['render_proc_ok']; - } else { - $salida = $config['render_proc_fail']; - } - break; - - default: - switch ($module['id_tipo_modulo']) { - case 15: - $value = db_get_value('snmp_oid', 'tagente_modulo', 'id_agente_modulo', $module['id_agente_modulo']); - if ($value == '.1.3.6.1.2.1.1.3.0' || $value == '.1.3.6.1.2.1.25.1.1.0') { - if ($module['post_process'] > 0) { - $salida = human_milliseconds_to_string(($module['datos'] / $module['post_process'])); - } else { - $salida = human_milliseconds_to_string($module['datos']); - } + default: + switch ($module['id_tipo_modulo']) { + case 15: + $value = db_get_value('snmp_oid', 'tagente_modulo', 'id_agente_modulo', $module['id_agente_modulo']); + if ($value == '.1.3.6.1.2.1.1.3.0' || $value == '.1.3.6.1.2.1.25.1.1.0') { + if ($module['post_process'] > 0) { + $salida = human_milliseconds_to_string(($module['datos'] / $module['post_process'])); } else { - $salida = remove_right_zeros(number_format($module['datos'], $config['graph_precision'])); + $salida = human_milliseconds_to_string($module['datos']); } - break; - - default: - $salida = remove_right_zeros(number_format($module['datos'], $config['graph_precision'])); - break; - } - break; - } - } else { - switch ($module['id_tipo_modulo']) { - case 15: - $value = db_get_value('snmp_oid', 'tagente_modulo', 'id_agente_modulo', $module['id_agente_modulo']); - if ($value == '.1.3.6.1.2.1.1.3.0' || $value == '.1.3.6.1.2.1.25.1.1.0') { - if ($module['post_process'] > 0) { - $salida = human_milliseconds_to_string(($module['datos'] / $module['post_process'])); } else { - $salida = human_milliseconds_to_string($module['datos']); + $salida = remove_right_zeros(number_format($module['datos'], $config['graph_precision'])); } - } else { + break; + + default: $salida = remove_right_zeros(number_format($module['datos'], $config['graph_precision'])); - } - break; - - default: - $salida = remove_right_zeros(number_format($module['datos'], $config['graph_precision'])); - break; - } - } - - // Show units ONLY in numeric data types - if (isset($module['unit'])) { - $data_macro = modules_get_unit_macro($module['datos'], $module['unit']); - if ($data_macro) { - $salida = $data_macro; - } else { - $salida .= ' '.''.io_safe_output($module['unit']).''; - } + break; + } + break; } } else { + switch ($module['id_tipo_modulo']) { + case 15: + $value = db_get_value('snmp_oid', 'tagente_modulo', 'id_agente_modulo', $module['id_agente_modulo']); + if ($value == '.1.3.6.1.2.1.1.3.0' || $value == '.1.3.6.1.2.1.25.1.1.0') { + if ($module['post_process'] > 0) { + $salida = human_milliseconds_to_string(($module['datos'] / $module['post_process'])); + } else { + $salida = human_milliseconds_to_string($module['datos']); + } + } else { + $salida = remove_right_zeros(number_format($module['datos'], $config['graph_precision'])); + } + break; + + default: + $salida = remove_right_zeros(number_format($module['datos'], $config['graph_precision'])); + break; + } + } + + // Show units ONLY in numeric data types + if (isset($module['unit'])) { $data_macro = modules_get_unit_macro($module['datos'], $module['unit']); if ($data_macro) { $salida = $data_macro; } else { - $salida = ui_print_module_string_value( - $module['datos'], - $module['id_agente_modulo'], - $module['current_interval'], - $module['module_name'] - ); + $salida .= ' '.''.io_safe_output($module['unit']).''; } } + } else { + $data_macro = modules_get_unit_macro($module['datos'], $module['unit']); + if ($data_macro) { + $salida = $data_macro; + } else { + $salida = ui_print_module_string_value( + $module['datos'], + $module['id_agente_modulo'], + $module['current_interval'], + $module['module_name'] + ); + } } if ($module['id_tipo_modulo'] != 25) { @@ -1111,11 +1120,11 @@ if (check_login()) { $draw_events = 0; } - $link = "winopeng('".'operation/agentes/stat_win.php?'."type=$graph_type&".'period='.SECONDS_1DAY.'&'.'id='.$module['id_agente_modulo'].'&'.'label='.rawurlencode( + $link = "winopeng_var('".'operation/agentes/stat_win.php?'."type=$graph_type&".'period='.SECONDS_1DAY.'&'.'id='.$module['id_agente_modulo'].'&'.'label='.rawurlencode( urlencode( base64_encode($module['nombre']) ) - ).'&'.'refresh='.SECONDS_10MINUTES.'&'."draw_events=$draw_events', 'day_".$win_handle."')"; + ).'&'.'refresh='.SECONDS_10MINUTES.'&'."draw_events=$draw_events', 'day_".$win_handle."', 1000, 650)"; if (!is_snapshot_data($module['datos'])) { $data[8] .= ''.html_print_image('images/chart_curve.png', true, ['border' => '0', 'alt' => '']).'   '; } @@ -1199,7 +1208,7 @@ if (check_login()) { false, 'offset', true, - '', + 'pagination-bottom', 'pagination_list_modules(offset_param)', [ 'count' => '', @@ -1221,5 +1230,3 @@ if (check_login()) { return; } } - - diff --git a/pandora_console/include/ajax/reporting.ajax.php b/pandora_console/include/ajax/reporting.ajax.php index a5737ea71e..55ed7dd216 100755 --- a/pandora_console/include/ajax/reporting.ajax.php +++ b/pandora_console/include/ajax/reporting.ajax.php @@ -198,12 +198,7 @@ if ($get_metaconsole_hash_data) { $console_password = $auth_serialized['console_password']; } - $pwd = $auth_token; - // Create HASH login info - $user = str_rot13($config['id_user']); - $hashdata = $user.$pwd; - $hashdata = md5($hashdata); - $url_hash = "&loginhash=auto&loginhash_data=$hashdata&loginhash_user=$user"; + $url_hash = metaconsole_get_servers_url_hash($server); echo $url_hash; return; diff --git a/pandora_console/include/ajax/snmp_browser.ajax.php b/pandora_console/include/ajax/snmp_browser.ajax.php index 11d233c676..85f8b3e68a 100644 --- a/pandora_console/include/ajax/snmp_browser.ajax.php +++ b/pandora_console/include/ajax/snmp_browser.ajax.php @@ -121,6 +121,7 @@ if (is_ajax()) { 'min_ff_event_normal' => 0, 'min_ff_event_warning' => 0, 'min_ff_event_critical' => 0, + 'ff_type' => 0, 'each_ff' => 0, ] ); diff --git a/pandora_console/include/ajax/task_list.ajax.php b/pandora_console/include/ajax/task_list.ajax.php new file mode 100644 index 0000000000..6d50b3c892 --- /dev/null +++ b/pandora_console/include/ajax/task_list.ajax.php @@ -0,0 +1,177 @@ + true]); + return; + } + + $task = db_get_row('trecon_task', 'id_rt', $id_task); + $global_progress = $task['status']; + $summary = json_decode($task['summary'], true); + + $result = '
    '; + if ($task['utimestamp']) { + $result .= '
    '; + $result .= '
    '; + $result .= ''._('Overall Progress').''; + + $result .= '
    '; + $result .= progress_circular_bar( + $id_task, + ($global_progress < 0) ? 100 : $global_progress, + 200, + 200, + '#7eb641', + '%', + '', + '#3A3A3A', + 0 + ); + + $result .= '
    '; + + if ($global_progress > 0) { + switch ($summary['step']) { + case STEP_SCANNING: + $str = __('Scanning network'); + break; + + case STEP_AFT: + $str = __('Finding AFT connectivity'); + break; + + case STEP_TRACEROUTE: + $str = __('Finding traceroute connectivity'); + break; + + case STEP_GATEWAY: + $str = __('Finding gateway connectivity'); + break; + + default: + $str = __('Searching for devices...'); + break; + } + + $result .= '
    '; + $result .= '
    '; + $result .= ''.$str.' '; + $result .= $summary['c_network_name']; + $result .= ''; + + $result .= '
    '; + $result .= progress_circular_bar( + $id_task.'_detail', + $summary['c_network_percent'], + 200, + 200, + '#7eb641', + '%', + '', + '#3A3A3A', + 0 + ); + $result .= '
    '; + } + + $result .= '
    '; + + $i = 0; + $table = new StdClasS(); + $table->class = 'databox data'; + $table->width = '75%'; + $table->styleTable = 'margin: 2em auto 0;border: 1px solid #ddd;background: white;'; + $table->rowid = []; + $table->data = []; + + // Content. + $table->data[$i][0] = ''.__('Hosts discovered').''; + $table->data[$i][1] = ''; + $table->data[$i][1] .= $summary['summary']['discovered']; + $table->data[$i++][1] .= ''; + + $table->data[$i][0] = ''.__('Alive').''; + $table->data[$i][1] = ''; + $table->data[$i][1] .= $summary['summary']['alive']; + $table->data[$i++][1] .= ''; + + $table->data[$i][0] = ''.__('Not alive').''; + $table->data[$i][1] = ''; + $table->data[$i][1] .= $summary['summary']['not_alive']; + $table->data[$i++][1] .= ''; + + $table->data[$i][0] = ''.__('Responding SNMP').''; + $table->data[$i][1] = ''; + $table->data[$i][1] .= $summary['summary']['SNMP']; + $table->data[$i++][1] .= ''; + + $table->data[$i][0] = ''.__('Responding WMI').''; + $table->data[$i][1] = ''; + $table->data[$i][1] .= $summary['summary']['WMI']; + $table->data[$i++][1] .= ''; + + $result .= '
    '.__('Summary').'
    '; + $result .= html_print_table($table, true).'
    '; + } else { + $global_progress = -1; + $result .= ui_print_error_message( + __('No data to show'), + '', + true + ).'
'; + } + + $result_array['status'] = $global_progress; + $result_array['html'] = $result; + + echo json_encode($result_array); + return; +} + +if ($showmap) { + include_once $config['homedir'].'/include/class/NetworkMap.class.php'; + $id_task = get_parameter('id', 0); + + $map = new NetworkMap( + [ + 'id_task' => $id_task, + 'pure' => 1, + 'widget' => true, + ] + ); + $map->printMap(); +} diff --git a/pandora_console/include/ajax/tree.ajax.php b/pandora_console/include/ajax/tree.ajax.php index 6c8365a924..9ea0a86e8e 100644 --- a/pandora_console/include/ajax/tree.ajax.php +++ b/pandora_console/include/ajax/tree.ajax.php @@ -43,6 +43,7 @@ if (is_ajax()) { include_once $config['homedir'].'/include/class/TreeModule.class.php'; include_once $config['homedir'].'/include/class/TreeTag.class.php'; include_once $config['homedir'].'/include/class/TreeGroup.class.php'; + include_once $config['homedir'].'/include/class/TreeService.class.php'; include_once $config['homedir'].'/include/class/TreeGroupEdition.class.php'; enterprise_include_once('include/class/TreePolicies.class.php'); enterprise_include_once('include/class/TreeGroupMeta.class.php'); @@ -120,6 +121,10 @@ if (is_ajax()) { $tree = new TreeGroupEdition($type, $rootType, $id, $rootID, $serverID, $childrenMethod, $access); break; + case 'services': + $tree = new TreeService($type, $rootType, $id, $rootID, $serverID, $childrenMethod, $access); + break; + default: // FIXME. No error handler return; @@ -127,6 +132,7 @@ if (is_ajax()) { $tree->setFilter($filter); ob_clean(); + echo json_encode(['success' => 1, 'tree' => $tree->getArray()]); return; } diff --git a/pandora_console/include/ajax/update_manager.ajax.php b/pandora_console/include/ajax/update_manager.ajax.php index bdb6710d20..7a7cefc82b 100644 --- a/pandora_console/include/ajax/update_manager.ajax.php +++ b/pandora_console/include/ajax/update_manager.ajax.php @@ -1,16 +1,32 @@ Not exits file. + * 0 -> File or directory deleted successfully. + * 1 -> Problem delete file or directory. + * 2 -> Not found file or directory. + * 3 -> Don`t read file deleet_files.txt. + * 4 -> "deleted" folder could not be created. + * 5 -> "deleted" folder was created. + * 6 -> The "delete files" could not be the "delete" folder. + * 7 -> The "delete files" is moved to the "delete" folder. + * Type: + * f -> File + * d -> Dir. + * route: Path. + */ + +if ($delete_desired_files === true) { + global $config; + + // Initialize result. + $result = []; + $result['status_list'] = []; + + // Flag exist folder "deleted". + $exist_deleted = true; + + // Route delete_files.txt. + $route_delete_files = $config['homedir']; + $route_delete_files .= '/extras/delete_files/delete_files.txt'; + + // Route directory deleted. + $route_dir_deleted = $config['homedir']; + $route_dir_deleted .= '/extras/delete_files/deleted/'; + + // Check isset directory deleted + // if it does not exist, try to create it. + if (is_dir($route_dir_deleted) === false) { + $res_mkdir = mkdir($route_dir_deleted, 0777, true); + $res = []; + if ($res_mkdir !== true) { + $exist_deleted = false; + $res['status'] = 4; + } else { + $res['status'] = 5; + } + + $res['type'] = 'd'; + $res['path'] = $url_to_delete; + array_push($result['status_list'], $res); + } + + // Check isset delete_files.txt. + if (file_exists($route_delete_files) === true && $exist_deleted === true) { + // Open file. + $file_read = fopen($route_delete_files, 'r'); + // Check if read delete_files.txt. + if ($file_read !== false) { + while ($file_to_delete = stream_get_line($file_read, 65535, "\n")) { + $file_to_delete = trim($file_to_delete); + $url_to_delete = $config['homedir'].'/'.$file_to_delete; + // Check is dir or file or not exists. + if (is_dir($url_to_delete) === true) { + $rmdir_recursive = rmdir_recursive( + $url_to_delete, + $result['status_list'] + ); + + array_push( + $result['status_list'], + $rmdir_recursive + ); + } else if (file_exists($url_to_delete) === true) { + $unlink = unlink($url_to_delete); + $res = []; + $res['status'] = ($unlink === true) ? 0 : 1; + $res['type'] = 'f'; + $res['path'] = $url_to_delete; + array_push($result['status_list'], $res); + } else { + $res = []; + $res['status'] = 2; + $res['path'] = $url_to_delete; + array_push($result['status_list'], $res); + } + } + } else { + $res = []; + $res['status'] = 3; + $res['path'] = $url_to_delete; + array_push($result['status_list'], $res); + } + + // Close file. + fclose($route_delete_files); + + // Move delete_files.txt to dir extras/deleted/. + $count_scandir = count(scandir($route_dir_deleted)); + $route_move = $route_dir_deleted.'/delete_files_'.$count_scandir.'.txt'; + $res_rename = rename( + $route_delete_files, + $route_move + ); + + $res = []; + $res['status'] = ($res_rename === true) ? 7 : 6; + $res['type'] = 'f'; + $res['path'] = $route_move; + array_push($result['status_list'], $res); + } else { + if ($exist_deleted === true) { + $res = []; + $res['status'] = -1; + array_push($result['status_list'], $res); + } + } + + // Translation diccionary neccesary. + $result['translation'] = [ + 'title' => __('Delete files'), + 'not_file' => __('The oum has no files to remove'), + 'not_found' => __('Not found'), + 'not_deleted' => __('Not deleted'), + 'not_read' => __('The file delete_file.txt can not be read'), + 'folder_deleted_f' => __('\'deleted\' folder could not be created'), + 'folder_deleted_t' => __('\'deleted\' folder was created'), + 'move_file_f' => __( + 'The "delete files" could not be the "delete" folder' + ), + 'move_file_d' => __( + 'The "delete files" is moved to the "delete" folder' + ), + ]; + + echo json_encode($result); + return; +} diff --git a/pandora_console/include/ajax/visual_console_builder.ajax.php b/pandora_console/include/ajax/visual_console_builder.ajax.php index 82c21eae8b..51ea636659 100755 --- a/pandora_console/include/ajax/visual_console_builder.ajax.php +++ b/pandora_console/include/ajax/visual_console_builder.ajax.php @@ -176,6 +176,7 @@ $default_color = get_parameter('default_color', '#FFFFFF'); $color_range_from_values = get_parameter('color_range_from_values', []); $color_range_to_values = get_parameter('color_range_to_values', []); $color_range_colors = get_parameter('color_range_colors', []); +$cache_expiration = (int) get_parameter('cache_expiration'); switch ($action) { case 'get_font': @@ -581,7 +582,21 @@ switch ($action) { $values['label_position'] = $label_position; $values['show_on_top'] = $show_on_top; - // In Graphs, background color is stored in column image (sorry) + switch ($type) { + case 'line_item': + case 'box_item': + case 'clock': + case 'icon': + case 'label': + $values['cache_expiration'] = 0; + break; + + default: + $values['cache_expiration'] = $cache_expiration; + break; + } + + // In Graphs, background color is stored in column image (sorry). if ($type == 'module_graph') { $values['image'] = $background_color; $values['type_graph'] = $type_graph; @@ -997,6 +1012,7 @@ switch ($action) { unset($values['id_layout_linked']); unset($values['element_group']); unset($values['id_layout_linked_weight']); + unset($values['cache_expiration']); // Don't change background color in graphs when move switch ($type) { case 'group_item': @@ -1070,6 +1086,16 @@ switch ($action) { ['id' => $id_element] ); + // Invalidate the item's cache. + if ($result !== false && $result > 0) { + db_process_sql_delete( + 'tvisual_console_elements_cache', + [ + 'vc_item_id' => (int) $id_element, + ] + ); + } + $return_val = []; $return_val['correct'] = (int) $result; $return_val['new_line'] = $new_line; @@ -1404,9 +1430,22 @@ switch ($action) { $values['show_on_top'] = $show_on_top; $values['image'] = $background_color; $values['type_graph'] = $type_graph; - $values['id_custom_graph'] = $id_custom_graph; + switch ($type) { + case 'line_item': + case 'box_item': + case 'clock': + case 'icon': + case 'label': + $values['cache_expiration'] = 0; + break; + + default: + $values['cache_expiration'] = $cache_expiration; + break; + } + switch ($type) { case 'line_item': $values['type'] = LINE_ITEM; diff --git a/pandora_console/include/api.php b/pandora_console/include/api.php index 3b04cedd24..e4977bb614 100644 --- a/pandora_console/include/api.php +++ b/pandora_console/include/api.php @@ -40,10 +40,10 @@ $info = get_parameter('info', ''); $other = parseOtherParameter($otherSerialize, $otherMode); +$other = parseOtherParameter($otherSerialize, $otherMode); $apiPassword = io_output_password(db_get_value_filter('value', 'tconfig', ['token' => 'api_password'])); $correctLogin = false; -$user_in_db = null; $no_login_msg = ''; // Clean unwanted output @@ -149,6 +149,44 @@ if ($correctLogin) { } break; + case 'delete_user_permission': + + if ($user_db === '') { + returnError(__('User or group not specified'), __('User, group not specified')); + return; + } + + $id_os = api_set_delete_user_profiles($thrash1, $thrash2, $other, $returnType); + + if ($id_os != 100) { + return; + } + + if ($id_os == false) { + returnError('not_allowed_operation_cluster', $returnType); + return false; + } + break; + + case 'add_permission_user_to_group': + + if ($user_db == null || $group_db == null || $id_up == null) { + returnError(__('User, group or profile not specified'), __('User, group or profile status not specified')); + return; + } + + $id_os = api_set_add_permission_user_to_group($thrash1, $thrash2, $other, $returnType); + + if ($id_os != 100) { + return; + } + + if ($id_os == false) { + returnError('not_allowed_operation_cluster', $returnType); + return false; + } + break; + default: // break; diff --git a/pandora_console/include/auth/mysql.php b/pandora_console/include/auth/mysql.php index 69e848d805..b9a5ede1e5 100644 --- a/pandora_console/include/auth/mysql.php +++ b/pandora_console/include/auth/mysql.php @@ -85,7 +85,7 @@ function process_user_login($login, $pass, $api=false) return process_user_login_local($login, $pass, $api); } else { $login_remote = process_user_login_remote($login, io_safe_output($pass), $api); - if ($login_remote == false && $config['fallback_local_auth'] == '1') { + if ($login_remote == false) { return process_user_login_local($login, $pass, $api); } else { return $login_remote; @@ -282,39 +282,42 @@ function process_user_login_remote($login, $pass, $api=false) } } } else if ($config['auth'] === 'ldap') { - if ($config['ldap_save_password']) { - $update_credentials = change_local_user_pass_ldap($login, $pass); + // Check if autocreate remote users is active. + if ($config['autocreate_remote_users'] == 1) { + if ($config['ldap_save_password']) { + $update_credentials = change_local_user_pass_ldap($login, $pass); - if ($update_credentials) { - $config['auth_error'] = __('Your permissions have changed. Please, login again.'); - return false; - } - } else { - delete_user_pass_ldap($login); - } - - $permissions = fill_permissions_ldap($sr); - if (empty($permissions)) { - $config['auth_error'] = __('User not found in database or incorrect password'); - return false; - } else { - // check permissions - $result = check_permission_ad( - $login, - $pass, - false, - $permissions, - defined('METACONSOLE') - ); - - if ($return === 'error_permissions') { - $config['auth_error'] = __('Problems with configuration permissions. Please contact with Administrator'); - return false; - } else { - if ($return === 'permissions_changed') { + if ($update_credentials) { $config['auth_error'] = __('Your permissions have changed. Please, login again.'); return false; } + } else { + delete_user_pass_ldap($login); + } + + $permissions = fill_permissions_ldap($sr); + if (empty($permissions)) { + $config['auth_error'] = __('User not found in database or incorrect password'); + return false; + } else { + // check permissions + $result = check_permission_ad( + $login, + $pass, + false, + $permissions, + defined('METACONSOLE') + ); + + if ($return === 'error_permissions') { + $config['auth_error'] = __('Problems with configuration permissions. Please contact with Administrator'); + return false; + } else { + if ($return === 'permissions_changed') { + $config['auth_error'] = __('Your permissions have changed. Please, login again.'); + return false; + } + } } } } @@ -1252,9 +1255,109 @@ function check_permission_ldap( function fill_permissions_ldap($sr) { global $config; - $permissions = []; - if (!$config['ldap_advanced_config']) { + $permissions_profile = []; + if (defined('METACONSOLE')) { + $meta = true; + } + + if ($meta && (bool) $config['ldap_save_profile'] === false && $config['ldap_advanced_config'] == 0) { + $result = 0; + $result = db_get_all_rows_filter( + 'tusuario_perfil', + ['id_usuario' => $sr['uid'][0]] + ); + if ($result == false) { + $permissions[0]['profile'] = $config['default_remote_profile']; + $permissions[0]['groups'][] = $config['default_remote_group']; + $permissions[0]['tags'] = $config['default_assign_tags']; + $permissions[0]['no_hierarchy'] = $config['default_no_hierarchy']; + return $permissions; + } + + foreach ($result as $perms) { + $permissions_profile[] = [ + 'profile' => $perms['id_perfil'], + 'groups' => [$perms['id_grupo']], + 'tags' => $perms['tags'], + 'no_hierarchy' => (bool) $perms['no_hierarchy'] ? 1 : 0, + ]; + } + + return $permissions_profile; + } + + if ((bool) $config['ldap_save_profile'] === false && $config['ldap_advanced_config'] == '') { + $result = db_get_all_rows_filter( + 'tusuario_perfil', + ['id_usuario' => $sr['uid'][0]] + ); + if ($result == false) { + $permissions[0]['profile'] = $config['default_remote_profile']; + $permissions[0]['groups'][] = $config['default_remote_group']; + $permissions[0]['tags'] = $config['default_assign_tags']; + $permissions[0]['no_hierarchy'] = $config['default_no_hierarchy']; + return $permissions; + } + + foreach ($result as $perms) { + $permissions_profile[] = [ + 'profile' => $perms['id_perfil'], + 'groups' => [$perms['id_grupo']], + 'tags' => $perms['tags'], + 'no_hierarchy' => (bool) $perms['no_hierarchy'] ? 1 : 0, + ]; + } + + return $permissions_profile; + } + + if ($config['ldap_advanced_config'] == 1 && $config['ldap_save_profile'] == 1) { + $ldap_adv_perms = json_decode(io_safe_output($config['ldap_adv_perms']), true); + foreach ($ldap_adv_perms as $ldap_adv_perm) { + $permissions[] = [ + 'profile' => $ldap_adv_perm['profile'], + 'groups' => $ldap_adv_perm['group'], + 'tags' => implode(',', $ldap_adv_perm['tags']), + 'no_hierarchy' => (bool) $ldap_adv_perm['no_hierarchy'] ? 1 : 0, + ]; + } + + return $permissions; + } + + if ($config['ldap_advanced_config'] == 1 && $config['ldap_save_profile'] == 0) { + $result = db_get_all_rows_filter( + 'tusuario_perfil', + ['id_usuario' => $sr['uid'][0]] + ); + if ($result == false) { + $ldap_adv_perms = json_decode(io_safe_output($config['ldap_adv_perms']), true); + foreach ($ldap_adv_perms as $ldap_adv_perm) { + $permissions[] = [ + 'profile' => $ldap_adv_perm['profile'], + 'groups' => $ldap_adv_perm['group'], + 'tags' => implode(',', $ldap_adv_perm['tags']), + 'no_hierarchy' => (bool) $ldap_adv_perm['no_hierarchy'] ? 1 : 0, + ]; + } + + return $permissions; + } + + foreach ($result as $perms) { + $permissions_profile[] = [ + 'profile' => $perms['id_perfil'], + 'groups' => [$perms['id_grupo']], + 'tags' => $perms['tags'], + 'no_hierarchy' => (bool) $perms['no_hierarchy'] ? 1 : 0, + ]; + }; + + return $permissions_profile; + } + + if ($config['autocreate_remote_users'] && $config['ldap_save_profile'] == 1) { $permissions[0]['profile'] = $config['default_remote_profile']; $permissions[0]['groups'][] = $config['default_remote_group']; $permissions[0]['tags'] = $config['default_assign_tags']; @@ -1369,8 +1472,12 @@ function local_ldap_search($ldap_host, $ldap_port=389, $ldap_version=3, $dn, $ac $tls = ' -ZZ '; } - $ldap_host = ' -h '.$ldap_host; - $ldap_port = ' -p '.$ldap_port; + if (stripos($ldap_host, 'ldap') !== false) { + $ldap_host = ' -H '.$ldap_host.':'.$ldap_port; + } else { + $ldap_host = ' -h '.$ldap_host.' -p '.$ldap_port; + } + $ldap_version = ' -P '.$ldap_version; if (!empty($ldap_admin_user)) { $ldap_admin_user = " -D '".$ldap_admin_user."'"; @@ -1382,7 +1489,7 @@ function local_ldap_search($ldap_host, $ldap_port=389, $ldap_version=3, $dn, $ac $dn = " -b '".$dn."'"; - $shell_ldap_search = explode("\n", shell_exec('ldapsearch -LLL -o ldif-wrap=no -x'.$ldap_host.$ldap_port.$ldap_version.' -E pr=10000/noprompt '.$ldap_admin_user.$ldap_admin_pass.$dn.$filter.$tls.' | grep -v "^#\|^$" | sed "s/:\+ /=>/g"')); + $shell_ldap_search = explode("\n", shell_exec('ldapsearch -LLL -o ldif-wrap=no -x'.$ldap_host.$ldap_version.' -E pr=10000/noprompt '.$ldap_admin_user.$ldap_admin_pass.$dn.$filter.$tls.' | grep -v "^#\|^$" | sed "s/:\+ /=>/g"')); foreach ($shell_ldap_search as $line) { $values = explode('=>', $line); if (!empty($values[0]) && !empty($values[1])) { diff --git a/pandora_console/include/chart_generator.php b/pandora_console/include/chart_generator.php index 96124afa4c..e7133fd79e 100644 --- a/pandora_console/include/chart_generator.php +++ b/pandora_console/include/chart_generator.php @@ -88,16 +88,13 @@ if (file_exists('languages/'.$user_language.'.mo')) { $params['menu'] = false; if ((!isset($params['width']) || ($params['width'] <= 0))) { - $params['width'] = 1048; + $params['width'] = 650; } $params_combined = json_decode($_REQUEST['data_combined'], true); $module_list = json_decode($_REQUEST['data_module_list'], true); $type_graph_pdf = $_REQUEST['type_graph_pdf']; - $aux_font_size = $config['font_size']; - $config['font_size'] = ($config['font_size'] + 3); - echo '
'; switch ($type_graph_pdf) { case 'combined': @@ -216,7 +213,6 @@ if (file_exists('languages/'.$user_language.'.mo')) { echo '
'; - $config['font_size'] = $aux_font_size; ?> '; + + return $output; + } + + + /** + * Generates a simple interface to interact with nodes. + * + * @return string HTML code for simple interface. + */ + public function loadSimpleInterface() + { + $output = ''; + + $output .= ''; + + return $output; + } + + + /** + * Show an advanced interface to manage dialogs. + * + * @return string HTML code with dialogs. + */ + public function loadAdvancedInterface() + { + $list_networkmaps = get_networkmaps($this->idMap); + if (empty($list_networkmaps)) { + $list_networkmaps = []; + } + + $output .= ''; + + $output .= ''; + + $output .= ''; + + $output .= ''; + + return $output; + } + + + /** + * Loads advanced map controller (JS). + * + * @return string HTML code for advanced controller. + */ + public function loadController() + { + $output = ''; + + if (enterprise_installed() + && $this->useTooltipster + ) { + $output .= ''; + } else { + // Generate JS for advanced controller. + $output .= ' + +'; + } + + if ($return === false) { + echo $output; + } + + return $output; + + } + + + /** + * Load networkmap HTML skel and JS requires. + * + * @return string HTML code for skel. + */ + public function loadMapSkel() + { + global $config; + + if (enterprise_installed() + && isset($this->useTooltipster) + && $this->useTooltipster == true + ) { + $output .= ''; + $output .= ''; + $output .= ''; + $output .= ''; + $output .= ''; + $output .= ''."\n"; + + $output .= '
fullSize) { + $output .= ' width:100%'; + $output .= ' ;height: 100%">'; + $output .= ''; + } else { + $output .= ' width:'.$this->mapOptions['width'].'px'; + $output .= ' ;height:'.$this->mapOptions['height'].'px">'; + $output .= ''; + } + + $output .= ''; + $output .= '
'; + } else { + // Load default interface. + ui_require_css_file('networkmap'); + ui_require_css_file('jquery.contextMenu', 'include/styles/js/'); + + $output = ''; + $minimap_display = ''; + if ($this->mapOptions['pure']) { + $minimap_display = 'none'; + } + + $networkmap = $this->map; + if (is_array($networkmap['filter']) === false) { + $networkmap['filter'] = json_decode($networkmap['filter'], true); + } + + $networkmap['filter']['l2_network_interfaces'] = 1; + + $output .= ''; + if (isset($this->map['__simulated']) === false) { + // Load context menu if manageable networkmap. + $output .= ''; + } + + $output .= ''; + + // Open networkconsole_id div. + $output .= '
fullSize) { + $output .= ' style="width: 100%; height: 100%;position: relative; overflow: hidden; background: #FAFAFA">'; + } else { + $output .= ' style="width: '.$this->mapOptions['width'].'px; height: '.$this->mapOptions['height'].'px;position: relative; overflow: hidden; background: #FAFAFA">'; + } + + $output .= '
'; + $output .= ''; + $output .= html_print_image('/images/minimap_open_arrow.png', true, ['id' => 'arrow_minimap_'.$networkmap['id']]); + $output .= '
'; + + $output .= '
'; + $output .= html_print_image('/images/icono_borrar.png', true, ['id' => 'image_hide_show_labels']); + $output .= '
'; + + $output .= '
'image_hide_show_labels']); + $output .= '
'; + + // Close networkconsole_id div. + $output .= "
\n"; + } + + return $output; + } + + + /** + * Print all components required to visualizate a network map. + * + * @param boolean $return Return as string or not. + * + * @return string HTML code. + */ + public function printMap($return=false) + { + global $config; + + // ACL. + $networkmap_read = check_acl( + $config['id_user'], + $networkmap['id_group'], + 'MR' + ); + $networkmap_write = check_acl( + $config['id_user'], + $networkmap['id_group'], + 'MW' + ); + $networkmap_manage = check_acl( + $config['id_user'], + $networkmap['id_group'], + 'MM' + ); + + if (!$networkmap_read + && !$networkmap_write + && !$networkmap_manage + ) { + db_pandora_audit( + 'ACL Violation', + 'Trying to access networkmap' + ); + include 'general/noaccess.php'; + return ''; + } + + $user_readonly = !$networkmap_write && !$networkmap_manage; + + if (isset($this->idMap) + && isset($this->map['__simulated']) === false + ) { + $output .= $this->loadMapSkel(); + $output .= $this->loadMapData(); + $output .= $this->loadController(); + if (!$this->noPopUp) { + $output .= $this->loadAdvancedInterface(); + } + } else { + // Simulated, no tmap entries. + $output .= $this->loadMapSkel(); + $output .= $this->loadMapData(); + $output .= $this->loadController(); + if (!$this->noPopUp) { + $output .= $this->loadSimpleInterface(); + } + } + + $output .= ' + + +'; + if ($return === false) { + echo $output; + } + + return $output; + } + + +} diff --git a/pandora_console/include/class/Tree.class.php b/pandora_console/include/class/Tree.class.php index eda92b48b5..f5af14a6db 100644 --- a/pandora_console/include/class/Tree.class.php +++ b/pandora_console/include/class/Tree.class.php @@ -57,6 +57,8 @@ class Tree protected $L2inner = ''; + protected $avoid_condition = false; + protected $L3forceTagCondition = false; const TV_DEFAULT_AGENT_STATUS = -1; @@ -77,6 +79,7 @@ class Tree $this->access = $access; $userGroupsACL = users_get_groups(false, $this->access); + $this->userGroupsACL = empty($userGroupsACL) ? false : $userGroupsACL; $this->userGroups = $this->userGroupsACL; $this->userGroupsArray = array_keys($this->userGroups); @@ -947,7 +950,6 @@ class Tree } $this->processAgents($data); - $this->tree = $data; } @@ -1032,7 +1034,6 @@ class Tree $data = $this->getProcessedModules($data); $this->processModules($data); - $this->tree = $data; } @@ -1051,8 +1052,13 @@ class Tree $tag_condition = $this->getTagCondition(); $tag_join = empty($tag_condition) && (!$this->L3forceTagCondition) ? '' : $this->getTagJoin(); - $condition = $this->L2condition; - $inner = $this->L2inner; + if ($this->avoid_condition === true) { + $condition = ''; + $inner = ''; + } else { + $condition = $this->L2condition; + $inner = $this->L2inner; + } $columns = 'DISTINCT(tam.id_agente_modulo) AS id, tam.nombre AS name, tam.id_tipo_modulo, tam.id_modulo, tae.estado, tae.datos, @@ -1076,10 +1082,10 @@ class Tree $group_acl $agent_search_filter $agent_status_filter - $module_status_filter $module_search_filter $tag_condition ORDER BY tam.nombre ASC, tam.id_agente_modulo ASC"; + return $sql; } diff --git a/pandora_console/include/class/TreeGroup.class.php b/pandora_console/include/class/TreeGroup.class.php index bef4287c7d..05ba271e24 100644 --- a/pandora_console/include/class/TreeGroup.class.php +++ b/pandora_console/include/class/TreeGroup.class.php @@ -36,9 +36,9 @@ class TreeGroup extends Tree ]; $this->L2conditionInside = 'AND ( - ta.id_grupo = '.$this->id.' - OR tasg.id_group = '.$this->id.' - )'; + ta.id_grupo = '.$this->id.' + OR tasg.id_group = '.$this->id.' + )'; } @@ -198,44 +198,44 @@ class TreeGroup extends Tree $module_search_filter = ''; if (!empty($this->filter['searchModule'])) { $module_search_inner = ' - INNER JOIN tagente_modulo tam - ON ta.id_agente = tam.id_agente - INNER JOIN tagente_estado tae - ON tae.id_agente_modulo = tam.id_agente_modulo'; + INNER JOIN tagente_modulo tam + ON ta.id_agente = tam.id_agente + INNER JOIN tagente_estado tae + ON tae.id_agente_modulo = tam.id_agente_modulo'; $module_search_filter = "AND tam.disabled = 0 - AND tam.nombre LIKE '%%".$this->filter['searchModule']."%%' ".$this->getModuleStatusFilterFromTestado(); + AND tam.nombre LIKE '%%".$this->filter['searchModule']."%%' ".$this->getModuleStatusFilterFromTestado(); } $table = is_metaconsole() ? 'tmetaconsole_agent' : 'tagente'; $table_sec = is_metaconsole() ? 'tmetaconsole_agent_secondary_group' : 'tagent_secondary_group'; $sql_model = "SELECT %s FROM - ( - SELECT COUNT(DISTINCT(ta.id_agente)) AS total, id_grupo AS g - FROM $table ta - $module_search_inner - WHERE ta.disabled = 0 - %s - $agent_search_filter - $agent_status_filter - $module_status_filter - $module_search_filter - $group_acl - GROUP BY id_grupo - UNION ALL - SELECT COUNT(DISTINCT(ta.id_agente)) AS total, id_group AS g - FROM $table ta INNER JOIN $table_sec tasg - ON ta.id_agente = tasg.id_agent - $module_search_inner - WHERE ta.disabled = 0 - %s - $agent_search_filter - $agent_status_filter - $module_status_filter - $module_search_filter - $secondary_group_acl - GROUP BY id_group - ) x GROUP BY g"; + ( + SELECT COUNT(DISTINCT(ta.id_agente)) AS total, id_grupo AS g + FROM $table ta + $module_search_inner + WHERE ta.disabled = 0 + %s + $agent_search_filter + $agent_status_filter + $module_status_filter + $module_search_filter + $group_acl + GROUP BY id_grupo + UNION ALL + SELECT COUNT(DISTINCT(ta.id_agente)) AS total, id_group AS g + FROM $table ta INNER JOIN $table_sec tasg + ON ta.id_agente = tasg.id_agent + $module_search_inner + WHERE ta.disabled = 0 + %s + $agent_search_filter + $agent_status_filter + $module_status_filter + $module_search_filter + $secondary_group_acl + GROUP BY id_group + ) x GROUP BY g"; $sql_array = []; foreach ($inside_fields as $inside_field) { $sql_array[] = sprintf( @@ -247,9 +247,9 @@ class TreeGroup extends Tree } $sql = "SELECT $fields FROM (".implode(' UNION ALL ', $sql_array).') x2 - RIGHT JOIN tgrupo tg - ON x2.g = tg.id_grupo - GROUP BY tg.id_grupo'; + RIGHT JOIN tgrupo tg + ON x2.g = tg.id_grupo + GROUP BY tg.id_grupo'; $stats = db_get_all_rows_sql($sql); $group_stats = []; diff --git a/pandora_console/include/class/TreeService.class.php b/pandora_console/include/class/TreeService.class.php new file mode 100644 index 0000000000..eaf3c55fea --- /dev/null +++ b/pandora_console/include/class/TreeService.class.php @@ -0,0 +1,352 @@ +L1fieldName = 'id_group'; + $this->L1extraFields = [ + 'ts.name AS `name`', + 'ts.id AS `sid`', + ]; + + $this->filter['statusAgent'] = AGENT_STATUS_ALL; + + $this->avoid_condition = true; + + $this->L2inner = 'LEFT JOIN tservice_element tse + ON tse.id_agent = ta.id_agente'; + + $this->L2condition = 'AND tse.id_service='.$this->id; + + } + + + public function setPropagateCounters($value) + { + $this->propagateCounters = (bool) $value; + } + + + public function setDisplayAllGroups($value) + { + $this->displayAllGroups = (bool) $value; + } + + + protected function getData() + { + if ($this->id == -1) { + $this->getFirstLevel(); + } else if ($this->type == 'services') { + $this->getSecondLevel(); + } else if ($this->type == 'agent') { + $this->getThirdLevel(); + } + } + + + protected function getFirstLevel() + { + $processed_items = $this->getProcessedServices(); + $ids = array_keys($processed_items); + + $filter = ['id' => $ids]; + + $own_info = get_user_info($config['id_user']); + + if ($own_info['is_admin'] || check_acl($config['id_user'], 0, 'PM')) { + $display_all_services = true; + } else { + $display_all_services = false; + } + + $this->tree = []; + + $services = services_get_services($filter, false, $display_all_services); + + foreach ($services as $row) { + $status = services_get_status($row, true); + + switch ($status) { + case SERVICE_STATUS_NORMAL: + $processed_items[$row['id']]['statusImageHTML'] = 'NORMAL status.'; + break; + + case SERVICE_STATUS_CRITICAL: + $processed_items[$row['id']]['statusImageHTML'] = 'CRITICAL status.'; + break; + + case SERVICE_STATUS_WARNING: + $processed_items[$row['id']][$key]['statusImageHTML'] = 'WARNING status.'; + break; + + case SERVICE_STATUS_UNKNOWN: + default: + $processed_items[$row['id']]['statusImageHTML'] = 'UNKNOWN status.'; + break; + } + } + + $this->tree = $processed_items; + } + + + protected function getProcessedServices() + { + $fields = $this->getFirstLevelFields(); + + if (users_can_manage_group_all('AR')) { + $groups_acl = ''; + } else { + $groups_acl = 'AND ts.id_group IN ('.implode(',', $this->userGroupsArray).')'; + } + + $sql = sprintf( + "SELECT t1.* + FROM tservice_element tss + RIGHT JOIN + (SELECT ts.id, ts.id_agent_module, ts.name, ts.name AS `alias`, ts.id AS `rootID`, + 'services' AS rootType, 'services' AS type, + 0 AS quiet, + SUM(if((tse.id_agent<>0), 1, 0)) AS `total_agents`, + SUM(if((tse.id_agente_modulo<>0), 1, 0)) AS `total_modules`, + SUM(if((tse.id_service_child<>0), 1, 0)) AS `total_services` + FROM tservice ts + LEFT JOIN tservice_element tse + ON ts.id=tse.id_service + GROUP BY id + ) as t1 + ON tss.id_service_child = t1.id + WHERE tss.id_service_child IS NULL + %s + ", + $groups_acl + ); + + $stats = db_get_all_rows_sql($sql); + + $services = []; + + foreach ($stats as $service) { + $services[$service['id']] = $this->getProcessedItem($services[$service['id']]); + if (($service['total_services'] + $service['total_agents'] + $service['total_modules']) > 0) { + $services[$service['id']]['searchChildren'] = 1; + } else { + $services[$service['id']]['searchChildren'] = 0; + } + + $services[$service['id']]['counters'] = [ + 'total_services' => $service['total_services'], + 'total_agents' => $service['total_agents'], + 'total_modules' => $service['total_modules'], + ]; + $services[$service['id']]['name'] = $service['name']; + $services[$service['id']]['id'] = $service['id']; + $services[$service['id']]['serviceDetail'] = 'index.php?sec=network&sec2=enterprise/operation/services/services&tab=service_map&id_service='.(int) $service['id']; + } + + return $services; + } + + + protected function getFirstLevelFields() + { + $fields = []; + + return implode(',', array_merge($fields, $this->L1extraFields)); + } + + + protected function getSecondLevel() + { + $data = []; + $data_agents = []; + $data_modules = []; + $data_services = []; + + $sql = $this->getSecondLevelSql(); + $data_agents = db_process_sql($sql); + + if (empty($data_agents)) { + $data_agents = []; + } + + $this->processAgents($data_agents); + + foreach ($data_agents as $key => $agent) { + $data_agents[$key]['showEventsBtn'] = 1; + $data_agents[$key]['eventAgent'] = $agent['id']; + } + + $sql = $this->getSecondLevelModulesSql(); + $data_modules = db_process_sql($sql); + + if (empty($data_modules)) { + $data_modules = []; + } else { + foreach ($data_modules as $key => $module) { + switch ($module['estado']) { + case '0': + $data_modules[$key]['statusImageHTML'] = 'NORMAL status.'; + break; + + case '1': + $data_modules[$key]['statusImageHTML'] = 'CRITICAL status.'; + break; + + case '2': + $data_modules[$key]['statusImageHTML'] = 'WARNING status.'; + break; + + case '4': + $data_modules[$key]['statusImageHTML'] = 'UNKNOWN status.'; + break; + + default: + // code... + break; + } + + $data_modules[$key]['showEventsBtn'] = 1; + $data_modules[$key]['eventModule'] = $module['id_agente_modulo']; + } + } + + $sql = $this->getSecondLevelServicesSql(); + $data_services = db_process_sql($sql); + + $service_stats = []; + + foreach ($data_services as $service) { + $service_stats[$service['id']]['id'] = (int) $service['id']; + $service_stats[$service['id']]['name'] = $service['name']; + $service_stats[$service['id']]['alias'] = $service['name']; + if (($service['total_services'] + $service['total_agents'] + $service['total_modules']) > 0) { + $service_stats[$service['id']]['searchChildren'] = 1; + } else { + $services[$service['id']]['searchChildren'] = 0; + } + + $service_stats[$service['id']]['rootID'] = $service['rootID']; + $service_stats[$service['id']]['rootType'] = $service['rootType']; + $service_stats[$service['id']]['type'] = 'services'; + $service_stats[$service['id']]['children'] = []; + $service_stats[$service['id']]['serviceDetail'] = 'index.php?sec=network&sec2=enterprise/operation/services/services&tab=service_map&id_service='.(int) $service['id']; + $service_stats[$service['id']]['counters'] = [ + 'total_services' => $service['total_services'], + 'total_agents' => $service['total_agents'], + 'total_modules' => $service['total_modules'], + ]; + } + + $own_info = get_user_info($config['id_user']); + + if ($own_info['is_admin'] || check_acl($config['id_user'], 0, 'PM')) { + $display_all_services = true; + } else { + $display_all_services = false; + } + + $services = services_get_services($filter, false, $display_all_services); + + foreach ($services as $row) { + if (!array_key_exists($row['id'], $service_stats)) { + continue; + } + + $status = services_get_status($row, true); + + switch ($status) { + case SERVICE_STATUS_NORMAL: + $service_stats[$row['id']]['statusImageHTML'] = 'NORMAL status.'; + break; + + case SERVICE_STATUS_CRITICAL: + $service_stats[$row['id']]['statusImageHTML'] = 'CRITICAL status.'; + break; + + case SERVICE_STATUS_WARNING: + $service_stats[$row['id']][$key]['statusImageHTML'] = 'WARNING status.'; + break; + + case SERVICE_STATUS_UNKNOWN: + default: + $service_stats[$row['id']]['statusImageHTML'] = 'UNKNOWN status.'; + break; + } + } + + $data_services = array_values($service_stats); + + $data = array_merge($data_services, $data_agents, $data_modules); + + if (empty($data)) { + $this->tree = []; + return; + } + + $this->tree = $data; + } + + + protected function getSecondLevelServicesSql() + { + $group_acl = $this->getGroupAclCondition(); + + $sql = "SELECT ts.id, ts.name, tse1.id_service AS `rootID`, 'services' AS rootType, 'services' AS type, 0 AS quiet, SUM(if((tse2.id_agent<>0), 1, 0)) AS `total_agents`, SUM(if((tse2.id_agente_modulo<>0), 1, 0)) AS `total_modules`, SUM(if((tse2.id_service_child<>0), 1, 0)) AS `total_services`, 0 AS fired_count, 0 AS normal_count, 0 AS warning_count, 0 AS critical_count, 0 AS unknown_count, 0 AS notinit_count, 0 AS state_critical, 0 AS state_warning, 0 AS state_unknown, 0 AS state_notinit, 0 AS state_normal, 0 AS state_total, '' AS statusImageHTML, '' AS alertImageHTML + FROM tservice_element tse1 + LEFT JOIN tservice_element tse2 ON tse1.id_service_child=tse2.id_service + LEFT JOIN tservice ts ON tse1.id_service_child=ts.id + WHERE tse1.id_service=$this->id AND tse1.id_service_child<>0 + GROUP BY tse1.id_service_child + "; + + return $sql; + } + + + protected function getSecondLevelModulesSql() + { + $sql = "SELECT tse.id_agente_modulo, nombre AS `name`, nombre AS `alias`, tse.id_service AS `rootID`, 'services' AS `rootType`, 'modules' AS `type`, estado + FROM tservice_element tse + INNER JOIN tagente_modulo tam ON tse.id_agente_modulo=tam.id_agente_modulo + INNER JOIN tagente_estado tae ON tam.id_agente_modulo=tae.id_agente_estado + WHERE tse.id_service=$this->id AND tse.id_agente_modulo<>0 + "; + + return $sql; + } + + + protected function getAgentStatusFilter($status=self::TV_DEFAULT_AGENT_STATUS) + { + return ''; + } + + +} diff --git a/pandora_console/include/config_process.php b/pandora_console/include/config_process.php index 4de1f20d2f..3bbde1736a 100644 --- a/pandora_console/include/config_process.php +++ b/pandora_console/include/config_process.php @@ -20,8 +20,8 @@ /** * Pandora build version and version */ -$build_version = 'PC190215'; -$pandora_version = 'v7.0NG.731'; +$build_version = 'PC190605'; +$pandora_version = 'v7.0NG.735'; // Do not overwrite default timezone set if defined. $script_tz = @date_default_timezone_get(); @@ -306,3 +306,9 @@ switch ($config['dbtype']) { } // ====================================================================== +// Menu display mode. +if ($_SESSION['menu_type']) { + $config['menu_type'] = $_SESSION['menu_type']; +} else { + $config['menu_type'] = 'classic'; +} diff --git a/pandora_console/include/constants.php b/pandora_console/include/constants.php index ce7b91735c..7266e9eff4 100644 --- a/pandora_console/include/constants.php +++ b/pandora_console/include/constants.php @@ -1,47 +1,57 @@ 0) { + include 'general/mysqlerr.php'; return false; } @@ -204,7 +205,7 @@ function mysql_db_get_value($field, $table, $field_search=1, $condition=1, $sear * * @return mixed The first row of a database query or false. */ -function mysql_db_get_row($table, $field_search, $condition, $fields=false) +function mysql_db_get_row($table, $field_search, $condition, $fields=false, $cache=true) { if (empty($fields)) { $fields = '*'; @@ -242,7 +243,7 @@ function mysql_db_get_row($table, $field_search, $condition, $fields=false) ); } - $result = db_get_all_rows_sql($sql); + $result = db_get_all_rows_sql($sql, false, $cache); if ($result === false) { return false; @@ -706,6 +707,7 @@ function mysql_db_format_array_where_clause_sql($values, $join='AND', $prefix=fa $i = 1; $max = count($values); foreach ($values as $field => $value) { + $negative = false; if (is_numeric($field)) { // User provide the exact operation to do $query .= $value; @@ -718,6 +720,11 @@ function mysql_db_format_array_where_clause_sql($values, $join='AND', $prefix=fa continue; } + if ($field[0] == '!') { + $negative = true; + $field = substr($field, 1); + } + if ($field[0] != '`') { // If the field is as ., don't scape. if (strstr($field, '.') === false) { @@ -732,7 +739,8 @@ function mysql_db_format_array_where_clause_sql($values, $join='AND', $prefix=fa } else if (is_float($value) || is_double($value)) { $query .= sprintf('%s = %f', $field, $value); } else if (is_array($value)) { - $query .= sprintf('%s IN ("%s")', $field, implode('", "', $value)); + $not = $negative ? ' NOT ' : ''; + $query .= sprintf('%s %sIN ("%s")', $field, $not, implode('", "', $value)); } else { if ($value === '') { // Search empty string diff --git a/pandora_console/include/fonts/mem5YaGs126MiZpBA-UN7rgOUuhp.woff2 b/pandora_console/include/fonts/mem5YaGs126MiZpBA-UN7rgOUuhp.woff2 new file mode 100755 index 0000000000..2b04b15bb7 Binary files /dev/null and b/pandora_console/include/fonts/mem5YaGs126MiZpBA-UN7rgOUuhp.woff2 differ diff --git a/pandora_console/include/fonts/mem5YaGs126MiZpBA-UNirkOUuhp.woff2 b/pandora_console/include/fonts/mem5YaGs126MiZpBA-UNirkOUuhp.woff2 new file mode 100755 index 0000000000..a0965b7a89 Binary files /dev/null and b/pandora_console/include/fonts/mem5YaGs126MiZpBA-UNirkOUuhp.woff2 differ diff --git a/pandora_console/include/fonts/mem8YaGs126MiZpBA-UFVZ0b.woff2 b/pandora_console/include/fonts/mem8YaGs126MiZpBA-UFVZ0b.woff2 new file mode 100755 index 0000000000..c8050c25f8 Binary files /dev/null and b/pandora_console/include/fonts/mem8YaGs126MiZpBA-UFVZ0b.woff2 differ diff --git a/pandora_console/include/fonts/mem8YaGs126MiZpBA-UFW50bbck.woff2 b/pandora_console/include/fonts/mem8YaGs126MiZpBA-UFW50bbck.woff2 new file mode 100755 index 0000000000..2312604864 Binary files /dev/null and b/pandora_console/include/fonts/mem8YaGs126MiZpBA-UFW50bbck.woff2 differ diff --git a/pandora_console/include/functions.php b/pandora_console/include/functions.php index 6f13388fc0..f299153da6 100644 --- a/pandora_console/include/functions.php +++ b/pandora_console/include/functions.php @@ -243,19 +243,25 @@ function format_numeric($number, $decimals=1) /** * Render numeric data for a graph. It adds magnitude suffix to the number - * (M for millions, K for thousands...) base-10 + * (M for millions, K for thousands...). Base can be modified with divider. * - * TODO: base-2 multiplication - * - * @param float $number Number to be rendered - * @param integer $decimals Numbers after comma. Default value: 1 - * @param dec_point Decimal separator character. Default value: . - * @param thousands_sep Thousands separator character. Default value: , + * @param float $number Number to be rendered. + * @param integer $decimals Numbers after comma (default 1). + * @param string $dec_point Decimal separator character (default .). + * @param string $thousands_sep Thousands separator character (default ,). + * @param integer $divider Number to divide the rendered number. + * @param string $sufix Units of the multiple. * * @return string A string with the number and the multiplier */ -function format_for_graph($number, $decimals=1, $dec_point='.', $thousands_sep=',') -{ +function format_for_graph( + $number, + $decimals=1, + $dec_point='.', + $thousands_sep=',', + $divider=1000, + $sufix='' +) { $shorts = [ '', 'K', @@ -268,15 +274,15 @@ function format_for_graph($number, $decimals=1, $dec_point='.', $thousands_sep=' 'Y', ]; $pos = 0; - while ($number >= 1000) { - // as long as the number can be divided by 1000 + while ($number >= $divider) { + // As long as the number can be divided by divider. $pos++; - // Position in array starting with 0 - $number = ($number / 1000); + // Position in array starting with 0. + $number = ($number / $divider); } - return remove_right_zeros(format_numeric($number, $decimals)).$shorts[$pos]; - // This will actually do the rounding and the decimals + // This will actually do the rounding and the decimals. + return remove_right_zeros(format_numeric($number, $decimals)).$shorts[$pos].$sufix; } @@ -852,6 +858,29 @@ function get_parameter_checkbox($name, $default='') } +/** + * Transforms a swicth data (on - non present) to a int value. + * + * @param string $name Variable, switch name. + * @param string $default Default value. + * + * @return integer Value, 1 on, 0 off. + */ +function get_parameter_switch($name, $default='') +{ + $data = get_parameter($name, null); + + if ($data === null) { + return (isset($default) ? $default : 0); + } else if ($data == 'on') { + return 1; + } + + // Return value assigned to switch. + return $data; +} + + function get_cookie($name, $default='') { if (isset($_COOKIE[$name])) { @@ -1416,7 +1445,13 @@ function enterprise_include($filename) global $config; // Load enterprise extensions - $filepath = realpath($config['homedir'].'/'.ENTERPRISE_DIR.'/'.$filename); + if (defined('DESTDIR')) { + $destdir = DESTDIR; + } else { + $destdir = ''; + } + + $filepath = realpath($destdir.$config['homedir'].'/'.ENTERPRISE_DIR.'/'.$filename); if ($filepath === false) { return ENTERPRISE_NOT_HOOK; @@ -1728,16 +1763,22 @@ function array_key_to_offset($array, $key) /** * Make a snmpwalk and return it. * - * @param string $ip_target The target address. - * @param string $snmp_version Version of the snmp: 1,2,2c or 3. - * @param string $snmp_community. - * @param string $snmp3_auth_user. - * @param string $snmp3_security_level. - * @param string $snmp3_auth_method. - * @param string $snmp3_auth_pass. - * @param string $snmp3_privacy_method. - * @param string $snmp3_privacy_pass. - * @param integer $quick_print 0 for all details, 1 for only value. + * @param string $ip_target The target address. + * @param string $snmp_version Version of the snmp: 1,2,2c or 3. + * @param string $snmp_community Snmp_community. + * @param string $snmp3_auth_user Snmp3_auth_user. + * @param string $snmp3_security_level Snmp3_security_level. + * @param string $snmp3_auth_method Snmp3_auth_method. + * @param string $snmp3_auth_pass Snmp3_auth_pass. + * @param string $snmp3_privacy_method Snmp3_privacy_method. + * @param string $snmp3_privacy_pass Snmp3_privacy_pass. + * @param integer $quick_print To get all details 0, 1: only value. + * @param string $base_oid Base_oid. + * @param string $snmp_port Snmp_port. + * @param integer $server_to_exec Server_to_exec. + * @param string $extra_arguments Extra_arguments. + * @param string $format Format to apply, for instance, to + * retrieve hex-dumps: --hexOutputLength. * * @return array SNMP result. */ @@ -1755,7 +1796,8 @@ function get_snmpwalk( $base_oid='', $snmp_port='', $server_to_exec=0, - $extra_arguments='' + $extra_arguments='', + $format='-Oa' ) { global $config; @@ -1806,15 +1848,15 @@ function get_snmpwalk( case '3': switch ($snmp3_security_level) { case 'authNoPriv': - $command_str = $snmpwalk_bin.' -m ALL -Oa '.$extra_arguments.' -v 3'.' -u '.escapeshellarg($snmp3_auth_user).' -A '.escapeshellarg($snmp3_auth_pass).' -l '.escapeshellarg($snmp3_security_level).' -a '.escapeshellarg($snmp3_auth_method).' '.escapeshellarg($ip_target).' '.$base_oid.' 2> '.$error_redir_dir; + $command_str = $snmpwalk_bin.' -m ALL '.$format.' '.$extra_arguments.' -v 3'.' -u '.escapeshellarg($snmp3_auth_user).' -A '.escapeshellarg($snmp3_auth_pass).' -l '.escapeshellarg($snmp3_security_level).' -a '.escapeshellarg($snmp3_auth_method).' '.escapeshellarg($ip_target).' '.$base_oid.' 2> '.$error_redir_dir; break; case 'noAuthNoPriv': - $command_str = $snmpwalk_bin.' -m ALL -Oa '.$extra_arguments.' -v 3'.' -u '.escapeshellarg($snmp3_auth_user).' -l '.escapeshellarg($snmp3_security_level).' '.escapeshellarg($ip_target).' '.$base_oid.' 2> '.$error_redir_dir; + $command_str = $snmpwalk_bin.' -m ALL '.$format.' '.$extra_arguments.' -v 3'.' -u '.escapeshellarg($snmp3_auth_user).' -l '.escapeshellarg($snmp3_security_level).' '.escapeshellarg($ip_target).' '.$base_oid.' 2> '.$error_redir_dir; break; default: - $command_str = $snmpwalk_bin.' -m ALL -Oa '.$extra_arguments.' -v 3'.' -u '.escapeshellarg($snmp3_auth_user).' -A '.escapeshellarg($snmp3_auth_pass).' -l '.escapeshellarg($snmp3_security_level).' -a '.escapeshellarg($snmp3_auth_method).' -x '.escapeshellarg($snmp3_privacy_method).' -X '.escapeshellarg($snmp3_privacy_pass).' '.escapeshellarg($ip_target).' '.$base_oid.' 2> '.$error_redir_dir; + $command_str = $snmpwalk_bin.' -m ALL '.$format.' '.$extra_arguments.' -v 3'.' -u '.escapeshellarg($snmp3_auth_user).' -A '.escapeshellarg($snmp3_auth_pass).' -l '.escapeshellarg($snmp3_security_level).' -a '.escapeshellarg($snmp3_auth_method).' -x '.escapeshellarg($snmp3_privacy_method).' -X '.escapeshellarg($snmp3_privacy_pass).' '.escapeshellarg($ip_target).' '.$base_oid.' 2> '.$error_redir_dir; break; } break; @@ -1823,7 +1865,7 @@ function get_snmpwalk( case '2c': case '1': default: - $command_str = $snmpwalk_bin.' -m ALL '.$extra_arguments.' -Oa -v '.escapeshellarg($snmp_version).' -c '.escapeshellarg(io_safe_output($snmp_community)).' '.escapeshellarg($ip_target).' '.$base_oid.' 2> '.$error_redir_dir; + $command_str = $snmpwalk_bin.' -m ALL '.$extra_arguments.' '.$format.' -v '.escapeshellarg($snmp_version).' -c '.escapeshellarg(io_safe_output($snmp_community)).' '.escapeshellarg($ip_target).' '.$base_oid.' 2> '.$error_redir_dir; break; } @@ -2634,7 +2676,7 @@ function get_news($arguments) case 'mysql': case 'postgresql': $sql = sprintf( - "SELECT subject,timestamp,text,author + "SELECT id_news,subject,timestamp,text,author FROM tnews WHERE id_group IN (%s) AND modal = %s AND (expire = 0 OR (expire = 1 AND expire_timestamp > '%s')) @@ -3507,25 +3549,27 @@ function series_type_graph_array($data, $show_elements_graph) break; } - if (isset($show_elements_graph['labels']) + if (isset($show_elements_graph['labels'][$value['agent_module_id']]) && is_array($show_elements_graph['labels']) && (count($show_elements_graph['labels']) > 0) ) { if ($show_elements_graph['unit']) { - $name_legend = $data_return['legend'][$key] = $value['agent_alias'].' / '.$value['module_name'].' / '.__('Unit ').' '.$show_elements_graph['unit'].': '; + $name_legend = $show_elements_graph['labels'][$value['agent_module_id']].' / '.__('Unit ').' '.$show_elements_graph['unit'].': '; + $data_return['legend'][$key] = $show_elements_graph['labels'][$value['agent_module_id']].' / '.__('Unit ').' '.$show_elements_graph['unit'].': '; } else { - $name_legend = $data_return['legend'][$key] = $value['agent_alias'].' / '.$value['module_name'].': '; + $name_legend = $show_elements_graph['labels'][$value['agent_module_id']].': '; + $data_return['legend'][$key] = $show_elements_graph['labels'][$value['agent_module_id']].': '; } } else { if (strpos($key, 'baseline') !== false) { - if ($show_elements_graph['unit']) { - $name_legend = $data_return['legend'][$key] = $value['agent_alias'].' / '.$value['module_name'].' / '.__('Unit ').' '.$show_elements_graph['unit'].'Baseline '; + if ($value['unit']) { + $name_legend = $data_return['legend'][$key] = $value['agent_alias'].' / '.$value['module_name'].' / '.__('Unit ').' '.$value['unit'].'Baseline '; } else { $name_legend = $data_return['legend'][$key] = $value['agent_alias'].' / '.$value['module_name'].'Baseline '; } } else { - if ($show_elements_graph['unit']) { - $name_legend = $data_return['legend'][$key] = $value['agent_alias'].' / '.$value['module_name'].' / '.__('Unit ').' '.$show_elements_graph['unit'].': '; + if ($value['unit']) { + $name_legend = $data_return['legend'][$key] = $value['agent_alias'].' / '.$value['module_name'].' / '.__('Unit ').' '.$value['unit'].': '; } else { $name_legend = $data_return['legend'][$key] = $value['agent_alias'].' / '.$value['module_name'].': '; } @@ -3819,9 +3863,10 @@ function pandora_xhprof_display_result($key='', $method='link') /** * From a network with a mask remove the smallest ip and the highest * - * @param string address to identify the network. - * @param string mask to identify the mask network - * @return array or false with smallest ip and highest ip + * @param string $address Identify the network. + * @param string $mask Identify the mask network. + * + * @return array or false with smallest ip and highest ip. */ function range_ips_for_network($address, $mask) { @@ -3829,15 +3874,15 @@ function range_ips_for_network($address, $mask) return false; } - // convert ip addresses to long form + // Convert ip addresses to long form. $address_long = ip2long($address); $mask_long = ip2long($mask); - // caculate first usable address + // Calculate first usable address. $ip_host_first = ((~$mask_long) & $address_long); - $ip_first = (($address_long ^ $ip_host_first) + 1); + $ip_first = (($address_long ^ $ip_host_first)); - // caculate last usable address + // Calculate last usable address. $ip_broadcast_invert = ~$mask_long; $ip_last = (($address_long | $ip_broadcast_invert) - 1); @@ -3853,9 +3898,10 @@ function range_ips_for_network($address, $mask) /** * from two ips find out if there is such an ip * - * @param string ip ip wont validate - * @param string ip_lower - * @param string ip_upper + * @param string ip ip wont validate + * @param string ip_lower + * @param string ip_upper + * * @return boolean true or false if the ip is between the two ips */ function is_in_network($ip, $ip_lower, $ip_upper) @@ -3906,3 +3952,1337 @@ function mask2cidr($mask) $base = ip2long('255.255.255.255'); return (32 - log((($long ^ $base) + 1), 2)); } + + +function get_help_info($section_name) +{ + global $config; + // hd($section_name); + $user_language = get_user_language($id_user); + + $es = false; + $result = 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:'; + if ($user_language == 'es') { + $es = true; + $result = 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:'; + } + + switch ($section_name) { + case 'tactical_view': + if ($es) { + $result .= 'Presentacion_datos/visualizacion&printable=yes#Vista_t.C3.A1ctica'; + } else { + $result .= 'Data_Presentation/Visualization&printable=yes#Tactical_view'; + } + break; + + case 'group_view': + if ($es) { + $result .= 'Presentacion_datos/visualizacion&printable=yes#Vista_de_Grupos'; + } else { + $result .= 'Data_Presentation/Visualization&printable=yes#Group_view'; + } + break; + + case 'tree_view': + if ($es) { + $result .= 'Presentacion_datos/visualizacion&printable=yes#Vista_de_.C3.A1rbol'; + } else { + $result .= 'Data_Presentation/Visualization&printable=yes#The_Tree_View'; + } + break; + + case 'monitor_detail_view': + if ($es) { + $result .= 'Presentacion_datos/visualizacion&printable=yes#Detalles_Monitores'; + } else { + $result .= 'Data_Presentation/Visualization&printable=yes#Monitor_Details'; + } + break; + + case 'tag_view': + if ($es) { + $result .= 'Presentacion_datos/visualizacion&printable=yes#Vista_de_etiquetas'; + } else { + $result .= 'Data_Presentation/Visualization&printable=yes#Tag_view'; + } + break; + + case 'alert_validation': + if ($es) { + $result .= 'Presentacion_datos/visualizacion&printable=yes#Detalles_de_Alertas'; + } else { + $result .= 'Data_Presentation/Visualization&printable=yes#Alert_Details'; + } + break; + + case 'agents_alerts_view': + if ($es) { + $result .= 'Presentacion_datos/visualizacion&printable=yes#Vista_de_agente_.2F_alerta'; + } else { + $result .= 'Data_Presentation/Visualization&printable=yes#Agent.2F_Alert_View'; + } + break; + + case 'agents_module_view': + if ($es) { + $result .= 'Presentacion_datos/visualizacion&printable=yes#Vista_de_agente_.2F_modulo'; + } else { + $result .= 'Data_Presentation/Visualization&printable=yes#Agents_.2F_Modules_View'; + } + break; + + case 'module_groups_view': + if ($es) { + $result .= 'Presentacion_datos/visualizacion&printable=yes#Vista_de_grupos_de_m.C3.B3dulos'; + } else { + $result .= 'Data_Presentation/Visualization&printable=yes#Module_Groups_View'; + } + break; + + case 'snmp_browser_view': + if ($es) { + $result .= 'Monitorizacion_remota&printable=yes#Navegador_SNMP_de_Pandora_FMS'; + } else { + $result .= 'Remote_Monitoring&printable=yes#Pandora_FMS_SNMP_MIB_Browser'; + } + break; + + case 'snmp_trap_generator_view': + if ($es) { + $result .= 'Monitorizacion_traps_SNMP&printable=yes#Generador_de_Traps'; + } else { + $result .= 'SNMP_traps_Monitoring&printable=yes#Trap_Generator'; + } + break; + + case 'real_time_view': + if ($es) { + $result .= 'Presentacion_datos/visualizacion&printable=yes#Gr.C3.A1ficas_Real-time'; + } else { + $result .= 'Data_Presentation/Visualization&printable=yes#Real-time_Graphs'; + } + break; + + case 'agent_status': + if ($es) { + $result .= 'Presentacion_datos/visualizacion&printable=yes#Detalles_del_agente'; + } else { + $result .= 'Data_Presentation/Visualization&printable=yes#Agent_Details'; + } + break; + + case 'agent_main_tab': + if ($es) { + $result .= 'Intro_Monitorizacion&printable=yes#Visualizaci.C3.B3n_del_agente'; + } else { + $result .= 'Intro_Monitoring&printable=yes#Agent_configuration_in_the_console_2'; + } + break; + + case 'alert_config': + if ($es) { + $result .= 'Alertas&printable=yes#Creaci.C3.B3n_de_una_Acci.C3.B3n'; + } else { + $result .= 'Alerts&printable=yes#Creating_an_Action'; + } + break; + + case 'alert_macros': + if ($es) { + $result .= 'Alertas&printable=yes#Macros_sustituibles_en_los_campos_Field1.2C_Field2.2C_Field3..._Field10'; + } else { + $result .= 'Alerts&printable=yes#Replaceable_Macros_within_Field_1_through_Field_10'; + } + break; + + case 'alerts_config': + if ($es) { + $result .= 'Alertas&printable=yes#Configuraci.C3.B3n_de_alertas_en_Pandora_FMS'; + } else { + $result .= 'Alerts&printable=yes#Alert_Configuration_in_Pandora_FMS'; + } + break; + + case 'alert_special_days': + if ($es) { + $result .= 'Alertas&printable=yes#Lista_de_d.C3.ADas_especiales'; + } else { + $result .= 'Alerts&printable=yes#List_of_special_days'; + } + break; + + case 'alerts': + if ($es) { + $result .= 'Politicas&printable=yes#Alertas'; + } else { + $result .= 'Policy&printable=yes#Alerts'; + } + break; + + case 'collections': + if ($es) { + $result .= 'Politicas&printable=yes#Colecciones_de_ficheros'; + } else { + $result .= 'Policy&printable=yes#File_Collections'; + } + break; + + case 'component_groups': + if ($es) { + $result .= 'Plantillas_y_Componentes&printable=yes#Grupos_de_componentes'; + } else { + $result .= 'Templates_and_components&printable=yes#Component_Groups'; + } + break; + + case 'configure_gis_map': + if ($es) { + $result .= 'Pandora_GIS&printable=yes#Introducci.C3.B3n'; + } else { + $result .= 'GIS&printable=yes#Introduction'; + } + break; + + case 'configure_gis_map_edit': + if ($es) { + $result .= 'Pandora_GIS&printable=yes#GIS_Maps'; + } else { + $result .= 'GIS&printable=yes#GIS_Maps'; + } + break; + + case 'event_alert': + if ($es) { + $result .= 'Eventos&printable=yes#Introducci.C3.B3n_2'; + } else { + $result .= 'Events&printable=yes#Introduction_2'; + } + break; + + case 'eventview': + if ($es) { + $result .= 'Eventos&printable=yes#Introducci.C3.B3n'; + } else { + $result .= 'Events&printable=yes#Introduction'; + } + break; + + case 'export_server': + if ($es) { + $result .= 'ExportServer&printable=yes#A.C3.B1adir_un_servidor_de_destino'; + } else { + $result .= 'Export_Server&printable=yes#Adding_a_Target_Server'; + } + break; + + case 'external_alert': + if ($es) { + $result .= 'Politicas&printable=yes#Alertas_Externas'; + } else { + $result .= 'Policy&printable=yes#External_Alerts'; + } + break; + + case 'gis_tab': + if ($es) { + $result .= 'Pandora_GIS&printable=yes#Configuraci.C3.B3n_del_Agent_GIS'; + } else { + $result .= 'GIS&printable=yes#The_Agent.27s_GIS_Setup'; + } + break; + + case 'graph_builder': + if ($es) { + $result .= 'Presentacion_datos/visualizacion&printable=yes#Crear_Gr.C3.A1ficas_combinadas'; + } else { + $result .= 'Data_Presentation/Visualization&printable=yes#Creating_combined_graphs'; + } + break; + + case 'graph_editor': + if ($es) { + $result .= 'Presentacion_datos/visualizacion&printable=yes#Agregar_elementos_a_gr.C3.A1ficas_combinadas'; + } else { + $result .= 'Data_Presentation/Visualization&printable=yes#Adding_elements_to_combined_graphs'; + } + break; + + case 'dashboards_tab': + if ($es) { + $result .= 'Dashboard&printable=yes#Introducci.C3.B3n'; + } else { + $result .= 'Dashboard&printable=yes#Introduction'; + } + break; + + case 'history_database': + if ($es) { + $result .= 'Configuracion_Consola&printable=yes#Base_de_datos_hist.C3.B3rica'; + } else { + $result .= 'Console_Setup&printable=yes#The_History_Database'; + } + break; + + case 'inventory_tab': + if ($es) { + $result .= 'Inventario&printable=yes#M.C3.B3dulos_de_inventario'; + } else { + $result .= 'Inventory&printable=yes#Inventory_Modules'; + } + break; + + case 'ipam_list_tab': + if ($es) { + $result .= 'IPAM&printable=yes#Introducci.C3.B3n'; + } else { + $result .= 'IPAM&printable=yes#Introduction'; + } + break; + + case 'ipam_calculator_tab': + if ($es) { + $result .= 'IPAM&printable=yes#Calculadora_de_subredes'; + } else { + $result .= 'IPAM&printable=yes#Subnetwork_calculator'; + } + break; + + case 'ipam_vlan_config_tab': + if ($es) { + $result .= 'IPAM&printable=yes#Vlan_IPAM'; + } else { + $result .= 'IPAM&printable=yes#VLAN_IPAM'; + } + break; + + case 'ipam_vlan_statistics_tab': + if ($es) { + $result .= 'IPAM&printable=yes#Estad.C3.ADsticas_IPAM_Vlan'; + } else { + $result .= 'IPAM&printable=yes#IPAM_VLAN_Stats'; + } + break; + + case 'ipam_vlan_wizard_tab': + if ($es) { + $result .= 'IPAM&printable=yes#Wizard_IPAM_Vlan'; + } else { + $result .= 'IPAM&printable=yes#IPAM_VLAN_Wizard:'; + } + break; + + case 'ipam_supernet_config_tab': + if ($es) { + $result .= 'IPAM&printable=yes#IPAM_Supernet'; + } else { + $result .= 'IPAM&printable=yes#IPAM_Supernet'; + } + break; + + case 'ipam_supernet_map_tab': + if ($es) { + $result .= 'IPAM&printable=yes#Mapa_Superred_IPAM'; + } else { + $result .= 'IPAM&printable=yes#IPAM_Supernet_Map'; + } + break; + + case 'ipam_supernet_statistics_tab': + if ($es) { + $result .= 'IPAM&printable=yes#Estad.C3.ADsticas_IPAM_Superred'; + } else { + $result .= 'IPAM&printable=yes#IPAM_Supernet_Stats'; + } + break; + + case 'ipam_new_tab': + case 'ipam_edit_tab': + if ($es) { + $result .= 'IPAM&printable=yes#Vista_de_edici.C3.B3n'; + } else { + $result .= 'IPAM&printable=yes#Edit_view'; + } + break; + + case 'ipam_massive_tab': + if ($es) { + $result .= 'IPAM&printable=yes#Vista_Operaciones_masivas'; + } else { + $result .= 'IPAM&printable=yes#Massive_operations_view'; + } + break; + + case 'ipam_network_tab': + case 'ipam_force_tab': + if ($es) { + $result .= 'IPAM&printable=yes#Vista_de_iconos'; + } else { + $result .= 'IPAM&printable=yes#Icon_view'; + } + break; + + case 'macros_visual_maps': + if ($es) { + $result .= 'Presentacion_datos/Mapas_visuales&printable=yes#Macros_en_las_consolas_visuales'; + } else { + $result .= 'Data_Presentation/Visual_Maps&printable=yes#Macros_in_Visual_Consoles'; + } + break; + + case 'linked_map_status_calc': + if ($es) { + $result .= 'Presentacion_datos/Mapas_visuales&printable=yes#Mapa_asociado'; + } else { + $result .= 'Data_Presentation/Visual_Maps&printable=yes#Associated_Map'; + } + break; + + case 'main_tab': + if ($es) { + $result .= 'Intro_Monitorizacion&printable=yes#Configuraci.C3.B3n_del_agente_en_consola'; + } else { + $result .= 'Intro_Monitoring&printable=yes#Agent_configuration_in_the_console'; + } + break; + + case 'manage_alert_list': + if ($es) { + $result .= 'Alertas&printable=yes#Gestionar_alertas_desde_el_agente'; + } else { + $result .= 'Alerts&printable=yes#Managing_Alerts_from_within_the_Agent'; + } + break; + + case 'alert_scalate': + if ($es) { + $result .= 'Alertas&printable=yes#Escalado_de_alertas'; + } else { + $result .= 'Alerts&printable=yes#Scaling_Alerts'; + } + break; + + case 'map_builder_intro': + if ($es) { + $result .= 'Presentacion_datos/Mapas_visuales&printable=yes#Introducci.C3.B3n'; + } else { + $result .= 'Data_Presentation/Visual_Maps&printable=yes#Introduction'; + } + break; + + case 'map_builder_favorite': + if ($es) { + $result .= 'Presentacion_datos/Mapas_visuales&printable=yes#Consolas_visuales_favoritas'; + } else { + $result .= 'Data_Presentation/Visual_Maps&printable=yes#Favorite_visual_consoles'; + } + break; + + case 'map_builder_template': + if ($es) { + $result .= 'Presentacion_datos/Mapas_visuales&printable=yes#Plantillas_de_consolas_visuales'; + } else { + $result .= 'Data_Presentation/Visual_Maps&printable=yes#Visual_Console_Templates'; + } + break; + + case 'map_builder_wizard': + if ($es) { + $result .= 'Presentacion_datos/Mapas_visuales&printable=yes#Asistente_de_consola_visuales'; + } else { + $result .= 'Data_Presentation/Visual_Maps&printable=yes#Wizard_Visual_Console'; + } + break; + + case 'module_linking': + if ($es) { + $result .= 'Politicas&printable=yes#Tipos_de_m.C3.B3dulos'; + } else { + $result .= 'Policy&printable=yes#Types_of_Modules'; + } + break; + + case 'network_map_enterprise_edit': + if ($es) { + $result .= 'Presentacion_datos/Mapas_de_red&printable=yes#Mapa_de_red_no_vac.C3.ADo'; + } else { + $result .= 'Data_Presentation/Network_Maps&printable=yes#Non_empty_network_map'; + } + break; + + case 'network_map_enterprise_list': + if ($es) { + $result .= 'Presentacion_datos/Mapas_de_red&printable=yes#Introducci.C3.B3n'; + } else { + $result .= 'Data_Presentation/Network_Maps&printable=yes#Introduction'; + } + break; + + case 'network_map_enterprise_empty': + if ($es) { + $result .= 'Presentacion_datos/Mapas_de_red&printable=yes#Mapa_de_red_vac.C3.ADo'; + } else { + $result .= 'Data_Presentation/Network_Maps&printable=yes#Empty_network_map'; + } + break; + + case 'network_map_enterprise_view': + if ($es) { + $result .= 'Presentacion_datos/Mapas_de_red&printable=yes#Vista_de_un_mapa_de_red'; + } else { + $result .= 'Data_Presentation/Network_Maps&printable=yes#Network_map_view'; + } + break; + + case 'transactional_view': + if ($es) { + $result .= 'Monitorizacion_transaccional&printable=yes#Introducci.C3.B3n'; + } else { + $result .= 'Transactional_Monitoring&printable=yes#Introduction'; + } + break; + + case 'pcap_filter': + if ($es) { + $result .= 'Netflow&printable=yes#Creaci.C3.B3n_del_filtro'; + } else { + $result .= 'Netflow&printable=yes#Filter_creation'; + } + break; + + case 'planned_downtime': + if ($es) { + $result .= 'Gestion_y_Administracion&printable=yes#Introducci.C3.B3n_4'; + } else { + $result .= 'Managing_and_Administration&printable=yes#Introduction_4'; + } + break; + + case 'planned_downtime_editor': + if ($es) { + $result .= 'Gestion_y_Administracion&printable=yes#Creaci.C3.B3n_parada_planificada'; + } else { + $result .= 'Managing_and_Administration&printable=yes#Create_a_scheduled_downtime'; + } + break; + + case 'plugin_definition': + if ($es) { + $result .= 'Anexo_Server_Plugins&printable=yes#Registro_manual_de_un_plugin_en_la_consola'; + } else { + $result .= 'Anexo_Server_plugins_developement&printable=yes#Plugin_manual_registration'; + } + break; + + case 'plugin_macros': + if ($es) { + $result .= 'Monitorizacion_remota&printable=yes#Macros_internas'; + } else { + $result .= 'Remote_Monitoring&printable=yes#Internal_Macros'; + } + break; + + case 'plugin_policy': + if ($es) { + $result .= 'Politicas&printable=yes#Plugins_de_agente'; + } else { + $result .= 'Policy&printable=yes#Agent_Plug_Ins'; + } + break; + + case 'policy_queue': + if ($es) { + $result .= 'Politicas&printable=yes#Gesti.C3.B3n_de_la_cola_de_pol.C3.ADticas'; + } else { + $result .= 'Policy&printable=yes#Policy_Queues_Management'; + } + break; + + case 'prediction_source_module': + if ($es) { + $result .= 'Monitorizacion_otra&printable=yes#Tipos_de_monitorizaci.C3.B3n_predictiva'; + } else { + $result .= 'Other_Monitoring&printable=yes#Types_of_predictive_monitoring'; + } + break; + + case 'wmi_module_tab': + if ($es) { + $result .= 'Monitorizacion_remota&printable=yes#Monitorizaci.C3.B3n_de_Windows_remotos_con_WMI'; + } else { + $result .= 'Remote_Monitoring&printable=yes#Windows_Remote_Monitoring_with_WMI'; + } + break; + + case 'template_reporting_tab': + if ($es) { + $result .= 'Presentacion_datos/Informes&printable=yes#Introducci.C3.B3n'; + } else { + $result .= 'Data_Presentation/Reports&printable=yes#Introduction'; + } + break; + + case 'reporting_template_list_item_tab': + if ($es) { + $result .= 'Presentacion_datos/Informes&printable=yes#Pesta.C3.B1a_List_Items'; + } else { + $result .= 'Data_Presentation/Reports&printable=yes#The_.27List_Items.27_Tab'; + } + break; + + case 'reporting_template_item_editor_tab': + if ($es) { + $result .= 'Presentacion_datos/Informes&printable=yes#Pesta.C3.B1a_Item_editor'; + } else { + $result .= 'Data_Presentation/Reports&printable=yes#The_.27Item_Editor.27_Tab'; + } + break; + + case 'reporting_template_advanced_tab': + if ($es) { + $result .= 'Presentacion_datos/Informes&printable=yes#Opciones_avanzadas_de_informe'; + } else { + $result .= 'Data_Presentation/Reports&printable=yes#The_Advanced_Options_Tab'; + } + break; + + case 'reporting_advanced_tab': + if ($es) { + $result .= 'Presentacion_datos/Informes&printable=yes#Opciones_avanzadas_de_informe'; + } else { + $result .= 'Data_Presentation/Reports&printable=yes#The_Advanced_Options_Tab'; + } + break; + + case 'reporting_global_tab': + if ($es) { + $result .= 'Presentacion_datos/Informes&printable=yes#Global'; + } else { + $result .= 'Data_Presentation/Reports&printable=yes#The_Global_Tab'; + } + break; + + case 'reporting_item_editor_tab': + if ($es) { + $result .= 'Presentacion_datos/Informes&printable=yes#Pesta.C3.B1a_Item_editor'; + } else { + $result .= 'Data_Presentation/Reports&printable=yes#The_.27Item_Editor.27_Tab'; + } + break; + + case 'reporting_list_items_tab': + if ($es) { + $result .= 'Presentacion_datos/Informes&printable=yes#Pesta.C3.B1a_List_Items'; + } else { + $result .= 'Data_Presentation/Reports&printable=yes#The_.27List_Items.27_Tab'; + } + break; + + case 'reporting_wizard_sla_tab': + if ($es) { + $result .= 'Presentacion_datos/Informes&printable=yes#Wizard_SLA'; + } else { + $result .= 'Data_Presentation/Reports&printable=yes#The_SLA_Wizard_Tab'; + } + break; + + case 'reporting_wizard_tab': + if ($es) { + $result .= 'Presentacion_datos/Informes&printable=yes#Wizard_general'; + } else { + $result .= 'Data_Presentation/Reports&printable=yes#The_Wizard_Tab'; + } + break; + + case 'response_macros': + if ($es) { + $result .= 'Eventos&printable=yes#Event_Responses_macros'; + } else { + $result .= 'Events&printable=yes#Event_Responses_macros'; + } + break; + + case 'events_responses_tab': + if ($es) { + $result .= 'Eventos&printable=yes#Introducci.C3.B3n_3'; + } else { + $result .= 'Events&printable=yes#Introduction_3'; + } + break; + + case 'servers': + if ($es) { + $result .= 'Interfaz&printable=yes#Gesti.C3.B3n_de_servidores'; + } else { + $result .= 'Interface&printable=yes#Server_management'; + } + break; + + case 'snmpwalk': + if ($es) { + $result .= 'Monitorizacion_remota&printable=yes#Navegador_SNMP_de_Pandora_FMS'; + } else { + $result .= 'Remote_Monitoring&printable=yes#Pandora_FMS_SNMP_MIB_Browser'; + } + break; + + case 'tags_config': + if ($es) { + $result .= 'Gestion_y_Administracion&printable=yes#Sistemas_de_permisos_ampliados_mediante_etiquetas_.28tags.29'; + } else { + $result .= 'Managing_and_Administration&printable=yes#Permission_system_extended_by_tags'; + } + break; + + case 'transactional_map_phases': + if ($es) { + $result .= 'Monitorizacion_transaccional&printable=yes#Creaci.C3.B3n_del_.C3.A1rbol_de_fases'; + } else { + $result .= 'Transactional_Monitoring&printable=yes#Creating_the_phase_tree'; + } + break; + + case 'transactional_map_phases_data': + if ($es) { + $result .= 'Monitorizacion_transaccional&printable=yes#Configuraci.C3.B3n_de_los_scripts_de_control'; + } else { + $result .= 'Transactional_Monitoring&printable=yes#Control_scripts_configuration'; + } + break; + + case 'wizard_reporting_tab': + if ($es) { + $result .= 'Presentacion_datos/Informes&printable=yes#Asistente_de_plantillas'; + } else { + $result .= 'Data_Presentation/Reports&printable=yes#Template_Wizard'; + } + break; + + case 'user_edit_notifications': + if ($es) { + $result .= 'Gestion_y_Administracion&printable=yes#Configuraci.C3.B3n_de_notificaciones'; + } else { + $result .= 'Managing_and_Administration&printable=yes#Notification_configuration'; + } + break; + + case 'view_services': + if ($es) { + $result .= 'Servicios&printable=yes#Introducci.C3.B3n'; + } else { + $result .= 'Services&printable=yes#Introduction'; + } + break; + + case 'visual_console_editor_data_tab': + if ($es) { + $result .= 'Presentacion_datos/Mapas_visuales&printable=yes#Creaci.C3.B3n_-_Datos_generales'; + } else { + $result .= 'Data_Presentation/Visual_Maps&printable=yes#Creation_-_General_data'; + } + break; + + case 'visual_console_editor_editor_tab': + if ($es) { + $result .= 'Presentacion_datos/Mapas_visuales&printable=yes#Creaci.C3.B3n_y_edici.C3.B3n_de_consolas_visuales'; + } else { + $result .= 'Data_Presentation/Visual_Maps&printable=yes#Creation_and_edition_of_Visual_Consoles'; + } + break; + + case 'visual_console_editor_list_elements_tab': + if ($es) { + $result .= 'Presentacion_datos/Mapas_visuales&printable=yes#Creaci.C3.B3n_-_lista_de_elementos'; + } else { + $result .= 'Data_Presentation/Visual_Maps&printable=yes#Creation_-_List_of_Elements'; + } + break; + + case 'visual_console_editor_wizard_tab': + if ($es) { + $result .= 'Presentacion_datos/Mapas_visuales&printable=yes#Creaci.C3.B3n_-_Wizard'; + } else { + $result .= 'Data_Presentation/Visual_Maps&printable=yes#Creation_-_Wizard'; + } + break; + + case 'visual_console_editor_wizard_services_tab': + if ($es) { + $result .= 'Presentacion_datos/Mapas_visuales&printable=yes#Creaci.C3.B3n_-_Wizard_de_Servicios'; + } else { + $result .= 'Data_Presentation/Visual_Maps&printable=yes#Creation_-_Service_Wizard'; + } + break; + + case 'visual_console_tab': + if ($es) { + $result .= 'Presentacion_datos/Mapas_visuales&printable=yes#Mapa_asociado'; + } else { + $result .= 'Data_Presentation/Visual_Maps&printable=yes#Associated_Map'; + } + break; + + case 'view_created_map_services_tab': + if ($es) { + $result .= 'Servicios&printable=yes#Vista_de_mapa_de_servicio'; + } else { + $result .= 'Services&printable=yes#Service_Map_View'; + } + break; + + case 'view_created_services_tab': + if ($es) { + $result .= 'Servicios&printable=yes#Lista_simple_de_un_servicio_y_todos_los_elementos_que_contiene'; + } else { + $result .= 'Services&printable=yes#List-based_view_of_a_Service_and_its_Elements'; + } + break; + + case 'config_service_element_tab': + if ($es) { + $result .= 'Servicios&printable=yes#Configuraci.C3.B3n_de_elementos'; + } else { + $result .= 'Services&printable=yes#Element_Configuration'; + } + break; + + case 'config_service_tab': + if ($es) { + $result .= 'Servicios&printable=yes#Configuraci.C3.B3n_inicial'; + } else { + $result .= 'Services&printable=yes#Initial_Configuration'; + } + break; + + case 'other_conf_tab': + if ($es) { + $result .= 'Configuracion_Consola&printable=yes#Otra_configuraci.C3.B3n'; + } else { + $result .= 'Console_Setup&printable=yes#Other_configuration'; + } + break; + + case 'services_conf_tab': + if ($es) { + $result .= 'Configuracion_Consola&printable=yes#Configuraci.C3.B3n_servicios'; + } else { + $result .= 'Console_Setup&printable=yes#Services_configuration'; + } + break; + + case 'visual_consoles_conf_tab': + if ($es) { + $result .= 'Configuracion_Consola&printable=yes#Configuraci.C3.B3n_de_las_consolas_visuales'; + } else { + $result .= 'Console_Setup&printable=yes#Visual_console_configuration'; + } + break; + + case 'charts_conf_tab': + if ($es) { + $result .= 'Configuracion_Consola&printable=yes#Configuraci.C3.B3n_de_gr.C3.A1ficas'; + } else { + $result .= 'Console_Setup&printable=yes#Chart_settings'; + } + break; + + case 'front_and_text_conf_tab': + if ($es) { + $result .= 'Configuracion_Consola&printable=yes#Configuraci.C3.B3n_de_Fuente_y_texto'; + } else { + $result .= 'Console_Setup&printable=yes#Font_and_text_settings'; + } + break; + + case 'gis_conf_tab': + if ($es) { + $result .= 'Configuracion_Consola&printable=yes#Configuraci.C3.B3n_GIS'; + } else { + $result .= 'Console_Setup&printable=yes#GIS_configuration'; + } + break; + + case 'style_conf_tab': + if ($es) { + $result .= 'Configuracion_Consola&printable=yes#Configuraci.C3.B3n_de_estilo'; + } else { + $result .= 'Console_Setup&printable=yes#Style_configuration'; + } + break; + + case 'behavoir_conf_tab': + if ($es) { + $result .= 'Configuracion_Consola&printable=yes#Configuraci.C3.B3n_del_comportamiento'; + } else { + $result .= 'Console_Setup&printable=yes#Behaviour_configuration'; + } + break; + + case 'setup_ehorus_tab': + if ($es) { + $result .= 'Configuracion_Consola&printable=yes#eHorus'; + } else { + $result .= 'Console_Setup&printable=yes#EHorus'; + } + break; + + case 'diagnostic_tool_tab': + if ($es) { + $result .= 'Gestion_y_Administracion&printable=yes#Diagnostic_tool'; + } else { + $result .= 'Managing_and_Administration&printable=yes#Diagnostic_tool'; + } + break; + + case 'performance_metrics_tab': + if ($es) { + $result .= 'Optimizacion&printable=yes#Comprobaci.C3.B3n_del_fichero_my.ini.2Fcnf'; + } else { + $result .= 'Optimization&printable=yes#Check_my.ini.2Fcnf_settings'; + } + break; + + case 'db_status_tab': + if ($es) { + $result .= 'Gestion_y_Administracion&printable=yes#DB_Schema_Check'; + } else { + $result .= 'Managing_and_Administration&printable=yes#DB_Schema_Check'; + } + break; + + case 'database_backup_utility_tab': + if ($es) { + $result .= 'Gestion_y_Administracion&printable=yes#Backup'; + } else { + $result .= 'Managing_and_Administration&printable=yes#Backup'; + } + break; + + case 'update_manager_offline_tab': + if ($es) { + $result .= 'Actualizacion&printable=yes#Actualizaciones_.22offline.22'; + } else { + $result .= 'Anexo_Upgrade&printable=yes#.22Offline.22_updates'; + } + break; + + case 'update_manager_online_tab': + if ($es) { + $result .= 'Actualizacion&printable=yes#Actualizaciones_.22online.22'; + } else { + $result .= 'Anexo_Upgrade&printable=yes#.22Online.22_updates'; + } + break; + + case 'others_database_maintenance_options_tab': + if ($es) { + $result .= 'Configuracion_Consola&printable=yes#Otros'; + } else { + $result .= 'Console_Setup&printable=yes#Others'; + } + break; + + case 'database_maintenance_options_tab': + if ($es) { + $result .= 'Configuracion_Consola&printable=yes#Opciones_de_mantenimiento_de_la_base_de_datos'; + } else { + $result .= 'Console_Setup&printable=yes#Database_maintenance_options'; + } + break; + + case 'database_maintenance_status_tab': + if ($es) { + $result .= 'Configuracion_Consola&printable=yes#Estado_del_mantenimiento_de_las_bases_de_datos'; + } else { + $result .= 'Console_Setup&printable=yes#Database_maintenance_status'; + } + break; + + case 'historical_database_maintenance_options_tab': + if ($es) { + $result .= 'Configuracion_Consola&printable=yes#Opciones_de_mantenimiento_de_la_base_de_datos_hist.C3.B3rica'; + } else { + $result .= 'Console_Setup&printable=yes#Historical_database_maintenance_options'; + } + break; + + case 'setup_enterprise_tab': + if ($es) { + $result .= 'Configuracion_Consola&printable=yes#Enterprise'; + } else { + $result .= 'Console_Setup&printable=yes#Features_of_the_Enterprise_Version'; + } + break; + + case 'setup_general_tab': + if ($es) { + $result .= 'Configuracion_Consola&printable=yes#General_Setup'; + } else { + $result .= 'Console_Setup&printable=yes#General_Setup'; + } + break; + + case 'export_target_tab': + if ($es) { + $result .= 'ExportServer&printable=yes#A.C3.B1adir_un_servidor_de_destino'; + } else { + $result .= 'Export_Server&printable=yes#Adding_a_Target_Server'; + } + break; + + case 'servers_ha_clusters_tab': + if ($es) { + $result .= 'HA&printable=yes#Alta_disponibilidad_del_Servidor_de_Datos'; + } else { + $result .= 'HA&printable=yes#HA_of_Data_Server'; + } + break; + + case 'plugins_tab': + if ($es) { + $result .= 'Anexo_Agent_Plugins&printable=yes#Caracter.C3.ADsticas_b.C3.A1sicas_de_plugin_de_agente'; + } else { + $result .= 'Anexo_Agent_Plugins&printable=yes#Basic_Features_of_the_Agent_Plugin'; + } + break; + + case 'create_agent': + if ($es) { + $result .= 'Intro_Monitorizacion&printable=yes#Configuraci.C3.B3n_del_agente_en_consola'; + } else { + $result .= 'Intro_Monitoring&printable=yes#Agent_configuration_in_the_console'; + } + break; + + case 'agent_snmp_explorer_tab': + if ($es) { + $result .= 'Monitorizacion_remota&printable=yes#Wizard_SNMP'; + } else { + $result .= 'Remote_Monitoring&printable=yes#SNMP_Wizard'; + } + break; + + case 'agent_snmp_interfaces_explorer_tab': + if ($es) { + $result .= 'Monitorizacion_remota&printable=yes#SNMP_Interfaces_wizard'; + } else { + $result .= 'Remote_Monitoring&printable=yes#SNMP_Interface_Wizard'; + } + break; + + case 'agent_snmp_wmi_explorer_tab': + if ($es) { + $result .= 'Monitorizacion_remota&printable=yes#Wizard_WMI'; + } else { + $result .= 'Remote_Monitoring&printable=yes#WMI_Wizard'; + } + break; + + case 'group_list_tab': + if ($es) { + $result .= 'Gestion_y_Administracion&printable=yes#Introducci.C3.B3n_2'; + } else { + $result .= 'Managing_and_Administration&printable=yes#Introduction_2'; + } + break; + + case 'acl_setup_tab': + if ($es) { + $result .= 'Gestion_y_Administracion&printable=yes#Introducci.C3.B3n_3'; + } else { + $result .= 'Managing_and_Administration&printable=yes#Introduction_3'; + } + break; + + case 'profile_tab': + if ($es) { + $result .= 'Gestion_y_Administracion&printable=yes#Perfiles_en_Pandora_FMS'; + } else { + $result .= 'Managing_and_Administration&printable=yes#Profiles_in_Pandora_FMS'; + } + break; + + case 'configure_profiles_tab': + if ($es) { + $result .= 'Gestion_y_Administracion&printable=yes#Perfiles_en_Pandora_FMS'; + } else { + $result .= 'Managing_and_Administration&printable=yes#Profiles_in_Pandora_FMS'; + } + break; + + case 'network_component_tab': + if ($es) { + $result .= 'Plantillas_y_Componentes&printable=yes#Componentes_de_red'; + } else { + $result .= 'Templates_and_components&printable=yes#Network_Components'; + } + break; + + case 'local_component_tab': + if ($es) { + $result .= 'Plantillas_y_Componentes&printable=yes#Componentes_locales'; + } else { + $result .= 'Templates_and_components&printable=yes#Local_Components'; + } + break; + + case 'module_template_tab': + if ($es) { + $result .= 'Plantillas_y_Componentes&printable=yes#Plantillas_de_m.C3.B3dulos'; + } else { + $result .= 'Templates_and_components&printable=yes#Module_Templates'; + } + break; + + case 'agent_autoconf_tab': + if ($es) { + $result .= 'Configuracion_Agentes&printable=yes#Introducci.C3.B3n'; + } else { + $result .= 'Configuration_Agents&printable=yes#Introduction'; + } + break; + + case 'policies_management_tab': + if ($es) { + $result .= 'Politicas&printable=yes#Introducci.C3.B3n'; + } else { + $result .= 'Policy&printable=yes#Introduction'; + } + break; + + case 'massive_agents_tab': + if ($es) { + $result .= 'Operaciones_Masivas&printable=yes#Edici.C3.B3n_masiva_de_agentes'; + } else { + $result .= 'Massive_Operations&printable=yes#Agent_massive_edition'; + } + break; + + case 'massive_modules_tab': + if ($es) { + $result .= 'Operaciones_Masivas&printable=yes#Edici.C3.B3n_masiva_de_m.C3.B3dulos'; + } else { + $result .= 'Massive_Operations&printable=yes#Modules_massive_edition'; + } + break; + + case 'massive_policies_tab': + if ($es) { + $result .= 'Operaciones_Masivas&printable=yes#Editar_m.C3.B3dulos_de_pol.C3.ADticas_masivamente'; + } else { + $result .= 'Massive_Operations&printable=yes#Edit_policy_modules_massively'; + } + break; + + case 'alert_templates_tab': + if ($es) { + $result .= 'Alertas&printable=yes#Introducci.C3.B3n_4'; + } else { + $result .= 'Alerts&printable=yes#Introduction_4'; + } + break; + + case 'configure_alert_template_step_1': + if ($es) { + $result .= 'Alertas&printable=yes#Paso_1:_General'; + } else { + $result .= 'Alerts&printable=yes#Step_1:_General'; + } + break; + + case 'configure_alert_template_step_2': + if ($es) { + $result .= 'Alertas&printable=yes#Paso_2:_Condiciones'; + } else { + $result .= 'Alerts&printable=yes#Step_2:_Conditions'; + } + break; + + case 'configure_alert_template_step_3': + if ($es) { + $result .= 'Alertas&printable=yes#Paso_3:_Campos_avanzados'; + } else { + $result .= 'Alerts&printable=yes#Step_3:_Advanced_fields'; + } + break; + + case 'alerts_action': + if ($es) { + $result .= 'Alertas&printable=yes#Introducci.C3.B3n_3'; + } else { + $result .= 'Alerts&printable=yes#Introduction_3'; + } + break; + + case 'alerts_command_tab': + if ($es) { + $result .= 'Alertas&printable=yes#Introducci.C3.B3n_2'; + } else { + $result .= 'Alerts&printable=yes#Introduction_2'; + } + break; + + case 'alerts_config_command_tab': + if ($es) { + $result .= 'Alertas&printable=yes#Creaci.C3.B3n_de_un_comando_para_una_alerta'; + } else { + $result .= 'Alerts&printable=yes#Command_Creation_for_an_Alert'; + } + break; + + case 'configure_alert_event_step_1': + if ($es) { + $result .= 'Eventos&printable=yes#Creaci.C3.B3n_alerta_de_evento'; + } else { + $result .= 'Events&printable=yes#Event_Alert_creation'; + } + break; + + case 'configure_event_rule_tab': + if ($es) { + $result .= 'Eventos&printable=yes#Creaci.C3.B3n_alerta_de_evento'; + } else { + $result .= 'Events&printable=yes#Event_Alert_creation'; + } + break; + + case 'snmp_alert_overview_tab': + if ($es) { + $result .= 'Monitorizacion_traps_SNMP&printable=yes#Introducci.C3.B3n_2'; + } else { + $result .= 'SNMP_traps_Monitoring&printable=yes#Introduction_2'; + } + break; + + case 'snmp_alert_update_tab': + if ($es) { + $result .= 'Monitorizacion_traps_SNMP&printable=yes#A.C3.B1adir_una_alerta'; + } else { + $result .= 'SNMP_traps_Monitoring&printable=yes#Alert_Creation'; + } + break; + + case 'sound_console_tab': + if ($es) { + $result .= 'Eventos&printable=yes#Uso'; + } else { + $result .= 'Events&printable=yes#Use'; + } + break; + + case 'local_module_tab': + if ($es) { + $result .= 'Intro_Monitorizacion&printable=yes#Par.C3.A1metros_comunes'; + } else { + $result .= 'Intro_Monitoring&printable=yes#Common_Parameters'; + } + break; + + case 'local_module': + if ($es) { + $result .= 'Operacion&printable=yes#Tipos_de_m.C3.B3dulos'; + } else { + $result .= 'Operations&printable=yes#Types_of_Modules'; + } + break; + + case 'data_server_module_tab': + if ($es) { + $result .= 'Operacion&printable=yes#Tipos_de_m.C3.B3dulos'; + } else { + $result .= 'Operations&printable=yes#Types_of_Modules'; + } + break; + + case 'network_module_tab': + if ($es) { + $result .= 'Monitorizacion_remota&printable=yes#Monitorizaci.C3.B3n_ICMP'; + } else { + $result .= 'Remote_Monitoring&printable=yes#ICMP_Monitoring'; + } + break; + + case 'wux_console': + if ($es) { + $result .= 'Monitorizacion_Usuario&printable=yes#Crear_un_m.C3.B3dulo_de_an.C3.A1lisis_web_en_Pandora_FMS_Console'; + } else { + $result .= 'User_Monitorization&printable=yes#Creating_a_Web_Analytics_module_in_Pandora_FMS_Console'; + } + break; + + case 'gis_basic_configurations_tab': + if ($es) { + $result .= 'Pandora_GIS&printable=yes#Configuraci.C3.B3n_B.C3.A1sica'; + } else { + $result .= 'GIS&printable=yes#Basic_Configuration'; + } + break; + + case 'gis_map_connection_tab': + if ($es) { + $result .= 'Pandora_GIS&printable=yes#Mapas_Open_Street'; + } else { + $result .= 'GIS&printable=yes#Open_Street_Maps'; + } + break; + + case 'icmp_module_tab': + if ($es) { + $result .= 'Monitorizacion_remota&printable=yes#Monitorizaci.C3.B3n_ICMP'; + } else { + $result .= 'Remote_Monitoring&printable=yes#ICMP_Monitoring'; + } + break; + + case 'snmp_module_tab': + if ($es) { + $result .= 'Monitorizacion_remota&printable=yes#Monitorizando_con_m.C3.B3dulos_de_red_tipo_SNMP'; + } else { + $result .= 'Remote_Monitoring&printable=yes#Monitoring_by_Network_Modules_with_SNMP'; + } + break; + + case 'tcp_module_tab': + if ($es) { + $result .= 'Monitorizacion_remota&printable=yes#Monitorizaci.C3.B3n_TCP'; + } else { + $result .= 'Remote_Monitoring&printable=yes#TCP_Monitoring'; + } + break; + + case 'webserver_module_tab': + if ($es) { + $result .= 'Monitorizacion_web&printable=yes#Creaci.C3.B3n_de_m.C3.B3dulos_web'; + } else { + $result .= 'Web_Monitoring&printable=yes#Creating_Web_Modules'; + } + break; + + case 'wmi_query_tab': + if ($es) { + $result .= 'Monitorizacion_remota&printable=yes#Monitorizaci.C3.B3n_de_Windows_remotos_con_WMI'; + } else { + $result .= 'Remote_Monitoring&printable=yes#Windows_Remote_Monitoring_with_WMI'; + } + break; + + case 'module_type_tab': + if ($es) { + $result .= 'Operacion&printable=yes#Tipos_de_m.C3.B3dulos'; + } else { + $result .= ''; + } + break; + + case 'render_view_tab': + if ($es) { + $result .= 'Pandora_GIS&printable=yes#Operaci.C3.B3n'; + } else { + $result .= 'GIS&printable=yes#Operation'; + } + break; + } + + // hd($result); + return $result; +} diff --git a/pandora_console/include/functions_agents.php b/pandora_console/include/functions_agents.php index 9aa9cf7dfd..fd5e922e32 100644 --- a/pandora_console/include/functions_agents.php +++ b/pandora_console/include/functions_agents.php @@ -82,17 +82,25 @@ function agents_get_agent_id_by_alias($alias) /** - * Creates an agent + * Creates an agent. * - * @param string Agent name. - * @param string Group to be included. - * @param int Agent interval - * @param string Agent IP + * @param string $name Agent name. + * @param string $id_group Group to be included. + * @param integer $interval Agent interval. + * @param string $ip_address Agent IP. + * @param mixed $values Other tagente fields. + * @param boolean $alias_as_name True to not assign an alias as name. * * @return integer New agent id if created. False if it could not be created. */ -function agents_create_agent($name, $id_group, $interval, $ip_address, $values=false) -{ +function agents_create_agent( + $name, + $id_group, + $interval, + $ip_address, + $values=false, + $alias_as_name=false +) { if (empty($name)) { return false; } @@ -101,7 +109,7 @@ function agents_create_agent($name, $id_group, $interval, $ip_address, $values=f return false; } - // Check interval greater than zero + // Check interval greater than zero. if ($interval < 0) { $interval = false; } @@ -115,7 +123,7 @@ function agents_create_agent($name, $id_group, $interval, $ip_address, $values=f } $values['alias'] = $name; - $values['nombre'] = hash('sha256', $name.'|'.$ip_address.'|'.time().'|'.sprintf('%04d', rand(0, 10000))); + $values['nombre'] = ($alias_as_name === false) ? hash('sha256', $name.'|'.$ip_address.'|'.time().'|'.sprintf('%04d', rand(0, 10000))) : $name; $values['id_grupo'] = $id_group; $values['intervalo'] = $interval; @@ -128,12 +136,12 @@ function agents_create_agent($name, $id_group, $interval, $ip_address, $values=f return false; } - // Create address for this agent in taddress + // Create address for this agent in taddress. if (!empty($ip_address)) { agents_add_address($id_agent, $ip_address); } - db_pandora_audit('Agent management', "New agent '$name' created"); + db_pandora_audit('Agent management', 'New agent '.$name.' created'); return $id_agent; } @@ -320,14 +328,21 @@ function agents_get_alerts_simple($id_agent=false, $filter='', $options=false, $ * * By default, it will return all the agents where the user has reading access. * - * @param array filter options in an indexed array. See - * db_format_array_where_clause_sql() - * @param array Fields to get. - * @param string Access needed in the agents groups. - * @param array $order The order of agents, by default is upward for field nombre. - * @param boolean $return Whether to return array with agents or false, or sql string statement + * @param array $filter Filter options in an indexed array. + * See db_format_array_where_clause_sql(). + * @param array $fields DB fields to get. + * @param string $access ACL level needed in the agents groups. + * @param array $order The order of agents, by default is upward + * for field nombre. + * @param boolean $return Whether to return array with agents or + * the sql string statement. + * @param boolean $disabled_agent Whether to return only the enabled agents + * or not. + * @param boolean $use_meta_table Whether to use the regular or the meta table + * to retrieve the agents. * - * @return mixed An array with all alerts defined for an agent or false in case no allowed groups are specified. + * @return mixed An array with all alerts defined for an agent + * or false in case no allowed groups are specified. */ function agents_get_agents( $filter=false, @@ -338,7 +353,8 @@ function agents_get_agents( 'order' => 'ASC', ], $return=false, - $disabled_agent=0 + $disabled_agent=0, + $use_meta_table=false ) { global $config; @@ -555,11 +571,15 @@ function agents_get_agents( ); } + $table_name = ($use_meta_table === true) ? 'tmetaconsole_agent' : 'tagente'; $sql = sprintf( 'SELECT DISTINCT %s - FROM tagente LEFT JOIN tagent_secondary_group ON tagent_secondary_group.id_agent=tagente.id_agente + FROM `%s` tagente + LEFT JOIN tagent_secondary_group + ON tagent_secondary_group.id_agent=tagente.id_agente WHERE %s %s', implode(',', $fields), + $table_name, $where, $order ); @@ -570,6 +590,7 @@ function agents_get_agents( } $sql = sprintf('%s %s', $sql, $limit_sql); + if ($return) { return $sql; } else { @@ -949,11 +970,11 @@ function agents_get_group_agents( $filter = []; - // check available groups for target user only if asking for 'All' group + // Check available groups for target user only if asking for 'All' group. if (!$noACL && $id_group == 0) { - $id_group = $id_group == 0 ? array_keys(users_get_groups(false, 'AR', false)) : groups_safe_acl($config['id_user'], $id_group, 'AR'); + $id_group = ($id_group == 0) ? array_keys(users_get_groups(false, 'AR', false)) : groups_safe_acl($config['id_user'], $id_group, 'AR'); if (empty($id_group)) { - // An empty array means the user doesn't have access + // An empty array means the user doesn't have access. return []; } } @@ -970,7 +991,7 @@ function agents_get_group_agents( $id_group = groups_get_id_recursive($id_group, true); } - // check available groups for target user only if asking for 'All' group + // Check available groups for target user only if asking for 'All' group. if (!$noACL && $id_group == 0) { $id_group = array_keys( users_get_groups(false, 'AR', true, false, (array) $id_group) @@ -978,7 +999,7 @@ function agents_get_group_agents( } } - // Search for primary and secondary groups + // Search for primary and secondary groups. if (!empty($id_group)) { $filter[] = '('.db_format_array_where_clause_sql( [ @@ -990,7 +1011,7 @@ function agents_get_group_agents( } if ($search === true) { - // No added search. Show both disabled and non-disabled + // No added search. Show both disabled and non-disabled. } else if (is_array($search)) { if (!$search['all_agents']) { $filter['disabled'] = 0; @@ -2194,7 +2215,7 @@ function agents_delete_agent($id_agents, $disableACL=false) // Delete agent in networkmap enterprise if (enterprise_installed()) { - enterprise_include_once('include/functions_pandora_networkmap.php'); + enterprise_include_once('include/functions_networkmap.php'); networkmap_delete_nodes_by_agent([$id_agent]); } @@ -3102,7 +3123,7 @@ function select_agents_for_module_group( 'AND', 'tagente_modulo', true, - [], + $filter['tags'], false ); $sql_tags_inner = 'INNER JOIN ttag_module diff --git a/pandora_console/include/functions_alerts.php b/pandora_console/include/functions_alerts.php index 6bfe709c32..011acafae9 100644 --- a/pandora_console/include/functions_alerts.php +++ b/pandora_console/include/functions_alerts.php @@ -664,6 +664,7 @@ function alerts_get_alert_templates_types() $types['unknown'] = __('Unknown status'); $types['onchange'] = __('On Change'); $types['always'] = __('Always'); + $types['not_normal'] = __('Not normal status'); return $types; } @@ -680,7 +681,7 @@ function alerts_get_alert_templates_type_name($type) { $types = alerts_get_alert_templates_types(); - if (! isset($type[$type])) { + if (!isset($types[$type])) { return __('Unknown'); } diff --git a/pandora_console/include/functions_api.php b/pandora_console/include/functions_api.php index 545d84d640..3c6cdbf595 100644 --- a/pandora_console/include/functions_api.php +++ b/pandora_console/include/functions_api.php @@ -363,23 +363,18 @@ function api_get_test_event_replication_db() // -------------------------DEFINED OPERATIONS FUNCTIONS----------------- function api_get_groups($thrash1, $thrash2, $other, $returnType, $user_in_db) { - if (defined('METACONSOLE')) { - return; + $returnAllGroup = true; + $returnAllColumns = false; + + if (isset($other['data'][1])) { + $returnAllGroup = ( $other['data'][1] == '1' ? true : false); } - if ($other['type'] == 'string') { - if ($other['data'] != '') { - returnError('error_parameter', 'Error in the parameters.'); - return; - } else { - // Default values - $separator = ';'; - } - } else if ($other['type'] == 'array') { - $separator = $other['data'][0]; + if (isset($other['data'][2])) { + $returnAllColumns = ( $other['data'][2] == '1' ? true : false); } - $groups = users_get_groups($user_in_db, 'IR'); + $groups = users_get_groups($user_in_db, 'IR', $returnAllGroup, $returnAllColumns); $data_groups = []; foreach ($groups as $id => $group) { @@ -389,6 +384,13 @@ function api_get_groups($thrash1, $thrash2, $other, $returnType, $user_in_db) ]; } + if (!isset($other['data'][0])) { + $separator = ';'; + // by default + } else { + $separator = $other['data'][0]; + } + $data['type'] = 'array'; $data['data'] = $data_groups; @@ -4582,7 +4584,7 @@ function api_set_new_snmp_component($id, $thrash1, $other, $thrash2) return; } - $id = network_components_create_network_component($id, $other['data'][0], $other['data'][25], $values); + $id = network_components_create_network_component($id, $other['data'][0], $other['data'][26], $values); if (!$id) { returnError('error_set_new_snmp_component', 'Error creating SNMP component.'); @@ -6173,17 +6175,29 @@ function api_set_planned_downtimes_deleted($id, $thrash1, $thrash2, $returnType) /** * Create a new planned downtime. + * e.g.: api.php?op=set&op2=planned_downtimes_created&id=pepito&other=testing|08-22-2015|08-31-2015|0|1|1|1|1|1|1|1|17:06:00|19:06:00|1|31|quiet|periodically|weekly&other_mode=url_encode_separator_| * * @param $id name of planned downtime. * @param $thrash1 Don't use. - * @param array $other it's array, $other as param is ;;;;; - * ;;;;;;;; - * ;;;;; in this order - * and separator char (after text ; ) and separator (pass in param othermode as othermode=url_encode_separator_) - * example: - * - * api.php?op=set&op2=planned_downtimes_created&id=pepito&other=testing|08-22-2015|08-31-2015|0|1|1|1|1|1|1|1|17:06:00|19:06:00|1|31|quiet|periodically|weekly&other_mode=url_encode_separator_| - * + * @param array $other Contains the following elements (in order): + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * * @param $thrash3 Don't use. */ @@ -6247,20 +6261,16 @@ function api_set_planned_downtimes_created($id, $thrash1, $other, $thrash3) /** * Add new items to planned Downtime. + * e.g.: api.php?op=set&op2=planned_downtimes_additem&id=123&other=1;2;3;4|Status;Unkown_modules&other_mode=url_encode_separator_| * * @param $id id of planned downtime. * @param $thrash1 Don't use. - * @param array $other it's array, $other as param is ; - * in this order - * and separator char (after text ; ) and separator (pass in param othermode as othermode=url_encode_separator_) - * example: - * - * api.php?op=set&op2=planned_downtimes_additem&id=123&other=1;2;3;4|Status;Unkown_modules&other_mode=url_encode_separator_| - * + * @param array $other + * The first index contains a list of agent Ids. + * The second index contains a list of module names. + * The list separator is the character ';'. * @param $thrash3 Don't use. */ - - function api_set_planned_downtimes_additem($id, $thrash1, $other, $thrash3) { if (defined('METACONSOLE')) { @@ -11598,7 +11608,9 @@ function api_set_add_event_comment($id, $thrash2, $other, $thrash3) global $config; if (defined('METACONSOLE')) { - return; + $meta = true; + } else { + $meta = $other['data'][1]; } if (!check_acl($config['id_user'], 0, 'EW')) { @@ -11610,8 +11622,7 @@ function api_set_add_event_comment($id, $thrash2, $other, $thrash3) returnError('error_parameter', 'Error in the parameters.'); return; } else if ($other['type'] == 'array') { - $comment = io_safe_input($other['data'][0]); - $meta = $other['data'][1]; + $comment = $other['data'][0]; $history = $other['data'][2]; $status = events_comment( @@ -14674,3 +14685,365 @@ function api_set_reset_agent_counts($id, $thrash1, $thrash2, $thrash3) } } + + +/** + * Functions por get all user to new feature for Carrefour + * It depends of returnType, the method will return csv or json data + * + * @param string $thrash1 don't use + * @param string $thrash2 don't use + * @param array $other don't use + * *@param string $returnType + * Example: + * api.php?op=get&op2=list_all_user&return_type=json&apipass=1234&user=admin&pass=pandora + * @return + */ + + +function api_get_list_all_user($thrash1, $thrash2, $other, $returnType) +{ + global $config; + + if (!check_acl($config['id_user'], 0, 'AR')) { + returnError('forbidden', 'string'); + return; + } + + $sql = 'SELECT + tup.id_usuario AS user_id, + tu.fullname AS fullname, + tp.id_perfil AS profile_id, + tup.id_up AS id_up, + tp.name AS profile_name, + tup.id_grupo AS group_id, + tgp.nombre AS group_name + FROM tperfil tp + INNER JOIN tusuario_perfil tup + ON tp.id_perfil = tup.id_perfil + LEFT OUTER JOIN tgrupo tgp + ON tup.id_grupo = tgp.id_grupo + LEFT OUTER JOIN tusuario tu + ON tu.id_user = tup.id_usuario'; + + $users = db_get_all_rows_sql($sql); + + $i = 0; + + foreach ($users as $up) { + $group_name = $up['group_name']; + if ($up['group_name'] === null) { + $group_name = 'All'; + } + + $values[$i] = [ + 'id_usuario' => $up['user_id'], + 'fullname' => $up['fullname'], + 'id_up' => $up['id_up'], + 'id_perfil' => $up['profile_id'], + 'perfil_name' => $up['profile_name'], + 'id_grupo' => $up['group_id'], + 'group_name' => $group_name, + ]; + $i += 1; + } + + if ($values === false) { + returnError('Error_user', __('Users could not be found.')); + return; + } + + $data = [ + 'type' => 'array', + 'data' => $values, + ]; + + returnData($returnType, $data, ';'); +} + + +/** + * Funtion for get all info user to new feature for Carrefour + * It depends of returnType, the method will return csv or json data + * + * @param string $thrash1 don't use + * @param string $thrash2 don't use + * @param array $other other[0] = user database + * @param string $returnType + * Example + * api.php?op=get&op2=info_user_name&return_type=json&other=admin&other_mode=url_encode_separator_|&apipass=1234&user=admin&pass=pandora + * + * @return + */ + + +function api_get_info_user_name($thrash1, $thrash2, $other, $returnType) +{ + global $config; + + if (!check_acl($config['id_user'], 0, 'AR')) { + returnError('forbidden', 'string'); + return; + } + + $sql = sprintf( + 'SELECT tup.id_usuario AS user_id, + tu.fullname AS fullname, + tup.id_up AS id_up, + tp.id_perfil AS profile_id, + tp.name AS profile_name, + tup.id_grupo AS group_id, + tg.nombre AS group_name + FROM tperfil tp + INNER JOIN tusuario_perfil tup + ON tp.id_perfil = tup.id_perfil + LEFT OUTER JOIN tgrupo tg + ON tup.id_grupo = tg.id_grupo + LEFT OUTER JOIN tusuario tu + ON tu.id_user = tup.id_usuario + WHERE tup.id_usuario = "%s"', + io_safe_output($other['data'][0]) + ); + + $user_profile = db_get_all_rows_sql($sql); + + $i = 0; + + foreach ($user_profile as $up) { + $group_name = $up['group_name']; + if ($up['group_name'] === null) { + $group_name = 'All'; + } + + $values[$i] = [ + 'id_usuario' => $up['user_id'], + 'fullname' => $up['fullname'], + 'id_up' => $up['id_up'], + 'id_perfil' => $up['profile_id'], + 'perfil_name' => $up['profile_name'], + 'id_grupo' => $up['group_id'], + 'group_name' => $group_name, + ]; + $i += 1; + } + + $data = [ + 'type' => 'array', + 'data' => $values, + ]; + + returnData($returnType, $data, ';'); +} + + +/** + * Function for get user from a group to new feature for Carrefour. + * It depends of returnType, the method will return csv or json data. + * + * @param string $thrash1 don't use + * @param string $thrash2 don't use + * @param array $other + * $other[0] = id group + * $other[1] = is disabled or not + * @param string $returnType + * Example + * api.php?op=get&op2=filter_user_group&return_type=json&other=0|0&other_mode=url_encode_separator_|&apipass=1234&user=admin&pass=pandora + * + * @return + */ + + +function api_get_filter_user_group($thrash1, $thrash2, $other, $returnType) +{ + global $config; + + if (!check_acl($config['id_user'], 0, 'AR')) { + returnError('forbidden', 'string'); + return; + } + + $filter = ''; + + if ($other['data'][0] !== '' && $other['data'][1] !== '') { + $filter = 'WHERE tup.id_grupo = '.$other['data'][0].' AND tu.disabled = '.$other['data'][1].''; + } else if ($other['data'][0] !== '') { + $filter = 'WHERE tup.id_grupo = '.$other['data'][0].''; + } else if ($other['data'][1] !== '') { + $filter = 'WHERE tu.disabled = '.$other['data'][1].''; + } + + $sql = sprintf( + 'SELECT DISTINCT + tup.id_usuario AS user_id, + tu.fullname AS fullname, + tup.id_up AS id_up, + tp.id_perfil AS profile_id, + tp.name AS profile_name, + tup.id_grupo AS group_id, + tg.nombre AS group_name + FROM tperfil tp + INNER JOIN tusuario_perfil tup + ON tp.id_perfil = tup.id_perfil + LEFT OUTER JOIN tgrupo tg + ON tup.id_grupo = tg.id_grupo + LEFT OUTER JOIN tusuario tu + ON tu.id_user = tup.id_usuario + '.$filter.'' + ); + + $filter_user = db_get_all_rows_sql($sql); + + $i = 0; + + foreach ($filter_user as $up) { + $group_name = $up['group_name']; + if ($up['group_name'] === null) { + $group_name = 'All'; + } + + $values[$i] = [ + 'id_usuario' => $up['user_id'], + 'fullname' => $up['fullname'], + 'id_up' => $up['id_up'], + 'id_perfil' => $up['profile_id'], + 'perfil_name' => $up['profile_name'], + 'id_grupo' => $up['group_id'], + 'group_name' => $group_name, + ]; + $i += 1; + } + + $data = [ + 'type' => 'array', + 'data' => $values, + ]; + + returnData($returnType, $data, ';'); + +} + + +/** + * Function for delete an user permission for Carrefour new feature + * The return of this function its only a message + * + * @param string $thrash1 don't use + * @param string $thrash2 don't use + * @param array $other + * $other[0] = id up + * @param string $returnType + * Example + * api.php?op=set&op2=delete_user_permission&return_type=json&other=user|2&other_mode=url_encode_separator_|&apipass=1234&user=admin&pass=pandora + * + * @return void + */ + + +function api_set_delete_user_permission($thrash1, $thrash2, $other, $returnType) +{ + global $config; + + if (!check_acl($config['id_user'], 0, 'AW')) { + returnError('forbidden', 'string'); + return; + } + + if ($other['data'][0] != '') { + $values = [ + 'id_up' => io_safe_output($other['data'][0]), + ]; + } else { + returnError('Error_delete', __('User profile could not be deleted.')); + return; + } + + $deleted_permission = db_process_sql_delete('tusuario_perfil', $values); + + if ($deleted_permission == false) { + returnError('Error_delete', __('User profile could not be deleted.')); + return; + } + + $data = [ + 'type' => 'string', + 'data' => $deleted_permission, + ]; + + returnData('string', ['type' => 'string', 'data' => $data]); +} + + +/** + * Function for add permission a user to a group for Carrefour new feature + * It depends of returnType, the method will return csv or json data + * + * @param string $thrash1 don't use + * @param string $thrash2 don't use + * @param array $other other[0] = user database + * other[1] = id group + * other[2] = id profile + * other[3] = no_hierarchy ( 0 or 1, if empty = 0) + * other[4] = id from tusuario_perfil table (optional) + * * @param string $returnType + * Example + * api.php?op=set&op2=add_permission_user_to_group&return_type=json&other=admin|0|1|1|20&other_mode=url_encode_separator_|&apipass=1234&user=admin&pass=pandora + * + * @return void + */ + + +function api_set_add_permission_user_to_group($thrash1, $thrash2, $other, $returnType) +{ + global $config; + + if (!check_acl($config['id_user'], 0, 'AW')) { + returnError('forbidden', 'string'); + return; + } + + $sql = 'SELECT id_up + FROM tusuario_perfil + WHERE id_up = '.$other['data'][4].''; + + $exist_profile = db_get_value_sql($sql); + + if ($other['data'][3] < 0 || $other['data'][3] > 1) { + returnError('Error_insert', __('User profile could not be available.')); + return; + } + + if ($other['data'][3] == null) { + $other['data'][3] = 0; + } + + $values = [ + 'id_usuario' => $other['data'][0], + 'id_perfil' => $other['data'][2], + 'id_grupo' => $other['data'][1], + 'no_hierarchy' => $other['data'][3], + 'assigned_by' => $config['id_user'], + 'id_policy' => 0, + 'tags' => '', + + ]; + + $where_id_up = ['id_up' => $other['data'][4]]; + if ($exist_profile === $other['data'][4] && $where_id_up !== null) { + $sucessfull_insert = db_process_sql_update('tusuario_perfil', $values, $where_id_up); + } else { + $sucessfull_insert = db_process_sql_insert('tusuario_perfil', $values); + } + + if ($sucessfull_insert == false) { + returnError('Error_insert', __('User profile could not be available.')); + return; + } + + $data = [ + 'type' => 'array', + 'data' => $values, + ]; + + returnData($returnType, $data, ';'); + +} diff --git a/pandora_console/include/functions_clippy.php b/pandora_console/include/functions_clippy.php index 725ce5078a..67999a75e0 100644 --- a/pandora_console/include/functions_clippy.php +++ b/pandora_console/include/functions_clippy.php @@ -1,23 +1,31 @@ = introJs(); .setOptions({ - steps: , - showBullets: , - showStepNumbers: , + steps: , + showBullets: + + , + showStepNumbers: + + , nextLabel: "", prevLabel: "", skipLabel: "", @@ -205,13 +241,22 @@ function clippy_write_javascript_helps_steps($tours) return exit; }); - if () { + clippy_set_help(''); + - if () { - .start(); + + .start(); + }); @@ -221,6 +266,13 @@ function clippy_write_javascript_helps_steps($tours) } +/** + * Undocumented function + * + * @param string $help Help. + * + * @return void + */ function clippy_context_help($help=null) { global $config; @@ -244,10 +296,10 @@ function clippy_context_help($help=null) $code = str_replace('{clippy}', '#'.$id, $code); $code = str_replace('{clippy_obj}', 'intro_'.$id, $code); - $return = $code.' width = '100%'; $table->id = 'table_filemanager'; if (!defined('METACONSOLE')) { - $table->class = 'databox data'; + $table->class = 'info_table'; $table->title = ''.__('Index of %s', $relative_directory).''; } if (defined('METACONSOLE')) { $table->class = 'databox_tactical'; - $table->title = ''.__('Index of images').''; + $table->title = ''.__('Index of %s', $relative_directory).''; } $table->colspan = []; @@ -582,13 +624,6 @@ function filemanager_file_explorer( $table->head[2] = __('Last modification'); $table->head[3] = __('Size'); $table->head[4] = __('Actions'); - if (!defined('METACONSOLE')) { - $table->headstyle[0] = 'background-color:#82B92E'; - $table->headstyle[1] = 'background-color:#82B92E'; - $table->headstyle[2] = 'background-color:#82B92E'; - $table->headstyle[3] = 'background-color:#82B92E'; - $table->headstyle[4] = 'background-color:#82B92E'; - } $prev_dir = explode('/', $relative_directory); $prev_dir_str = ''; @@ -608,85 +643,6 @@ function filemanager_file_explorer( $table->colspan[0][1] = 5; } - if (is_writable($real_directory)) { - $table->rowstyle[1] = 'display: none;'; - $table->data[1][0] = ''; - $table->data[1][1] = ''; - - $table->data[1][1] .= ''; - - $table->data[1][1] .= ''; - - $table->data[1][1] .= ''; - - $table->colspan[1][1] = 5; - } - foreach ($files as $fileinfo) { $fileinfo['realpath'] = str_replace('\\', '/', $fileinfo['realpath']); $relative_path = str_replace($_SERVER['DOCUMENT_ROOT'], '', $fileinfo['realpath']); @@ -777,6 +733,7 @@ function filemanager_file_explorer( $data[4] .= html_print_input_hidden('delete_file', 1, true); $relative_dir = str_replace($homedir_filemanager, '', str_replace('\\', '/', dirname($fileinfo['realpath']))); + if ($relative_dir[0] == '/') { $relative_dir = substr($relative_dir, 1); } @@ -812,13 +769,44 @@ function filemanager_file_explorer( if (!$readOnly) { if (is_writable($real_directory)) { // The buttons to make actions - if (defined('METACONSOLE')) { - echo "
"; - } else { - echo "
"; - } + $tabs_dialog = ''; - echo ""; + echo ''; + + echo ''; + + echo ' '; + + echo "'; } else { - echo "
"; + echo "
"; echo "".__('The directory is read-only'); echo '
'; } @@ -938,4 +926,3 @@ function filemanager_list_dir($dirpath) return array_merge($dirs, $files); } - diff --git a/pandora_console/include/functions_graph.php b/pandora_console/include/functions_graph.php index 6f8601bea5..cde59c52bb 100644 --- a/pandora_console/include/functions_graph.php +++ b/pandora_console/include/functions_graph.php @@ -1,16 +1,32 @@ 0) { - // Propagate the last known data to the end of the interval + // Propagate the last known data to the end of the interval. $nextData = [ 'datos' => $data[(count($data) - 1)]['datos'], 'utimestamp' => $date_array['final_date'], @@ -114,9 +144,8 @@ function grafico_modulo_sparse_data_chart( array_push($data, $nextData); } - // Check available data + // Check available data. if (count($data) < 1) { - // return fs_error_image (); return false; } @@ -126,7 +155,7 @@ function grafico_modulo_sparse_data_chart( $array_percentil = []; foreach ($data as $k => $v) { - // convert array + // Convert array. if ($params['flag_overlapped']) { $array_data['sum'.$series_suffix]['data'][$k] = [ (($v['utimestamp'] + $date_array['period'] ) * 1000), @@ -139,40 +168,43 @@ function grafico_modulo_sparse_data_chart( ]; } - // min + // Min. if ($min_value > $v['datos']) { $min_value = $v['datos']; } - // max + // Max. if ($max_value < $v['datos']) { $max_value = $v['datos']; } - // avg + // Avg. $sum_data += $v['datos']; $count_data++; - // percentil - if (!is_null($params['percentil']) && $params['percentil']) { + // Percentil. + if (!isset($params['percentil']) && $params['percentil']) { $array_percentil[] = $v['datos']; } } - $array_data['sum'.$series_suffix]['min'] = $min_value; - $array_data['sum'.$series_suffix]['max'] = $max_value; - $array_data['sum'.$series_suffix]['avg'] = ($sum_data / $count_data); + $array_data['sum'.$series_suffix]['min'] = $min_value; + $array_data['sum'.$series_suffix]['max'] = $max_value; + $array_data['sum'.$series_suffix]['avg'] = ($sum_data / $count_data); $array_data['sum'.$series_suffix]['agent_module_id'] = $agent_module_id; $array_data['sum'.$series_suffix]['id_module_type'] = $data_module_graph['id_module_type']; - $array_data['sum'.$series_suffix]['agent_name'] = $data_module_graph['agent_name']; - $array_data['sum'.$series_suffix]['module_name'] = $data_module_graph['module_name']; - $array_data['sum'.$series_suffix]['agent_alias'] = $data_module_graph['agent_alias']; + $array_data['sum'.$series_suffix]['agent_name'] = $data_module_graph['agent_name']; + $array_data['sum'.$series_suffix]['module_name'] = $data_module_graph['module_name']; + $array_data['sum'.$series_suffix]['agent_alias'] = $data_module_graph['agent_alias']; - if (!is_null($params['percentil']) + if (!isset($params['percentil']) && $params['percentil'] && !$params['flag_overlapped'] ) { - $percentil_result = get_percentile($params['percentil'], $array_percentil); + $percentil_result = get_percentile( + $params['percentil'], + $array_percentil + ); $array_data['percentil'.$series_suffix]['data'][0] = [ ($date_array['start_date'] * 1000), $percentil_result, @@ -188,6 +220,17 @@ function grafico_modulo_sparse_data_chart( } +/** + * Prepare data for send to function js paint charts. + * + * @param integer $agent_module_id ID. + * @param array $date_array Date stasrt finish and period. + * @param array $data_module_graph Data module. + * @param array $params Params graphs. + * @param integer $series_suffix Int. + * + * @return array Prepare data to paint js. + */ function grafico_modulo_sparse_data( $agent_module_id, $date_array, @@ -210,7 +253,7 @@ function grafico_modulo_sparse_data( $params['type_mode_graph'] ); } else { - // uncompress data except boolean and string. + // Uncompress data except boolean and string. if ($data_module_graph['id_module_type'] == 23 || $data_module_graph['id_module_type'] == 3 || $data_module_graph['id_module_type'] == 17 @@ -232,6 +275,7 @@ function grafico_modulo_sparse_data( $series_suffix ); } else { + $data_slice = ($date_array['period'] / (250 * $params['zoom']) + 100); $array_data = fullscale_data( $agent_module_id, $date_array, @@ -239,23 +283,27 @@ function grafico_modulo_sparse_data( $params['percentil'], $series_suffix, $params['flag_overlapped'], - $data_slice = ($date_array['period'] / (250 * $params['zoom']) + 100), + $data_slice, $params['type_mode_graph'] ); } } - if ($array_data === false || (!$params['graph_combined'] && !isset($array_data['sum1']['data'][0][1]))) { + if ($array_data === false && (!$params['graph_combined'] + && !isset($array_data['sum1']['data'][0][1]) && !$params['baseline']) + ) { return false; } $array_data['sum'.$series_suffix]['agent_module_id'] = $agent_module_id; $array_data['sum'.$series_suffix]['id_module_type'] = $data_module_graph['id_module_type']; - $array_data['sum'.$series_suffix]['agent_name'] = $data_module_graph['agent_name']; - $array_data['sum'.$series_suffix]['module_name'] = $data_module_graph['module_name']; - $array_data['sum'.$series_suffix]['agent_alias'] = $data_module_graph['agent_alias']; + $array_data['sum'.$series_suffix]['agent_name'] = $data_module_graph['agent_name']; + $array_data['sum'.$series_suffix]['module_name'] = $data_module_graph['module_name']; + $array_data['sum'.$series_suffix]['agent_alias'] = $data_module_graph['agent_alias']; + $array_data['sum'.$series_suffix]['unit'] = $data_module_graph['unit']; - // This is for a specific type of report that consists in passing an interval and doing the average sum and avg. + // This is for a specific type of report that consists in passing + // an interval and doing the average sum and avg. if ($params['force_interval'] != '') { $period_time_interval = ($date_array['period'] * 1000); $start_period = ($date_array['start_date'] * 1000); @@ -267,7 +315,9 @@ function grafico_modulo_sparse_data( while ($period_time_interval > 0) { foreach ($array_data['sum1']['data'] as $key => $value) { - if ($value[0] >= $start_period && $value[0] < ($start_period + $params['time_interval'] * 1000)) { + if ($value[0] >= $start_period + && $value[0] < ($start_period + $params['time_interval'] * 1000) + ) { $sum_data = $value[1]; $array_data_only[] = $value[1]; $count_data++; @@ -275,7 +325,9 @@ function grafico_modulo_sparse_data( } else { if ($params['force_interval'] == 'max_only') { $acum_array_data[$i][0] = $start_period; - if (is_array($array_data_only) && count($array_data_only) > 0) { + if (is_array($array_data_only) + && count($array_data_only) > 0 + ) { $acum_array_data[$i][1] = max($array_data_only); $data_last_acum = $array_data_only[(count($array_data_only) - 1)]; } else { @@ -285,7 +337,9 @@ function grafico_modulo_sparse_data( if ($params['force_interval'] == 'min_only') { $acum_array_data[$i][0] = $start_period; - if (is_array($array_data_only) && count($array_data_only) > 0) { + if (is_array($array_data_only) + && count($array_data_only) > 0 + ) { $acum_array_data[$i][1] = min($array_data_only); $data_last_acum = $array_data_only[(count($array_data_only) - 1)]; } else { @@ -295,7 +349,9 @@ function grafico_modulo_sparse_data( if ($params['force_interval'] == 'avg_only') { $acum_array_data[$i][0] = $start_period; - if (is_array($array_data_only) && count($array_data_only) > 0) { + if (is_array($array_data_only) + && count($array_data_only) > 0 + ) { $acum_array_data[$i][1] = ($sum_data / $count_data); } else { $acum_array_data[$i][1] = $data_last_acum; @@ -314,7 +370,7 @@ function grafico_modulo_sparse_data( $period_time_interval = ($period_time_interval - $params['time_interval']); } - // drag the last value to paint the graph correctly + // Drag the last value to paint the graph correctly. $acum_array_data[] = [ 0 => $start_period, 1 => $acum_array_data[($i - 1)][1], @@ -358,7 +414,6 @@ function grafico_modulo_sparse_data( $date_array['final_date'], $data_module_graph['history_db'], 1 - // fix the time ranges to start_date - final_date ); if ($unknown_events !== false) { @@ -493,66 +548,59 @@ function grafico_modulo_sparse_data( } -/* - $params =array( - 'agent_module_id' => $agent_module_id, - 'period' => $period, - 'show_events' => false, - 'width' => $width, - 'height' => $height, - 'title' => '', - 'unit_name' => null, - 'show_alerts' => false, - 'date' => 0, - 'unit' => '', - 'baseline' => 0, - 'return_data' => 0, - 'show_title' => true, - 'only_image' => false, - 'homeurl' => $config['homeurl'], - 'ttl' => 1, - 'adapt_key' => '', - 'compare' => false, - 'show_unknown' => false, - 'menu' => true, - 'backgroundColor' => 'white', - 'percentil' => null, - 'dashboard' => false, - 'vconsole' => false, - 'type_graph' => 'area', - 'fullscale' => false, - 'id_widget_dashboard' => false, - 'force_interval' => '', - 'time_interval' => 300, - 'array_data_create' => 0, - 'show_legend' => true, - 'show_overview' => true, - 'return_img_base_64' => false, - 'image_treshold' => false, - 'graph_combined' => false, - 'zoom' => 1, - 'server_id' => null - ); -*/ +/** + * Functions tu create graphs. + * + * @param array $params Details builds graphs. For example: + * 'agent_module_id' => $agent_module_id, + * 'period' => $period, + * 'show_events' => false, + * 'width' => $width, + * 'height' => $height, + * 'title' => '', + * 'unit_name' => null, + * 'show_alerts' => false, + * 'date' => 0, + * 'unit' => '', + * 'baseline' => 0, + * 'return_data' => 0, + * 'show_title' => true, + * 'only_image' => false, + * 'homeurl' => $config['homeurl'], + * 'ttl' => 1, + * 'adapt_key' => '', + * 'compare' => false, + * 'show_unknown' => false, + * 'menu' => true, + * 'backgroundColor' => 'white', + * 'percentil' => null, + * 'dashboard' => false, + * 'vconsole' => false, + * 'type_graph' => 'area', + * 'fullscale' => false, + * 'id_widget_dashboard' => false, + * 'force_interval' => '', + * 'time_interval' => 300, + * 'array_data_create' => 0, + * 'show_legend' => true, + * 'show_overview' => true, + * 'return_img_base_64' => false, + * 'image_treshold' => false, + * 'graph_combined' => false, + * 'zoom' => 1, + * 'server_id' => null, + * 'stacked' => 0. + * + * @return string html Content graphs. + */ function grafico_modulo_sparse($params) { global $config; - /* - XXXXXXXXXXXX Documnetar - *Set all variable - */ - if (!isset($params) || !is_array($params)) { return false; } - if (!isset($params['agent_module_id'])) { - return false; - } else { - $agent_module_id = $params['agent_module_id']; - } - if (!isset($params['period'])) { return false; } @@ -696,11 +744,10 @@ function grafico_modulo_sparse($params) } if (!isset($params['zoom'])) { - $params['zoom'] = $config['zoom_graph'] ? $config['zoom_graph'] : 1; + $params['zoom'] = ($config['zoom_graph']) ? $config['zoom_graph'] : 1; } if (!isset($params['type_mode_graph'])) { - // $config['type_mode_graph'] $params['type_mode_graph'] = $config['type_mode_graph']; } @@ -708,10 +755,21 @@ function grafico_modulo_sparse($params) $params['projection'] = false; } - // XXXX Configurable - $params['grid_color'] = '#C1C1C1'; + if (!isset($params['agent_module_id'])) { + return graph_nodata_image($params['width'], $params['height']); + } else { + $agent_module_id = $params['agent_module_id']; + } + + if (!isset($params['stacked'])) { + $params['stacked'] = 0; + } + + // TODO: Configurable. + $params['grid_color'] = '#C1C1C1'; $params['legend_color'] = '#636363'; - $params['font'] = $config['fontpath']; + + $params['font'] = $config['fontpath']; $params['font_size'] = $config['font_size']; $params['short_data'] = $config['short_module_graph_data']; @@ -722,8 +780,8 @@ function grafico_modulo_sparse($params) global $graphic_type; global $array_events_alerts; - $array_data = []; - $legend = []; + $array_data = []; + $legend = []; $array_events_alerts = []; $date_array = []; @@ -738,25 +796,36 @@ function grafico_modulo_sparse($params) ); $data_module_graph = []; - $data_module_graph['history_db'] = db_search_in_history_db($date_array['start_date']); - $data_module_graph['agent_name'] = modules_get_agentmodule_agent_name($agent_module_id); - $data_module_graph['agent_alias'] = modules_get_agentmodule_agent_alias($agent_module_id); - $data_module_graph['agent_id'] = $module_data['id_agente']; - $data_module_graph['module_name'] = $module_data['nombre']; + $data_module_graph['history_db'] = db_search_in_history_db( + $date_array['start_date'] + ); + $data_module_graph['agent_name'] = modules_get_agentmodule_agent_name( + $agent_module_id + ); + $data_module_graph['agent_alias'] = modules_get_agentmodule_agent_alias( + $agent_module_id + ); + $data_module_graph['agent_id'] = $module_data['id_agente']; + $data_module_graph['module_name'] = $module_data['nombre']; $data_module_graph['id_module_type'] = $module_data['id_tipo_modulo']; - $data_module_graph['module_type'] = modules_get_moduletype_name($data_module_graph['id_module_type']); - $data_module_graph['uncompressed'] = is_module_uncompressed($data_module_graph['module_type']); - $data_module_graph['w_min'] = $module_data['min_warning']; - $data_module_graph['w_max'] = $module_data['max_warning']; - $data_module_graph['w_inv'] = $module_data['warning_inverse']; - $data_module_graph['c_min'] = $module_data['min_critical']; - $data_module_graph['c_max'] = $module_data['max_critical']; - $data_module_graph['c_inv'] = $module_data['critical_inverse']; + $data_module_graph['module_type'] = modules_get_moduletype_name( + $data_module_graph['id_module_type'] + ); + $data_module_graph['uncompressed'] = is_module_uncompressed( + $data_module_graph['module_type'] + ); + $data_module_graph['w_min'] = $module_data['min_warning']; + $data_module_graph['w_max'] = $module_data['max_warning']; + $data_module_graph['w_inv'] = $module_data['warning_inverse']; + $data_module_graph['c_min'] = $module_data['min_critical']; + $data_module_graph['c_max'] = $module_data['max_critical']; + $data_module_graph['c_inv'] = $module_data['critical_inverse']; + $data_module_graph['unit'] = $module_data['unit']; } else { $data_module_graph = false; } - // format of the graph + // Format of the graph. if (empty($params['unit'])) { $params['unit'] = $module_data['unit']; if (modules_is_unit_macro($params['unit'])) { @@ -766,7 +835,12 @@ function grafico_modulo_sparse($params) if (!$params['array_data_create']) { if ($params['baseline']) { - $array_data = get_baseline_data($agent_module_id, $date_array, $data_module_graph, $params); + $array_data = get_baseline_data( + $agent_module_id, + $date_array, + $data_module_graph, + $params + ); } else { if ($params['compare'] !== false) { $series_suffix = 2; @@ -792,10 +866,14 @@ function grafico_modulo_sparse($params) switch ($params['compare']) { case 'separated': case 'overlapped': - // Store the chart calculated + // Store the chart calculated. $array_data_prev = $array_data; $legend_prev = $legend; break; + + default: + // Not defined. + break; } } @@ -848,7 +926,7 @@ function grafico_modulo_sparse($params) $data_module_graph['series_suffix'] = $series_suffix; - // Check available data + // Check available data. if ($params['compare'] === 'separated') { if (!empty($array_data)) { $return = area_graph( @@ -922,67 +1000,41 @@ function grafico_modulo_sparse($params) /** - * Produces a combined/user defined graph + * Functions tu create graphs. * - * @param array List of source modules - * @param array List of weighs for each module - * @param int Period (in seconds) - * @param int Width, in pixels - * @param int Height, in pixels - * @param string Title for graph - * @param string Unit name, for render in legend - * @param int Show events in graph (set to 1) - * @param int Show alerts in graph (set to 1) - * @param int Pure mode (without titles) (set to 1) - * @param int Date to start of getting info. - * @param mixed If is a projection graph this parameter will be module data with prediction data (the projection) - * or false in other case. - * @param array List of names for the items. Should have the same size as the module list. - * @param array List of units for the items. Should have the same size as the module list. - * @param bool Show the last value of the item on the list. - * @param bool Show the max value of the item on the list. - * @param bool Show the min value of the item on the list. - * @param bool Show the average value of the item on the list. + * @param array $module_list Array modules. + * @param array $params Details builds graphs. For example: + * 'period' => $period, + * 'show_events' => false, + * 'width' => $width, + * 'height' => $height, + * 'title' => '', + * 'unit_name' => null, + * 'show_alerts' => false, + * 'date' => 0, + * 'unit' => '', + * 'only_image' => false, + * 'homeurl' => '', + * 'ttl' => 1, + * 'percentil' => null, + * 'dashboard' => false, + * 'vconsole' => false, + * 'fullscale' => false, + * 'id_widget_dashboard' => false. + * @param array $params_combined Details builds graphs. For example: + * 'weight_list' => array(), + * 'stacked' => 0, + * 'projection' => false, + * 'labels' => array(), + * 'from_interface' => false, + * 'summatory' => 0, + * 'average' => 0, + * 'modules_series' => 0, + * 'id_graph' => 0, + * 'return' => 1. * - * @return Mixed + * @return string html Content graphs. */ - - -/* - $params =array( - 'period' => $period, - 'show_events' => false, - 'width' => $width, - 'height' => $height, - 'title' => '', - 'unit_name' => null, - 'show_alerts' => false, - 'date' => 0, - 'unit' => '', - 'only_image' => false, - 'homeurl' => '', - 'ttl' => 1, - 'percentil' => null, - 'dashboard' => false, - 'vconsole' => false, - 'fullscale' => false, - 'id_widget_dashboard' => false, - ); - - $params_combined = array( - 'weight_list' => array(), - 'stacked' => 0, - 'projection' => false, - 'labels' => array(), - 'from_interface' => false, - 'summatory' => 0, - 'average' => 0, - 'modules_series' => 0, - 'id_graph' => 0, - 'return' => 1 - ); -*/ - function graphic_combined_module( $module_list, $params, @@ -1162,18 +1214,24 @@ function graphic_combined_module( $params_combined['graph_combined'] = true; if ($params['only_image']) { - return generator_chart_to_pdf('combined', $params, $params_combined, $module_list); + return generator_chart_to_pdf( + 'combined', + $params, + $params_combined, + $module_list + ); } if (!isset($params['zoom'])) { $params['zoom'] = 1; } - // XXXX Configurable + // TODO: Configurable. $params['grid_color'] = '#C1C1C1'; $params['legend_color'] = '#636363'; - $params['font'] = $config['fontpath']; - $params['font_size'] = $config['font_size']; + + $params['font'] = $config['fontpath']; + $params['font_size'] = $config['font_size']; $params['short_data'] = $config['short_module_graph_data']; @@ -1218,11 +1276,13 @@ function graphic_combined_module( foreach ($sources as $source) { array_push($modules, $source['id_agent_module']); array_push($weights, $source['weight']); - if ($source['label'] != '') { - $item['type'] = 'custom_graph'; - $item['id_agent'] = agents_get_module_id($source['id_agent_module']); + if ($source['label'] != '' || $params_combined['labels']) { + $item['type'] = 'custom_graph'; + $item['id_agent'] = agents_get_module_id( + $source['id_agent_module'] + ); $item['id_agent_module'] = $source['id_agent_module']; - $labels[$source['id_agent_module']] = reporting_label_macro($item, $source['label']); + $labels[$source['id_agent_module']] = ($source['label'] != '') ? reporting_label_macro($item, $source['label']) : reporting_label_macro($item, $params_combined['labels']); } } } @@ -1272,13 +1332,13 @@ function graphic_combined_module( } } - $width = $params['width']; - $height = $params['height']; - $homeurl = $params['homeurl']; - $ttl = $params['ttl']; + $width = $params['width']; + $height = $params['height']; + $homeurl = $params['homeurl']; + $ttl = $params['ttl']; $background_color = $params['backgroundColor']; - $datelimit = $date_array['start_date']; - $fixed_font_size = $config['font_size']; + $datelimit = $date_array['start_date']; + $fixed_font_size = $config['font_size']; if ($config['fixed_graph'] == false) { $water_mark = [ @@ -1316,6 +1376,10 @@ function graphic_combined_module( $array_data = []; foreach ($module_list as $key => $agent_module_id) { + if ((bool) $agent_module_id === false) { + continue; + } + if (is_metaconsole() && $params_combined['type_report'] == 'automatic_graph') { $server = metaconsole_get_connection_by_id($agent_module_id['server']); if (metaconsole_connect($server) != NOERR) { @@ -1331,23 +1395,34 @@ function graphic_combined_module( ); $data_module_graph = []; - $data_module_graph['history_db'] = db_search_in_history_db($date_array['start_date']); - $data_module_graph['agent_name'] = modules_get_agentmodule_agent_name($agent_module_id); - $data_module_graph['agent_alias'] = modules_get_agentmodule_agent_alias($agent_module_id); - $data_module_graph['agent_id'] = $module_data['id_agente']; - $data_module_graph['module_name'] = $module_data['nombre']; + $data_module_graph['history_db'] = db_search_in_history_db( + $date_array['start_date'] + ); + $data_module_graph['agent_name'] = modules_get_agentmodule_agent_name( + $agent_module_id + ); + $data_module_graph['agent_alias'] = modules_get_agentmodule_agent_alias( + $agent_module_id + ); + $data_module_graph['agent_id'] = $module_data['id_agente']; + $data_module_graph['module_name'] = $module_data['nombre']; $data_module_graph['id_module_type'] = $module_data['id_tipo_modulo']; - $data_module_graph['module_type'] = modules_get_moduletype_name($data_module_graph['id_module_type']); - $data_module_graph['uncompressed'] = is_module_uncompressed($data_module_graph['module_type']); - $data_module_graph['w_min'] = $module_data['min_warning']; - $data_module_graph['w_max'] = $module_data['max_warning']; - $data_module_graph['w_inv'] = $module_data['warning_inverse']; - $data_module_graph['c_min'] = $module_data['min_critical']; - $data_module_graph['c_max'] = $module_data['max_critical']; - $data_module_graph['c_inv'] = $module_data['critical_inverse']; - $data_module_graph['module_id'] = $agent_module_id; + $data_module_graph['module_type'] = modules_get_moduletype_name( + $data_module_graph['id_module_type'] + ); + $data_module_graph['uncompressed'] = is_module_uncompressed( + $data_module_graph['module_type'] + ); + $data_module_graph['w_min'] = $module_data['min_warning']; + $data_module_graph['w_max'] = $module_data['max_warning']; + $data_module_graph['w_inv'] = $module_data['warning_inverse']; + $data_module_graph['c_min'] = $module_data['min_critical']; + $data_module_graph['c_max'] = $module_data['max_critical']; + $data_module_graph['c_inv'] = $module_data['critical_inverse']; + $data_module_graph['module_id'] = $agent_module_id; + $data_module_graph['unit'] = $module_data['unit']; - // stract data + // Stract data. $array_data_module = grafico_modulo_sparse_data( $agent_module_id, $date_array, @@ -1358,12 +1433,14 @@ function graphic_combined_module( $series_suffix = $i; - // convert to array graph and weight + // Convert to array graph and weight. foreach ($array_data_module as $key => $value) { $array_data[$key] = $value; - if ($params_combined['weight_list'][$i] > 1) { + if ($params_combined['weight_list'][$i] != 1) { foreach ($value['data'] as $k => $v) { - $array_data[$key]['data'][$k][1] = ($v[1] * $params_combined['weight_list'][$i]); + if ($v[1] != false) { + $array_data[$key]['data'][$k][1] = ($v[1] * $params_combined['weight_list'][$i]); + } } } } @@ -1384,16 +1461,26 @@ function graphic_combined_module( // Work around for fixed the agents name with huge size chars. $fixed_font_size = $config['font_size']; - // $array_events_alerts[$series_suffix] = $events; $i++; - if (is_metaconsole() && $params_combined['type_report'] == 'automatic_graph') { + if (is_metaconsole() + && $params_combined['type_report'] == 'automatic_graph' + ) { metaconsole_restore_db(); } } + if (empty($array_data)) { + if ($params_combined['return']) { + return graph_nodata_image($width, $height); + } + + echo graph_nodata_image($width, $height); + return false; + } + if ($params_combined['projection']) { - // If projection doesn't have data then don't draw graph + // If projection doesn't have data then don't draw graph. if ($output_projection != null) { $date_array_projection = max($output_projection); $date_array['final_date'] = ($date_array_projection[0] / 1000); @@ -1401,9 +1488,13 @@ function graphic_combined_module( } } - // summatory and average series - if ($params_combined['stacked'] == CUSTOM_GRAPH_AREA || $params_combined['stacked'] == CUSTOM_GRAPH_LINE) { - if ($params_combined['summatory'] || $params_combined['average']) { + // Summatory and average series. + if ($params_combined['stacked'] == CUSTOM_GRAPH_AREA + || $params_combined['stacked'] == CUSTOM_GRAPH_LINE + ) { + if ($params_combined['summatory'] + || $params_combined['average'] + ) { $array_data = combined_graph_summatory_average( $array_data, $params_combined['average'], @@ -1446,9 +1537,19 @@ function graphic_combined_module( $do_it_critical_inverse = true; foreach ($module_list as $index => $id_module) { - // Get module warning_min and critical_min - $warning_min = db_get_value('min_warning', 'tagente_modulo', 'id_agente_modulo', $id_module); - $critical_min = db_get_value('min_critical', 'tagente_modulo', 'id_agente_modulo', $id_module); + // Get module warning_min and critical_min. + $warning_min = db_get_value( + 'min_warning', + 'tagente_modulo', + 'id_agente_modulo', + $id_module + ); + $critical_min = db_get_value( + 'min_critical', + 'tagente_modulo', + 'id_agente_modulo', + $id_module + ); if ($index == 0) { $compare_warning = $warning_min; @@ -1469,8 +1570,18 @@ function graphic_combined_module( if ($do_it_warning_min || $do_it_critical_min) { foreach ($module_list as $index => $id_module) { - $warning_max = db_get_value('max_warning', 'tagente_modulo', 'id_agente_modulo', $id_module); - $critical_max = db_get_value('max_critical', 'tagente_modulo', 'id_agente_modulo', $id_module); + $warning_max = db_get_value( + 'max_warning', + 'tagente_modulo', + 'id_agente_modulo', + $id_module + ); + $critical_max = db_get_value( + 'max_critical', + 'tagente_modulo', + 'id_agente_modulo', + $id_module + ); if ($index == 0) { $yellow_up = $warning_max; @@ -1492,8 +1603,18 @@ function graphic_combined_module( if ($do_it_warning_min || $do_it_critical_min) { foreach ($module_list as $index => $id_module) { - $warning_inverse = db_get_value('warning_inverse', 'tagente_modulo', 'id_agente_modulo', $id_module); - $critical_inverse = db_get_value('critical_inverse', 'tagente_modulo', 'id_agente_modulo', $id_module); + $warning_inverse = db_get_value( + 'warning_inverse', + 'tagente_modulo', + 'id_agente_modulo', + $id_module + ); + $critical_inverse = db_get_value( + 'critical_inverse', + 'tagente_modulo', + 'id_agente_modulo', + $id_module + ); if ($index == 0) { $yellow_inverse = $warning_inverse; @@ -1513,18 +1634,24 @@ function graphic_combined_module( } } - if ($do_it_warning_min && $do_it_warning_max && $do_it_warning_inverse) { + if ($do_it_warning_min + && $do_it_warning_max + && $do_it_warning_inverse + ) { $yellow_threshold = $compare_warning; $threshold_data['yellow_threshold'] = $compare_warning; - $threshold_data['yellow_up'] = $yellow_up; - $threshold_data['yellow_inverse'] = (bool) $yellow_inverse; + $threshold_data['yellow_up'] = $yellow_up; + $threshold_data['yellow_inverse'] = (bool) $yellow_inverse; } - if ($do_it_critical_min && $do_it_critical_max && $do_it_critical_inverse) { + if ($do_it_critical_min + && $do_it_critical_max + && $do_it_critical_inverse + ) { $red_threshold = $compare_critical; $threshold_data['red_threshold'] = $compare_critical; - $threshold_data['red_up'] = $red_up; - $threshold_data['red_inverse'] = (bool) $red_inverse; + $threshold_data['red_up'] = $red_up; + $threshold_data['red_inverse'] = (bool) $red_inverse; } $params['threshold_data'] = $threshold_data; @@ -1571,9 +1698,12 @@ function graphic_combined_module( foreach ($module_list as $module_item) { $automatic_custom_graph_meta = false; if ($config['metaconsole']) { - // Automatic custom graph from the report template in metaconsole + // Automatic custom graph from the report + // template in metaconsole. if (is_array($module_list[$i])) { - $server = metaconsole_get_connection_by_id($module_item['server']); + $server = metaconsole_get_connection_by_id( + $module_item['server'] + ); metaconsole_connect($server); $automatic_custom_graph_meta = true; } @@ -1610,16 +1740,27 @@ function graphic_combined_module( $value = false; } - if (!empty($params_combined['labels']) && isset($params_combined['labels'][$module])) { + if (!empty($params_combined['labels']) + && isset($params_combined['labels'][$module]) + ) { $label = io_safe_input($params_combined['labels'][$module]); } else { - $alias = db_get_value('alias', 'tagente', 'id_agente', $temp[$module]['id_agente']); + $alias = db_get_value( + 'alias', + 'tagente', + 'id_agente', + $temp[$module]['id_agente'] + ); $label = $alias.': '.$temp[$module]['nombre']; } $temp[$module]['label'] = $label; $temp[$module]['value'] = $value; - $temp_max = reporting_get_agentmodule_data_max($module, $params['period'], $params['date']); + $temp_max = reporting_get_agentmodule_data_max( + $module, + $params['period'], + $params['date'] + ); if ($temp_max < 0) { $temp_max = 0; } @@ -1630,7 +1771,11 @@ function graphic_combined_module( $temp[$module]['max'] = ($temp_max === false) ? 0 : $temp_max; } - $temp_min = reporting_get_agentmodule_data_min($module, $params['period'], $params['date']); + $temp_min = reporting_get_agentmodule_data_min( + $module, + $params['period'], + $params['date'] + ); if ($temp_min < 0) { $temp_min = 0; } @@ -1638,7 +1783,8 @@ function graphic_combined_module( $temp[$module]['min'] = ($temp_min === false) ? 0 : $temp_min; if ($config['metaconsole']) { - // Automatic custom graph from the report template in metaconsole + // Automatic custom graph from the + // report template in metaconsole. if (is_array($module_list[0])) { metaconsole_restore_db(); } @@ -1663,7 +1809,12 @@ function graphic_combined_module( $color, $module_name_list, $long_index, - ui_get_full_url('images/image_problem_area_small.png', false, false, false), + ui_get_full_url( + 'images/image_problem_area_small.png', + false, + false, + false + ), '', '', $water_mark, @@ -1674,7 +1825,6 @@ function graphic_combined_module( $homeurl, $background_color ); - break; case CUSTOM_GRAPH_GAUGE: @@ -1683,9 +1833,12 @@ function graphic_combined_module( foreach ($module_list as $module_item) { $automatic_custom_graph_meta = false; if ($config['metaconsole']) { - // Automatic custom graph from the report template in metaconsole + // Automatic custom graph from + // the report template in metaconsole. if (is_array($module_list[$i])) { - $server = metaconsole_get_connection_by_id($module_item['server']); + $server = metaconsole_get_connection_by_id( + $module_item['server'] + ); metaconsole_connect($server); $automatic_custom_graph_meta = true; } @@ -1722,7 +1875,14 @@ function graphic_combined_module( $temp[$module]['label'] = ($params_combined['labels'][$module] != '') ? $params_combined['labels'][$module] : $temp[$module]['nombre']; $temp[$module]['value'] = $value; - $temp[$module]['label'] = ui_print_truncate_text($temp[$module]['label'], 'module_small', false, true, false, '..'); + $temp[$module]['label'] = ui_print_truncate_text( + $temp[$module]['label'], + 'module_small', + false, + true, + false, + '..' + ); if ($temp[$module]['unit'] == '%') { $temp[$module]['min'] = 0; @@ -1730,7 +1890,11 @@ function graphic_combined_module( } else { $min = $temp[$module]['min']; if ($temp[$module]['max'] == 0) { - $max = reporting_get_agentmodule_data_max($module, $params['period'], $params['date']); + $max = reporting_get_agentmodule_data_max( + $module, + $params['period'], + $params['date'] + ); } else { $max = $temp[$module]['max']; } @@ -1742,7 +1906,8 @@ function graphic_combined_module( $temp[$module]['gauge'] = uniqid('gauge_'); if ($config['metaconsole']) { - // Automatic custom graph from the report template in metaconsole + // Automatic custom graph from the report + // template in metaconsole. if (is_array($module_list[0])) { metaconsole_restore_db(); } @@ -1769,13 +1934,17 @@ function graphic_combined_module( $height, $color, $module_name_list, - ui_get_full_url('images/image_problem_area_small.png', false, false, false), + ui_get_full_url( + 'images/image_problem_area_small.png', + false, + false, + false + ), $config['fontpath'], $fixed_font_size, '', $homeurl ); - break; case CUSTOM_GRAPH_HBARS: @@ -1784,9 +1953,12 @@ function graphic_combined_module( foreach ($module_list as $module_item) { $automatic_custom_graph_meta = false; if ($config['metaconsole']) { - // Automatic custom graph from the report template in metaconsole + // Automatic custom graph from the report + // template in metaconsole. if (is_array($module_list[$i])) { - $server = metaconsole_get_connection_by_id($module_item['server']); + $server = metaconsole_get_connection_by_id( + $module_item['server'] + ); metaconsole_connect($server); $automatic_custom_graph_meta = true; } @@ -1815,17 +1987,25 @@ function graphic_combined_module( modules_get_agentmodule_agent_name($module) ); - if (!empty($params_combined['labels']) && isset($params_combined['labels'][$module])) { + if (!empty($params_combined['labels']) + && isset($params_combined['labels'][$module]) + ) { $label = $params_combined['labels'][$module]; } else { - $alias = db_get_value('alias', 'tagente', 'id_agente', $module_data['id_agente']); + $alias = db_get_value( + 'alias', + 'tagente', + 'id_agente', + $module_data['id_agente'] + ); $label = $alias.' - '.$module_data['nombre']; } $temp[$label]['g'] = round($temp_data, 4); if ($config['metaconsole']) { - // Automatic custom graph from the report template in metaconsole + // Automatic custom graph from the report + // template in metaconsole. if (is_array($module_list[0])) { metaconsole_restore_db(); } @@ -1849,7 +2029,12 @@ function graphic_combined_module( $color, $module_name_list, $long_index, - ui_get_full_url('images/image_problem_area_small.png', false, false, false), + ui_get_full_url( + 'images/image_problem_area_small.png', + false, + false, + false + ), '', '', $water_mark, @@ -1871,7 +2056,12 @@ function graphic_combined_module( $color, $module_name_list, $long_index, - ui_get_full_url('images/image_problem_area_small.png', false, false, false), + ui_get_full_url( + 'images/image_problem_area_small.png', + false, + false, + false + ), '', '', $water_mark, @@ -1893,9 +2083,12 @@ function graphic_combined_module( foreach ($module_list as $module_item) { $automatic_custom_graph_meta = false; if ($config['metaconsole']) { - // Automatic custom graph from the report template in metaconsole + // Automatic custom graph from the report + // template in metaconsole. if (is_array($module_list[$i])) { - $server = metaconsole_get_connection_by_id($module_item['server']); + $server = metaconsole_get_connection_by_id( + $module_item['server'] + ); metaconsole_connect($server); $automatic_custom_graph_meta = true; } @@ -1934,10 +2127,19 @@ function graphic_combined_module( $total_modules += $value; - if (!empty($params_combined['labels']) && isset($params_combined['labels'][$module])) { - $label = io_safe_output($params_combined['labels'][$module]); + if (!empty($params_combined['labels']) + && isset($params_combined['labels'][$module]) + ) { + $label = io_safe_output( + $params_combined['labels'][$module] + ); } else { - $alias = db_get_value('alias', 'tagente', 'id_agente', $data_module['id_agente']); + $alias = db_get_value( + 'alias', + 'tagente', + 'id_agente', + $data_module['id_agente'] + ); $label = io_safe_output($alias.': '.$data_module['nombre']); } @@ -1946,7 +2148,8 @@ function graphic_combined_module( 'unit' => $data_module['unit'], ]; if ($config['metaconsole']) { - // Automatic custom graph from the report template in metaconsole + // Automatic custom graph from the report + // template in metaconsole. if (is_array($module_list[0])) { metaconsole_restore_db(); } @@ -1979,7 +2182,6 @@ function graphic_combined_module( false, $background_color ); - break; } @@ -1991,8 +2193,24 @@ function graphic_combined_module( } -function combined_graph_summatory_average($array_data, $average=false, $summatory=false, $modules_series=false, $baseline=false) -{ +/** + * Function for convert data summatory. + * + * @param array $array_data Data array. + * @param boolean $average Average. + * @param boolean $summatory Summatory. + * @param boolean $modules_series Series module. + * @param boolean $baseline Baseline data. + * + * @return array Data. + */ +function combined_graph_summatory_average( + $array_data, + $average=false, + $summatory=false, + $modules_series=false, + $baseline=false +) { if (isset($array_data) && is_array($array_data)) { foreach ($array_data as $key => $value) { if (strpos($key, 'sum') !== false) { @@ -2010,10 +2228,13 @@ function combined_graph_summatory_average($array_data, $average=false, $summator $data_array_pop = []; $count = 0; - while (count($data_array_reverse['sum0']) > 0) { + $count_data_array_reverse = count($data_array_reverse['sum0']); + while ($count_data_array_reverse > 0) { foreach ($data_array_reverse as $key_reverse => $value_reverse) { if (is_array($value_reverse) && count($value_reverse) > 0) { - $data_array_pop[$key_reverse] = array_pop($data_array_reverse[$key_reverse]); + $data_array_pop[$key_reverse] = array_pop( + $data_array_reverse[$key_reverse] + ); } } @@ -2067,12 +2288,18 @@ function combined_graph_summatory_average($array_data, $average=false, $summator $count++; } - if ($summatory && isset($array_sum_reverse) && is_array($array_sum_reverse) && count($array_sum_reverse) > 0) { + if ($summatory && isset($array_sum_reverse) + && is_array($array_sum_reverse) + && count($array_sum_reverse) > 0 + ) { $array_data['summatory']['data'] = $array_sum_reverse; $array_data['summatory']['color'] = 'purple'; } - if ($average && isset($array_avg_reverse) && is_array($array_avg_reverse) && count($array_avg_reverse) > 0) { + if ($average && isset($array_avg_reverse) + && is_array($array_avg_reverse) + && count($array_avg_reverse) > 0 + ) { if ($baseline) { $array_data['baseline']['data'] = $array_avg_reverse; $array_data['baseline']['color'] = 'green'; @@ -2093,19 +2320,28 @@ function combined_graph_summatory_average($array_data, $average=false, $summator /** * Print a graph with access data of agents * - * @param integer id_agent Agent ID - * @param integer width pie graph width - * @param integer height pie graph height - * @param integer period time period - * @param bool return or echo the result flag + * @param integer $id_agent Agent ID. + * @param integer $width Pie graph width. + * @param integer $height Pie graph height. + * @param integer $period Time period. + * @param boolean $return Return. + * @param boolean $tree View tree. + * + * @return string Return or echo the result flag. */ -function graphic_agentaccess($id_agent, $width, $height, $period=0, $return=false, $tree=false) -{ +function graphic_agentaccess( + $id_agent, + $width, + $height, + $period=0, + $return=false, + $tree=false +) { global $config; global $graphic_type; - $date = get_system_time(); - $datelimit = ($date - $period); + $date = get_system_time(); + $datelimit = ($date - $period); $data_array = []; $data = db_get_all_rows_sql( @@ -2135,7 +2371,12 @@ function graphic_agentaccess($id_agent, $width, $height, $period=0, $return=fals if ($config['fixed_graph'] == false) { $water_mark = [ 'file' => $config['homedir'].'/images/logo_vertical_water.png', - 'url' => ui_get_full_url('images/logo_vertical_water.png', false, false, false), + 'url' => ui_get_full_url( + 'images/logo_vertical_water.png', + false, + false, + false + ), ]; } @@ -2238,7 +2479,7 @@ function truncate_negatives(&$element) * @param bool return or echo flag * @param bool show_not_init flag */ -function graph_agent_status($id_agent=false, $width=300, $height=200, $return=false, $show_not_init=false, $data_agents=false) +function graph_agent_status($id_agent=false, $width=300, $height=200, $return=false, $show_not_init=false, $data_agents=false, $donut_narrow_graph=false) { global $config; @@ -2304,25 +2545,37 @@ function graph_agent_status($id_agent=false, $width=300, $height=200, $return=fa $data = []; } - $out = pie_graph( - $data, - $width, - $height, - __('other'), - ui_get_full_url(false, false, false, false), - '', - $config['fontpath'], - $config['font_size'], - 1, - 'hidden', - $colors, - 0 - ); - - if ($return) { + if ($donut_narrow_graph == true) { + $data_total = array_sum($data); + $out = print_donut_narrow_graph( + $colors, + $width, + $height, + $data, + $data_total + ); return $out; } else { - echo $out; + $out = pie_graph( + $data, + $width, + $height, + __('other'), + ui_get_full_url(false, false, false, false), + '', + $config['fontpath'], + $config['font_size'], + 1, + 'hidden', + $colors, + 0 + ); + + if ($return) { + return $out; + } else { + echo $out; + } } } @@ -3679,7 +3932,14 @@ function graph_graphic_moduleevents($id_agent, $id_module, $width, $height, $per } -// Prints an error image +/** + * Function for retun image no data. + * + * @param integer $width Width. + * @param integer $height Height. + * + * @return string Image. + */ function fs_error_image($width=300, $height=110) { global $config; @@ -3687,15 +3947,29 @@ function fs_error_image($width=300, $height=110) } +/** + * Function for uncompressed data module for cherts. + * + * @param integer $agent_module_id Id modulo. + * @param array $date_array Date start, finish, period. + * @param integer $show_unknown Show Unknown. + * @param integer $show_percentil Show Percentil. + * @param integer $series_suffix Series. + * @param boolean $compare Type compare. + * @param boolean $data_slice Size slice. + * @param string $type_mode_graph Type. + * + * @return array Return array data uncompresess. + */ function fullscale_data( $agent_module_id, $date_array, $show_unknown=0, $show_percentil=0, - $series_suffix, + $series_suffix=0, $compare=false, $data_slice=false, - $type_mode_graph + $type_mode_graph='' ) { global $config; $data_uncompress = db_uncompress_module_data( @@ -3707,218 +3981,234 @@ function fullscale_data( $data = []; $previous_data = 0; - // normal + // Normal. $min_value_total = PHP_INT_MAX; - $max_value_total = -PHP_INT_MAX; - // max + $max_value_total = (-PHP_INT_MAX); + // Max. $max_value_min = PHP_INT_MAX; - $max_value_max = -PHP_INT_MAX; - // min + $max_value_max = (-PHP_INT_MAX); + // Min. $min_value_min = PHP_INT_MAX; - $min_value_max = -PHP_INT_MAX; - // avg + $min_value_max = (-PHP_INT_MAX); + // Avg. $avg_value_min = PHP_INT_MAX; - $avg_value_max = -PHP_INT_MAX; + $avg_value_max = (-PHP_INT_MAX); $flag_unknown = 0; $array_percentil = []; if ($data_slice) { - foreach ($data_uncompress as $k) { - $sum_data = 0; - $count_data = 0; - $min_value = PHP_INT_MAX; - $max_value = -PHP_INT_MAX; - $flag_virtual_data = 0; - foreach ($k['data'] as $v) { - if (isset($v['type']) && $v['type'] == 1) { - // skip unnecesary virtual data - continue; - $flag_virtual_data = 1; - } + if (isset($data_uncompress) === true + && is_array($data_uncompress) === true + ) { + foreach ($data_uncompress as $k) { + $sum_data = 0; + $count_data = 0; + $min_value = PHP_INT_MAX; + $max_value = (-PHP_INT_MAX); + $flag_virtual_data = 0; + foreach ($k['data'] as $v) { + if (isset($v['type']) && $v['type'] == 1) { + // Skip unnecesary virtual data. + continue; + $flag_virtual_data = 1; + } - if ($compare) { - // * 1000 need js utimestam mlsecond - $real_date = (($v['utimestamp'] + $date_array['period']) * 1000); - } else { - $real_date = ($v['utimestamp'] * 1000); - } + if ($compare) { + // Data * 1000 need js utimestam mlsecond. + $real_date = (($v['utimestamp'] + $date_array['period']) * 1000); + } else { + $real_date = ($v['utimestamp'] * 1000); + } - if ($v['datos'] === null) { - // Unknown - if ($show_unknown) { - if (!$compare) { - if ($flag_unknown) { - $data['unknown'.$series_suffix]['data'][] = [ - $real_date, - 1, - ]; - } else { - $data['unknown'.$series_suffix]['data'][] = [ - ($real_date - 1), - 0, - ]; - $data['unknown'.$series_suffix]['data'][] = [ - $real_date, - 1, - ]; - $flag_unknown = 1; + if ($v['datos'] === null) { + // Unknown. + if ($show_unknown) { + if (!$compare) { + if ($flag_unknown) { + $data['unknown'.$series_suffix]['data'][] = [ + $real_date, + 1, + ]; + } else { + $data['unknown'.$series_suffix]['data'][] = [ + ($real_date - 1), + 0, + ]; + $data['unknown'.$series_suffix]['data'][] = [ + $real_date, + 1, + ]; + $flag_unknown = 1; + } + } + } + + $v['datos'] = $previous_data; + } else { + // Normal. + $previous_data = $v['datos']; + if ($show_unknown) { + if (!$compare) { + if ($flag_unknown) { + $data['unknown'.$series_suffix]['data'][] = [ + $real_date, + 0, + ]; + $flag_unknown = 0; + } } } } - $v['datos'] = $previous_data; - } else { - // normal - $previous_data = $v['datos']; - if ($show_unknown) { - if (!$compare) { - if ($flag_unknown) { - $data['unknown'.$series_suffix]['data'][] = [ - $real_date, - 0, - ]; - $flag_unknown = 0; - } + if (isset($v['datos']) && $v['datos']) { + // Max. + if ($v['datos'] >= $max_value) { + $max_value = $v['datos']; + } + + // Min. + if ($v['datos'] <= $min_value) { + $min_value = $v['datos']; + } + + // Avg sum. + $sum_data += $v['datos']; + } + + // Avg count. + $count_data++; + + if ($show_percentil && !$compare) { + $array_percentil[] = $v['datos']; + } + + $last_data = $v['datos']; + } + + if (!$flag_virtual_data) { + if ($compare) { + // Data * 1000 need js utimestam mlsecond. + $real_date = (($k['data'][0]['utimestamp'] + $date_array['period']) * 1000); + } else { + $real_date = ($k['data'][0]['utimestamp'] * 1000); + } + + $data['sum'.$series_suffix]['data'][] = [ + $real_date, + ($sum_data / $count_data), + ]; + if ($type_mode_graph && !$params['baseline']) { + if ($min_value != PHP_INT_MAX) { + $data['min'.$series_suffix]['data'][] = [ + $real_date, + $min_value, + ]; + } + + if ($max_value != (-PHP_INT_MAX)) { + $data['max'.$series_suffix]['data'][] = [ + $real_date, + $max_value, + ]; + } + } else { + if ($min_value != PHP_INT_MAX) { + $data['sum'.$series_suffix]['slice_data'][$real_date]['min'] = $min_value; + } + + $data['sum'.$series_suffix]['slice_data'][$real_date]['avg'] = ($sum_data / $count_data); + + if ($max_value != (-PHP_INT_MAX)) { + $data['sum'.$series_suffix]['slice_data'][$real_date]['max'] = $max_value; } } - } - if (isset($v['datos']) && $v['datos']) { - // max - if ($v['datos'] >= $max_value) { - $max_value = $v['datos']; + // Max total. + if ($max_value >= $max_value_total + && $max_value != (-PHP_INT_MAX) + ) { + $max_value_total = $max_value; } - // min - if ($v['datos'] <= $min_value) { - $min_value = $v['datos']; + // Min total. + if ($min_value <= $min_value_total + && $min_value != PHP_INT_MAX + ) { + $min_value_total = $min_value; } - // avg sum - $sum_data += $v['datos']; - } + // Avg sum total. + $sum_data_total += ($sum_data / $count_data); - // avg count - $count_data++; + // Avg count total. + $count_data_total++; - if ($show_percentil && !$compare) { - $array_percentil[] = $v['datos']; - } + if ($type_mode_graph && !$params['baseline']) { + // MIN. + // max min. + if ($min_value >= $min_value_max + && $min_value != PHP_INT_MAX + ) { + $min_value_max = $min_value; + } - $last_data = $v['datos']; - } + // Min min. + if ($min_value <= $min_value_min + && $min_value != PHP_INT_MAX + ) { + $min_value_min = $min_value; + } - if (!$flag_virtual_data) { - if ($compare) { - // * 1000 need js utimestam mlsecond - $real_date = (($k['data'][0]['utimestamp'] + $date_array['period']) * 1000); - } else { - $real_date = ($k['data'][0]['utimestamp'] * 1000); - } + // Avg sum min. + if ($min_value != PHP_INT_MAX) { + $sum_data_min += $min_value; + } - $data['sum'.$series_suffix]['data'][] = [ - $real_date, - ($sum_data / $count_data), - ]; - if ($type_mode_graph && !$params['baseline']) { - if ($min_value != PHP_INT_MAX) { - $data['min'.$series_suffix]['data'][] = [ - $real_date, - $min_value, - ]; + // MAX. + // Max max. + if ($max_value >= $max_value_max + && $max_value != (-PHP_INT_MAX) + ) { + $max_value_max = $max_value; + } + + // Min max. + if ($max_value <= $max_value_min + && $max_value != (-PHP_INT_MAX) + ) { + $max_value_min = $max_value; + } + + // Avg Sum max. + if ($max_value != (-PHP_INT_MAX)) { + $sum_data_max += $max_value; + } + + // AVG. + // Max max. + if (($sum_data / $count_data) >= $avg_value_max) { + $avg_value_max = ($sum_data / $count_data); + } + + // Min max. + if (($sum_data / $count_data) <= $avg_value_min) { + $avg_value_min = ($sum_data / $count_data); + } + + // Avg sum max. + $sum_data_avg += ($sum_data / $count_data); } - - if ($max_value != -PHP_INT_MAX) { - $data['max'.$series_suffix]['data'][] = [ - $real_date, - $max_value, - ]; - } - } else { - if ($min_value != PHP_INT_MAX) { - $data['sum'.$series_suffix]['slice_data'][$real_date]['min'] = $min_value; - } - - $data['sum'.$series_suffix]['slice_data'][$real_date]['avg'] = ($sum_data / $count_data); - - if ($max_value != -PHP_INT_MAX) { - $data['sum'.$series_suffix]['slice_data'][$real_date]['max'] = $max_value; - } - } - - // max_total - if ($max_value >= $max_value_total && $max_value != -PHP_INT_MAX) { - $max_value_total = $max_value; - } - - // min_total - if ($min_value <= $min_value_total && $min_value != PHP_INT_MAX) { - $min_value_total = $min_value; - } - - // avg sum_total - $sum_data_total += ($sum_data / $count_data); - - // avg count_total - $count_data_total++; - - if ($type_mode_graph && !$params['baseline']) { - /* - MIN*/ - // max_min - if ($min_value >= $min_value_max && $min_value != PHP_INT_MAX) { - $min_value_max = $min_value; - } - - // min_min - if ($min_value <= $min_value_min && $min_value != PHP_INT_MAX) { - $min_value_min = $min_value; - } - - // avg sum_min - if ($min_value != PHP_INT_MAX) { - $sum_data_min += $min_value; - } - - /* - MAX*/ - // max_max - if ($max_value >= $max_value_max && $max_value != -PHP_INT_MAX) { - $max_value_max = $max_value; - } - - // min_max - if ($max_value <= $max_value_min && $max_value != -PHP_INT_MAX) { - $max_value_min = $max_value; - } - - // avg sum_max - if ($max_value != -PHP_INT_MAX) { - $sum_data_max += $max_value; - } - - /* - AVG*/ - // max_max - if (($sum_data / $count_data) >= $avg_value_max) { - $avg_value_max = ($sum_data / $count_data); - } - - // min_max - if (($sum_data / $count_data) <= $avg_value_min) { - $avg_value_min = ($sum_data / $count_data); - } - - // avg sum_max - $sum_data_avg += ($sum_data / $count_data); } } } $data['sum'.$series_suffix]['min'] = $min_value_total; $data['sum'.$series_suffix]['max'] = $max_value_total; - $data['sum'.$series_suffix]['avg'] = ($sum_data_total / $count_data_total); + $data['sum'.$series_suffix]['avg'] = 0; + if (isset($count_data_total) === true) { + $data['sum'.$series_suffix]['avg'] = ($sum_data_total / $count_data_total); + } if ($type_mode_graph && !$params['baseline']) { $data['min'.$series_suffix]['min'] = $min_value_min; @@ -3941,19 +4231,19 @@ function fullscale_data( foreach ($data_uncompress as $k) { foreach ($k['data'] as $v) { if (isset($v['type']) && $v['type'] == 1) { - // skip unnecesary virtual data + // Skip unnecesary virtual data. continue; } if ($compare) { - // * 1000 need js utimestam mlsecond + // Data * 1000 need js utimestam mlsecond. $real_date = (($v['utimestamp'] + $date_array['period']) * 1000); } else { $real_date = ($v['utimestamp'] * 1000); } if ($v['datos'] === null) { - // Unknown + // Unknown. if ($show_unknown) { if (!$compare) { if ($flag_unknown) { @@ -3980,7 +4270,7 @@ function fullscale_data( $previous_data, ]; } else { - // normal + // Normal. $previous_data = $v['datos']; $data['sum'.$series_suffix]['data'][] = [ $real_date, @@ -4000,21 +4290,21 @@ function fullscale_data( } if (isset($v['datos']) && $v['datos']) { - // max + // Max. if ((float) $v['datos'] >= $max_value_max) { $max_value_max = $v['datos']; } - // min + // Min. if ((float) $v['datos'] <= $min_value_min) { $min_value_min = $v['datos']; } - // avg sum + // Avg sum. $sum_data += $v['datos']; } - // avg count + // Avg count. $count_data++; if ($show_percentil && !$compare) { @@ -4027,7 +4317,7 @@ function fullscale_data( $data['sum'.$series_suffix]['min'] = $min_value_min; $data['sum'.$series_suffix]['max'] = $max_value_max; - $data['sum'.$series_suffix]['avg'] = $count_data == 0 ? 0 : ($sum_data / $count_data); + $data['sum'.$series_suffix]['avg'] = ($count_data == 0) ? 0 : ($sum_data / $count_data); } if ($show_percentil && !$compare) { @@ -4053,7 +4343,7 @@ function fullscale_data( } } - // Add missed last data + // Add missed last data. if ($compare) { $data['sum'.$series_suffix]['data'][] = [ (($date_array['final_date'] + $date_array['period']) * 1000), @@ -4076,7 +4366,11 @@ function fullscale_data( ]; } else { $data['sum'.$series_suffix]['slice_data'][($date_array['final_date'] * 1000)]['min'] = $min_value; - $data['sum'.$series_suffix]['slice_data'][($date_array['final_date'] * 1000)]['avg'] = ($sum_data / $count_data); + $data['sum'.$series_suffix]['slice_data'][($date_array['final_date'] * 1000)]['avg'] = 0; + if (isset($count_data) === true) { + $data['sum'.$series_suffix]['slice_data'][($date_array['final_date'] * 1000)]['avg'] = ($sum_data / $count_data); + } + $data['sum'.$series_suffix]['slice_data'][($date_array['final_date'] * 1000)]['max'] = $max_value; } } @@ -4089,7 +4383,7 @@ function fullscale_data( /** * Print an area graph with netflow aggregated */ -function graph_netflow_aggregate_area($data, $period, $width, $height, $unit='', $ttl=1, $only_image=false) +function graph_netflow_aggregate_area($data, $period, $width, $height, $ttl=1, $only_image=false, $date=null) { global $config; global $graphic_type; @@ -4099,7 +4393,7 @@ function graph_netflow_aggregate_area($data, $period, $width, $height, $unit='', return; } - // Calculate source indexes + // Calculate source indexes. foreach ($data['sources'] as $key => $value) { $i = 0; foreach ($data['data'] as $k => $v) { @@ -4118,7 +4412,12 @@ function graph_netflow_aggregate_area($data, $period, $width, $height, $unit='', if ($config['fixed_graph'] == false) { $water_mark = [ 'file' => $config['homedir'].'/images/logo_vertical_water.png', - 'url' => ui_get_full_url('images/logo_vertical_water.png', false, false, false), + 'url' => ui_get_full_url( + 'images/logo_vertical_water.png', + false, + false, + false + ), ]; $water_mark = $config['homedir'].'/images/logo_vertical_water.png'; @@ -4135,7 +4434,7 @@ function graph_netflow_aggregate_area($data, $period, $width, $height, $unit='', 'period' => $period, 'width' => '90%', 'height' => 450, - 'unit' => $unit, + 'unit' => 'bytes', 'only_image' => $only_image, 'homeurl' => $homeurl, 'menu' => true, @@ -4144,6 +4443,10 @@ function graph_netflow_aggregate_area($data, $period, $width, $height, $unit='', 'font' => $config['fontpath'], 'font_size' => $config['font_size'], 'array_data_create' => $chart, + 'stacked' => 1, + 'date' => $date, + 'show_export_csv' => false, + 'show_overview' => false, ]; return grafico_modulo_sparse($params); @@ -4265,9 +4568,16 @@ function graph_netflow_aggregate_pie($data, $aggregate, $ttl=1, $only_image=fals /** - * Print a circular graph with the data transmitted between IPs + * Print a circular mesh array. + * + * @param array $data Array with properly data structure. Array with two + * elements required: + * 'elements': Non-associative array with all the relationships. + * 'matrix': Array of arrays with value of the relationship. + * + * @return string HTML data. */ -function graph_netflow_circular_mesh($data, $unit, $radius=700) +function graph_netflow_circular_mesh($data) { global $config; @@ -4277,14 +4587,14 @@ function graph_netflow_circular_mesh($data, $unit, $radius=700) include_once $config['homedir'].'/include/graphs/functions_d3.php'; - return d3_relationship_graph($data['elements'], $data['matrix'], $unit, $radius, true); + return d3_relationship_graph($data['elements'], $data['matrix'], 700, true); } /** * Print a rectangular graph with the traffic of the ports for each IP */ -function graph_netflow_host_traffic($data, $unit, $width=700, $height=700) +function graph_netflow_host_traffic($data, $width=700, $height=700) { global $config; @@ -4913,26 +5223,38 @@ function graph_monitor_wheel($width=550, $height=600, $filter=false) } -function get_baseline_data($agent_module_id, $date_array, $data_module_graph, $params) -{ +/** + * Function that on a date requests 3 times that period and takes an average. + * + * @param integer $agent_module_id ID module. + * @param array $date_array Date array start finish period. + * @param array $data_module_graph Data module. + * @param array $params Params. + * + * @return array Data baseline graph. + */ +function get_baseline_data( + $agent_module_id, + $date_array, + $data_module_graph, + $params +) { $period = $date_array['period']; $date = $date_array['final_date']; $array_data = []; + for ($i = 0; $i < 4; $i++) { $date_array = []; $date_array['period'] = $period; - $date_array['final_date'] = ($date - $period * $i); - $date_array['start_date'] = ($date - $period * ($i + 1)); - - $data = grafico_modulo_sparse_data( + $date_array['final_date'] = ($date - ($period * $i)); + $date_array['start_date'] = ($date - ($period * ($i + 1))); + $array_data[] = grafico_modulo_sparse_data( $agent_module_id, $date_array, $data_module_graph, $params, $i ); - - $array_data[] = $data; } $result = []; @@ -4955,8 +5277,18 @@ function get_baseline_data($agent_module_id, $date_array, $data_module_graph, $p } $result['avg'] = (($array_data[0]['sum0']['avg'] + $array_data[1]['sum1']['avg'] + $array_data[2]['sum2']['avg'] + $array_data[3]['sum3']['avg']) / 4); - $result['max'] = max($array_data[0]['sum0']['max'], $array_data[1]['sum1']['max'], $array_data[2]['sum2']['max'], $array_data[3]['sum3']['max']); - $result['min'] = min($array_data[0]['sum0']['min'], $array_data[1]['sum1']['min'], $array_data[2]['sum2']['min'], $array_data[3]['sum3']['min']); + $result['max'] = max( + $array_data[0]['sum0']['max'], + $array_data[1]['sum1']['max'], + $array_data[2]['sum2']['max'], + $array_data[3]['sum3']['max'] + ); + $result['min'] = min( + $array_data[0]['sum0']['min'], + $array_data[1]['sum1']['min'], + $array_data[2]['sum2']['min'], + $array_data[3]['sum3']['min'] + ); $result['agent_module_id'] = $array_data[0]['sum0']['agent_module_id']; $result['id_module_type'] = $array_data[0]['sum0']['id_module_type']; diff --git a/pandora_console/include/functions_html.php b/pandora_console/include/functions_html.php index 9c6819d535..010845caf6 100644 --- a/pandora_console/include/functions_html.php +++ b/pandora_console/include/functions_html.php @@ -20,19 +20,19 @@ if (!isset($config)) { $working_dir = getcwd(); $working_dir = str_replace('\\', '/', $working_dir); - // Windows compatibility + // Windows compatibility. $levels = substr_count($working_dir, '/'); for ($i = 0; $i < $levels; $i++) { if (file_exists(str_repeat('../', $i).'config.php')) { include_once str_repeat('../', $i).'config.php'; break; - // Skip config.php loading after load the first one + // Skip config.php loading after load the first one. } else if (file_exists(str_repeat('../', $i).'include/config.php')) { // For path from the enterprise structure dirs. include_once str_repeat('../', $i).'include/config.php'; break; - // Skip config.php loading after load the first one + // Skip config.php loading after load the first one. } } } else { @@ -436,7 +436,9 @@ function html_print_select_groups( $keys_field='id_grupo', $strict_user=false, $delete_groups=false, - $include_groups=false + $include_groups=false, + $size=false, + $simple_multiple_options=false ) { global $config; @@ -481,7 +483,12 @@ function html_print_select_groups( $class, $disabled, $style, - $option_style + $option_style, + $size, + false, + '', + false, + $simple_multiple_options ); if ($return) { @@ -529,7 +536,8 @@ function html_print_select( $size=false, $modal=false, $message='', - $select_all=false + $select_all=false, + $simple_multiple_options=false ) { $output = "\n"; @@ -557,6 +565,14 @@ function html_print_select( } } + if ($simple_multiple_options === true) { + if ($size !== false) { + $attributes .= ' size="'.$size.'"'; + } else { + $attributes .= ' size="10"'; + } + } + if (!empty($class)) { $attributes .= ' class="'.$class.'"'; } @@ -644,7 +660,7 @@ function html_print_select( } if ($optlabel === '') { - $output .= '>'.$value.''; + $output .= '>None'; } else { $output .= '>'.$optlabel.''; } @@ -1060,10 +1076,10 @@ function html_print_extended_select_for_time( 'images/pencil.png', true, [ - 'class' => $uniq_name.'_toggler', + 'class' => $uniq_name.'_toggler '.$class, 'alt' => __('Custom'), 'title' => __('Custom'), - 'style' => 'width: 18px;'.$style_icon, + 'style' => 'width: 18px; margin-bottom: -5px;'.$style_icon, ], false, false, @@ -1098,7 +1114,7 @@ function html_print_extended_select_for_time( 'class' => $uniq_name.'_toggler', 'alt' => __('List'), 'title' => __('List'), - 'style' => 'width: 18px;'.$style_icon, + 'style' => 'width: 18px;margin-bottom: -5px;'.$style_icon, ] ).'
'; echo '
'; @@ -1774,7 +1790,7 @@ function html_print_button($label='OK', $name='', $disabled=false, $script='', $ */ function html_print_textarea($name, $rows, $columns, $value='', $attributes='', $return=false, $class='') { - $output = ''; @@ -2307,7 +2323,7 @@ function html_print_checkbox($name, $value, $checked=false, $return=false, $disa /** - * Render a checkbox button input toogle switch type. Extended version, use html_print_checkbox_toogle_switch() to simplify. + * Render a checkbox button input switch type. Extended version, use html_print_checkbox_switch() to simplify. * * @param string Input name. * @param string Input value. @@ -2321,7 +2337,7 @@ function html_print_checkbox($name, $value, $checked=false, $return=false, $disa */ -function html_print_checkbox_toogle_switch_extended($name, $value, $checked, $disabled, $script, $attributes, $return=false, $id='') +function html_print_checkbox_switch_extended($name, $value, $checked, $disabled, $script, $attributes, $return=false, $id='') { static $idcounter = []; @@ -2334,7 +2350,7 @@ function html_print_checkbox_toogle_switch_extended($name, $value, $checked, $di $id_aux = preg_replace('/[^a-z0-9\:\;\-\_]/i', '', $name.($idcounter[$name] ? $idcounter[$name] : '')); - $output = '
+
'.html_print_image($img_node, true, false, false, true).'
'.$name.'
>, + shape="doublecircle", + tooltip="ajax.php?page=operation/agentes/ver_agente&get_agent_status_tooltip=1&id_agent='.$node['id'].'"];'; + + return $result; +} + + +/** + * Returns an edge definition. + * + * @param string $head Origin. + * @param string $tail Target. + * + * @return string Edge str. + */ +function create_edge($head, $tail) +{ + // Token edgeURL allows node navigation. + $edge = $head.' -- '.$tail.'[color="#BDBDBD", headclip=false, tailclip=false];'."\n"; + + return $edge; +} + + +// Closes a graph definition +function close_graph() +{ + return '}'; +} + + +function loadfile_map($file='', $graph) +{ + global $config; + + $networkmap_nodes = []; + + $relations = []; + + $other_file = file($file); + $graph = explode(']', $graph); + + $ids = []; + foreach ($graph as $node) { + $line = str_replace("\n", ' ', $node); + if (preg_match('/([0-9]+) \[.*tooltip.*id_agent=([0-9]+)/', $line, $match) != 0) { + $ids[$match[1]] = ['id_agent' => $match[2]]; + } + } + + foreach ($other_file as $key => $line) { + $line = preg_replace('/[ ]+/', ' ', $line); + + $data = []; + + if (preg_match('/^node.*$/', $line) != 0) { + $items = explode(' ', $line); + $node_id = $items[1]; + $node_x = ($items[2] * 100); + // 200 is for show more big + $node_y = ($height_map - $items[3] * 100); + // 200 is for show more big + $data['id'] = $node_id; + $data['image'] = ''; + $data['width'] = 10; + $data['height'] = 10; + $data['id_agent'] = 0; + + if (preg_match('/ $line_orig, + 'dest' => $line_dest, + ]; + } + } + + return $networkmap_nodes; +} diff --git a/pandora_console/include/functions_menu.php b/pandora_console/include/functions_menu.php index 39e5adf455..0dbe1049bc 100644 --- a/pandora_console/include/functions_menu.php +++ b/pandora_console/include/functions_menu.php @@ -1,22 +1,40 @@ '; // Use $config because a global var is required because normal - // and godmode menu are painted separately + // and godmode menu are painted separately. if (!isset($config['count_main_menu'])) { $config['count_main_menu'] = 0; } @@ -75,7 +93,19 @@ function menu_print_menu(&$menu) } $submenu = false; - $classes = ['menu_icon']; + + if ($config['menu_type'] == 'classic') { + $classes = [ + 'menu_icon', + 'no_hidden_menu', + ]; + } else { + $classes = [ + 'menu_icon', + 'menu_icon_collapsed', + ]; + } + if (isset($main['sub'])) { $classes[] = ''; $submenu = true; @@ -98,7 +128,7 @@ function menu_print_menu(&$menu) if (! $submenu) { $main['sub'] = []; - // Empty array won't go through foreach + // Empty array won't go through foreach. } $submenu_output = ''; @@ -110,12 +140,12 @@ function menu_print_menu(&$menu) foreach ($main['sub'] as $subsec2 => $sub) { $count_sub++; - // Init some variables + // Init some variables. $visible = false; $selected = false; $subsec2 = io_safe_output($subsec2); - // Choose valid suboptions (sec2) + // Choose valid suboptions (sec2). $check_2 = true; if (isset($sub['sub2'])) { $check_2 = false; @@ -125,7 +155,7 @@ function menu_print_menu(&$menu) continue; } - // We store the first subsection to use it if the main section has not access + // We store the first subsection to use it if the main section has not access. if ($count_sub_access == 0) { $first_sub_sec2 = $subsec2; } @@ -145,7 +175,7 @@ function menu_print_menu(&$menu) $sec2 = ' '; } - // Check if some submenu was selected to mark this (the parent) as selected + // Check if some submenu was selected to mark this (the parent) as selected. foreach (array_keys($sub['sub2']) as $key) { if (strpos($key, $sec2) !== false) { $selected_submenu2 = true; @@ -154,13 +184,13 @@ function menu_print_menu(&$menu) } } - // Create godmode option if submenu has godmode on + // Create godmode option if submenu has godmode on. if (isset($sub['subsecs'])) { // Sometimes you need to add all paths because in the // same dir are code from visual console and reports - // for example + // for example. if (is_array($sub['subsecs'])) { - // Compare each string + // Compare each string. foreach ($sub['subsecs'] as $god_path) { if (strpos($sec2, $god_path) !== false) { $selected_submenu2 = true; @@ -168,19 +198,19 @@ function menu_print_menu(&$menu) } } } else { - // If there is only a string just compare + // If there is only a string just compare. if (strpos($sec2, $sub['subsecs']) !== false) { $selected_submenu2 = true; } } } - // Set class + // Set class. if (($sec2 == $subsec2 || $allsec2 == $subsec2 || $selected_submenu2) && isset($sub[$subsec2]['options']) && ( get_parameter_get($sub[$subsec2]['options']['name']) == $sub[$subsec2]['options']['value']) ) { - // If the subclass is selected and there are options and that options value is true + // If the subclass is selected and there are options and that options value is true. $class .= 'submenu_selected selected'; $menu_selected = true; $selected = true; @@ -201,7 +231,7 @@ function menu_print_menu(&$menu) $selected = true; $visible = true; } else { - // Else it's not selected + // Else it's not selected. $class .= 'submenu_not_selected'; } @@ -209,7 +239,7 @@ function menu_print_menu(&$menu) $sub['refr'] = 0; } - // Define submenu class to draw tree image + // Define submenu class to draw tree image. if ($count_sub >= count($main['sub'])) { $sub_tree_class = 'submenu_text submenu_text_last'; } else { @@ -217,7 +247,7 @@ function menu_print_menu(&$menu) } if (isset($sub['type']) && $sub['type'] == 'direct') { - // This is an external link + // This is an external link. $submenu_output .= '
  • '; if (isset($sub['subtype']) && $sub['subtype'] == 'nolink') { @@ -228,7 +258,7 @@ function menu_print_menu(&$menu) $submenu_output .= '
    '.$sub['text'].'
    '; } } else { - // This is an internal link + // This is an internal link. if (isset($sub[$subsec2]['options'])) { $link_add = '&'.$sub[$subsec2]['options']['name'].'='.$sub[$subsec2]['options']['value']; } else { @@ -237,7 +267,7 @@ function menu_print_menu(&$menu) $submenu_output .= '
  • '; - // Ini Add icon extension + // Ini Add icon extension. $secExtension = null; if (array_key_exists('extension', $sub)) { $secExtensionBool = $sub['extension']; @@ -245,7 +275,7 @@ function menu_print_menu(&$menu) $secExtensionBool = false; } - // DISABLE SUBMENU IMAGES + // DISABLE SUBMENU IMAGES. $secExtensionBool = false; if ($secExtensionBool) { @@ -298,7 +328,7 @@ function menu_print_menu(&$menu) } } - // Print second level submenu + // Print second level submenu. if (isset($sub['sub2'])) { $submenu2_list = ''; @@ -324,7 +354,7 @@ function menu_print_menu(&$menu) $class .= ' selected'; } - // Define submenu2 class to draw tree image + // Define submenu2 class to draw tree image. if ($count_sub2 >= count($sub['sub2'])) { $sub_tree_class = 'submenu_text submenu2_text_last'; } else { @@ -342,11 +372,8 @@ function menu_print_menu(&$menu) $sub_title = ''; } - // Added a top on inline styles - $top = menu_calculate_top($config['count_main_menu'], $count_sub, $count_sub2); - - // Add submenu2 to submenu string - $submenu_output .= '
  • '; } @@ -510,9 +541,7 @@ function menu_add_extras(&$menu) $menu_extra['workspace']['sub']['operation/incidents/incident_detail']['text'] = __('Manage incident'); - $menu_extra['reporting']['sub']['godmode/reporting/visual_console_builder']['text'] = __('Manage visual console'); - - // Duplicate extensions as sec=extension to check it from url + // Duplicate extensions as sec=extension to check it from url. foreach ($menu as $k => $m) { if (!isset($m['sub'])) { continue; @@ -556,7 +585,7 @@ function menu_get_sec($with_categories=false) if ($with_categories) { if (!$in_godmode && $k[0] == 'g') { // Hack to dont confuse with gis activated because godmode - // sec starts with g (like gismaps) + // sec starts with g (like gismaps). if ($k != 'gismaps') { $in_godmode = true; } @@ -625,17 +654,17 @@ function menu_get_sec_pages($sec, $menu_hash=false) $sec2_array = []; if (isset($sec)) { - // Get the sec2 of the main section + // Get the sec2 of the main section. $sec2_array[$menu[$sec]['sec2']] = $menu[$sec]['text']; - // Get the sec2 of the subsections + // Get the sec2 of the subsections. foreach ($menu[$sec]['sub'] as $k => $v) { - // Avoid special cases of standalone windows + // Avoid special cases of standalone windows. if (preg_match('/^javascript:/', $k) || preg_match('/\.php/', $k)) { continue; } - // If this value has various parameters, we only get the first + // If this value has various parameters, we only get the first. $k = explode('&', $k); $k = $k[0]; @@ -643,12 +672,14 @@ function menu_get_sec_pages($sec, $menu_hash=false) } } + $sec2_array = array_unique($sec2_array); return $sec2_array; } /** * Get the pages in a section2 + * $menu * * @param string sec code * @param string menu hash. All the menu structure (For example @@ -668,8 +699,8 @@ function menu_get_sec2_pages($sec, $sec2, $menu_hash=false) $sec3_array = []; - if (isset($menu[$sec]['sub']) and isset($menu[$sec]['sub'][$sec2]['sub2'])) { - // Get the sec2 of the subsections + if (isset($menu[$sec]['sub']) && isset($menu[$sec]['sub'][$sec2]['sub2'])) { + // Get the sec2 of the subsections. foreach ($menu[$sec]['sub'][$sec2]['sub2'] as $k => $v) { $sec3_array[$k] = $v['text']; } @@ -691,7 +722,7 @@ function menu_sec2_in_sec($sec, $sec2) { $sec2_array = menu_get_sec_pages($sec); - // If this value has various parameters, we only get the first + // If this value has various parameters, we only get the first. $sec2 = explode('&', $sec2); $sec2 = $sec2[0]; @@ -707,7 +738,7 @@ function menu_sec3_in_sec2($sec, $sec2, $sec3) { $sec3_array = menu_get_sec2_pages($sec, $sec2, $menu_hash = false); - // If this value has various parameters, we only get the first + // If this value has various parameters, we only get the first. $sec3 = explode('&', $sec3); $sec3 = $sec3[0]; @@ -717,34 +748,3 @@ function menu_sec3_in_sec2($sec, $sec2, $sec3) return false; } - - -// Positionate the menu element. Added a negative top. -// 35px is the height of a menu item -function menu_calculate_top($level1, $level2, $level3=false) -{ - $level2--; - if ($level3 !== false) { - // If level3 is set, the position is calculated like box is in the center. - // wiouth considering level2 box can be moved. - $level3--; - $total = ($level1 + $level3); - $comp = $level3; - } else { - $total = ($level1 + $level2); - $comp = $level2; - } - - // Positionate in the middle - if ($total > 12 && (($total < 18) || (($level1 - $comp) <= 4))) { - return - ( floor($comp / 2) * 35); - } - - // Positionate in the bottom - if ($total >= 18) { - return (- $comp * 35); - } - - // return 0 by default - return 0; -} diff --git a/pandora_console/include/functions_messages.php b/pandora_console/include/functions_messages.php index 60f2d71172..1bc54c9c89 100644 --- a/pandora_console/include/functions_messages.php +++ b/pandora_console/include/functions_messages.php @@ -1,55 +1,150 @@ $usuario_origen, + 'subject' => $subject, + 'mensaje' => $mensaje, + 'id_source' => get_notification_source_id('message'), + 'timestamp' => get_system_time(), + ] + ); + + // Update URL + // Update targets. + if ($message_id !== false) { + $ret = message_set_targets( + $message_id, + $target_users, + $target_groups + ); + if ($ret === false) { + // Failed to deliver messages. Erase message and show error. + db_process_sql_delete( + 'tmensajes', + ['id_mensaje' => $message_id] + ); + return false; + } } - $values = []; - $values['id_usuario_origen'] = $usuario_origen; - $values['id_usuario_destino'] = $usuario_destino; - $values['subject'] = $subject; - $values['mensaje'] = $mensaje; - $values['timestamp'] = get_system_time(); - - $return = db_process_sql_insert('tmensajes', $values); - if ($return === false) { return false; } else { @@ -58,108 +153,133 @@ function messages_create_message($usuario_origen, $usuario_destino, $subject, $m } -/** - * Creates private messages to be forwarded to groups - * - * @param string The sender of the message - * @param string The receivers (group) of the message - * @param string Subject of the message (much like E-Mail) - * @param string The actual message. This message will be cleaned by io_safe_input - * (html is allowed but loose html chars will be translated) - * - * @return boolean true when delivered, false in case of error - */ -function messages_create_group($usuario_origen, $dest_group, $subject, $mensaje) -{ - $users = users_get_info(); - $group_users = groups_get_users($dest_group); - - if (! array_key_exists($usuario_origen, $users)) { - // Users don't exist in the system - return false; - } else if (empty($group_users)) { - // There are no users in the group, so it hasn't failed although it hasn't done anything. - return true; - } - - // array unique - foreach ($group_users as $user) { - foreach ($user as $key => $us) { - if ($key == 'id_user') { - $group_user[$us] = $us; - } - } - } - - foreach ($group_user as $user) { - $return = messages_create_message($usuario_origen, get_user_id($user), $subject, $mensaje); - if ($return === false) { - // Error sending message - return false; - } - } - - return true; -} - - /** * Deletes a private message * - * @param integer $id_message + * @param integer $id_message Message to be deleted. * * @return boolean true when deleted, false in case of error */ -function messages_delete_message($id_message) +function messages_delete_message(int $id_message) { global $config; - $where = [ - // 'id_usuario_destino' => $config["id_user"], - 'id_mensaje' => $id_message, - ]; - return (bool) db_process_sql_delete('tmensajes', $where); + // Check if user has grants to access the message. + if (check_notification_readable($id_message) === false) { + return false; + } + + $utimestamp = time(); + + $ret = db_process_sql_update( + 'tnotification_user', + ['utimestamp_erased' => $utimestamp], + [ + 'id_mensaje' => $id_message, + 'id_user' => $config['id_user'], + ] + ); + + if ($ret === 0) { + // No previous updates. + // Message available to user due group assignment. + $ret = db_process_sql_insert( + 'tnotification_user', + [ + 'id_mensaje' => $id_message, + 'id_user' => $config['id_user'], + 'utimestamp_erased' => $utimestamp, + ] + ); + + // Quick fix. Insertions returns 0. + if ($ret !== false) { + $ret = 1; + } + } + + return (bool) $ret; } /** * Marks a private message as read/unread * - * @param integer $message_id The message to modify - * @param boolean $read To set unread pass 0, false or empty value + * @param integer $message_id The message to modify. + * @param boolean $read To set unread pass 0, false or empty value. * * @return boolean true when marked, false in case of error */ -function messages_process_read($message_id, $read=true) -{ - if (empty($read)) { - $read = 0; - } else { - $read = 1; +function messages_process_read( + int $message_id, + bool $read=true +) { + global $config; + // Check if user has grants to read the message. + if (check_notification_readable($message_id) === false) { + return false; } - return (bool) db_process_sql_update('tmensajes', ['estado' => $read], ['id_mensaje' => $message_id]); + if (empty($read)) { + // Mark as unread. + $utimestamp = null; + } else { + // Mark as read. + $utimestamp = time(); + } + + $ret = db_process_sql_update( + 'tnotification_user', + ['utimestamp_read' => $utimestamp], + [ + 'id_mensaje' => $message_id, + 'id_user' => $config['id_user'], + 'utimestamp_read' => null, + ] + ); + + if ($ret === 0) { + // No previous updates. + // Message available to user due group assignment. + $ret = db_process_sql_insert( + 'tnotification_user', + [ + 'id_mensaje' => $message_id, + 'id_user' => $config['id_user'], + 'utimestamp_read' => $utimestamp, + ] + ); + } + + return (bool) $ret; } /** * Gets a private message * - * This function abstracts the database backend so it can simply be replaced with another system + * This function abstracts the database backend so it can simply be + * replaced with another system * - * @param integer $message_id + * @param integer $message_id Message to be retrieved. * * @return mixed False if it doesn't exist or a filled array otherwise */ -function messages_get_message($message_id) +function messages_get_message(int $message_id) { global $config; + // Check if user has grants to read the message. + if (check_notification_readable($message_id) === false) { + return false; + } + $sql = sprintf( - "SELECT id_usuario_origen, id_usuario_destino, subject, mensaje, timestamp - FROM tmensajes - WHERE id_usuario_destino='%s' AND id_mensaje=%d", - $config['id_user'], + 'SELECT *, nu.utimestamp_read > 0 as "read" + FROM tmensajes tm + LEFT JOIN tnotification_user nu + ON nu.id_mensaje = tm.id_mensaje + WHERE tm.id_mensaje=%d', $message_id ); $row = db_get_row_sql($sql); @@ -168,6 +288,8 @@ function messages_get_message($message_id) return false; } + $row['id_usuario_destino'] = $config['id_user']; + return $row; } @@ -175,20 +297,21 @@ function messages_get_message($message_id) /** * Gets a sent message * - * This function abstracts the database backend so it can simply be replaced with another system + * This function abstracts the database backend so it can simply be + * replaced with another system * - * @param integer $message_id + * @param integer $message_id Message to be retrieved. * * @return mixed False if it doesn't exist or a filled array otherwise */ -function messages_get_message_sent($message_id) +function messages_get_message_sent(int $message_id) { global $config; $sql = sprintf( - "SELECT id_usuario_origen, id_usuario_destino, subject, mensaje, timestamp - FROM tmensajes - WHERE id_usuario_origen='%s' AND id_mensaje=%d", + "SELECT id_usuario_origen, subject, mensaje, timestamp + FROM tmensajes + WHERE id_usuario_origen='%s' AND id_mensaje=%d", $config['id_user'], $message_id ); @@ -198,6 +321,16 @@ function messages_get_message_sent($message_id) return false; } + $targets = get_notification_targets($message_id); + + $row['id_usuario_destino'] = implode( + ',', + $targets['users'] + ).','.implode( + ',', + $targets['groups'] + ); + return $row; } @@ -205,29 +338,77 @@ function messages_get_message_sent($message_id) /** * Counts private messages * - * @param string $user - * @param boolean $incl_read Whether or not to include read messages + * @param string $user Target user. + * @param boolean $incl_read Whether or not to include read messages. + * @param boolean $ignore_source Ignore source. * * @return integer The number of messages this user has */ -function messages_get_count($user=false, $incl_read=false) -{ +function messages_get_count( + string $user='', + bool $incl_read=false, + bool $ignore_source=false +) { if (empty($user)) { global $config; $user = $config['id_user']; } - if (empty($incl_read)) { - $filter = 'AND estado = 0'; + if (!empty($incl_read)) { + // Do not filter. + $read = ' 1=1 '; } else { - $filter = ''; + // Retrieve only unread messages. + $read = ' t.read is null'; + } + + if ($ignore_source === true) { + $source_select = ''; + $source_sql = ''; + $source_extra = ''; + } else { + $source_select = ',IF(ns.user_editable,nsu.enabled,ns.enabled) as enabled'; + + // Row in tnotification_source_user could exist or not. + $source_sql = sprintf( + 'INNER JOIN ( + tnotification_source ns + LEFT JOIN tnotification_source_user nsu + ON ns.id=nsu.id_source + AND nsu.id_user="%s") + ON tm.id_source=ns.id', + $user + ); + $source_extra = 'AND (t.enabled=1 OR t.enabled is null)'; } $sql = sprintf( - "SELECT COUNT(*) - FROM tmensajes WHERE id_usuario_destino='%s' %s", + 'SELECT count(*) as "n" FROM ( + SELECT + tm.*, + utimestamp_read > 0 as "read" + %s + FROM tmensajes tm + %s + LEFT JOIN tnotification_user nu + ON tm.id_mensaje=nu.id_mensaje + AND nu.id_user="%s" + LEFT JOIN (tnotification_group ng + INNER JOIN tusuario_perfil up + ON ng.id_group=up.id_grupo + AND up.id_grupo=ng.id_group) + ON tm.id_mensaje=ng.id_mensaje + WHERE utimestamp_erased is null + AND (nu.id_user="%s" OR up.id_usuario="%s" OR ng.id_group=0) + ) t + WHERE %s %s', + $source_select, + $source_sql, $user, - $filter + $user, + $user, + $read, + $source_extra ); return (int) db_get_sql($sql); @@ -235,13 +416,13 @@ function messages_get_count($user=false, $incl_read=false) /** - * Counts sended messages + * Counts messages sent. * - * @param string $user + * @param string $user Target user. * * @return integer The number of messages this user has sent */ -function messages_get_count_sent($user=false) +function messages_get_count_sent(string $user='') { if (empty($user)) { global $config; @@ -250,7 +431,7 @@ function messages_get_count_sent($user=false) $sql = sprintf( "SELECT COUNT(*) - FROM tmensajes WHERE id_usuario_origen='%s'", + FROM tmensajes WHERE id_usuario_origen='%s'", $user ); @@ -261,20 +442,36 @@ function messages_get_count_sent($user=false) /** * Get message overview in array * - * @param string $order How to order them valid: - * (status (default), subject, timestamp, sender) - * @param string $order_dir Direction of order (ASC = Ascending, DESC = Descending) + * @param string $order How to order them valid: + * (status (default), subject, timestamp, sender). + * @param string $order_dir Direction of order + * (ASC = Ascending, DESC = Descending). + * @param boolean $incl_read Include read messages in return. + * @param boolean $incl_source_info Include source info. + * @param integer $limit Maximum number of result in the query. + * @param array $other_filter Add a filter on main query. + * @param string $join_other_filter How to join filter on main query. * * @return integer The number of messages this user has */ -function messages_get_overview($order='status', $order_dir='ASC') -{ +function messages_get_overview( + string $order='status', + string $order_dir='ASC', + bool $incl_read=true, + bool $incl_source_info=false, + int $limit=0, + array $other_filter=[], + string $join_other_filter='AND' +) { global $config; switch ($order) { - case 'timestamp': - case 'sender': - case 'subject': + case 'timestamp':{ + } + case 'sender':{ + } + case 'subject':{ + } break; case 'status': @@ -287,21 +484,63 @@ function messages_get_overview($order='status', $order_dir='ASC') $order .= ' DESC'; } - $result = []; - $return = db_get_all_rows_field_filter('tmensajes', 'id_usuario_destino', $config['id_user'], $order); - - if ($return === false) { - return $result; + if (!empty($incl_read)) { + // Do not filter. + $read = ''; + } else { + // Retrieve only unread messages. + $read = 'where t.read is null'; } - foreach ($return as $message) { - $result[$message['id_mensaje']]['sender'] = $message['id_usuario_origen']; - $result[$message['id_mensaje']]['subject'] = $message['subject']; - $result[$message['id_mensaje']]['timestamp'] = $message['timestamp']; - $result[$message['id_mensaje']]['status'] = $message['estado']; + $source_fields = ''; + $source_join = ''; + if ($incl_source_info) { + $source_fields = ', tns.*'; + $source_join = 'INNER JOIN tnotification_source tns + ON tns.id=tm.id_source + INNER JOIN tnotification_source_user nsu + ON nsu.id_source=tns.id + AND nsu.enabled = 1 + OR tns.enabled = 1'; } - return $result; + // Using distinct because could be double assignment due group/user. + $sql = sprintf( + 'SELECT * FROM ( + SELECT DISTINCT tm.*, utimestamp_read > 0 as "read" %s + FROM tmensajes tm + LEFT JOIN tnotification_user nu + ON tm.id_mensaje=nu.id_mensaje + AND nu.id_user="%s" + LEFT JOIN (tnotification_group ng + INNER JOIN tusuario_perfil up + ON ng.id_group=up.id_grupo + AND up.id_grupo=ng.id_group + ) ON tm.id_mensaje=ng.id_mensaje + %s + WHERE utimestamp_erased is null + AND (nu.id_user="%s" OR up.id_usuario="%s" OR ng.id_group=0) + ) t + %s + %s + ORDER BY %s + %s', + $source_fields, + $config['id_user'], + $source_join, + $config['id_user'], + $config['id_user'], + $read, + db_format_array_where_clause_sql( + $other_filter, + $join_other_filter, + ' AND ' + ), + $order, + ($limit !== 0) ? ' LIMIT '.$limit : '' + ); + + return db_get_all_rows_sql($sql); } @@ -309,19 +548,25 @@ function messages_get_overview($order='status', $order_dir='ASC') * Get sent message overview in array * * @param string $order How to order them valid: - * (status (default), subject, timestamp, sender) - * @param string $order_dir Direction of order (ASC = Ascending, DESC = Descending) + * (status (default), subject, timestamp, sender). + * @param string $order_dir Direction of order + * (ASC = Ascending, DESC = Descending). * * @return integer The number of messages this user has */ -function messages_get_overview_sent($order='timestamp', $order_dir='ASC') -{ +function messages_get_overview_sent( + string $order='timestamp', + string $order_dir='ASC' +) { global $config; switch ($order) { - case 'timestamp': - case 'sender': - case 'subject': + case 'timestamp':{ + } + case 'sender':{ + } + case 'subject':{ + } break; case 'status': @@ -334,19 +579,85 @@ function messages_get_overview_sent($order='timestamp', $order_dir='ASC') $order .= ' DESC'; } - $result = []; - $return = db_get_all_rows_field_filter('tmensajes', 'id_usuario_origen', $config['id_user'], $order); - - if ($return === false) { - return $result; - } - - foreach ($return as $message) { - $result[$message['id_mensaje']]['dest'] = $message['id_usuario_destino']; - $result[$message['id_mensaje']]['subject'] = $message['subject']; - $result[$message['id_mensaje']]['timestamp'] = $message['timestamp']; - $result[$message['id_mensaje']]['status'] = $message['estado']; - } - - return $result; + return db_get_all_rows_field_filter( + 'tmensajes', + 'id_usuario_origen', + $config['id_user'], + $order + ); +} + + +/** + * Get a message interpreted as a conversation. + * + * @param mixed $data Complete message or message id. + * + * @return mixed False if fails. A string array with the conversation. + */ +function messages_get_conversation($data) +{ + if (is_array($data)) { + $message = $data; + } else { + $message = messages_get_message($data); + } + + if (!isset($message) || !is_array($message)) { + return []; + } + + $conversation = []; + $target_str = $message['mensaje']; + + while (preg_match_all( + '/(.*)On(.*)wrote:(.*)/', + $target_str, + $decoded, + PREG_PATTERN_ORDER + ) !== false && empty($target_str) !== true) { + if (empty($decoded[2]) !== true) { + array_push( + $conversation, + [ + 'message' => array_pop($decoded)[0], + 'date' => array_pop($decoded)[0], + ] + ); + } else { + array_push( + $conversation, + ['message' => $target_str] + ); + } + + $target_str = $decoded[1][0]; + } + + return $conversation; +} + + +/** + * Get the URL of a message. If field in db is null, it returs a link to + * messages view. + * + * @param integer $message_id Message id to get URL. + * + * @return mixed False if fails. A string with URL otherwise. + */ +function messages_get_url($message_id) +{ + $messages = messages_get_message($message_id); + if ($messages === false) { + return false; + } + + // Return URL stored if is set in database. + if (isset($messages['url'])) { + return $messages['url']; + } + + // Return the message direction. + return ui_get_full_url('index.php?sec=message_list&sec2=operation/messages/message_edit&read_message=1&id_message='.$message_id); } diff --git a/pandora_console/include/functions_modules.php b/pandora_console/include/functions_modules.php index ed19c6d2c1..b9ed8e41d5 100755 --- a/pandora_console/include/functions_modules.php +++ b/pandora_console/include/functions_modules.php @@ -663,10 +663,11 @@ function modules_create_agent_module( 'estado' => $status, 'known_status' => $status, 'id_agente' => (int) $id_agent, - 'utimestamp' => 0, + 'utimestamp' => (time() - (int) $values['interval']), 'status_changes' => 0, 'last_status' => $status, 'last_known_status' => $status, + 'current_interval' => (int) $values['interval'], ] ); @@ -2293,6 +2294,54 @@ function modules_get_modulegroup_name($modulegroup_id) } +/** + * Returns target color to be used based on the status received. + * + * @param integer $status Source information. + * + * @return string HTML tag for color. + */ +function modules_get_color_status($status) +{ + if (isset($status) === false) { + return COL_UNKNOWN; + } + + switch ($status) { + case AGENT_MODULE_STATUS_NORMAL: + case AGENT_STATUS_NORMAL: + return COL_NORMAL; + + case AGENT_MODULE_STATUS_NOT_INIT: + case AGENT_STATUS_NOT_INIT: + return COL_NOTINIT; + + case AGENT_MODULE_STATUS_CRITICAL_BAD: + case AGENT_STATUS_CRITICAL: + return COL_CRITICAL; + + case AGENT_MODULE_STATUS_WARNING: + case AGENT_STATUS_WARNING: + return COL_WARNING; + + case AGENT_MODULE_STATUS_CRITICAL_ALERT: + case AGENT_MODULE_STATUS_WARNING_ALERT: + case AGENT_STATUS_ALERT_FIRED: + return COL_ALERTFIRED; + + case AGENT_MODULE_STATUS_UNKNOWN: + case AGENT_STATUS_UNKNOWN: + return COL_UNKNOWN; + + default: + // Ignored. + break; + } + + return COL_IGNORED; +} + + /** * Gets a module status an modify the status and title reference variables * @@ -2321,7 +2370,7 @@ function modules_get_status($id_agent_module, $db_status, $data, &$status, &$tit $status = STATUS_MODULE_OK; $title = __('NORMAL'); } else if ($db_status == AGENT_MODULE_STATUS_UNKNOWN) { - $status = STATUS_AGENT_DOWN; + $status = STATUS_MODULE_UNKNOWN; $last_status = modules_get_agentmodule_last_status($id_agent_module); switch ($last_status) { case AGENT_STATUS_NORMAL: diff --git a/pandora_console/include/functions_netflow.php b/pandora_console/include/functions_netflow.php index 84f3c26169..69aa0a1608 100644 --- a/pandora_console/include/functions_netflow.php +++ b/pandora_console/include/functions_netflow.php @@ -1,36 +1,60 @@ id_name)) or filters filtered * - * @param mixed Array with filter conditions to retrieve filters or false. + * @param mixed $filter Array with filter conditions to retrieve filters or + * false. * - * @return array List of all filters + * @return array List of all filters. */ function netflow_get_filters($filter=false) { @@ -56,9 +80,10 @@ function netflow_get_filters($filter=false) /** * Selects all netflow reports (array (id_name => id_name)) or filters filtered * - * @param mixed Array with filter conditions to retrieve filters or false. + * @param mixed $filter Array with filter conditions to retrieve filters or + * false. * - * @return array List of all filters + * @return array List of all filters. */ function netflow_get_reports($filter=false) { @@ -81,14 +106,20 @@ function netflow_get_reports($filter=false) } -// permite validar si un filtro pertenece a un grupo permitido para el usuario +/** + * Check if a filter owns to a certain group. + * + * @param integer $id_sg Id group to check. + * + * @return boolean True if user manages that group. + */ function netflow_check_filter_group($id_sg) { global $config; $id_group = db_get_value('id_group', 'tnetflow_filter', 'id_sg', $id_sg); $own_info = get_user_info($config['id_user']); - // Get group list that user has access + // Get group list that user has access. $groups_user = users_get_groups($config['id_user'], 'IW', $own_info['is_admin'], true); $groups_id = []; $has_permission = false; @@ -103,44 +134,12 @@ function netflow_check_filter_group($id_sg) } -/* - Permite validar si un informe pertenece a un grupo permitido para el usuario. - * Si mode = false entonces es modo godmode y solo puede ver el grupo All el admin - * Si es modo operation (mode = true) entonces todos pueden ver el grupo All - */ - -function netflow_check_report_group($id_report, $mode=false) -{ - global $config; - - if (!$mode) { - $own_info = get_user_info($config['id_user']); - $mode = $own_info['is_admin']; - } - - $id_group = db_get_value('id_group', 'tnetflow_report', 'id_report', $id_report); - - // Get group list that user has access - $groups_user = users_get_groups($config['id_user'], 'IW', $mode, true); - $groups_id = []; - $has_permission = false; - - foreach ($groups_user as $key => $groups) { - if ($groups['id_grupo'] == $id_group) { - return true; - } - } - - return false; -} - - /** * Get a filter. * - * @param int filter id to be fetched. - * @param array Extra filter. - * @param array Fields to be fetched. + * @param integer $id_sg Filter id to be fetched. + * @param mixed $filter Extra filter. + * @param mixed $fields Fields to be fetched. * * @return array A netflow filter matching id and filter. */ @@ -156,52 +155,11 @@ function netflow_filter_get_filter($id_sg, $filter=false, $fields=false) } -/** - * Get options. - * - * @param int filter id to be fetched. - * @param array Extra filter. - * @param array Fields to be fetched. - * - * @return array A netflow filter matching id and filter. - */ -function netflow_reports_get_reports($id_report, $filter=false, $fields=false) -{ - if (empty($id_report)) { - return false; - } - - if (! is_array($filter)) { - $filter = []; - } - - $filter['id_report'] = (int) $id_report; - - return db_get_row_filter('tnetflow_report', $filter, $fields); -} - - -function netflow_reports_get_content($id_rc, $filter=false, $fields=false) -{ - if (empty($id_rc)) { - return false; - } - - if (! is_array($filter)) { - $filter = []; - } - - $filter['id_rc'] = (int) $id_rc; - - return db_get_row_filter('tnetflow_report_content', $filter, $fields); -} - - /** * Compare two flows according to the 'data' column. * - * @param array a First flow. - * @param array b Second flow. + * @param array $a First flow. + * @param array $b Second flow. * * @return Result of the comparison. */ @@ -214,7 +172,9 @@ function compare_flows($a, $b) /** * Sort netflow data according to the 'data' column. * - * @param array netflow_data Netflow data array. + * @param array $netflow_data Netflow data array. + * + * @return void (Array passed by reference) */ function sort_netflow_data(&$netflow_data) { @@ -225,22 +185,22 @@ function sort_netflow_data(&$netflow_data) /** * Show a table with netflow statistics. * - * @param array data Statistic data. - * @param string start_date Start date. - * @param string end_date End date. - * @param string aggregate Aggregate field. - * @param string unit Unit to show. + * @param array $data Statistic data. + * @param string $start_date Start date. + * @param string $end_date End date. + * @param string $aggregate Aggregate field. * - * @return The statistics table. + * @return string HTML statistics table. */ -function netflow_stat_table($data, $start_date, $end_date, $aggregate, $unit) +function netflow_stat_table($data, $start_date, $end_date, $aggregate) { global $nfdump_date_format; $start_date = date($nfdump_date_format, $start_date); $end_date = date($nfdump_date_format, $end_date); $values = []; - $table->width = '40%'; + $table = new stdClass(); + $table->width = '100%'; $table->cellspacing = 0; $table->class = 'databox'; $table->data = []; @@ -249,7 +209,7 @@ function netflow_stat_table($data, $start_date, $end_date, $aggregate, $unit) $table->head = []; $table->head[0] = ''.netflow_format_aggregate($aggregate).''; - $table->head[1] = ''.netflow_format_unit($unit).''; + $table->head[1] = ''.__('Value').''; $table->style[0] = 'padding: 6px;'; $table->style[1] = 'padding: 6px;'; @@ -257,14 +217,13 @@ function netflow_stat_table($data, $start_date, $end_date, $aggregate, $unit) $agg = $data[$j]['agg']; if (!isset($values[$agg])) { $values[$agg] = $data[$j]['data']; - $table->data[$x][0] = $agg; - $table->data[$x][1] = format_numeric($data[$j]['data']).' '.netflow_format_unit($unit); } else { $values[$agg] += $data[$j]['data']; - $table->data[$x][0] = $agg; - $table->data[$x][1] = format_numeric($data[$j]['data']).' '.netflow_format_unit($unit); } + $table->data[$x][0] = $agg; + $table->data[$x][1] = network_format_bytes($data[$j]['data']); + $j++; $x++; } @@ -276,14 +235,14 @@ function netflow_stat_table($data, $start_date, $end_date, $aggregate, $unit) /** * Show a table with netflow data. * - * @param array data Netflow data. - * @param string start_date Start date. - * @param string end_date End date. - * @param string aggregate Aggregate field. + * @param array $data Netflow data. + * @param string $start_date Start date. + * @param string $end_date End date. + * @param string $aggregate Aggregate field. * - * @return The statistics table. + * @return string HTML data table. */ -function netflow_data_table($data, $start_date, $end_date, $aggregate, $unit) +function netflow_data_table($data, $start_date, $end_date, $aggregate) { global $nfdump_date_format; @@ -291,7 +250,7 @@ function netflow_data_table($data, $start_date, $end_date, $aggregate, $unit) $start_date = date($nfdump_date_format, $start_date); $end_date = date($nfdump_date_format, $end_date); - // Set the format + // Set the format. if ($period <= SECONDS_6HOURS) { $time_format = 'H:i:s'; } else if ($period < SECONDS_1DAY) { @@ -305,6 +264,7 @@ function netflow_data_table($data, $start_date, $end_date, $aggregate, $unit) } $values = []; + $table = new stdClass(); $table->size = ['100%']; $table->class = 'databox'; $table->cellspacing = 0; @@ -332,7 +292,7 @@ function netflow_data_table($data, $start_date, $end_date, $aggregate, $unit) $table->style[1] = 'padding: 4px;'; } - // No aggregates + // No aggregates. if ($source_count == 0) { $table->head[1] = __('Data'); $table->align[1] = 'right'; @@ -340,21 +300,17 @@ function netflow_data_table($data, $start_date, $end_date, $aggregate, $unit) foreach ($data as $timestamp => $value) { $table->data[$i][0] = date($time_format, $timestamp); - $table->data[$i][1] = format_numeric($value['data']).' '.netflow_format_unit($unit); + $table->data[$i][1] = network_format_bytes($value['data']); $i++; } - } - // Aggregates - else { + } else { $i = 0; foreach ($data['data'] as $timestamp => $values) { $table->data[$i][0] = date($time_format, $timestamp); for ($j = 0; $j < $source_count; $j++) { - if (isset($values[$source_index[$j]])) { - $table->data[$i][($j + 1)] = format_numeric($values[$source_index[$j]]).' '.netflow_format_unit($unit); - } else { - $table->data[$i][($j + 1)] = (0).' '.netflow_format_unit($unit); - } + $table->data[$i][($j + 1)] = network_format_bytes( + $values[$source_index[$j]] + ); } $i++; @@ -368,18 +324,19 @@ function netflow_data_table($data, $start_date, $end_date, $aggregate, $unit) /** * Show a table with a traffic summary. * - * @param array data Summary data. + * @param array $data Summary data. * - * @return The statistics table. + * @return string HTML summary table. */ function netflow_summary_table($data) { global $nfdump_date_format; $values = []; - $table->size = ['50%']; + $table = new stdClass(); $table->cellspacing = 0; $table->class = 'databox'; + $table->styleTable = 'width: 100%'; $table->data = []; $table->style[0] = 'font-weight: bold; padding: 6px'; @@ -387,32 +344,32 @@ function netflow_summary_table($data) $row = []; $row[] = __('Total flows'); - $row[] = format_numeric($data['totalflows']); + $row[] = format_for_graph($data['totalflows'], 2); $table->data[] = $row; $row = []; $row[] = __('Total bytes'); - $row[] = format_numeric($data['totalbytes']); + $row[] = network_format_bytes($data['totalbytes']); $table->data[] = $row; $row = []; $row[] = __('Total packets'); - $row[] = format_numeric($data['totalpackets']); + $row[] = format_for_graph($data['totalpackets'], 2); $table->data[] = $row; $row = []; $row[] = __('Average bits per second'); - $row[] = format_numeric($data['avgbps']); + $row[] = network_format_bytes($data['avgbps']); $table->data[] = $row; $row = []; $row[] = __('Average packets per second'); - $row[] = format_numeric($data['avgpps']); + $row[] = format_for_graph($data['avgpps'], 2); $table->data[] = $row; $row = []; $row[] = __('Average bytes per packet'); - $row[] = format_numeric($data['avgbpp']); + $row[] = format_for_graph($data['avgbpp'], 2); $table->data[] = $row; $html = html_print_table($table, true); @@ -424,7 +381,7 @@ function netflow_summary_table($data) /** * Returns 1 if the given address is a network address. * - * @param string address Host or network address. + * @param string $address Host or network address. * * @return 1 if the address is a network address, 0 otherwise. */ @@ -441,225 +398,173 @@ function netflow_is_net($address) /** * Returns netflow data for the given period in an array. * - * @param string start_date Period start date. - * @param string end_date Period end date. - * @param string filter Netflow filter. - * @param string aggregate Aggregate field. - * @param int max Maximum number of aggregates. - * @param string unit Unit to show. + * @param string $start_date Period start date. + * @param string $end_date Period end date. + * @param mixed $interval_length Resolution points or hourly or daily. + * @param string $filter Netflow filter. + * @param string $aggregate Aggregate field. + * @param integer $max Maximum number of aggregates. + * @param boolean $absolute True to give the absolute data and false + * to get troughput. + * @param string $connection_name Node name when data is get in meta. + * @param boolean $address_resolution True to resolve ips to hostnames. * - * @return An array with netflow stats. + * @return array An array with netflow stats. */ -function netflow_get_data($start_date, $end_date, $interval_length, $filter, $aggregate, $max, $unit, $connection_name='', $address_resolution=false) -{ +function netflow_get_data( + $start_date, + $end_date, + $interval_length, + $filter, + $aggregate, + $max, + $absolute, + $connection_name='', + $address_resolution=false +) { global $nfdump_date_format; global $config; - // Requesting remote data + // Requesting remote data. if (defined('METACONSOLE') && $connection_name != '') { - $data = metaconsole_call_remote_api($connection_name, 'netflow_get_data', "$start_date|$end_date|$interval_length|".base64_encode(json_encode($filter))."|$aggregate|$max|$unit".(int) $address_resolution); + $data = metaconsole_call_remote_api( + $connection_name, + 'netflow_get_data', + "$start_date|$end_date|$interval_length|".base64_encode(json_encode($filter))."|$aggregate|$max|1".(int) $address_resolution + ); return json_decode($data, true); } - // Calculate the number of intervals - if ($interval_length <= 0) { - // $num_intervals = $config['graph_res'] * 50; - $num_intervals = 250; - $period = ($end_date - $start_date); - $interval_length = (int) ($period / $num_intervals); - } else { - $period = ($end_date - $start_date); - $num_intervals = (int) ($period / $interval_length); + if ($start_date > $end_date) { + return []; } - // Set a max number of intervals - if ($num_intervals > $config['netflow_max_resolution']) { - $num_intervals = $config['netflow_max_resolution']; - $interval_length = (int) ($period / $num_intervals); + // Calculate the number of intervals. + $multiplier_time = ($end_date - $start_date); + switch ($interval_length) { + case NETFLOW_RES_LOWD: + case NETFLOW_RES_MEDD: + case NETFLOW_RES_HID: + case NETFLOW_RES_ULTRAD: + $multiplier_time = ceil(($end_date - $start_date) / $interval_length); + break; + + case NETFLOW_RES_HOURLY: + $multiplier_time = SECONDS_1HOUR; + break; + + case NETFLOW_RES_DAILY: + $multiplier_time = SECONDS_1DAY; + break; + + default: + $multiplier_time = ($end_date - $start_date); + break; } - // If there is aggregation calculate the top n - if ($aggregate != 'none') { - $values['data'] = []; - $values['sources'] = []; - - // Get the command to call nfdump - $command = netflow_get_command($filter); - - // Suppress the header line and the statistics at the bottom and configure piped output - $command .= ' -q -o csv'; - - // Call nfdump - $agg_command = $command." -n $max -s $aggregate/bytes -t ".date($nfdump_date_format, $start_date).'-'.date($nfdump_date_format, $end_date); - exec($agg_command, $string); - - // Remove the first line - $string[0] = ''; - - // Parse aggregates - foreach ($string as $line) { - if ($line == '') { - continue; - } - - $val = explode(',', $line); - if ($aggregate == 'proto') { - $values['sources'][$val[3]] = 1; - } else { - $values['sources'][$val[4]] = 1; - } - } - - // Update the filter - switch ($aggregate) { - case 'proto': - $extra_filter = 'proto'; - break; - - default: - case 'srcip': - $extra_filter = 'ip_src'; - break; - case 'srcport': - $extra_filter = 'src_port'; - break; - - case 'dstip': - $extra_filter = 'ip_dst'; - break; - - case 'dstport': - $extra_filter = 'dst_port'; - break; - } - - if (isset($filter[$extra_filter]) && $filter[$extra_filter] != '') { - $filter[$extra_filter] .= ','; - } - - $filter[$extra_filter] = implode( - ',', - array_keys($values['sources']) + // Recalculate to not pass of netflow_max_resolution. + if ($config['netflow_max_resolution'] > 0 + && (($end_date - $start_date) / $multiplier_time) > 50 + ) { + $multiplier_time = ceil( + (($end_date - $start_date) / $config['netflow_max_resolution']) ); - } else { - $values = []; } - // Address resolution start - $get_hostnames = false; - if ($address_resolution && ($aggregate == 'srcip' || $aggregate == 'dstip')) { - $get_hostnames = true; - global $hostnames; + // Put all points into an array. + $intervals = [($start_date - $multiplier_time)]; + while ((end($intervals) < $end_date) === true) { + $intervals[] = (end($intervals) + $multiplier_time); + } - $sources = []; - foreach ($values['sources'] as $source => $value) { - if (!isset($hostnames[$source])) { - $hostname = gethostbyaddr($source); - if ($hostname !== false) { - $hostnames[$source] = $hostname; - $source = $hostname; + if (end($intervals) != $end_date) { + $intervals[] = $end_date; + } + + // Calculate the top values. + $values = netflow_get_top_data( + $start_date, + $end_date, + $filter, + $aggregate, + $max + ); + + // Update the filter to get properly next data. + netflow_update_second_level_filter( + $filter, + $aggregate, + array_keys($values['sources']) + ); + + // Resolve addresses if required. + $get_hostnames = false; + if ($address_resolution === true) { + global $hostnames; + netflow_address_resolution($values, $get_hostnames, $aggregate); + } + + foreach ($intervals as $k => $time) { + $interval_start = $time; + if (!isset($intervals[($k + 1)])) { + continue; + } + + $interval_end = $intervals[($k + 1)]; + + // Set default values. + foreach ($values['sources'] as $source => $discard) { + $values['data'][$interval_end][$source] = 0; + } + + $data = netflow_get_stats( + $interval_start, + $interval_end, + $filter, + $aggregate, + $max, + $absolute, + $connection_name + ); + + foreach ($data as $line) { + // Address resolution start. + if ($get_hostnames) { + if (!isset($hostnames[$line['agg']])) { + $hostname = false; + // Trying to get something like an IP from the description. + if (preg_match('/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/', $line['agg'], $matches) + || preg_match( + "/(((?=(?>.*?(::))(?!.+\3)))\3?|([\dA-F]{1,4}(\3|:?)|\2))(?4){5}((?4){2}|(25[0-5]| + (2[0-4]|1\d|[1-9])?\d)(\.(?7)){3})/i", + $line['agg'], + $matches + ) + ) { + if ($matches[0]) { + $hostname = gethostbyaddr($line['agg']); + } + } + + if ($hostname !== false) { + $hostnames[$line['agg']] = $hostname; + $line['agg'] = $hostname; + } + } else { + $line['agg'] = $hostnames[$line['agg']]; } - } else { - $source = $hostnames[$source]; } - $sources[$source] = $value; - } - - $values['sources'] = $sources; - } - - // Address resolution end - $interval_start = $start_date; - for ($i = 0; $i < $num_intervals; $i++, $interval_start += ($interval_length + 1)) { - $interval_end = ($interval_start + $interval_length); - if ($interval_end > $end_date) { - $interval_end = $end_date; - } - - if ($aggregate == 'none') { - $data = netflow_get_summary($interval_start, $interval_end, $filter, $connection_name); - if (! isset($data['totalbytes'])) { - $values[$interval_start]['data'] = 0; + // Address resolution end. + if (! isset($values['sources'][$line['agg']])) { continue; } - switch ($unit) { - case 'megabytes': - $values[$interval_start]['data'] = ($data['totalbytes'] / 1048576); - break; - - case 'megabytespersecond': - $values[$interval_start]['data'] = ($data['avgbps'] / 1048576 / 8); - break; - - case 'kilobytes': - $values[$interval_start]['data'] = ($data['totalbytes'] / 1024); - break; - - case 'kilobytespersecond': - $values[$interval_start]['data'] = ($data['avgbps'] / 1024 / 8); - break; - - default: - $values[$interval_start]['data'] = $data['totalbytes']; - break; - } - } else { - // Set default values - foreach ($values['sources'] as $source => $discard) { - $values['data'][$interval_start][$source] = 0; - } - - $data = netflow_get_stats( - $interval_start, - $interval_end, - $filter, - $aggregate, - $max, - $unit, - $connection_name - ); - - foreach ($data as $line) { - // Address resolution start - if ($get_hostnames) { - if (!isset($hostnames[$line['agg']])) { - $hostname = false; - // Trying to get something like an IP from the description - if (preg_match('/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/', $line['agg'], $matches) - || preg_match( - "/(((?=(?>.*?(::))(?!.+\3)))\3?|([\dA-F]{1,4}(\3|:?)|\2))(?4){5}((?4){2}|(25[0-5]| - (2[0-4]|1\d|[1-9])?\d)(\.(?7)){3})/i", - $line['agg'], - $matches - ) - ) { - if ($matches[0]) { - $hostname = gethostbyaddr($line['agg']); - } - } - - if ($hostname !== false) { - $hostnames[$line['agg']] = $hostname; - $line['agg'] = $hostname; - } - } else { - $line['agg'] = $hostnames[$line['agg']]; - } - } - - // Address resolution end - if (! isset($values['sources'][$line['agg']])) { - continue; - } - - $values['data'][$interval_start][$line['agg']] = $line['data']; - } + $values['data'][$interval_end][$line['agg']] = $line['data']; } } - if (($aggregate != 'none') && (empty($values['data']))) { + if (empty($values['data'])) { return []; } @@ -670,29 +575,40 @@ function netflow_get_data($start_date, $end_date, $interval_length, $filter, $ag /** * Returns netflow stats for the given period in an array. * - * @param string start_date Period start date. - * @param string end_date Period end date. - * @param string filter Netflow filter. - * @param string aggregate Aggregate field. - * @param int max Maximum number of aggregates. - * @param string unit Unit to show. + * @param string $start_date Period start date. + * @param string $end_date Period end date. + * @param string $filter Netflow filter. + * @param string $aggregate Aggregate field. + * @param integer $max Maximum number of aggregates. + * @param boolean $absolute True to give the absolute data and false + * to get troughput. + * @param string $connection_name Node name when data is get in meta. + * @param boolean $address_resolution True to resolve ips to hostnames. * - * @return An array with netflow stats. + * @return array With netflow stats. */ -function netflow_get_stats($start_date, $end_date, $filter, $aggregate, $max, $unit, $connection_name='', $address_resolution=false) -{ +function netflow_get_stats( + $start_date, + $end_date, + $filter, + $aggregate, + $max, + $absolute=true, + $connection_name='', + $address_resolution=false +) { global $config, $nfdump_date_format; - // Requesting remote data + // Requesting remote data. if (defined('METACONSOLE') && $connection_name != '') { - $data = metaconsole_call_remote_api($connection_name, 'netflow_get_stats', "$start_date|$end_date|".base64_encode(json_encode($filter))."|$aggregate|$max|$unit|".(int) $address_resolution); + $data = metaconsole_call_remote_api($connection_name, 'netflow_get_stats', "$start_date|$end_date|".base64_encode(json_encode($filter))."|$aggregate|$max|$absolute|".(int) $address_resolution); return json_decode($data, true); } - // Get the command to call nfdump + // Get the command to call nfdump. $command = netflow_get_command($filter); - // Execute nfdump + // Execute nfdump. $command .= " -o csv -q -n $max -s $aggregate/bytes -t ".date($nfdump_date_format, $start_date).'-'.date($nfdump_date_format, $end_date); exec($command, $string); @@ -700,7 +616,7 @@ function netflow_get_stats($start_date, $end_date, $filter, $aggregate, $max, $u return []; } - // Remove the first line + // Remove the first line. $string[0] = ''; $i = 0; @@ -716,60 +632,35 @@ function netflow_get_stats($start_date, $end_date, $filter, $aggregate, $max, $u $values[$i]['date'] = $val[0]; $values[$i]['time'] = $val[1]; - // create field to sort array + // Create field to sort array. $datetime = $val[0]; $end_date = strtotime($datetime); $values[$i]['datetime'] = $end_date; - if ($aggregate == 'proto') { - $values[$i]['agg'] = $val[3]; - } else { - // Address resolution start - if ($address_resolution && ($aggregate == 'srcip' || $aggregate == 'dstip')) { - global $hostnames; + // Address resolution start. + if ($address_resolution && ($aggregate == 'srcip' || $aggregate == 'dstip')) { + global $hostnames; - if (!isset($hostnames[$val[4]])) { - $hostname = gethostbyaddr($val[4]); - if ($hostname !== false) { - $hostnames[$val[4]] = $hostname; - $val[4] = $hostname; - } - } else { - $val[4] = $hostnames[$val[4]]; + if (!isset($hostnames[$val[4]])) { + $hostname = gethostbyaddr($val[4]); + if ($hostname !== false) { + $hostnames[$val[4]] = $hostname; + $val[4] = $hostname; } + } else { + $val[4] = $hostnames[$val[4]]; } - - // Address resolution end - $values[$i]['agg'] = $val[4]; } + // Address resolution end. + $values[$i]['agg'] = $val[4]; + if (! isset($val[9])) { return []; } - switch ($unit) { - case 'megabytes': - $values[$i]['data'] = ($val[9] / 1048576); - break; - - case 'megabytespersecond': - $values[$i]['data'] = ($val[9] / 1048576 / $interval_length); - break; - - case 'kilobytes': - $values[$i]['data'] = ($val[9] / 1024); - break; - - case 'kilobytespersecond': - $values[$i]['data'] = ($val[9] / 1024 / $interval_length); - break; - - default: - case 'bytes': - $values[$i]['data'] = $val[9]; - break; - case 'bytespersecond': - $values[$i]['data'] = ($val[9] / $interval_length); - break; + $values[$i]['data'] = $val[9]; + if (!$absolute) { + $values[$i]['data'] = ($values[$i]['data'] / $interval_length); } $i++; @@ -784,27 +675,28 @@ function netflow_get_stats($start_date, $end_date, $filter, $aggregate, $max, $u /** * Returns a traffic summary for the given period in an array. * - * @param string start_date Period start date. - * @param string end_date Period end date. - * @param string filter Netflow filter. + * @param string $start_date Period start date. + * @param string $end_date Period end date. + * @param string $filter Netflow filter. + * @param string $connection_name Node name when data is get in meta. * - * @return An array with netflow stats. + * @return array With netflow summary data. */ function netflow_get_summary($start_date, $end_date, $filter, $connection_name='') { global $nfdump_date_format; global $config; - // Requesting remote data + // Requesting remote data. if (defined('METACONSOLE') && $connection_name != '') { $data = metaconsole_call_remote_api($connection_name, 'netflow_get_summary', "$start_date|$end_date|".base64_encode(json_encode($filter))); return json_decode($data, true); } - // Get the command to call nfdump + // Get the command to call nfdump. $command = netflow_get_command($filter); - // Execute nfdump + // Execute nfdump. $command .= ' -o csv -n 1 -s srcip/bytes -t '.date($nfdump_date_format, $start_date).'-'.date($nfdump_date_format, $end_date); exec($command, $string); @@ -812,7 +704,7 @@ function netflow_get_summary($start_date, $end_date, $filter, $connection_name=' return []; } - // Read the summary + // Read the summary. $summary = explode(',', $string[5]); if (! isset($summary[5])) { return []; @@ -830,137 +722,174 @@ function netflow_get_summary($start_date, $end_date, $filter, $connection_name=' /** - * Returns a traffic record for the given period in an array. + * Returns a relationships data for the given period in an array. * - * @param string start_date Period start date. - * @param string end_date Period end date. - * @param string filter Netflow filter. - * @param int max Maximum number of elements. - * @param string unit to show. + * @param string $start_date Period start date. + * @param string $end_date Period end date. + * @param string $filter Netflow filter. + * @param integer $max Maximum number of elements. + * @param string $aggregate One of srcip, srcport, dstip, dstport. * - * @return An array with netflow stats. + * @return array With raw relationship data. */ -function netflow_get_record($start_date, $end_date, $filter, $max, $unit, $address_resolution=false) -{ +function netflow_get_relationships_raw_data( + $start_date, + $end_date, + $filter, + $max, + $aggregate +) { global $nfdump_date_format; global $config; - // TIME_START = 0; - // TIME_END = 1; - // DURATION = 2; - // SOURCE_ADDRESS = 3; - // DESTINATION_ADDRESS = 4; - // SOURCE_PORT = 5; - // DESTINATION_PORT = 6; - // PROTOCOL = 7; - // INPUT_BYTES = 12; - // Get the command to call nfdump + $max_data = netflow_get_top_data( + $start_date, + $end_date, + $filter, + $aggregate, + $max + ); + + // Update src and dst filter (both). + $sources_array = array_keys($max_data['sources']); + $is_ip = netflow_aggregate_is_ip($aggregate); + netflow_update_second_level_filter( + $filter, + ($is_ip === true) ? 'dstip' : 'dstport', + $sources_array + ); + netflow_update_second_level_filter( + $filter, + ($is_ip === true) ? 'srcip' : 'srcport', + $sources_array + ); + + // Get the command to call nfdump. + $command = sprintf( + '%s -q -o csv -n %s -s %s/bytes -t %s-%s', + netflow_get_command($filter), + NETFLOW_MAX_DATA_CIRCULAR_MESH, + 'record', + date($nfdump_date_format, $start_date), + date($nfdump_date_format, $end_date) + ); + + // Get the command to call nfdump. $command = netflow_get_command($filter); - // Execute nfdump - $command .= " -q -o csv -n $max -s record/bytes -t ".date($nfdump_date_format, $start_date).'-'.date($nfdump_date_format, $end_date); + // Execute nfdump. + $command .= ' -q -o csv -n 10000 -s record/bytes -t '.date($nfdump_date_format, $start_date).'-'.date($nfdump_date_format, $end_date); exec($command, $result); if (! is_array($result)) { + return [ + 'lines' => [], + 'sources' => [], + ]; + } + + return [ + 'lines' => $result, + 'sources' => $sources_array, + ]; +} + + +/** + * Parse the raw relationships data to be painted by circular mesh chart. + * + * @param array $result Lines gotten from nfdump call. + * @param array $sources_array Array with sources involved in the chart. + * @param boolean $is_ip Is ip or port. + * + * @return array With data to be parsed on circular mesh chart. + */ +function netflow_parse_relationships_for_circular_mesh( + $result, + $sources_array, + $is_ip +) { + if (empty($result)) { return []; } - $values = []; - foreach ($result as $key => $line) { - $data = []; + // Initialize some data structures. + $data = [ + 'elements' => [], + 'matrix' => [], + ]; + $initial_data = []; + // This array has the ips or port like keys and the array position as value. + $inverse_sources_array = array_flip($sources_array); + foreach ($sources_array as $sdata) { + $data['elements'][$inverse_sources_array[$sdata]] = $sdata; + $initial_data[$inverse_sources_array[$sdata]] = 0; + } + foreach ($sources_array as $sdata) { + $data['matrix'][$inverse_sources_array[$sdata]] = $initial_data; + } + + // Port are situated in a different places from addreses. + $src_key = ($is_ip === true) ? 3 : 5; + $dst_key = ($is_ip === true) ? 4 : 6; + // Store a footprint of initial data to be compared at the end. + $freeze_data = md5(serialize($data)); + foreach ($result as $line) { + if (empty($line) === true) { + continue; + } + + // Parse the line. $items = explode(',', $line); - $data['time_start'] = $items[0]; - $data['time_end'] = $items[1]; - $data['duration'] = ($items[2] / 1000); - $data['source_address'] = $items[3]; - $data['destination_address'] = $items[4]; - $data['source_port'] = $items[5]; - $data['destination_port'] = $items[6]; - $data['protocol'] = $items[7]; + // Get the required data. + $src_item = $inverse_sources_array[$items[$src_key]]; + $dst_item = $inverse_sources_array[$items[$dst_key]]; + $value = $items[12]; - switch ($unit) { - case 'megabytes': - $data['data'] = ($items[12] / 1048576); - break; - - case 'megabytespersecond': - $data['data'] = ($items[12] / 1048576 / $data['duration']); - break; - - case 'kilobytes': - $data['data'] = ($items[12] / 1024); - break; - - case 'kilobytespersecond': - $data['data'] = ($items[12] / 1024 / $data['duration']); - break; - - default: - case 'bytes': - $data['data'] = $items[12]; - break; - case 'bytespersecond': - $data['data'] = ($items[12] / $data['duration']); - break; + // Check if valid data. + if (!isset($value) + || !isset($data['matrix'][$dst_item][$src_item]) + || !isset($data['matrix'][$src_item][$dst_item]) + ) { + continue; } - $values[] = $data; + // Update the value. + $data['matrix'][$src_item][$dst_item] += (int) $value; } - // Address resolution start - if ($address_resolution) { - global $hostnames; - - for ($i = 0; $i < count($values); $i++) { - if (!isset($hostnames[$values[$i]['source_address']])) { - $hostname = gethostbyaddr($values[$i]['source_address']); - if ($hostname !== false) { - $hostnames[$values[$i]['source_address']] = $hostname; - $values[$i]['source_address'] = $hostname; - } - } else { - $values[$i]['source_address'] = $hostnames[$values[$i]['source_address']]; - } - - if (!isset($hostnames[$values[$i]['destination_address']])) { - $hostname = gethostbyaddr($values[$i]['destination_address']); - if ($hostname !== false) { - $hostnames[$values[$i]['destination_address']] = $hostname; - $values[$i]['destination_address'] = $hostname; - } - } else { - $values[$i]['destination_address'] = $hostnames[$values[$i]['destination_address']]; - } - } + // Comparte footprints. + if ($freeze_data === md5(serialize($data))) { + // Taht means that all relationships are 0. + return []; } - // Address resolution end - return $values; + return $data; } /** * Returns the command needed to run nfdump for the given filter. * - * @param array filter Netflow filter. + * @param array $filter Netflow filter. * - * @return Command to run. + * @return string Command to run. */ function netflow_get_command($filter) { global $config; - // Build command + // Build command. $command = io_safe_output($config['netflow_nfdump']).' -N'; - // Netflow data path + // Netflow data path. if (isset($config['netflow_path']) && $config['netflow_path'] != '') { $command .= ' -R. -M '.$config['netflow_path']; } - // Filter options + // Filter options. $command .= netflow_get_filter_arguments($filter); return $command; @@ -970,13 +899,13 @@ function netflow_get_command($filter) /** * Returns the nfdump command line arguments that match the given filter. * - * @param array filter Netflow filter. + * @param array $filter Netflow filter. * - * @return Command line argument string. + * @return string Command line argument string. */ function netflow_get_filter_arguments($filter) { - // Advanced filter + // Advanced filter. $filter_args = ''; if ($filter['advanced_filter'] != '') { $filter_args = preg_replace('/["\r\n]/', '', io_safe_output($filter['advanced_filter'])); @@ -987,7 +916,7 @@ function netflow_get_filter_arguments($filter) $filter_args .= ' "(router ip '.$filter['router_ip'].')'; } - // Normal filter + // Normal filter. if ($filter['ip_dst'] != '') { $filter_args .= ' "('; $val_ipdst = explode(',', io_safe_output($filter['ip_dst'])); @@ -1102,74 +1031,11 @@ function netflow_get_filter_arguments($filter) function netflow_get_chart_types() { return [ - 'netflow_area' => __('Area graph'), - 'netflow_pie_summatory' => __('Pie graph and Summary table'), - 'netflow_statistics' => __('Statistics table'), - 'netflow_data' => __('Data table'), - 'netflow_mesh' => __('Circular mesh'), - 'netflow_host_treemap' => __('Host detailed traffic'), - ]; -} - - -/** - * Gets valid intervals for a netflow chart in the format: - * - * interval_length => interval_description - * - * @return array of valid intervals. - */ -function netflow_get_valid_intervals() -{ - return [ - (string) SECONDS_10MINUTES => __('10 mins'), - (string) SECONDS_15MINUTES => __('15 mins'), - (string) SECONDS_30MINUTES => __('30 mins'), - (string) SECONDS_1HOUR => __('1 hour'), - (string) SECONDS_2HOUR => __('2 hours'), - (string) SECONDS_5HOUR => __('5 hours'), - (string) SECONDS_12HOURS => __('12 hours'), - (string) SECONDS_1DAY => __('1 day'), - (string) SECONDS_2DAY => __('2 days'), - (string) SECONDS_5DAY => __('5 days'), - (string) SECONDS_15DAYS => __('15 days'), - (string) SECONDS_1WEEK => __('Last week'), - (string) SECONDS_1MONTH => __('Last month'), - (string) SECONDS_2MONTHS => __('2 months'), - (string) SECONDS_3MONTHS => __('3 months'), - (string) SECONDS_6MONTHS => __('6 months'), - (string) SECONDS_1YEAR => __('Last year'), - (string) SECONDS_2YEARS => __('2 years'), - ]; -} - - -/** - * Gets valid intervals for a netflow chart in the format: - * - * interval_length => interval_description - * - * @return array of valid intervals. - */ -function netflow_get_valid_subintervals() -{ - return [ - (string) SECONDS_1MINUTE => __('1 min'), - (string) SECONDS_2MINUTES => __('2 mins'), - (string) SECONDS_5MINUTES => __('5 mins'), - (string) SECONDS_10MINUTES => __('10 mins'), - (string) SECONDS_15MINUTES => __('15 mins'), - (string) SECONDS_30MINUTES => __('30 mins'), - (string) SECONDS_1HOUR => __('1 hour'), - (string) SECONDS_2HOUR => __('2 hours'), - (string) SECONDS_5HOUR => __('5 hours'), - (string) SECONDS_12HOURS => __('12 hours'), - (string) SECONDS_1DAY => __('1 day'), - (string) SECONDS_2DAY => __('2 days'), - (string) SECONDS_5DAY => __('5 days'), - (string) SECONDS_15DAYS => __('15 days'), - (string) SECONDS_1WEEK => __('1 week'), - (string) SECONDS_1MONTH => __('1 month'), + 'netflow_area' => __('Area graph'), + 'netflow_summary' => __('Summary'), + 'netflow_data' => __('Data table'), + 'netflow_mesh' => __('Circular mesh'), + 'netflow_host_treemap' => __('Host detailed traffic'), ]; } @@ -1177,20 +1043,31 @@ function netflow_get_valid_subintervals() /** * Draw a netflow report item. * - * @param string start_date Period start date. - * @param string end_date Period end date. - * @param string interval_length Interval length in seconds (num_intervals * interval_length = start_date - end_date). - * @param string type Chart type. - * @param array filter Netflow filter. - * @param int max_aggregates Maximum number of aggregates. - * @param string output Output format. Only HTML and XML are supported. + * @param string $start_date Period start date. + * @param string $end_date Period end date. + * @param mixed $interval_length Resolution points or hourly or daily. + * @param string $type Chart type. + * @param array $filter Netflow filter. + * @param integer $max_aggregates Maximum number of aggregates. + * @param string $connection_name Node name when data is get in meta. + * @param string $output Output format. Only HTML, PDF and XML + * are supported. + * @param boolean $address_resolution True to resolve ips to hostnames. * - * @return The netflow report in the appropriate format. + * @return string The netflow report in the appropriate format. */ -function netflow_draw_item($start_date, $end_date, $interval_length, $type, $filter, $max_aggregates, $connection_name='', $output='HTML', $address_resolution=false) -{ +function netflow_draw_item( + $start_date, + $end_date, + $interval_length, + $type, + $filter, + $max_aggregates, + $connection_name='', + $output='HTML', + $address_resolution=false +) { $aggregate = $filter['aggregate']; - $unit = $filter['output']; $interval = ($end_date - $start_date); if (defined('METACONSOLE')) { $width = 950; @@ -1200,106 +1077,17 @@ function netflow_draw_item($start_date, $end_date, $interval_length, $type, $fil $height = 320; - // Process item + // Process item. switch ($type) { - case '0': case 'netflow_area': - $data = netflow_get_data($start_date, $end_date, $interval_length, $filter, $aggregate, $max_aggregates, $unit, $connection_name, $address_resolution); - if (empty($data)) { - break; - } - - if ($aggregate != 'none') { - if ($output == 'HTML') { - $html = ''.__('Unit').': '.netflow_format_unit($unit); - $html .= ' '.__('Aggregate').': '.netflow_format_aggregate($aggregate); - if ($interval_length != 0) { - $html .= ' '._('Resolution').": $interval_length ".__('seconds'); - } - - $html .= graph_netflow_aggregate_area($data, $interval, $width, $height, netflow_format_unit($unit)); - return $html; - } else if ($output == 'PDF') { - $html = ''.__('Unit').': '.netflow_format_unit($unit); - $html .= ' '.__('Aggregate').': '.netflow_format_aggregate($aggregate); - if ($interval_length != 0) { - $html .= ' '._('Resolution').": $interval_length ".__('seconds'); - } - - $html .= graph_netflow_aggregate_area($data, $interval, $width, $height, netflow_format_unit($unit), 2, true); - return $html; - } else if ($output == 'XML') { - $xml = "$unit\n"; - $xml .= "$aggregate\n"; - $xml .= "$interval_length\n"; - $xml .= netflow_aggregate_area_xml($data); - return $xml; - } - } else { - if ($output == 'HTML') { - $html = ''.__('Unit').': '.netflow_format_unit($unit); - if ($interval_length != 0) { - $html .= ' '._('Resolution').": $interval_length ".__('seconds'); - } - - $html .= graph_netflow_total_area($data, $interval, 660, 320, netflow_format_unit($unit)); - return $html; - } else if ($output == 'PDF') { - $html = ''.__('Unit').': '.netflow_format_unit($unit); - if ($interval_length != 0) { - $html .= ' '._('Resolution').": $interval_length ".__('seconds'); - } - - $html .= graph_netflow_total_area($data, $interval, 660, 320, netflow_format_unit($unit), 2, true); - return $html; - } else if ($output == 'XML') { - $xml = "$unit\n"; - $xml .= "$interval_length\n"; - $xml .= netflow_total_area_xml($data); - return $xml; - } - } - break; - - case '2': - case 'netflow_data': - $data = netflow_get_data($start_date, $end_date, $interval_length, $filter, $aggregate, $max_aggregates, $unit, $connection_name, $address_resolution); - - if (empty($data)) { - break; - } - - if ($output == 'HTML' || $output == 'PDF') { - $html = ''.__('Unit').': '.netflow_format_unit($unit); - $html .= ' '.__('Aggregate').': '.netflow_format_aggregate($aggregate); - if ($interval_length != 0) { - $html .= ' '._('Resolution').": $interval_length ".__('seconds'); - } - - $html .= "
    "; - $html .= netflow_data_table($data, $start_date, $end_date, $aggregate, $unit); - $html .= '
    '; - - return $html; - } else if ($output == 'XML') { - $xml = "$unit\n"; - $xml .= "$aggregate\n"; - $xml .= "$interval_length\n"; - // Same as netflow_aggregate_area_xml - $xml .= netflow_aggregate_area_xml($data); - return $xml; - } - break; - - case '3': - case 'netflow_statistics': - $data = netflow_get_stats( + $data = netflow_get_data( $start_date, $end_date, + $interval_length, $filter, $aggregate, $max_aggregates, - $unit, + false, $connection_name, $address_resolution ); @@ -1308,14 +1096,55 @@ function netflow_draw_item($start_date, $end_date, $interval_length, $type, $fil } if ($output == 'HTML' || $output == 'PDF') { - $html = netflow_stat_table($data, $start_date, $end_date, $aggregate, $unit); + $html .= graph_netflow_aggregate_area( + $data, + $interval, + $width, + $height, + ($output === 'HTML') ? 1 : 2, + ($output === 'HTML'), + $end_date + ); return $html; } else if ($output == 'XML') { - return netflow_stat_xml($data); + $xml .= ''.$aggregate."\n"; + $xml .= ''.$interval_length."\n"; + $xml .= netflow_aggregate_area_xml($data); + return $xml; + } + break; + + case 'netflow_data': + $data = netflow_get_data( + $start_date, + $end_date, + $interval_length, + $filter, + $aggregate, + $max_aggregates, + true, + $connection_name, + $address_resolution + ); + if (empty($data)) { + break; + } + + if ($output == 'HTML' || $output == 'PDF') { + $html .= "
    "; + $html .= netflow_data_table($data, $start_date, $end_date, $aggregate); + $html .= '
    '; + + return $html; + } else if ($output == 'XML') { + $xml .= ''.$aggregate."\n"; + $xml .= ''.$interval_length."\n"; + // Same as netflow_aggregate_area_xml. + $xml .= netflow_aggregate_area_xml($data); + return $xml; } break; - case '4': case 'netflow_summary': $data_summary = netflow_get_summary( $start_date, @@ -1327,22 +1156,13 @@ function netflow_draw_item($start_date, $end_date, $interval_length, $type, $fil break; } - if ($output == 'HTML' || $output == 'PDF') { - return netflow_summary_table($data_summary); - } else if ($output == 'XML') { - return netflow_summary_xml($data_summary); - } - break; - - case '1': - case 'netflow_pie': $data_pie = netflow_get_stats( $start_date, $end_date, $filter, $aggregate, $max_aggregates, - $unit, + true, $connection_name, $address_resolution ); @@ -1350,131 +1170,65 @@ function netflow_draw_item($start_date, $end_date, $interval_length, $type, $fil break; } - if ($output == 'HTML') { - $html = ''.__('Unit').': '.netflow_format_unit($unit); - $html .= ' '.__('Aggregate').': '.netflow_format_aggregate($aggregate); - $html .= graph_netflow_aggregate_pie($data_pie, netflow_format_aggregate($aggregate)); + if ($output === 'HTML' || $output === 'PDF') { + $html = ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= '
    '; + $html .= netflow_summary_table($data_summary); + $html .= ''; + $html .= graph_netflow_aggregate_pie( + $data_pie, + netflow_format_aggregate($aggregate), + ($output === 'HTML') ? 1 : 2, + ($output === 'HTML') + ); + $html .= '
    '; + $html .= netflow_stat_table( + $data_pie, + $start_date, + $end_date, + $aggregate + ); return $html; - } else if ($output == 'PDF') { - $html = ''.__('Unit').': '.netflow_format_unit($unit); - $html .= ' '.__('Aggregate').": $aggregate"; - $html .= graph_netflow_aggregate_pie($data_pie, netflow_format_aggregate($aggregate), 2, true); - return $html; - } else if ($output == 'XML') { - $xml = "$unit\n"; - $xml .= "$aggregate\n"; - $xml .= netflow_aggregate_pie_xml($data_pie); - return $xml; - } - break; - - case 'netflow_pie_summatory': - $data_summary = netflow_get_summary( - $start_date, - $end_date, - $filter, - $connection_name - ); - if (empty($data_summary)) { - break; - } - - $data_pie = netflow_get_stats( - $start_date, - $end_date, - $filter, - $aggregate, - $max_aggregates, - $unit, - $connection_name, - $address_resolution - ); - if (empty($data_pie)) { - break; - } - - switch ($output) { - case 'HTML': - $html = ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - $html .= '
    '; - $html .= netflow_summary_table($data_summary); - $html .= ''.__('Unit').': '.netflow_format_unit($unit); - $html .= ' '.__('Aggregate').': '.netflow_format_aggregate($aggregate); - $html .= ''; - $html .= graph_netflow_aggregate_pie($data_pie, netflow_format_aggregate($aggregate)); - $html .= '
    '; - return $html; - - break; - case 'PDF': - break; - - case 'XML': - return netflow_summary_xml($data_summary); - - break; + } else if ($output === 'XML') { + return netflow_summary_xml($data_summary, $data_pie); } break; case 'netflow_mesh': - $netflow_data = netflow_get_record($start_date, $end_date, $filter, $max_aggregates, $unit, $address_resolution); - - switch ($aggregate) { - case 'srcport': - case 'dstport': - $source_type = 'source_port'; - $destination_type = 'destination_port'; - break; - - default: - case 'dstip': - case 'srcip': - $source_type = 'source_address'; - $destination_type = 'destination_address'; - break; - } - - $data = []; - $data['elements'] = []; - $data['matrix'] = []; - foreach ($netflow_data as $record) { - if (!in_array($record[$source_type], $data['elements'])) { - $data['elements'][] = $record[$source_type]; - $data['matrix'][] = []; - } - - if (!in_array($record[$destination_type], $data['elements'])) { - $data['elements'][] = $record[$destination_type]; - $data['matrix'][] = []; - } - } - - for ($i = 0; $i < count($data['matrix']); $i++) { - $data['matrix'][$i] = array_fill(0, count($data['matrix']), 0); - } - - foreach ($netflow_data as $record) { - $source_key = array_search($record[$source_type], $data['elements']); - $destination_key = array_search($record[$destination_type], $data['elements']); - if ($source_key !== false && $destination_key !== false) { - $data['matrix'][$source_key][$destination_key] += $record['data']; - } - } + $data = netflow_get_relationships_raw_data( + $start_date, + $end_date, + $filter, + $max_aggregates, + $aggregate, + $address_resolution + ); + $data_circular = netflow_parse_relationships_for_circular_mesh( + $data['lines'], + $data['sources'], + netflow_aggregate_is_ip($aggregate) + ); $html = '
    '; - $html .= graph_netflow_circular_mesh($data, netflow_format_unit($unit), 700); + $html .= graph_netflow_circular_mesh($data_circular); $html .= '
    '; - return $html; - break; case 'netflow_host_treemap': - $netflow_data = netflow_get_record($start_date, $end_date, $filter, $max_aggregates, $unit, $address_resolution); - + $data_stats = netflow_get_stats( + $start_date, + $end_date, + $filter, + $aggregate, + $max_aggregates, + true, + $connection_name, + $address_resolution + ); switch ($aggregate) { case 'srcip': case 'srcport': @@ -1492,51 +1246,30 @@ function netflow_draw_item($start_date, $end_date, $interval_length, $type, $fil break; } - $data_aux = []; - foreach ($netflow_data as $record) { - $address = $record[$address_type]; - $port = $record[$port_type]; - - if (!isset($data_aux[$address])) { - $data_aux[$address] = []; - } - - if (!isset($data_aux[$address][$port])) { - $data_aux[$address][$port] = 0; - } - - $data_aux[$address][$port] += $record['data']; - } - + $data_graph = [ + 'name' => __('Host detailed traffic').': '.$type, + 'children' => [], + ]; $id = -1; - $data = []; - - if (! empty($netflow_data)) { - $data['name'] = __('Host detailed traffic').': '.$type; - $data['children'] = []; - - foreach ($data_aux as $address => $ports) { - $children = []; - $children['id'] = $id++; - $children['name'] = $address; - $children['children'] = []; - foreach ($ports as $port => $value) { - $children_data = []; - $children_data['id'] = $id++; - $children_data['name'] = $port; - $children_data['value'] = $value; - $children_data['tooltip_content'] = "$port: ".format_numeric($value).' '.netflow_format_unit($unit).''; - $children['children'][] = $children_data; - } - - $data['children'][] = $children; - } + foreach ($data_stats as $sdata) { + $data_graph['children'][] = [ + 'id' => $i++, + 'name' => $sdata['agg'], + 'children' => [ + [ + 'id' => $i++, + 'name' => $sdata['agg'], + 'value' => $sdata['data'], + 'tooltip_content' => network_format_bytes($sdata['data']), + ], + ], + ]; } - return graph_netflow_host_traffic($data, netflow_format_unit($unit), 'auto', 400); + return graph_netflow_host_traffic($data_graph, 'auto', 400); - break; default: + // Nothing to do. break; } @@ -1546,107 +1279,32 @@ function netflow_draw_item($start_date, $end_date, $interval_length, $type, $fil } -/** - * Render a netflow report as an XML. - * - * @param int ID of the netflow report. - * @param string end_date Period start date. - * @param string end_date Period end date. - * @param string interval_length Interval length in seconds (num_intervals * interval_length = start_date - end_date). - */ -function netflow_xml_report($id, $start_date, $end_date, $interval_length=0) -{ - // Get report data - $report = db_get_row_sql('SELECT * FROM tnetflow_report WHERE id_report ='.(int) $id); - if ($report === false) { - echo ''.__('Error generating report')."\n"; - return; - } - - // Print report header - $time = get_system_time(); - echo ''; - echo "\n"; - echo " \n"; - echo ' '.$time."\n"; - echo ' '.date('r', $time)."\n"; - echo " \n"; - echo ' '.io_safe_output($report['id_name'])."\n"; - echo ' '.io_safe_output($report['description'])."\n"; - echo ' '.date('r', $start_date)."\n"; - echo ' '.date('r', $end_date)."\n"; - - // Get netflow item types - $item_types = netflow_get_chart_types(); - - // Print report items - $report_contents = db_get_all_rows_sql( - "SELECT * - FROM tnetflow_report_content - WHERE id_report='".$report['id_report']."' - ORDER BY `order`" - ); - foreach ($report_contents as $content) { - // Get item filters - $filter = db_get_row_sql( - "SELECT * - FROM tnetflow_filter - WHERE id_sg = '".io_safe_input($content['id_filter'])."'", - false, - true - ); - if ($filter === false) { - continue; - } - - echo " \n"; - echo ' '.io_safe_output($content['description'])."\n"; - echo ' '.io_safe_output($item_types[$content['show_graph']])."\n"; - echo ' '.$content['max']."\n"; - echo " \n"; - echo ' '.io_safe_output($filter['id_name'])."\n"; - echo ' '.io_safe_output($filter['ip_src'])."\n"; - echo ' '.io_safe_output($filter['ip_dst'])."\n"; - echo ' '.io_safe_output($filter['src_port'])."\n"; - echo ' '.io_safe_output($filter['src_port'])."\n"; - echo ' '.io_safe_output($filter['advanced_filter'])."\n"; - echo ' '.io_safe_output($filter['aggregate'])."\n"; - echo ' '.io_safe_output($filter['output'])."\n"; - echo " \n"; - - echo netflow_draw_item($start_date, $end_date, $interval_length, $content['show_graph'], $filter, $content['max'], $report['server_name'], 'XML'); - - echo " \n"; - } - - echo "\n"; -} - - /** * Render an aggregated area chart as an XML. * - * @param array Netflow data. + * @param array $data Netflow data. + * + * @return void XML is echoed. */ function netflow_aggregate_area_xml($data) { - // Print source information + // Print source information. if (isset($data['sources'])) { echo "\n"; foreach ($data['sources'] as $source => $discard) { - echo "$source\n"; + echo ''.$source."\n"; } echo "\n"; - // Print flow information + // Print flow information. echo "\n"; foreach ($data['data'] as $timestamp => $flow) { echo "\n"; echo ' '.$timestamp."\n"; echo " \n"; foreach ($flow as $source => $data) { - echo " $source\n"; + echo ' '.$source."\n"; echo ' '.$data."\n"; } @@ -1669,133 +1327,49 @@ function netflow_aggregate_area_xml($data) } -/** - * Render an area chart as an XML. - * - * @param array Netflow data. - */ -function netflow_total_area_xml($data) -{ - // Print flow information - $xml = "\n"; - foreach ($data as $timestamp => $flow) { - $xml .= "\n"; - $xml .= ' '.$timestamp."\n"; - $xml .= ' '.$flow['data']."\n"; - $xml .= "\n"; - } - - $xml .= "\n"; - - return $xml; -} - - -/** - * Render a pie chart as an XML. - * - * @param array Netflow data. - */ -function netflow_aggregate_pie_xml($data) -{ - // Calculate total - $total = 0; - foreach ($data as $flow) { - $total += $flow['data']; - } - - if ($total == 0) { - return; - } - - // Print percentages - echo "\n"; - foreach ($data as $flow) { - echo ''.$flow['agg']."\n"; - echo ''.format_numeric((100 * $flow['data'] / $total), 2)."%\n"; - } - - echo "\n"; -} - - -/** - * Render a stats table as an XML. - * - * @param array Netflow data. - */ -function netflow_stat_xml($data) -{ - // Print stats - $xml .= "\n"; - foreach ($data as $flow) { - $xml .= ''.$flow['agg']."\n"; - $xml .= ''.$flow['data']."\n"; - } - - $xml .= "\n"; - - return $xml; -} - - /** * Render a summary table as an XML. * - * @param array Netflow data. + * @param array $data Netflow data. + * @param array $rows_data Table info (top N hosts). + * + * @return string Wiht XML data. */ -function netflow_summary_xml($data) +function netflow_summary_xml($data, $rows_data) { - // Print summary + // Print summary. $xml = "\n"; - $xml .= ' '.$data['totalflows']."\n"; - $xml .= ' '.$data['totalbytes']."\n"; - $xml .= ' '.$data['totalbytes']."\n"; - $xml .= ' '.$data['avgbps']."\n"; - $xml .= ' '.$data['avgpps']."\n"; - $xml .= ' '.$data['avgpps']."\n"; + $xml = " \n"; + $xml .= ' '.$data['totalflows']."\n"; + $xml .= ' '.$data['totalbytes']."\n"; + $xml .= ' '.$data['totalbytes']."\n"; + $xml .= ' '.$data['avgbps']."\n"; + $xml .= ' '.$data['avgpps']."\n"; + $xml .= ' '.$data['avgpps']."\n"; + $xml .= " \n"; + + // Add the data table. + $xml .= " \n"; + foreach ($rows_data as $d) { + $xml .= "\n"; + $xml .= ''.$d['agg']."\n"; + $xml .= ''.$d['data']."\n"; + $xml .= "\n"; + } + + $xml .= " \n"; $xml .= "\n"; return $xml; } -/** - * Return a string describing the given unit. - * - * @param string Netflow unit. - */ -function netflow_format_unit($unit) -{ - switch ($unit) { - case 'megabytes': - return __('MB'); - - case 'megabytespersecond': - return __('MB/s'); - - case 'kilobytes': - return __('kB'); - - case 'kilobytespersecond': - return __('kB/s'); - - case 'bytes': - return __('Bytes'); - - case 'bytespersecond': - return __('B/s'); - - default: - return ''; - } -} - - /** * Return a string describing the given aggregate. * - * @param string Netflow aggregate. + * @param string $aggregate Netflow aggregate. + * + * @return string With formatted aggregate. */ function netflow_format_aggregate($aggregate) { @@ -1806,9 +1380,6 @@ function netflow_format_aggregate($aggregate) case 'dstip': return __('Dst IP'); - case 'proto': - return __('Protocol'); - case 'srcip': return __('Src IP'); @@ -1824,20 +1395,20 @@ function netflow_format_aggregate($aggregate) /** * Check the nfdump binary for compatibility. * - * @param string nfdump binary full path. + * @param string $nfdump_binary Nfdump binary full path. * - * @return 1 if the binary does not exist or is not executable, 2 if a + * @return integer 1 if the binary does not exist or is not executable, 2 if a * version older than 1.6.8 is installed or the version cannot be * determined, 0 otherwise. */ function netflow_check_nfdump_binary($nfdump_binary) { - // Check that the binary exists and is executable + // Check that the binary exists and is executable. if (! is_executable($nfdump_binary)) { return 1; } - // Check at least version 1.6.8 + // Check at least version 1.6.8. $output = ''; $rc = -1; exec($nfdump_binary.' -V', $output, $rc); @@ -1866,3 +1437,462 @@ function netflow_check_nfdump_binary($nfdump_binary) return 2; } + + +/** + * Get the netflow datas to build a netflow explorer data structure. + * + * @param integer $max Number of result displayed. + * @param string $top_action Action to do (listeners,talkers,tcp or udp). + * @param integer $start_date In utimestamp. + * @param integer $end_date In utimestamp. + * @param string $filter Ip to filter. + * @param string $order Select one of bytes,pkts,flow. + * + * @return array With data (host, sum_bytes, sum_pkts and sum_flows). + */ +function netflow_get_top_summary( + $max, + $top_action, + $start_date, + $end_date, + $filter='', + $order='bytes' +) { + global $nfdump_date_format; + $netflow_filter = []; + $sort = ''; + switch ($top_action) { + case 'listeners': + if (empty(!$filter)) { + $netflow_filter['ip_src'] = $filter; + } + + $sort = 'dstip'; + break; + + case 'talkers': + if (empty(!$filter)) { + $netflow_filter['ip_dst'] = $filter; + } + + $sort = 'srcip'; + break; + + case 'tcp': + case 'udp': + $netflow_filter['proto'] = $top_action; + $sort = 'port'; + if (empty(!$filter)) { + $netflow_filter['advanced_filter'] = sprintf( + '((dst port %s) or (src port %s)) and (proto %s)', + $filter, + $filter, + $top_action + ); + // Display ips when filter is set in port. + $sort = 'ip'; + } + break; + + default: + return []; + } + + $command = netflow_get_command($netflow_filter); + + // Execute nfdump. + $order_text = ''; + switch ($order) { + case 'flows': + $order_text = 'flows'; + break; + + case 'pkts': + $order_text = 'packets'; + break; + + case 'bytes': + default: + $order_text = 'bytes'; + break; + } + + $command .= " -q -o csv -n $max -s $sort/$order_text -t ".date($nfdump_date_format, $start_date).'-'.date($nfdump_date_format, $end_date); + exec($command, $result); + + if (! is_array($result)) { + return []; + } + + // Remove first line (avoiding slow array_shift). + $result = array_reverse($result); + array_pop($result); + $result = array_reverse($result); + + $top_info = []; + foreach ($result as $line) { + if (empty($line)) { + continue; + } + + $data = explode(',', $line); + if (!isset($data[9])) { + continue; + } + + $top_info[(string) $data[4]] = [ + 'host' => $data[4], + 'sum_bytes' => $data[9], + 'sum_pkts' => $data[7], + 'sum_flows' => $data[5], + 'pct_bytes' => $data[10], + 'pct_pkts' => $data[8], + 'pct_flows' => $data[6], + ]; + } + + return $top_info; +} + + +/** + * Check the netflow version and print an error message if there is not correct. + * + * @return boolean True if version check is correct. + */ +function netflow_print_check_version_error() +{ + global $config; + + switch (netflow_check_nfdump_binary($config['netflow_nfdump'])) { + case 0: + return true; + + case 1: + ui_print_error_message( + __('nfdump binary (%s) not found!', $config['netflow_nfdump']) + ); + return false; + + case 2: + default: + ui_print_error_message( + __('Make sure nfdump version 1.6.8 or newer is installed!') + ); + return false; + } +} + + +/** + * Returns the array for netflow resolution select. + * + * @return array With all values. + */ +function netflow_resolution_select_params() +{ + return [ + NETFLOW_RES_LOWD => __('Low'), + NETFLOW_RES_MEDD => __('Medium'), + NETFLOW_RES_HID => __('High'), + NETFLOW_RES_ULTRAD => __('Ultra High'), + NETFLOW_RES_HOURLY => __('Hourly'), + NETFLOW_RES_DAILY => __('Daily'), + ]; +} + + +/** + * Get the resolution name. + * + * @param mixed $value Type. + * + * @return string Translated name. Unknown for unrecognized resolution names. + */ +function netflow_get_resolution_name($value) +{ + $resolutions = netflow_resolution_select_params(); + return (isset($resolutions[$value])) ? $resolutions[$value] : __('Unknown'); +} + + +/** + * Report formatted subtitle. + * + * @param string $aggregate Aggregate by param. + * @param string $resolution Netfow live view resolution. + * @param string $type Type of view. + * + * @return string HTML with formatted subtitle. + */ +function netflow_generate_subtitle_report($aggregate, $resolution, $type) +{ + $subt = __( + 'Agregate by %s', + netflow_format_aggregate($aggregate) + ); + + // Display the resolution only in required reports. + if (in_array($type, ['netflow_area', 'netflow_data']) === true) { + $subt .= ' - '; + $subt .= __( + 'Resolution %s', + netflow_get_resolution_name($resolution) + ); + } + + return $subt; +} + + +/** + * Returns netflow stats for the given period in an array. + * + * @param string $start_date Period start date. + * @param string $end_date Period end date. + * @param string $filter Netflow filter. + * @param string $aggregate Aggregate field. + * @param integer $max Maximum number of aggregates. + * + * @return array With netflow stats. + */ +function netflow_get_top_data( + $start_date, + $end_date, + $filter, + $aggregate, + $max +) { + global $nfdump_date_format; + + $values = [ + 'data' => [], + 'sources' => [], + ]; + + // Get the command to call nfdump. + $agg_command = sprintf( + '%s -q -o csv -n %s -s %s/bytes -t %s-%s', + netflow_get_command($filter), + $max, + $aggregate, + date($nfdump_date_format, $start_date), + date($nfdump_date_format, $end_date) + ); + + // Call nfdump. + exec($agg_command, $string); + + // Remove the first line. + $string[0] = ''; + + // Parse aggregates. + foreach ($string as $line) { + if (empty($line) === true) { + continue; + } + + $val = explode(',', $line); + $values['sources'][$val[4]] = 1; + } + + return $values; +} + + +/** + * Returns netflow stats for the given period in an array. + * + * @param string $filter Netflow filter (passed by reference). + * @param string $aggregate Aggregate field. + * @param array $sources Sources to aggregate to filter. + * + * @return void $filter is passed by reference. + */ +function netflow_update_second_level_filter(&$filter, $aggregate, $sources) +{ + // Update the filter. + switch ($aggregate) { + default: + case 'srcip': + $extra_filter = 'ip_src'; + break; + case 'srcport': + $extra_filter = 'src_port'; + break; + + case 'dstip': + $extra_filter = 'ip_dst'; + break; + + case 'dstport': + $extra_filter = 'dst_port'; + break; + } + + if (isset($filter[$extra_filter]) && $filter[$extra_filter] != '') { + $filter[$extra_filter] .= ','; + } + + $filter[$extra_filter] = implode(',', $sources); +} + + +/** + * Change some values on address resolve. + * + * @param array $values Where data will be overwritten (ref). + * @param boolean $get_hostnames Change it if address resolution es done (ref). + * @param string $aggregate One of srcip, srcport, dstip, dstport. + * + * @return void Referenced passed params will be changed. + */ +function netflow_address_resolution(&$values, &$get_hostnames, $aggregate) +{ + if ($aggregate !== 'srcip' && $aggregate !== 'dstip') { + return; + } + + $get_hostnames = true; + global $hostnames; + + $sources = []; + foreach ($values['sources'] as $source => $value) { + if (!isset($hostnames[$source])) { + $hostname = gethostbyaddr($source); + if ($hostname !== false) { + $hostnames[$source] = $hostname; + $source = $hostname; + } + } else { + $source = $hostnames[$source]; + } + + $sources[$source] = $value; + } + + $values['sources'] = $sources; +} + + +/** + * Check if is aggregate by IP or by port + * + * @param string $aggregate Aggregate tag. + * + * @return boolean True if is IP. False for port. + */ +function netflow_aggregate_is_ip($aggregate) +{ + return in_array($aggregate, ['dstip', 'srcip']); +} + + +/** + * Build netflow data structure to network map. + * + * @param integer $start_date Time in timestamp format. + * @param integer $end_date Time in timestamp format. + * @param integer $top Max data to show. + * @param integer $aggregate One of dstip or srcip. + * + * @return array With map structure. + */ +function netflow_build_map_data($start_date, $end_date, $top, $aggregate) +{ + // Pass an empty filter data structure. + $data = netflow_get_relationships_raw_data( + $start_date, + $end_date, + [ + 'id_name' => '', + 'id_group' => 0, + 'aggregate' => $aggregate, + 'id_dst' => '', + 'ip_src' => '', + 'dst_port' => '', + 'src_port' => '', + 'advanced_filter' => '', + 'router_ip' => '', + ], + $top, + $aggregate + ); + + $nodes = array_map( + function ($elem) { + return network_init_node_map($elem); + }, + array_merge($data['sources'], [__('Others')]) + ); + + $relations = []; + $inverse_nodes = array_flip($data['sources']); + + // Port are situated in a different places from addreses. + $is_ip = true; + $src_key = ($is_ip === true) ? 3 : 5; + $dst_key = ($is_ip === true) ? 4 : 6; + $retrieved_data = array_fill_keys($inverse_nodes, false); + + foreach ($data['lines'] as $line) { + if (empty($line) === true) { + continue; + } + + // Parse the line. + $items = explode(',', $line); + + // Get the required data. + $src_item = $inverse_nodes[$items[$src_key]]; + $dst_item = $inverse_nodes[$items[$dst_key]]; + $value = $items[12]; + $index_rel = $src_item.'-'.$dst_item; + + // Check if valid data. + if (!isset($value) || (!isset($src_item) && !isset($dst_item))) { + continue; + } + + // Mark as connected source and destination. + $retrieved_data[$src_item] = true; + $retrieved_data[$dst_item] = true; + + if (isset($relations[$index_rel])) { + $relations[$index_rel]['text_start'] += $value; + } else { + // Update the value. + network_init_relation_map($relations, $src_item, $dst_item, $value); + } + } + + // Format the data in edges. + array_walk( + $relations, + function (&$elem) { + $elem['text_start'] = network_format_bytes($elem['text_start']); + } + ); + + // Search for orphan nodes. + $orphan_hosts = []; + $orphan_index = (end($inverse_nodes) + 1); + foreach ($retrieved_data as $position => $rd) { + if ($rd === true) { + continue; + } + + network_init_relation_map($orphan_hosts, $position, $orphan_index); + } + + // If there is not any orphan node, delete it. + if (empty($orphan_hosts)) { + array_pop($nodes); + } + + return network_general_map_configuration( + $nodes, + array_merge($relations, $orphan_hosts) + ); +} diff --git a/pandora_console/include/functions_network.php b/pandora_console/include/functions_network.php new file mode 100644 index 0000000000..9c9e1456b4 --- /dev/null +++ b/pandora_console/include/functions_network.php @@ -0,0 +1,320 @@ + %d AND utimestamp < %d + %s + %s + GROUP BY %s + ORDER BY %s DESC + LIMIT %d', + $field_to_group, + $start, + $end, + $filter_sql, + $host_filter_sql, + $field_to_group, + $field_to_order, + $top + ); + + $data = db_get_all_rows_sql($sql); + + return ($data !== false) ? $data : []; +} + + +/** + * Get the possible actions on networking. + * + * @param boolean $network True if network. False if netflow. + * + * @return array With the actions to print in a select. + */ +function network_get_report_actions($network=true) +{ + $common_actions = [ + 'listeners' => __('Top listeners'), + 'talkers' => __('Top talkers'), + ]; + + if ($network) { + return $common_actions; + } + + return array_merge( + $common_actions, + [ + 'tcp' => __('Top TCP protocols'), + 'udp' => __('Top UDP protocols'), + ] + ); +} + + +/** + * Print the header of the network + * + * @param string $title Title of header. + * @param string $order Current ordering. + * @param string $selected Selected order. + * @param array $hidden_data All the data to hide into the button. + * + * @return string With HTML data. + */ +function network_print_explorer_header( + $title, + $order, + $selected, + $hidden_data +) { + $cell = '
    '; + $cell .= $title; + $cell .= html_print_link_with_params( + 'images/arrow-down-white.png', + array_merge($hidden_data, ['order_by' => $order]), + 'image', + ($selected === $order) ? 'opacity: 0.5' : '' + ); + $cell .= '
    '; + + return $cell; +} + + +/** + * Alias for format_for_graph to print bytes. + * + * @param integer $value Value to parse like bytes. + * + * @return string Number parsed. + */ +function network_format_bytes($value) +{ + if (!isset($value)) { + $value = 0; + } + + $value = (int) $value; + + return format_for_graph( + $value, + 2, + '.', + ',', + 1024, + 'B' + ); +} + + +/** + * Build netflow data structure to network map. + * + * @param integer $start Time in timestamp format. + * @param integer $end Time in timestamp format. + * @param integer $top Max data to show. + * @param boolean $talker True to get top tolkers. False for listeners. + * + * @return array With map structure. + */ +function network_build_map_data($start, $end, $top, $talker) +{ + $data = network_matrix_get_top($top, $talker, $start, $end); + + $hosts = array_map( + function ($elem) { + return $elem['host']; + }, + $data + ); + $inverse_hosts = array_flip($hosts); + + $nodes = array_map( + function ($elem) { + return network_init_node_map($elem); + }, + $hosts + ); + + $relations = []; + $orphan_relations = []; + foreach ($hosts as $host) { + $host_top = network_matrix_get_top( + $top, + !$talker, + $start, + $end, + $host, + true, + $hosts + ); + foreach ($host_top as $sd) { + $src_index = $inverse_hosts[$host]; + $dst_index = $inverse_hosts[$sd['host']]; + if (isset($src_index) === false || isset($dst_index) === false) { + continue; + } + + network_init_relation_map( + $relations, + $src_index, + $dst_index, + network_format_bytes($sd['sum_bytes']) + ); + } + + // Put the orphans on Other node. + if (empty($host_top)) { + $other_id = (end($inverse_hosts) + 1); + // TODOS: Add the data. + network_init_relation_map( + $orphan_relations, + $other_id, + $inverse_hosts[$host] + ); + } + } + + // Put the Others node and their relations. + if (empty($orphan_relations) === false) { + $nodes[] = network_init_node_map(__('Others')); + $relations = array_merge($relations, $orphan_relations); + } + + return network_general_map_configuration($nodes, $relations); +} + + +/** + * Return the array to pass to constructor to NetworkMap. + * + * @param array $nodes Nodes data structure. + * @param array $relations Relations data structure. + * + * @return array To be passed to NetworMap class. + */ +function network_general_map_configuration($nodes, $relations) +{ + return [ + 'nodes' => $nodes, + 'relations' => $relations, + 'pure' => 1, + 'no_pandora_node' => 1, + 'no_popup' => 1, + 'map_options' => [ + 'generation_method' => LAYOUT_SPRING1, + 'map_filter' => [ + 'node_radius' => 40, + 'node_sep' => 7, + ], + ], + ]; +} + + +/** + * Added a relation to relations array + * + * @param array $relations Relations array (passed by reference). + * @param integer $parent Parent id (numeric). + * @param integer $child Child id (numeric). + * @param string $text Text to show at the end of edge (optional). + * + * @return void Relations will be modified (passed by reference). + */ +function network_init_relation_map(&$relations, $parent, $child, $text='') +{ + $index = $parent.'-'.$child; + $relations[$index] = [ + 'id_parent' => $parent, + 'parent_type' => NODE_GENERIC, + 'child_type' => NODE_GENERIC, + 'id_child' => $child, + 'link_color' => '#82B92E', + ]; + + if (empty($text) === false) { + $relations[$index]['text_start'] = $text; + } +} + + +/** + * Initialize a node structure to NetworkMap class. + * + * @param string $name Node name. + * + * @return array Node data structure. + */ +function network_init_node_map($name) +{ + return [ + 'name' => $name, + 'type' => NODE_GENERIC, + 'width' => 20, + 'height' => 20, + 'status' => '#82B92E', + ]; +} diff --git a/pandora_console/include/functions_networkmap.php b/pandora_console/include/functions_networkmap.php index adbaa00922..af11deb541 100644 --- a/pandora_console/include/functions_networkmap.php +++ b/pandora_console/include/functions_networkmap.php @@ -1,32 +1,36 @@ = 1) { + /* + * Select data origin. + * group + * discovery task + * - Cloud + * - Application + * - Standar or custom + * network/mask + */ + + if ($group >= 0 && empty($ip_mask)) { if ($dont_show_subgroups) { $filter['id_grupo'] = $group; } else { @@ -372,22 +358,8 @@ function networkmap_generate_dot( } else if ($group == -666) { $agents = false; } else if (!empty($ip_mask)) { - $agents = networkmap_get_new_nodes_from_ip_mask( - $ip_mask, - [ - 'id_grupo', - 'nombre', - 'id_os', - 'id_parent', - 'id_agente', - 'normal_count', - 'warning_count', - 'critical_count', - 'unknown_count', - 'total_count', - 'notinit_count', - ], - $strict_user + $agents = networkmap_get_nodes_from_ip_mask( + $ip_mask ); } else { $agents = agents_get_agents( @@ -455,7 +427,6 @@ function networkmap_generate_dot( // Get agent modules data $modules = agents_get_modules($agent['id_agente'], '*', $filter, true, true); - if ($modules === false) { $modules = []; } @@ -518,11 +489,11 @@ function networkmap_generate_dot( // Create void statistics array $stats = []; - - $count = 0; - $group_nodes = 10; - $graph .= networkmap_create_transparent_node($count); - foreach (array_keys($orphans) as $node) { + /* + $count = 0; + $group_nodes = 10; + $graph .= networkmap_create_transparent_node($count); + foreach (array_keys($orphans) as $node) { if ($group_nodes == 0) { $count++; $graph .= networkmap_create_transparent_node($count); @@ -536,7 +507,8 @@ function networkmap_generate_dot( ); $group_nodes--; - } + } + */ // Create nodes foreach ($nodes as $node_id => $node) { @@ -694,17 +666,57 @@ function networkmap_generate_dot( } -// Returns an edge definition -function networkmap_create_edge($head, $tail, $layout, $nooverlap, $pure, $zoom, $ranksep, $simple, $regen, $font_size, $group, $sec2='operation/agentes/networkmap', $tab='topology', $id_networkmap=0) -{ +/** + * Returns an edge definition. + * + * @param mixed $head Head. + * @param mixed $tail Tail. + * @param string $layout Layout. + * @param string $nooverlap Nooverlap. + * @param integer $pure Pure. + * @param float $zoom Zoom. + * @param float $ranksep Ranksep. + * @param integer $simple Simple. + * @param integer $regen Regen. + * @param integer $font_size Font_size. + * @param integer $group Group. + * @param string $sec2 Sec2. + * @param string $tab Tab. + * @param integer $id_networkmap Id_networkmap. + * + * @return string Dot string. + */ +function networkmap_create_edge( + $head, + $tail, + $layout, + $nooverlap, + $pure, + $zoom, + $ranksep, + $simple, + $regen, + $font_size, + $group, + $sec2='operation/agentes/networkmap', + $tab='topology', + $id_networkmap=0 +) { if (defined('METACONSOLE')) { $url = ''; } else { - $url = 'index.php?sec=estado&'.'sec2='.$sec2.'&'.'tab='.$tab.'&'.'recenter_networkmap=1&'.'center='.$head.'&'.'layout='.$layout.'&'.'nooverlap='.$nooverlap.'&'.'pure='.$pure.'&'.'zoom='.$zoom.'&'.'ranksep='.$ranksep.'&'.'simple='.$simple.'&'.'regen=1'.'&'.'font_size='.$font_size.'&'.'group='.$group.'&'.'id_networkmap='.$id_networkmap; + $url = 'index.php?sec=estado&sec2='.$sec2.'&tab='.$tab.'&'; + $url .= 'recenter_networkmap=1¢er='.$head.'&'; + $url .= 'layout='.$layout.'&nooverlap='.$nooverlap.'&'; + $url .= 'pure='.$pure.'&zoom='.$zoom.'&ranksep='.$ranksep.'&'; + $url .= 'simple='.$simple.'®en=1&font_size='.$font_size.'&'; + $url .= 'group='.$group.'&id_networkmap='.$id_networkmap; } - // edgeURL allows node navigation - $edge = "\n".$head.' -- '.$tail.'[color="#BDBDBD", headclip=false, tailclip=false, edgeURL=""];'."\n"; + // Option edgeURL allows node navigation. + $edge = "\n".$head.' -- '.$tail; + $edge .= '[len='.$ranksep.', color="#BDBDBD", headclip=false, tailclip=false, edgeURL=""];'; + $edge .= "\n"; return $edge; } @@ -719,96 +731,6 @@ function networkmap_create_transparent_edge($head, $tail) } -// Returns a group node definition -function networkmap_create_group_node($group, $simple=0, $font_size=10, $metaconsole=false, $id_server=null, $strict_user=false) -{ - global $config; - global $hack_networkmap_mobile; - - $status = groups_get_status($group['id_grupo'], $strict_user); - - // Set node status - switch ($status) { - case 0: - $status_color = COL_NORMAL; - // Normal monitor - break; - - case 1: - $status_color = COL_CRITICAL; - // Critical monitor - break; - - case 2: - $status_color = COL_WARNING; - // Warning monitor - break; - - case 4: - $status_color = COL_ALERTFIRED; - // Alert fired - break; - - default: - $status_color = COL_UNKNOWN; - // Unknown monitor - break; - } - - $icon = groups_get_icon($group['id_grupo']); - - if ($simple == 0) { - // Set node icon - if ($hack_networkmap_mobile) { - $img_node = $config['homedir'].'/images/groups_small/'.$icon.'.png'; - - if (!file_exists($img_node)) { - $img_node = '-'; - } - - $img_node = ''; - } else if (file_exists(html_print_image('images/groups_small/'.$icon.'.png', true, false, true, true))) { - $img_node = html_print_image('images/groups_small/'.$icon.'.png', true, false, false, true); - } else { - $img_node = '-'; - } - - if (strlen(groups_get_name($group['id_grupo'])) > 40) { - $name = substr(groups_get_name($group['id_grupo']), 0, 40).'...'; - } else { - $name = groups_get_name($group['id_grupo']); - } - - if (defined('METACONSOLE')) { - $url = ''; - $url_tooltip = ''; - } else { - $url = 'index.php?sec=estado&sec2=operation/agentes/estado_agente&refr=60&group_id='.$group['id_grupo']; - $url_tooltip = 'ajax.php?page=operation/agentes/ver_agente&get_group_status_tooltip=1&id_group='.$group['id_grupo']; - } - - $node = "\n".$group['id_node'].' [ color="'.$status_color.'", fontsize='.$font_size.', style="filled", fixedsize=true, width=0.30, height=0.30, '.'label=< -
    '.$img_node.'
    '.io_safe_output($name).'
    >, - shape="invtrapezium", URL="'.$url.'", - tooltip="'.$url_tooltip.'"];'."\n"; - } else { - if (defined('METACONSOLE')) { - $url = ''; - $url_tooltip = ''; - } else { - $url = 'index.php?sec=estado&sec2=operation/agentes/estado_agente&refr=60&group_id='.$group['id_grupo']; - $url_tooltip = 'ajax.php?page=operation/agentes/ver_agente&get_group_status_tooltip=1&id_group='.$group['id_grupo']; - } - - $node = "\n".$group['id_node'].' [ color="'.$status_color.'", fontsize='.$font_size.', shape="invtrapezium", - URL="'.$url.'", style="filled", fixedsize=true, width=0.20, height=0.20, label="", - tooltip="'.$url_tooltip.'"];'."\n"; - } - - return $node; -} - - // Returns a node definition function networkmap_create_agent_node($agent, $simple=0, $font_size=10, $cut_names=true, $relative=false, $metaconsole=false, $id_server=null, $strict_user=false) { @@ -952,76 +874,6 @@ function networkmap_create_agent_node($agent, $simple=0, $font_size=10, $cut_nam } -function networkmap_create_module_group_node($module_group, $simple=0, $font_size=10, $metaconsole=false, $id_server=null) -{ - global $config; - global $hack_networkmap_mobile; - - // Set node status - switch ($module_group['status']) { - case 0: - $status_color = COL_NORMAL; - // Normal monitor - break; - - case 1: - $status_color = COL_CRITICAL; - // Critical monitor - break; - - case 2: - $status_color = COL_WARNING; - // Warning monitor - break; - - case 4: - $status_color = COL_ALERTFIRED; - // Alert fired - break; - - default: - $status_color = COL_UNKNOWN; - // Unknown monitor - break; - } - - if ($simple == 0) { - if (defined('METACONSOLE')) { - $url = ''; - $url_tooltip = ''; - } else { - $url = ''; - $url_tooltip = ''; - } - - $node = $module_group['id_node'].' [ color="'.$status_color.'", fontsize='.$font_size.', style="filled", '.'fixedsize=true, width=0.30, height=0.30, '.'label=<
    '.io_safe_output($module_group['name']).'
    >, - shape="square", URL="'.$url.'", - tooltip="'.$url_tooltip.'"];'; - } else { - if ($hack_networkmap_mobile) { - $img_node = ui_print_moduletype_icon($module['id_tipo_modulo'], true, true, false, true); - - $img_node = $config['homedir'].'/'.$img_node; - $img_node = ''; - } else { - $img_node = ui_print_moduletype_icon($module['id_tipo_modulo'], true, true, false); - } - - if (defined('METACONSOLE')) { - $url = ''; - $url_tooltip = ''; - } else { - $url = ''; - $url_tooltip = ''; - } - - $node = $module_group['id_node'].' [ color="'.$status_color.'", fontsize='.$font_size.', shape="square", URL="'.$url.'", '.'style="filled", fixedsize=true, width=0.20, '.'height=0.20, label="", tooltip="'.$url_tooltip.'"];'; - } - - return $node; -} - - // Returns a module node definition function networkmap_create_module_node($module, $simple=0, $font_size=10, $metaconsole=false, $id_server=null) { @@ -1175,35 +1027,13 @@ function networkmap_create_transparent_node($count=0) } -// Opens a group definition -function networkmap_open_group($id) -{ - $img = 'images/'.groups_get_icon($id).'.png'; - $name = groups_get_name($id); - - $group = 'subgraph cluster_'.$id.' { style=filled; color=darkolivegreen3; label=< - -
    '.html_print_image($img, true).''.$name.'
    >; tooltip="'.$name.'"; - URL="index.php?sec=estado&sec2=operation/agentes/estado_agente&group_id='.$id.'";'; - - return $group; -} - - -// Closes a group definition -function networkmap_close_group() -{ - return '}'; -} - - // Opens a graph definition function networkmap_open_graph( $layout, $nooverlap, $pure, $zoom, - $ranksep, + $rank_sep, $font_size, $size_canvas, $map_filter=[] @@ -1236,7 +1066,7 @@ function networkmap_open_graph( if (isset($map_filter['node_sep'])) { $node_sep = $map_filter['node_sep']; } else { - $node_sep = 0.25; + $node_sep = 0.1; } if (isset($map_filter['rank_sep'])) { @@ -1258,14 +1088,14 @@ function networkmap_open_graph( if (isset($map_filter['kval'])) { $kval = $map_filter['kval']; } else { - $kval = 0.3; + $kval = 0.1; } // BEWARE: graphwiz DONT use single ('), you need double (") $head = 'graph networkmap { dpi=100; bgcolor="transparent"; labeljust=l; margin=0; pad="0.75,0.75";'; if ($nooverlap != '') { $head .= 'overlap="false";'; - $head .= 'outputorder=edgesfirst;'; + $head .= 'outputorder=first;'; } if ($layout == 'flat' || $layout == 'spring1' || $layout == 'spring2') { @@ -1290,12 +1120,13 @@ function networkmap_open_graph( $head .= "mindist=\"$mindist\";"; } - $head .= 'ratio=fill;'; + $head .= 'ratio="fill";'; $head .= 'root=0;'; $head .= "nodesep=\"$node_sep\";"; $head .= "size=\"$size\";"; $head .= "\n"; + return $head; } @@ -1338,67 +1169,6 @@ function networkmap_get_filter($layout) } -/** - * Creates a networkmap. - * - * @param string Network map name. - * @param string Network map type (topology, groups or policies). - * @param layout Network map layout (circular, flat, radial, spring1 or spring2). - * @param bool overlapping activate flag. - * @param bool simple view activate flag. - * @param bool regenerate file activate flag. - * @param int font size. - * @param int group id filter (0 for all). - * @param int module group id filter (0 for all). - * @param int policy id filter (0 for all). - * @param string depth level. - * @param bool only modules with alerts flag. - * @param bool hide policy modules flag - * @param float zoom factor - * - * @return mixed New networkmap id if created. False if it could not be created. - */ -function networkmap_create_networkmap($values) -{ - global $config; - - // The name is required - if (! isset($values['name'])) { - return false; - } - - // Set defaults for the empty values - set_unless_defined($values['type'], 'topology'); - set_unless_defined($values['layout'], 'radial'); - set_unless_defined($values['nooverlap'], true); - set_unless_defined($values['simple'], false); - set_unless_defined($values['regenerate'], true); - set_unless_defined($values['font_size'], 12); - set_unless_defined($values['store_group'], 0); - set_unless_defined($values['id_group'], 0); - set_unless_defined($values['regenerate'], true); - set_unless_defined($values['id_module_group'], 0); - set_unless_defined($values['depth'], 'all'); - set_unless_defined($values['only_modules_with_alerts'], false); - set_unless_defined($values['hide_policy_modules'], false); - set_unless_defined($values['zoom'], 1); - set_unless_defined($values['distance_nodes'], 2.5); - set_unless_defined($values['center'], 0); - set_unless_defined($values['id_user'], $config['id_user']); - set_unless_defined($values['text_filter'], ''); - set_unless_defined($values['regenerate'], true); - set_unless_defined($values['dont_show_subgroups'], 0); - set_unless_defined($values['show_groups'], false); - set_unless_defined($values['pandoras_children'], false); - set_unless_defined($values['show_modules'], false); - set_unless_defined($values['show_snmp_modules'], 0); - set_unless_defined($values['l2_network'], 0); - set_unless_defined($values['server_name'], ''); - - return @db_process_sql_insert('tnetwork_map', $values); -} - - /** * Get a network map report. * @@ -1517,57 +1287,6 @@ function networkmap_type_to_str_type($type) } -/** - * Deletes a network map if the property is that user. - * - * @param string User id that call this funtion. - * @param int Map id to be deleted. - * - * @return boolean True if the map was deleted, false the map is not yours. - */ -function networkmap_delete_user_networkmap($id_user='', $id_networkmap) -{ - if ($id_user == '') { - $id_user = $config['id_user']; - } - - $id_networkmap = safe_int($id_networkmap); - if (empty($id_networkmap)) { - return false; - } - - $networkmap = networkmap_get_networkmap($id_networkmap); - if ($networkmap === false) { - return false; - } - - return @db_process_sql_delete('tnetwork_map', ['id_networkmap' => $id_networkmap, 'id_user' => $id_user]); -} - - -/** - * Updates a network map. - * - * @param int Map id. - * @param array Extra values to be set. - * - * @return boolean True if the map was updated. False otherwise. - */ -function networkmap_update_networkmap($id_networkmap, $values) -{ - $networkmap = networkmap_get_networkmap($id_networkmap); - if ($networkmap === false) { - return false; - } - - return (db_process_sql_update( - 'tnetwork_map', - $values, - ['id_networkmap' => $id_networkmap] - )) !== false; -} - - /** * Get different networkmaps types for creation. * @@ -1597,108 +1316,78 @@ function networkmap_get_types($strict_user=false) /** - * Get networkmaps types. + * Retrieve agent list matching desired network. * - * @return array Networkmap diferent types. + * @param string $ip_mask Networks. + * @param array $fields Extra fields. + * + * @return array Of agents. */ -function networkmap_get_filter_types($strict_user=false) -{ - $networkmap_types = []; - - $is_enterprise = enterprise_include_once('include/functions_policies.php'); - - $networkmap_types['topology'] = __('Topology'); - $networkmap_types['groups'] = __('Group'); - $networkmap_types['dynamic'] = __('Dynamic'); - if (!$strict_user) { - $networkmap_types['radial_dynamic'] = __('Radial dynamic'); - } - - if (($is_enterprise !== ENTERPRISE_NOT_HOOK) && (!$strict_user)) { - $enterprise_types = enterprise_hook('policies_get_networkmap_filter_types'); - - $networkmap_types = array_merge($networkmap_types, $enterprise_types); - } - - return $networkmap_types; -} - - -function networkmap_cidr_match($ip, $cidr_mask) -{ - // copy from open source code - // https://gist.github.com/linickx/1309388 - $chunks = explode('/', $cidr_mask); - $subnet = $chunks[0]; - $bits = $chunks[1]; - - $ip = ip2long($ip); - $subnet = ip2long($subnet); - $mask = (-1 << (32 - $bits)); - $subnet &= $mask; - // nb: in case the supplied subnet wasn't correctly aligned - return ($ip & $mask) == $subnet; -} - - -function networkmap_get_new_nodes_from_ip_mask( +function networkmap_get_nodes_from_ip_mask( $ip_mask, - $fields=[], - $strict_user=false + $return_ids_only=false ) { $list_ip_masks = explode(',', $ip_mask); - $list_address = db_get_all_rows_in_table('taddress'); - if (empty($address)) { - $address = []; - } - - if ($strict_user) { - $filter['group_by'] = 'tagente.id_agente'; - $fields = ['tagente.id_agente']; - $acltags = tags_get_user_groups_and_tags($config['id_user'], 'AR', $strict_user); - $user_agents = tags_get_all_user_agents(false, $config['id_user'], $acltags, $filter, $fields, false, $strict_user, true); - - foreach ($all_user_agents as $agent) { - $user_agents[$agent['id_agente']] = $agent['id_agente']; - } + if (empty($list_ip_masks)) { + return []; } $agents = []; - foreach ($list_address as $address) { - foreach ($list_ip_masks as $ip_mask) { - if (networkmap_cidr_match($address['ip'], $ip_mask)) { - $id_agent = db_get_value_filter( - 'id_agent', - 'taddress_agent', - ['id_a' => $address['id_a']] - ); + foreach ($list_ip_masks as $subnet) { + $net = explode('/', $subnet); - if (empty($id_agent)) { - continue; - } + // Calculate real network address. Avoid user bad input. + $mask = ~((1 << (32 - $net[1])) - 1); + $network = long2ip(ip2long($net[0]) & $mask); - if (empty($fields)) { - if ($strict_user) { - if (array_key_exists($id_agent, $user_agents)) { - $agents[] = db_get_value_filter('id_agent', 'taddress_agent', ['id_a' => $address['id_a']]); - } - } else { - $agents[] = db_get_value_filter('id_agent', 'taddress_agent', ['id_a' => $address['id_a']]); - } - } else { - if ($strict_user) { - if (array_key_exists($id_agent, $user_agents)) { - $agents[] = db_get_row('tagente', 'id_agente', $id_agent, $fields); - } - } else { - $agents[] = db_get_row('tagente', 'id_agente', $id_agent, $fields); - } - } - } + $sql = sprintf( + 'SELECT * + FROM `tagente` + INNER JOIN + (SELECT DISTINCT `id_agent` FROM + (SELECT `id_agente` AS "id_agent", `direccion` AS "ip" + FROM `tagente` + UNION + SELECT ag.`id_agent`, a.`ip` + FROM `taddress_agent` ag + INNER JOIN `taddress` a + ON ag.id_a=a.id_a + ) t_tmp + WHERE (-1 << %d) & INET_ATON(t_tmp.ip) = INET_ATON("%s") + ) t_res + ON t_res.`id_agent` = `tagente`.`id_agente`', + (32 - $net[1]), + $network + ); + + $subnet_agents = db_get_all_rows_sql($sql); + + if ($subnet_agents !== false) { + $agents = array_merge($agents, $subnet_agents); } } + if ($return_ids_only === false) { + $agents = array_reduce( + $agents, + function ($carry, $item) { + $carry[$item['id_agente']] = $item; + return $carry; + }, + [] + ); + } else { + $agents = array_reduce( + $agents, + function ($carry, $item) { + $carry[$item['id_agente']] = $item['id_agente']; + return $carry; + }, + [] + ); + } + return $agents; } @@ -1729,7 +1418,944 @@ function modules_get_all_interfaces($id_agent) } -?> +function networkmap_delete_networkmap($id=0) +{ + if (enterprise_installed()) { + // Relations + $result = delete_relations($id); + + // Nodes + $result = delete_nodes($id); + } + + // Map + $result = db_process_sql_delete('tmap', ['id' => $id]); + + return $result; +} + + +function networkmap_delete_nodes($id_map) +{ + return db_process_sql_delete('titem', ['id_map' => $id_map]); +} + + +function get_networkmaps($id) +{ + $groups = array_keys(users_get_groups(null, 'IW')); + + $filter = []; + $filter['id_group'] = $groups; + $filter['id'] = '<>'.$id; + $networkmaps = db_get_all_rows_filter('tmap', $filter); + if ($networkmaps === false) { + $networkmaps = []; + } + + $return = []; + $return[0] = __('None'); + foreach ($networkmaps as $networkmap) { + $return[$networkmap['id']] = $networkmap['name']; + } + + return $return; +} + + +/** + * Translates node (nodes_and_relations) into JS node. + * + * @param array $node Node. + * @param integer $count Count. + * @param integer $count_item_holding_area Count_item_holding_area. + * @param boolean $simulated Simulated. + * + * @return array JS nodes. + */ +function networkmap_db_node_to_js_node( + $node, + &$count, + &$count_item_holding_area, + $simulated=false +) { + global $config; + + $networkmap = db_get_row('tmap', 'id', $node['id_map']); + + $networkmap['filter'] = json_decode($networkmap['filter'], true); + + // Hardcoded + $networkmap['filter']['holding_area'] = [ + 500, + 500, + ]; + + // 40 = DEFAULT NODE RADIUS + // 30 = for to align + $holding_area_max_y = ($networkmap['height'] + 30 + 40 * 2 - $networkmap['filter']['holding_area'][1] + 10 * 40); + + $item = []; + $item['id'] = $count; + + if (enterprise_installed() && $simulated === false) { + enterprise_include_once('include/functions_networkmap.php'); + $item['id_db'] = $node['id_in_db']; + } else { + $item['id_db'] = (int) $node['id']; + } + + if ((int) $node['type'] == 0) { + $item['type'] = 0; + $item['id_agent'] = (int) $node['source_data']; + $item['id_module'] = ''; + } else if ((int) $node['type'] == 1) { + $item['type'] = 1; + $item['id_agent'] = (int) $node['style']['id_agent']; + $item['id_module'] = (int) $node['source_data']; + } else { + $item['type'] = 3; + } + + $item['fixed'] = true; + $item['x'] = (int) $node['x']; + $item['y'] = (int) $node['y']; + $item['px'] = (int) $node['x']; + $item['py'] = (int) $node['y']; + $item['z'] = (int) $node['z']; + $item['state'] = $node['state']; + $item['deleted'] = $node['deleted']; + if ($item['state'] == 'holding_area') { + // 40 = DEFAULT NODE RADIUS + // 30 = for to align + $holding_area_x = ($networkmap['width'] + 30 + 40 * 2 - $networkmap['filter']['holding_area'][0] + ($count_item_holding_area % 11) * 40); + $holding_area_y = ($networkmap['height'] + 30 + 40 * 2 - $networkmap['filter']['holding_area'][1] + (int) (($count_item_holding_area / 11)) * 40); + + if ($holding_area_max_y <= $holding_area_y) { + $holding_area_y = $holding_area_max_y; + } + + $item['x'] = $holding_area_x; + $item['y'] = $holding_area_y; + + // Increment for the next node in holding area + $count_item_holding_area++; + } + + $item['image_url'] = ''; + $item['image_width'] = 0; + $item['image_height'] = 0; + if (!empty($node['style']['image'])) { + $item['image_url'] = html_print_image( + $node['style']['image'], + true, + false, + true + ); + $image_size = getimagesize( + $config['homedir'].'/'.$node['style']['image'] + ); + $item['image_width'] = (int) $image_size[0]; + $item['image_height'] = (int) $image_size[1]; + } + + $item['raw_text'] = $node['style']['label']; + $item['text'] = io_safe_output($node['style']['label']); + $item['shape'] = $node['style']['shape']; + + switch ($node['type']) { + case 0: + $color = get_status_color_networkmap($node['source_data']); + break; + + default: + // Old code + if ($node['source_data'] == -1) { + $color = '#364D1F'; + } else if ($node['source_data'] == -2) { + $color = '#364D1F'; + } else { + $color = get_status_color_networkmap($node['source_data']); + } + break; + } + + $item['color'] = $color; + $item['map_id'] = 0; + if (isset($node['id_map'])) { + $item['map_id'] = $node['id_map']; + } + + if (!isset($node['style']['id_networkmap']) || $node['style']['id_networkmap'] == '' || $node['style']['id_networkmap'] == 0) { + $item['networkmap_id'] = 0; + } else { + $item['networkmap_id'] = $node['style']['id_networkmap']; + } + + $count++; + + return $item; +} + + +function get_status_color_networkmap($id, $color=true) +{ + // $status = agents_get_status($id); + $agent_data = db_get_row_sql('SELECT * FROM tagente WHERE id_agente = '.$id); + + if ($agent_data === false) { + return COL_UNKNOWN; + } + + $status = agents_get_status_from_counts($agent_data); + + if (!$color) { + return $status; + } + + if ($agent_data['fired_count'] > 0) { + return COL_ALERTFIRED; + } + + // Select node color by checking status. + switch ($status) { + case AGENT_MODULE_STATUS_NORMAL: + return COL_NORMAL; + + case AGENT_MODULE_STATUS_NOT_INIT: + return COL_NOTINIT; + + case AGENT_MODULE_STATUS_CRITICAL_BAD: + return COL_CRITICAL; + + case AGENT_MODULE_STATUS_WARNING: + return COL_WARNING; + + case AGENT_MODULE_STATUS_UNKNOWN: + default: + return COL_UNKNOWN; + } + + return COL_UNKNOWN; +} + + +function networkmap_clean_relations_for_js(&$relations) +{ + do { + $cleaned = true; + + foreach ($relations as $key => $relation) { + if ($relation['id_parent_source_data'] == $relation['id_child_source_data']) { + if (($relation['child_type'] != 3) && $relation['parent_type'] != 3) { + $cleaned = false; + + if ($relation['parent_type'] == 1) { + $to_find = $relation['id_parent_source_data']; + $to_replace = $relation['id_child_source_data']; + } else if ($relation['child_type'] == 1) { + $to_find = $relation['id_child_source_data']; + $to_replace = $relation['id_parent_source_data']; + } + + // Replace and erase the links + foreach ($relations as $key2 => $relation2) { + if ($relation2['id_parent_source_data'] == $to_find) { + $relations[$key2]['id_parent_source_data'] = $to_replace; + } else if ($relation2['id_child_source_data'] == $to_find) { + $relations[$key2]['id_child_source_data'] = $to_replace; + } + } + + unset($relations[$key]); + + break; + } + } + } + } while (!$cleaned); +} + + +/** + * Transform networkmap relations into js links. + * + * @param array $relations Relations. + * @param array $nodes_graph Nodes_graph. + * @param boolean $simulated Simulated. + * + * @return array JS relations. + */ +function networkmap_links_to_js_links( + $relations, + $nodes_graph, + $simulated=false +) { + $return = []; + + if (enterprise_installed() && $simulated === false) { + enterprise_include_once('include/functions_networkmap.php'); + } + + $count = 0; + foreach ($relations as $key => $relation) { + if (($relation['parent_type'] == NODE_MODULE) + && ($relation['child_type'] == NODE_MODULE) + ) { + $id_target_agent = agents_get_agent_id_by_module_id( + $relation['id_parent_source_data'] + ); + $id_source_agent = agents_get_agent_id_by_module_id( + $relation['id_child_source_data'] + ); + $id_target_module = $relation['id_parent_source_data']; + $id_source_module = $relation['id_child_source_data']; + } else if (($relation['parent_type'] == NODE_MODULE) + && ($relation['child_type'] == NODE_AGENT) + ) { + $id_target_agent = agents_get_agent_id_by_module_id( + $relation['id_parent_source_data'] + ); + $id_target_module = $relation['id_parent_source_data']; + $id_source_agent = $relation['id_child_source_data']; + } else if (($relation['parent_type'] == NODE_AGENT) + && ($relation['child_type'] == NODE_MODULE) + ) { + $id_target_agent = $relation['id_parent_source_data']; + $id_source_module = $relation['id_child_source_data']; + $id_source_agent = agents_get_agent_id_by_module_id( + $relation['id_child_source_data'] + ); + } else { + $id_target_agent = $relation['id_parent_source_data']; + $id_source_agent = $relation['id_child_source_data']; + } + + $item = []; + $item['id'] = $count; + $count++; + if (enterprise_installed() && $simulated === false) { + $item['id_db'] = get_relation_id($relation); + } else { + $item['id_db'] = $key; + } + + $item['arrow_start'] = ''; + $item['arrow_end'] = ''; + $item['status_start'] = ''; + $item['status_end'] = ''; + $item['id_module_start'] = 0; + $item['id_agent_start'] = (int) $id_source_agent; + $item['id_module_end'] = 0; + $item['id_agent_end'] = (int) $id_target_agent; + $item['link_color'] = '#999'; + $item['target'] = -1; + $item['source'] = -1; + $item['deleted'] = $relation['deleted']; + + if (enterprise_installed() && $simulated === false) { + $target_and_source = []; + $target_and_source = get_id_target_and_source_in_db($relation); + $item['target_id_db'] = (int) $target_and_source['target']; + $item['source_id_db'] = (int) $target_and_source['source']; + } else { + if (($relation['parent_type'] == NODE_MODULE) && ($relation['child_type'] == NODE_MODULE)) { + $item['target_id_db'] = $id_target_agent; + $item['source_id_db'] = $id_source_agent; + } else if (($relation['parent_type'] == NODE_AGENT) && ($relation['child_type'] == NODE_AGENT)) { + $item['target_id_db'] = (int) $relation['id_parent_source_data']; + $item['source_id_db'] = $id_source_agent; + } else { + $item['target_id_db'] = (int) $relation['id_parent_source_data']; + $item['source_id_db'] = (int) $relation['id_child_source_data']; + } + } + + $item['text_end'] = ''; + $item['text_start'] = ''; + + if ($relation['parent_type'] == 1) { + $item['arrow_end'] = 'module'; + $item['status_end'] = modules_get_agentmodule_status((int) $id_target_module, false, false, null); + $item['id_module_end'] = (int) $id_target_module; + $text_end = modules_get_agentmodule_name((int) $id_target_module); + if (preg_match('/(.+)_ifOperStatus$/', (string) $text_end, $matches)) { + if ($matches[1]) { + // It's ok to safe_output as it inlo goint to be user into the map line + $item['text_end'] = io_safe_output($matches[1]); + } + } + } + + if ($relation['child_type'] == NODE_MODULE) { + $item['arrow_start'] = 'module'; + $item['status_start'] = modules_get_agentmodule_status((int) $id_source_module, false, false, null); + $item['id_module_start'] = (int) $id_source_module; + $text_start = modules_get_agentmodule_name((int) $id_source_module); + if (preg_match('/(.+)_ifOperStatus$/', (string) $text_start, $matches)) { + if ($matches[1]) { + // It's ok to safe_output as it inlo goint to be user into the map line + $item['text_start'] = io_safe_output($matches[1]); + } + } + } + + $agent = 0; + $agent2 = 0; + $control1 = false; + $control2 = false; + + if (($relation['parent_type'] == NODE_MODULE) && ($relation['child_type'] == NODE_MODULE)) { + if (($item['status_start'] == AGENT_MODULE_STATUS_CRITICAL_BAD) || ($item['status_end'] == AGENT_MODULE_STATUS_CRITICAL_BAD)) { + $item['link_color'] = '#FC4444'; + } else if (($item['status_start'] == AGENT_MODULE_STATUS_WARNING) || ($item['status_end'] == AGENT_MODULE_STATUS_WARNING)) { + $item['link_color'] = '#FAD403'; + } + + $agent = agents_get_agent_id_by_module_id( + $relation['id_parent_source_data'] + ); + $agent2 = agents_get_agent_id_by_module_id( + $relation['id_child_source_data'] + ); + foreach ($nodes_graph as $key2 => $node) { + if (isset($node['id_agent'])) { + if ($node['id_agent'] == $agent) { + $agent = $node['id_db']; + $control1 = true; + } + + if ($node['id_agent'] == $agent2) { + $agent2 = $node['id_db']; + $control2 = true; + } + + if ($control1 && $control2) { + break; + } + } + } + } else if ($relation['child_type'] == NODE_MODULE) { + if ($item['status_start'] == AGENT_MODULE_STATUS_CRITICAL_BAD) { + $item['link_color'] = '#FC4444'; + } else if ($item['status_start'] == AGENT_MODULE_STATUS_WARNING) { + $item['link_color'] = '#FAD403'; + } + + $agent2 = agents_get_agent_id_by_module_id( + $relation['id_child_source_data'] + ); + foreach ($nodes_graph as $key2 => $node) { + if (isset($node['id_agent'])) { + if ($node['id_agent'] == $relation['id_parent_source_data']) { + $agent = $node['id_db']; + $control1 = true; + } + + if ($node['id_agent'] == $agent2) { + $agent2 = $node['id_db']; + $control2 = true; + } + + if ($control1 && $control2) { + break; + } + } + } + } else if ($relation['parent_type'] == NODE_MODULE) { + if ($item['status_end'] == AGENT_MODULE_STATUS_CRITICAL_BAD) { + $item['link_color'] = '#FC4444'; + } else if ($item['status_end'] == AGENT_MODULE_STATUS_WARNING) { + $item['link_color'] = '#FAD403'; + } + + $agent = agents_get_agent_id_by_module_id( + $relation['id_parent_source_data'] + ); + foreach ($nodes_graph as $key2 => $node) { + if (isset($node['id_agent'])) { + if ($node['id_agent'] == $agent) { + $agent = $node['id_db']; + $control1 = true; + } + + if ($node['id_agent'] == $relation['id_child_source_data']) { + $agent2 = $node['id_db']; + $control2 = true; + } + + if ($control1 && $control2) { + break; + } + } + } + } else if (($relation['parent_type'] == NODE_PANDORA) + && ($relation['child_type'] == NODE_PANDORA) + ) { + foreach ($nodes_graph as $key2 => $node) { + if ($relation['id_parent'] == $node['id_db']) { + $agent = $node['id_db']; + } + } + + foreach ($nodes_graph as $key2 => $node) { + if ($relation['id_child'] == $node['id_db']) { + $agent2 = $node['id_db']; + } + } + } else if (($relation['parent_type'] == NODE_PANDORA) + || ($relation['child_type'] == NODE_PANDORA) + ) { + if ($relation['parent_type'] == NODE_PANDORA) { + foreach ($nodes_graph as $key2 => $node) { + if ($relation['id_parent'] == $node['id_db']) { + $agent = $node['id_db']; + } else if ($node['id_agent'] == $relation['id_child_source_data']) { + $agent2 = $node['id_db']; + } + } + } else if ($relation['child_type'] == NODE_PANDORA) { + foreach ($nodes_graph as $key2 => $node) { + if ($relation['id_child'] == $node['id_db']) { + $agent2 = $node['id_db']; + } else if ($node['id_agent'] == $relation['id_parent_source_data']) { + $agent = $node['id_db']; + } + } + } + } else { + foreach ($nodes_graph as $key2 => $node) { + if (isset($node['id_agent'])) { + if ($node['id_agent'] == $relation['id_parent_source_data']) { + $agent = $node['id_db']; + } else if ($node['id_agent'] == $relation['id_child_source_data']) { + $agent2 = $node['id_db']; + } + } + } + } + + foreach ($nodes_graph as $node) { + if ($node['id_db'] == $agent) { + $item['target'] = $node['id']; + } else if ($node['id_db'] == $agent2) { + $item['source'] = $node['id']; + } + } + + if ((($item['target'] == -1) || ($item['source'] == -1)) + && $relation['parent_type'] == NODE_MODULE + && $relation['child_type'] == NODE_MODULE + ) { + continue; + } + + $return[] = $item; + } + + return $return; +} + + +function get_status_color_module_networkmap($id_agente_modulo) +{ + $status = modules_get_agentmodule_status($id_agente_modulo); + + // Set node status + switch ($status) { + case 0: + // At the moment the networkmap enterprise does not show the + // alerts. + case AGENT_MODULE_STATUS_NORMAL_ALERT: + $status_color = COL_NORMAL; + // Normal monitor + break; + + case 1: + $status_color = COL_CRITICAL; + // Critical monitor + break; + + case 2: + $status_color = COL_WARNING; + // Warning monitor + break; + + case 4: + $status_color = COL_ALERTFIRED; + // Alert fired + break; + + default: + $status_color = COL_UNKNOWN; + // Unknown monitor + break; + } + + return $status_color; +} + + +function duplicate_networkmap($id) +{ + $return = true; + + $values = db_get_row('tmap', 'id', $id); + unset($values['id']); + $free_name = false; + $values['name'] = io_safe_input(__('Copy of ')).$values['name']; + $count = 1; + while (!$free_name) { + $exist = db_get_row_filter('tmap', ['name' => $values['name']]); + if ($exist === false) { + $free_name = true; + } else { + $values['name'] = $values['name'].io_safe_input(' '.$count); + } + } + + $correct_or_id = db_process_sql_insert('tmap', $values); + if ($correct_or_id === false) { + $return = false; + } else { + if (enterprise_installed()) { + $new_id = $correct_or_id; + duplicate_map_insert_nodes_and_relations($id, $new_id); + } + } + + if ($return) { + return true; + } else { + // Clean DB. + if (enterprise_installed()) { + // Relations + delete_relations($new_id); + + // Nodes + delete_nodes($new_id); + } + + db_process_sql_delete('tmap', ['id' => $new_id]); + + return false; + } +} + + +function clean_duplicate_links($relations) +{ + if (enterprise_installed()) { + enterprise_include_once('include/functions_networkmap.php'); + } + + $segregation_links = []; + $index = 0; + $index2 = 0; + $index3 = 0; + $index4 = 0; + foreach ($relations as $rel) { + if (($rel['parent_type'] == 0) && ($rel['child_type'] == 0)) { + $segregation_links['aa'][$index] = $rel; + $index++; + } else if (($rel['parent_type'] == 1) && ($rel['child_type'] == 1)) { + $segregation_links['mm'][$index2] = $rel; + $index2++; + } else if (($rel['parent_type'] == 3) && ($rel['child_type'] == 3)) { + $segregation_links['ff'][$index4] = $rel; + $index4++; + } else { + $segregation_links['am'][$index3] = $rel; + $index3++; + } + } + + $final_links = []; + + // ---------------------------------------------------------------- + // --------------------- Clean duplicate links -------------------- + // ---------------------------------------------------------------- + $duplicated = false; + $index_to_del = 0; + $index = 0; + if (isset($segregation_links['aa']) === true + && is_array($segregation_links['aa']) === true + ) { + foreach ($segregation_links['aa'] as $link) { + foreach ($segregation_links['aa'] as $link2) { + if ($link['id_parent'] == $link2['id_child'] + && $link['id_child'] == $link2['id_parent'] + ) { + if (enterprise_installed()) { + delete_link($segregation_links['aa'][$index_to_del]); + } + + unset($segregation_links['aa'][$index_to_del]); + } + + $index_to_del++; + } + + $final_links['aa'][$index] = $link; + $index++; + + $duplicated = false; + $index_to_del = 0; + } + } + + $duplicated = false; + $index_to_del = 0; + $index2 = 0; + if (isset($segregation_links['mm']) === true + && is_array($segregation_links['mm']) === true + ) { + foreach ($segregation_links['mm'] as $link) { + foreach ($segregation_links['mm'] as $link2) { + if ($link['id_parent'] == $link2['id_child'] + && $link['id_child'] == $link2['id_parent'] + ) { + if (enterprise_installed()) { + delete_link($segregation_links['mm'][$index_to_del]); + } + } + + $index_to_del++; + } + + $final_links['mm'][$index2] = $link; + $index2++; + + $duplicated = false; + $index_to_del = 0; + } + } + + $duplicated = false; + $index_to_del = 0; + $index3 = 0; + + if (isset($segregation_links['ff']) === true + && is_array($segregation_links['ff']) === true + ) { + foreach ($segregation_links['ff'] as $link) { + foreach ($segregation_links['ff'] as $link2) { + if ($link['id_parent'] == $link2['id_child'] + && $link['id_child'] == $link2['id_parent'] + ) { + if (enterprise_installed()) { + delete_link($segregation_links['ff'][$index_to_del]); + } + + unset($segregation_links['ff'][$index_to_del]); + } + + $index_to_del++; + } + + $final_links['ff'][$index3] = $link; + $index3++; + + $duplicated = false; + $index_to_del = 0; + } + } + + $final_links['am'] = $segregation_links['am']; + + /* + ---------------------------------------------------------------- + ----------------- AA, AM and MM links management --------------- + ------------------ Priority: ----------------------------------- + -------------------- 1 -> MM (module - module) ----------------- + -------------------- 2 -> AM (agent - module) ------------------ + -------------------- 3 -> AA (agent - agent) ------------------- + ---------------------------------------------------------------- + */ + + $final_links2 = []; + $index = 0; + $l3_link = []; + $agent1 = 0; + $agent2 = 0; + + if (isset($final_links['mm']) === true + && is_array($final_links['mm']) === true + ) { + foreach ($final_links['mm'] as $rel_mm) { + $module_parent = $rel_mm['id_parent_source_data']; + $module_children = $rel_mm['id_child_source_data']; + $agent1 = (int) agents_get_agent_id_by_module_id($module_parent); + $agent2 = (int) agents_get_agent_id_by_module_id($module_children); + foreach ($final_links['aa'] as $key => $rel_aa) { + $l3_link = $rel_aa; + $id_p_source_data = (int) $rel_aa['id_parent_source_data']; + $id_c_source_data = (int) $rel_aa['id_child_source_data']; + if ((($id_p_source_data == $agent1) + && ($id_c_source_data == $agent2)) + || (($id_p_source_data == $agent2) + && ($id_c_source_data == $agent1)) + ) { + if (enterprise_installed()) { + delete_link($final_links['aa'][$key]); + } + + unset($final_links['aa'][$key]); + } + } + } + } + + $final_links2['aa'] = $final_links['aa']; + $final_links2['mm'] = $final_links['mm']; + $final_links2['am'] = $final_links['am']; + $final_links2['ff'] = $final_links['ff']; + + $same_m = []; + $index = 0; + if (isset($final_links2['am']) === true + && is_array($final_links2['am']) === true + ) { + foreach ($final_links2['am'] as $rel_am) { + foreach ($final_links2['am'] as $rel_am2) { + if (($rel_am['id_child_source_data'] == $rel_am2['id_child_source_data']) + && ($rel_am['id_parent_source_data'] != $rel_am2['id_parent_source_data']) + ) { + $same_m[$index]['rel'] = $rel_am2; + $same_m[$index]['agent_parent'] = $rel_am['id_parent_source_data']; + $index++; + } + } + } + } + + $final_links3 = []; + $index = 0; + $l3_link = []; + $have_l3 = false; + if (isset($final_links2['aa']) === true + && is_array($final_links2['aa']) === true + ) { + foreach ($final_links2['aa'] as $key => $rel_aa) { + $l3_link = $rel_aa; + foreach ($same_m as $rel_am) { + if ((($rel_aa['id_parent_source_data'] == $rel_am['parent']['id_parent_source_data']) + && ($rel_aa['id_child_source_data'] == $rel_am['rel']['id_parent_source_data'])) + || (($rel_aa['id_child_source_data'] == $rel_am['parent']['id_parent_source_data']) + && ($rel_aa['id_parent_source_data'] == $rel_am['rel']['id_parent_source_data'])) + ) { + if (enterprise_installed()) { + delete_link($final_links2['aa'][$key]); + } + + unset($final_links2['aa'][$key]); + } + } + } + } + + $final_links3['aa'] = $final_links2['aa']; + $final_links3['mm'] = $segregation_links['mm']; + $final_links3['am'] = $segregation_links['am']; + $final_links3['ff'] = $final_links2['ff']; + + $cleaned_links = []; + if (isset($final_links3['aa']) === true + && is_array($final_links3['aa']) === true + ) { + foreach ($final_links3['aa'] as $link) { + $cleaned_links[] = $link; + } + } + + if (isset($final_links3['am']) === true + && is_array($final_links3['am']) === true + ) { + foreach ($final_links3['am'] as $link) { + $cleaned_links[] = $link; + } + } + + if (isset($final_links3['mm']) === true + && is_array($final_links3['mm']) === true + ) { + foreach ($final_links3['mm'] as $link) { + $cleaned_links[] = $link; + } + } + + if (isset($final_links3['ff']) === true + && is_array($final_links3['ff']) === true + ) { + foreach ($final_links3['ff'] as $link) { + $cleaned_links[] = $link; + } + } + + return $cleaned_links; +} + + +function migrate_older_open_maps($id) +{ + global $config; + + $old_networkmap = db_get_row_filter( + 'tnetwork_map', + ['id_networkmap' => $id] + ); + + $map_values = []; + $map_values['id_group'] = $old_networkmap['id_group']; + $map_values['id_user'] = $old_networkmap['id_user']; + $map_values['type'] = 0; + $map_values['subtype'] = 0; + $map_values['name'] = $old_networkmap['name']; + + $new_map_filter = []; + $new_map_filter['dont_show_subgroups'] = $old_networkmap['dont_show_subgroups']; + $new_map_filter['node_radius'] = 40; + $new_map_filter['id_migrate_map'] = $id; + $map_values['filter'] = json_encode($new_map_filter); + + $map_values['description'] = 'Mapa open migrado'; + $map_values['width'] = 4000; + $map_values['height'] = 4000; + $map_values['center_x'] = 2000; + $map_values['center_y'] = 2000; + $map_values['background'] = ''; + $map_values['background_options'] = 0; + $map_values['source_period'] = 60; + $map_values['source'] = 0; + $map_values['source_data'] = $old_networkmap['id_group']; + if ($old_networkmap['type'] == 'radial_dinamic') { + $map_values['generation_method'] = 6; + } else { + $map_values['generation_method'] = 4; + } + + $map_values['generated'] = 0; + + $id_new_map = db_process_sql_insert('tmap', $map_values); + + if (!$id_new_map) { + return false; + } + + return true; +} + + +/** + * Load cluetip required files and JS. + * + * @return void + */ +function networkmap_load_cluetip() +{ + ui_require_css_file('cluetip', 'include/styles/js/'); + + ?> + [], + 'groups' => [], + ]; + + if (empty($id_message)) { + return $targets; + } + + $ret = db_get_all_rows_sql( + sprintf( + 'SELECT id_user + FROM tnotification_user nu + WHERE nu.id_mensaje = %d', + $id_message + ) + ); + + if (is_array($ret)) { + foreach ($ret as $row) { + array_push( + $targets['users'], + get_user_fullname($row['id_user']) + ); + } + } + + $ret = db_get_all_rows_sql( + sprintf( + 'SELECT COALESCE(tg.nombre,ng.id_group) as "id_group" + FROM tnotification_group ng + LEFT JOIN tgrupo tg + ON tg.id_grupo=ng.id_group + WHERE ng.id_mensaje = %d', + $id_message + ) + ); + + if (is_array($ret)) { + foreach ($ret as $row) { + if ($row['id_group'] == '0') { + $row['id_group'] = ''.__('All').''; + } + + array_push($targets['groups'], $row['id_group']); + } + } + + return $targets; +} + + +/** + * Check if current user has grants to read this notification + * + * @param integer $id_message Target message. + * + * @return boolean true, read available. False if not. + */ +function check_notification_readable(int $id_message) +{ + global $config; + + if (empty($id_message)) { + return false; + } + + // Using distinct to avoid double response on group messages read by user. + $sql = sprintf( + 'SELECT DISTINCT tm.*, utimestamp_read > 0 as "read" + FROM tmensajes tm + LEFT JOIN tnotification_user nu + ON tm.id_mensaje=nu.id_mensaje + AND nu.id_user="%s" + AND tm.id_mensaje=%d + LEFT JOIN (tnotification_group ng + INNER JOIN tusuario_perfil up + ON ng.id_group=up.id_grupo + AND up.id_grupo=ng.id_group + ) ON tm.id_mensaje=ng.id_mensaje + WHERE utimestamp_erased is null + AND (nu.id_user="%s" OR up.id_usuario="%s" OR ng.id_group=0)', + $config['id_user'], + $id_message, + $config['id_user'], + $config['id_user'] + ); + + return (bool) db_get_value_sql($sql); +} + + +/** + * Returns the target users and groups assigned to be notified on + * desired source. + * + * @param integer $id_source Source identificator. + * + * @return array [users] and [groups] with the targets. + */ +function get_notification_source_targets(int $id_source) +{ + $ret = []; + + $users = db_get_all_rows_sql( + sprintf( + 'SELECT + id_user, + IF(ns.user_editable = 1,nsu.also_mail,ns.also_mail) AS also_mail + FROM tnotification_source_user nsu + INNER JOIN tnotification_source ns + ON ns.id=nsu.id_source + WHERE ns.id = %d + AND ((ns.enabled is NULL OR ns.enabled != 0) + OR (nsu.enabled is NULL OR nsu.enabled != 0))', + $id_source + ) + ); + + if ($users !== false) { + $i = 0; + foreach ($users as $user) { + $ret['users'][$i]['id_user'] = $user['id_user']; + $ret['users'][$i++]['also_mail'] = $user['also_mail']; + } + } + + $groups = db_get_all_rows_sql( + sprintf( + 'SELECT id_group,ns.also_mail + FROM tnotification_source_group nsg + INNER JOIN tnotification_source ns + ON ns.id=nsg.id_source + WHERE ns.id = %d + AND (ns.enabled is NULL OR ns.enabled != 0)', + $id_source + ) + ); + + if ($groups !== false) { + $i = 0; + foreach ($groups as $group) { + $ret['groups'][$i]['id_group'] = $group['id_group']; + $ret['groups'][$i++]['also_mail'] = $group['also_mail']; + } + } + + return $ret; +} + + +/** + * Return all info from tnotification_source + * + * @param array $filter Filter to table tnotification_source. + * + * @return array with sources info + */ +function notifications_get_all_sources($filter=[]) +{ + return db_get_all_rows_filter('tnotification_source', $filter); +} + + +/** + * Return the user sources to be inserted into a select + * + * @param integer $source_id Source database identificator. + * + * @return array with the user id in keys and user id in value too + */ +function notifications_get_user_sources_for_select($source_id) +{ + $users = notifications_get_user_sources( + ['id_source' => $source_id], + ['id_user'] + ); + + return index_array($users, 'id_user', 'id_user'); +} + + +/** + * Get the user sources + * + * @param array $filter Filter of sql query. + * @param array $fields Fields to get of query. + * + * @return array Array with user sources data. + */ +function notifications_get_user_sources($filter=[], $fields=[]) +{ + $users = db_get_all_rows_filter( + 'tnotification_source_user', + $filter, + $fields + ); + // If fails or no one is selected, return empty array. + if ($users === false) { + return []; + } + + return $users; +} + + +/** + * Return the groups sources to be inserted into a select + * + * @param integer $source_id Source database identificator. + * + * @return array with the group id in keys and group name in value + */ +function notifications_get_group_sources_for_select($source_id) +{ + $groups = notifications_get_group_sources( + ['id_source' => $source_id], + ['id_group'] + ); + return index_array($groups, 'id_group', 'name'); +} + + +/** + * Get the group sources + * + * @param array $filter Filter of sql query. + * @param array $fields Fields retrieved. + * + * @return array With the group info + */ +function notifications_get_group_sources($filter=[], $fields=[]) +{ + // Get only the tnotifications_source_group fields in addition to group name. + if (empty($fields)) { + $fields[] = 'tnsg.*'; + } + + $fields = array_map( + function ($field) { + if (!preg_match('/^tnsg./', $field)) { + $field = 'tnsg.'.$field; + } + + return $field; + }, + $fields + ); + + // Get groups. + $groups = db_get_all_rows_filter( + 'tnotification_source_group tnsg + LEFT JOIN tgrupo tg ON tnsg.id_group = tg.id_grupo', + $filter, + array_merge($fields, ['IFNULL(tg.nombre, "All") AS name']) + ); + + // If fails or no one is selected, return empty array. + if ($groups === false) { + return []; + } + + return $groups; +} + + +/** + * Delete a set of groups from notification source + * + * @param integer $source_id Source id. + * @param array $groups Id of groups to be deleted. + * + * @return boolean True if success. False otherwise. + */ +function notifications_remove_group_from_source($source_id, $groups) +{ + // Source id is mandatory. + if (!isset($source_id)) { + return false; + } + + // Delete from database. + return db_process_sql_delete( + 'tnotification_source_group', + [ + 'id_group' => $groups, + 'id_source' => $source_id, + ] + ) !== false; +} + + +/** + * Delete a set of users from notification source + * + * @param integer $source_id Source id. + * @param array $users Id of users to be deleted. + * + * @return boolean True if success. False otherwise. + */ +function notifications_remove_users_from_source($source_id, $users) +{ + // Source id is mandatory. + if (!isset($source_id)) { + return false; + } + + // Delete from database. + return db_process_sql_delete( + 'tnotification_source_user', + [ + 'id_user' => $users, + 'id_source' => $source_id, + ] + ) !== false; +} + + +/** + * Insert a set of groups to notification source + * + * @param integer $source_id Source id. + * @param array $groups Id of groups to be deleted. + * + * @return boolean True if success. False otherwise. + */ +function notifications_add_group_to_source($source_id, $groups) +{ + // Source id is mandatory. + if (!isset($source_id)) { + return false; + } + + // Insert into database all groups passed. + $res = true; + foreach ($groups as $group) { + if (!isset($group)) { + continue; + } + + $res = $res && db_process_sql_insert( + 'tnotification_source_group', + [ + 'id_group' => $group, + 'id_source' => $source_id, + ] + ) !== false; + } + + return $res; +} + + +/** + * Insert a set of users to notification source + * + * @param integer $source_id Source id. + * @param array $users Id of users to be deleted. + * + * @return boolean True if success. False otherwise. + */ +function notifications_add_users_to_source($source_id, $users) +{ + // Source id is mandatory. + if (!isset($source_id)) { + return false; + } + + // Insert into database all groups passed. + $res = true; + $also_mail = db_get_value( + 'also_mail', + 'tnotification_source', + 'id', + $source_id + ); + foreach ($users as $user) { + if (empty($user)) { + continue; + } + + $res = $res && db_process_sql_insert( + 'tnotification_source_user', + [ + 'id_user' => $user, + 'id_source' => $source_id, + 'enabled' => 1, + 'also_mail' => (int) $also_mail, + ] + ) !== false; + } + + return $res; +} + + +/** + * Get the groups that not own to a source and, for that reason, they can be + * added to the source. + * + * @param integer $source_id Source id. + * + * @return array Indexed by id group all selectable groups. + */ +function notifications_get_group_source_not_configured($source_id) +{ + $groups_selected = notifications_get_group_sources_for_select($source_id); + $all_groups = users_get_groups_for_select(false, 'AR', false, true, $groups_selected); + return array_diff($all_groups, $groups_selected); +} + + +/** + * Get the users that not own to a source and, for that reason, they can be + * added to the source. + * + * @param integer $source_id Source id. + * + * @return array Indexed by id user, all selectable users. + */ +function notifications_get_user_source_not_configured($source_id) +{ + $users_selected = array_keys(notifications_get_user_sources_for_select($source_id)); + $users = get_users( + 'id_user', + ['!id_user' => $users_selected], + ['id_user'] + ); + return index_array($users, 'id_user', 'id_user'); +} + + +/** + * Build a data struct to handle the value of a label + * + * @param mixed $status Status value. + * @param mixed $enabled Enabled value. + * + * @return array with status (1|0) and enabled (1|0) + */ +function notifications_build_user_enable_return($status, $enabled) +{ + return [ + 'status' => ((bool) $status === true) ? 1 : 0, + 'enabled' => ((bool) $enabled === true) ? 1 : 0, + ]; +} + + +/** + * Get user label (enabled, also_mail...) status. + * + * @param integer $source Id of notification source. + * @param string $user User id. + * @param string $label Label id (enabled, also_email...). + * + * @return array Return of notifications_build_user_enable_return. + */ +function notifications_get_user_label_status($source, $user, $label) +{ + // If not enabled, it cannot be modificable. + if (!$source['enabled']) { + return notifications_build_user_enable_return(false, false); + } + + // See at first for direct reference. + $user_source = notifications_get_user_sources( + [ + 'id_source' => $source['id'], + 'id_user' => $user, + ] + ); + if (!empty($user_source)) { + return notifications_build_user_enable_return( + isset($user_source[0][$label]) ? $user_source[0][$label] : false, + $source['user_editable'] + ); + } + + $common_groups = array_intersect( + array_keys(users_get_groups($user)), + array_keys( + notifications_get_group_sources_for_select($source['id']) + ) + ); + // No group found, return no permissions. + $value = empty($common_groups) ? false : $source[$label]; + return notifications_build_user_enable_return( + $value, + false + ); +} + + +/** + * Set the status to a single label on config of users notifications. + * + * @param integer $source Id of notification source. + * @param string $user User id. + * @param string $label Label id (enabled, also_email...). + * @param mixed $value Numeric value: 1 or 0. + * + * @return boolean True if success. + */ +function notifications_set_user_label_status($source, $user, $label, $value) +{ + $source_info = notifications_get_all_sources(['id' => $source]); + if (!isset($source_info[0]) + || !$source_info[0]['enabled'] + || !$source_info[0]['user_editable'] + ) { + return false; + } + + return (bool) db_process_sql_update( + 'tnotification_source_user', + [$label => $value], + [ + 'id_user' => $user, + 'id_source' => $source, + ] + ); +} + + +/** + * Get the counters of notification. Usefull to print the header notification + * ball. + * + * @return array With the fields: + * 'notifications' => Total new notifications, + * 'last_id' => Id of last read value. Usefull to make comparisons. + */ +function notifications_get_counters() +{ + $num_notifications = 0; + $last_id = 0; + $last_message = messages_get_overview( + 'timestamp', + 'DESC', + false, + false, + 1 + ); + if (!empty($last_message)) { + $num_notifications = messages_get_count(); + $last_id = $last_message[0]['id_mensaje']; + } + + return [ + 'notifications' => $num_notifications, + 'last_id' => $last_id, + ]; +} + + +// ///////////////////////////////////////////////////////////////////////////// +// UI FUNCTIONS +// ///////////////////////////////////////////////////////////////////////////// + + +/** + * Print the notification ball to see unread messages. + * + * @param integer $num_notifications Number of messages shown + * in notification ball. + * @param integer $last_id Id of last message shown + * in the notification ball. + * + * @return string with HTML code of notification ball. + */ +function notifications_print_ball($num_notifications, $last_id) +{ + $no_notifications = (int) $num_notifications === 0; + $class_status = ($no_notifications) ? 'notification-ball-no-messages' : 'notification-ball-new-messages'; + return sprintf( + '
    + %s +
    ', + ($no_notifications) ? '' : 'onclick="addNotifications(event)"', + $class_status, + $last_id, + $num_notifications + ); +} + + +/** + * Print notification configuration global + * + * @param array $source Notification source data. + * + * @return string with HTML of source configuration + */ +function notifications_print_global_source_configuration($source) +{ + // Get some values to generate the title. + $switch_values = [ + 'name' => 'enable-'.$source['id'], + 'value' => $source['enabled'], + 'id' => 'nt-'.$source['id'].'-enabled', + 'class' => 'elem-clickable', + ]; + + // Search if group all is set and handle that situation. + $source_groups = notifications_get_group_sources_for_select($source['id']); + $is_group_all = isset($source_groups['0']); + if ($is_group_all) { + unset($source_groups['0']); + } + + // Generate the title. + $html_title = "
    "; + $html_title .= html_print_switch($switch_values); + $html_title .= '

    '.$source['description'].'

    '; + $html_title .= '
    '; + + // Generate the html for title. + $html_selectors = "
    "; + $html_selectors .= notifications_print_source_select_box( + notifications_get_user_sources_for_select($source['id']), + 'users', + $source['id'] + ); + $html_selectors .= notifications_print_source_select_box( + $source_groups, + 'groups', + $source['id'] + ); + $html_selectors .= '
    '; + // Generate the checkboxes and time select. + $html_checkboxes = "
    "; + $html_checkboxes .= ' '; + $html_checkboxes .= html_print_checkbox_extended('all-'.$source['id'], 1, $is_group_all, false, '', 'class= "elem-clickable"', true, 'id="nt-'.$source['id'].'-all_users"'); + $html_checkboxes .= __('Notify all users'); + $html_checkboxes .= '
    '; + $html_checkboxes .= html_print_checkbox_extended('mail-'.$source['id'], 1, $source['also_mail'], false, '', 'class= "elem-clickable"', true, 'id="nt-'.$source['id'].'-also_mail"'); + $html_checkboxes .= __('Also email users with notification content'); + $html_checkboxes .= '
    '; + $html_checkboxes .= html_print_checkbox_extended('user-'.$source['id'], 1, $source['user_editable'], false, '', 'class= "elem-clickable"', true, 'id="nt-'.$source['id'].'-user_editable"'); + $html_checkboxes .= __('Users can modify notification preferences'); + $html_checkboxes .= ' '; + $html_checkboxes .= '
    '; + + // Generate the select with the time. + $html_select_pospone = __('Users can postpone notifications up to'); + // FIXMEit should not be disabled. + $html_select_pospone .= html_print_select( + [ + SECONDS_5MINUTES => __('5 minutes'), + SECONDS_15MINUTES => __('15 minutes'), + SECONDS_12HOURS => __('12 hours'), + SECONDS_1DAY => __('1 day'), + SECONDS_1WEEK => __('1 week'), + SECONDS_15DAYS => __('15 days'), + SECONDS_1MONTH => __('1 month'), + NOTIFICATIONS_POSTPONE_FOREVER => __('forever'), + ], + 'nt-'.$source['id'].'-max_postpone_time', + $source['max_postpone_time'], + '', + '', + 0, + true, + false, + true, + 'elem-changeable', + true + ); + + // Return all html. + return $html_title.$html_selectors.$html_checkboxes.$html_select_pospone; +} + + +/** + * Print select boxes of notified users or groups + * + * @param array $info_selec All info required for build the selector. + * @param string $id One of users|groups. + * @param string $source_id Id of source. + * + * @return string HTML with the generated selector + */ +function notifications_print_source_select_box( + $info_selec, + $id, + $source_id +) { + $title = ($id === 'users') ? __('Notified users') : __('Notified groups'); + $add_title = ($id === 'users') ? __('Add users') : __('Add groups'); + $delete_title = ($id === 'users') ? __('Delete users') : __('Delete groups'); + + // Generate the HTML. + return sprintf( + " +
    +
    +

    %s

    + %s +
    +
    + %s + %s +
    +
    + ", + $title, + // Put a true if empty sources to avoid to sow the 'None' value. + html_print_select( + empty($info_selec) ? true : $info_selec, + 'multi-'.$id.'-'.$source_id.'[]', + 0, + false, + '', + '', + true, + true + ), + html_print_image( + 'images/input_add.png', + true, + [ + 'title' => $add_title, + 'onclick' => sprintf( + "add_source_dialog('%s', '%s')", + $id, + $source_id + ), + ] + ), + html_print_image( + 'images/input_delete.png', + true, + [ + 'title' => $delete_title, + 'onclick' => sprintf( + "remove_source_elements('%s', '%s')", + $id, + $source_id + ), + ] + ) + ); +} + + +/** + * Print the select with right and left arrows to select new sources + * (groups or users). + * + * @param array $info_selec Array with source info. + * @param string $users One of users|groups. + * @param source $source_id Source id. + * + * @return string HTML with the select code. + */ +function notifications_print_two_ways_select($info_selec, $users, $source_id) +{ + return sprintf( + " +
    + %s +
    + %s + %s +
    + %s +
    + %s + ", + html_print_select( + empty($info_selec) ? true : $info_selec, + 'all-multi-'.$users.'-'.$source_id.'[]', + 0, + false, + '', + '', + true, + true, + true, + '' + ), + html_print_image( + 'images/darrowright.png', + true, + [ + 'title' => __('Add elements'), + 'onclick' => sprintf( + "notifications_modify_two_ways_element('%s', '%s', 'add')", + $users, + $source_id + ), + ] + ), + html_print_image( + 'images/darrowleft.png', + true, + [ + 'title' => __('Remove elements'), + 'onclick' => sprintf( + "notifications_modify_two_ways_element('%s', '%s', 'remove')", + $users, + $source_id + ), + ] + ), + html_print_select( + true, + 'selected-multi-'.$users.'-'.$source_id.'[]', + 0, + false, + '', + '', + true, + true, + true, + '' + ), + html_print_button( + __('Add'), + 'Add', + false, + sprintf( + "notifications_add_source_element_to_database('%s', '%s')", + $users, + $source_id + ), + "class='sub add'", + true + ) + ); +} + + +/** + * Print a label status represented by a switch + * + * @param integer $source Source id. + * @param string $user User id. + * @param string $label Label (enabled, also_mail...). + * + * @return string With HTML code + */ +function notifications_print_user_switch($source, $user, $label) +{ + $status = notifications_get_user_label_status($source, $user, $label); + return html_print_switch( + [ + 'name' => $label, + 'value' => $status['status'], + 'disabled' => !$status['enabled'], + 'class' => 'notifications-user-label_individual', + 'id' => 'notifications-user-'.$source['id'].'-label-'.$label, + ] + ); +} + + +/** + * Generates the dropdown notifications menu. + * + * @return string HTML with dropdown menu. + */ +function notifications_print_dropdown() +{ + $mess = messages_get_overview('status', 'DESC', false, true); + if ($mess === false) { + $mess = []; + } + + return sprintf( + "
    +
    + %s +
    +
    +
    +
    + ", + array_reduce( + $mess, + function ($carry, $message) { + return $carry.notifications_print_dropdown_element($message); + }, + '' + ) + ); +} + + +/** + * Print a single notification box + * + * @param array $message_info Info of printed message. + * + * @return string HTML code of single message + */ +function notifications_print_dropdown_element($message_info) +{ + $action = ''; + + switch ($message_info['description']) { + case 'Official communication': + $action = 'show_modal(this.id);'; + $target = ''; + $body_preview = __('Click here to get more information'); + break; + + default: + $action = ''; + $target = '_blank'; + $body_preview = strip_tags( + io_safe_output($message_info['mensaje']), + '
    '
    +            );
    +        break;
    +    }
    +
    +    return sprintf(
    +        "
    +            %s
    +            
    +

    + %s +

    +

    + %s +

    +
    +
    ", + $action.';click_on_notification_toast(event)', + $message_info['id_mensaje'], + messages_get_url($message_info['id_mensaje']), + $target, + html_print_image('images/'.$message_info['icon'], true), + io_safe_output($message_info['subject']), + $body_preview + ); +} diff --git a/pandora_console/include/functions_pandora_networkmap.php b/pandora_console/include/functions_pandora_networkmap.php index c1eb630d52..cad7fc7edf 100644 --- a/pandora_console/include/functions_pandora_networkmap.php +++ b/pandora_console/include/functions_pandora_networkmap.php @@ -1,2130 +1,29 @@ $id]); - - return $result; -} - - -function networkmap_delete_nodes($id_map) -{ - return db_process_sql_delete('titem', ['id_map' => $id_map]); -} - - -function networkmap_process_networkmap($id=0) -{ - global $config; - - include_once 'include/functions_os.php'; - - $numNodes = (int) db_get_num_rows( - ' - SELECT * - FROM titem - WHERE id_map = '.$id.' and deleted = 0' - ); - - $networkmap = db_get_row_filter( - 'tmap', - ['id' => $id] - ); - $map_filter = json_decode($networkmap['filter'], true); - - $pure = (int) get_parameter('pure', 0); - - switch ($networkmap['generation_method']) { - case 0: - $filter = 'circo'; - $layout = 'circular'; - break; - - case 1: - $filter = 'dot'; - $layout = 'flat'; - break; - - case 2: - $filter = 'twopi'; - $layout = 'radial'; - break; - - case 3: - $filter = 'neato'; - $layout = 'spring1'; - break; - - case 4: - $filter = 'fdp'; - $layout = 'spring2'; - break; - } - - $simple = 0; - $font_size = 12; - $nooverlap = false; - $zoom = 1; - $ranksep = 0.5; - $center = 0; - $regen = 1; - $show_snmp_modules = false; - $dont_show_subgroups = false; - - $id_group = $networkmap['id_group']; - $ip_mask = ''; - switch ($networkmap['source']) { - case 1: - $recon_task = db_get_row_filter( - 'trecon_task', - ['id_rt' => $networkmap['source_data']] - ); - - $ip_mask = $recon_task['subnet']; - break; - - case 2: - $ip_mask = $networkmap['source_data']; - break; - } - - $nodes_and_relations = []; - - if (enterprise_installed() && ($numNodes > 0)) { - $nodes_and_relations = get_structure_nodes($id); - } else { - if ($map_filter['empty_map']) { - // Open Graph - $graph = networkmap_open_graph( - $layout, - $nooverlap, - $pure, - $zoom, - $ranksep, - $font_size, - null - ); - $graph .= networkmap_create_pandora_node(get_product_name(), $font_size, $simple); - $graph .= networkmap_close_graph(); - - switch (PHP_OS) { - case 'WIN32': - case 'WINNT': - case 'Windows': - $filename_dot = sys_get_temp_dir()."\\networkmap_".$filter; - break; - - default: - $filename_dot = sys_get_temp_dir().'/networkmap_'.$filter; - break; - } - - if ($simple) { - $filename_dot .= '_simple'; - } - - if ($nooverlap) { - $filename_dot .= '_nooverlap'; - } - - $filename_dot .= '_'.$id.'.dot'; - - file_put_contents($filename_dot, $graph); - - switch (PHP_OS) { - case 'WIN32': - case 'WINNT': - case 'Windows': - $filename_plain = sys_get_temp_dir().'\\plain.txt'; - - $cmd = io_safe_output( - $config['graphviz_bin_dir']."\\$filter.exe -Tplain -o ".$filename_plain.' '.$filename_dot - ); - break; - - default: - $filename_plain = sys_get_temp_dir().'/plain.txt'; - - $cmd = "$filter -Tplain -o ".$filename_plain.' '.$filename_dot; - break; - } - - system($cmd); - - unlink($filename_dot); - - $nodes = networkmap_loadfile( - $id, - $filename_plain, - $relation_nodes, - $graph - ); - - unlink($filename_plain); - - // Set the position of modules - foreach ($nodes as $key => $node) { - if ($node['type'] == 'module') { - // Search the agent of this module for to get the - // position - foreach ($nodes as $key2 => $node2) { - if ($node2['id_agent'] != 0 && $node2['type'] == 'agent') { - if ($node2['id_agent'] == $node['id_agent']) { - $nodes[$key]['coords'][0] = ($nodes[$key2]['coords'][0] + $node['height'] / 2); - $nodes[$key]['coords'][1] = ($nodes[$key2]['coords'][1] + $node['width'] / 2); - } - } - } - } - } - - $nodes_and_relations['nodes'] = []; - $index = 0; - foreach ($nodes as $key => $node) { - $nodes_and_relations['nodes'][$index]['id'] = $node['id']; - $nodes_and_relations['nodes'][$index]['id_map'] = $id; - - $nodes_and_relations['nodes'][$index]['x'] = (int) $node['coords'][0]; - $nodes_and_relations['nodes'][$index]['y'] = (int) $node['coords'][1]; - - if (($node['type'] == 'agent') || ($node['type'] == '')) { - $nodes_and_relations['nodes'][$index]['source_data'] = $node['id_agent']; - $nodes_and_relations['nodes'][$index]['type'] = 0; - } else { - $nodes_and_relations['nodes'][$index]['source_data'] = $node['id_module']; - $nodes_and_relations['nodes'][$index]['id_agent'] = $node['id_agent']; - $nodes_and_relations['nodes'][$index]['type'] = 1; - } - - $style = []; - $style['shape'] = 'circle'; - $style['image'] = $node['image']; - $style['width'] = $node['width']; - $style['height'] = $node['height']; - $style['label'] = $node['text']; - $style['id_networkmap'] = $node['networkmap']; - $nodes_and_relations['nodes'][$index]['style'] = json_encode($style); - - $index++; - } - - $nodes_and_relations['relations'] = []; - - if (enterprise_installed()) { - enterprise_include_once('include/functions_pandora_networkmap.php'); - save_generate_nodes($id, $nodes_and_relations); - } - } else { - // Generate dot file - $graph = networkmap_generate_dot( - get_product_name(), - $id_group, - $simple, - $font_size, - $layout, - $nooverlap, - $zoom, - $ranksep, - $center, - $regen, - $pure, - $id, - $show_snmp_modules, - false, - // cut_names - true, - // relative - '', - $ip_mask, - $dont_show_subgroups, - false, - null, - $old_mode, - $map_filter - ); - - switch (PHP_OS) { - case 'WIN32': - case 'WINNT': - case 'Windows': - $filename_dot = sys_get_temp_dir()."\\networkmap_".$filter; - break; - - default: - $filename_dot = sys_get_temp_dir().'/networkmap_'.$filter; - break; - } - - if ($simple) { - $filename_dot .= '_simple'; - } - - if ($nooverlap) { - $filename_dot .= '_nooverlap'; - } - - $filename_dot .= '_'.$id.'.dot'; - - file_put_contents($filename_dot, $graph); - - switch (PHP_OS) { - case 'WIN32': - case 'WINNT': - case 'Windows': - $filename_plain = sys_get_temp_dir().'\\plain.txt'; - - $cmd = io_safe_output( - $config['graphviz_bin_dir']."\\$filter.exe -Tplain -o ".$filename_plain.' '.$filename_dot - ); - break; - - default: - $filename_plain = sys_get_temp_dir().'/plain.txt'; - - $cmd = "$filter -Tplain -o ".$filename_plain.' '.$filename_dot; - break; - } - - system($cmd); - - unlink($filename_dot); - - $nodes = networkmap_loadfile( - $id, - $filename_plain, - $relation_nodes, - $graph - ); - - unlink($filename_plain); - - // Set the position of modules - foreach ($nodes as $key => $node) { - if ($node['type'] == 'module') { - // Search the agent of this module for to get the - // position - foreach ($nodes as $key2 => $node2) { - if ($node2['id_agent'] != 0 && $node2['type'] == 'agent') { - if ($node2['id_agent'] == $node['id_agent']) { - $nodes[$key]['coords'][0] = ($nodes[$key2]['coords'][0] + $node['height'] / 2); - $nodes[$key]['coords'][1] = ($nodes[$key2]['coords'][1] + $node['width'] / 2); - } - } - } - } - } - - $nodes_and_relations['nodes'] = []; - $index = 0; - $node_center = []; - foreach ($nodes as $key => $node) { - $nodes_and_relations['nodes'][$index]['id'] = $node['id']; - $nodes_and_relations['nodes'][$index]['id_map'] = $id; - - $children_count = 0; - foreach ($relation_nodes as $relation) { - if (($relation['parent_type'] == 'agent') || ($relation['parent_type'] == '')) { - if ($nodes[$relation['id_parent']]['id_agent'] == $node['id_agent']) { - $children_count++; - } - } else if ($relation['parent_type'] == 'module') { - if ($nodes[$relation['id_parent']]['id_module'] == $node['id_module']) { - $children_count++; - } - } - } - - if (empty($node_center) || $node_center['counter'] < $children_count) { - $node_center['x'] = (int) $node['coords'][0]; - $node_center['y'] = (int) $node['coords'][1]; - $node_center['counter'] = $children_count; - } - - $nodes_and_relations['nodes'][$index]['x'] = (int) $node['coords'][0]; - $nodes_and_relations['nodes'][$index]['y'] = (int) $node['coords'][1]; - - if (($node['type'] == 'agent') || ($node['type'] == '')) { - $nodes_and_relations['nodes'][$index]['source_data'] = $node['id_agent']; - $nodes_and_relations['nodes'][$index]['type'] = 0; - } else { - $nodes_and_relations['nodes'][$index]['source_data'] = $node['id_module']; - $nodes_and_relations['nodes'][$index]['id_agent'] = $node['id_agent']; - $nodes_and_relations['nodes'][$index]['type'] = 1; - } - - $style = []; - $style['shape'] = 'circle'; - $style['image'] = $node['image']; - $style['width'] = $node['width']; - $style['height'] = $node['height']; - $style['label'] = $node['text']; - $nodes_and_relations['nodes'][$index]['style'] = json_encode($style); - - $index++; - } - - $nodes_and_relations['relations'] = []; - $index = 0; - foreach ($relation_nodes as $relation) { - $nodes_and_relations['relations'][$index]['id_map'] = $id; - - if (($relation['parent_type'] == 'agent') || ($relation['parent_type'] == '')) { - $nodes_and_relations['relations'][$index]['id_parent'] = $relation['id_parent']; - $nodes_and_relations['relations'][$index]['id_parent_source_data'] = $nodes[$relation['id_parent']]['id_agent']; - $nodes_and_relations['relations'][$index]['parent_type'] = 0; - } else if ($relation['parent_type'] == 'module') { - $nodes_and_relations['relations'][$index]['id_parent'] = $relation['id_parent']; - $nodes_and_relations['relations'][$index]['id_parent_source_data'] = $nodes[$relation['id_parent']]['id_module']; - $nodes_and_relations['relations'][$index]['parent_type'] = 1; - } else { - $nodes_and_relations['relations'][$index]['id_parent'] = $relation['id_parent']; - $nodes_and_relations['relations'][$index]['id_child_source_data'] = -2; - $nodes_and_relations['relations'][$index]['parent_type'] = 3; - } - - if (($relation['child_type'] == 'agent') || ($relation['child_type'] == '')) { - $nodes_and_relations['relations'][$index]['id_child'] = $relation['id_child']; - $nodes_and_relations['relations'][$index]['id_child_source_data'] = $nodes[$relation['id_child']]['id_agent']; - $nodes_and_relations['relations'][$index]['child_type'] = 0; - } else if ($relation['child_type'] == 'module') { - $nodes_and_relations['relations'][$index]['id_child'] = $relation['id_child']; - $nodes_and_relations['relations'][$index]['id_child_source_data'] = $nodes[$relation['id_child']]['id_module']; - $nodes_and_relations['relations'][$index]['child_type'] = 1; - } else { - $nodes_and_relations['relations'][$index]['id_child'] = $relation['id_child']; - $nodes_and_relations['relations'][$index]['id_child_source_data'] = -2; - $nodes_and_relations['relations'][$index]['child_type'] = 3; - } - - $index++; - } - - if (enterprise_installed()) { - enterprise_include_once('include/functions_pandora_networkmap.php'); - save_generate_nodes($id, $nodes_and_relations); - } - - $pandorafms_node = $nodes_and_relations['nodes'][0]; - $center = [ - 'x' => $node_center['x'], - 'y' => $node_center['y'], - ]; - - $networkmap['center_x'] = $center['x']; - $networkmap['center_y'] = $center['y']; - db_process_sql_update( - 'tmap', - [ - 'center_x' => $networkmap['center_x'], - 'center_y' => $networkmap['center_y'], - ], - ['id' => $id] - ); - } - } - - return $nodes_and_relations; -} - - -function get_networkmaps($id) -{ - $groups = array_keys(users_get_groups(null, 'IW')); - - $filter = []; - $filter['id_group'] = $groups; - $filter['id'] = '<>'.$id; - $networkmaps = db_get_all_rows_filter('tmap', $filter); - if ($networkmaps === false) { - $networkmaps = []; - } - - $return = []; - $return[0] = __('None'); - foreach ($networkmaps as $networkmap) { - $return[$networkmap['id']] = $networkmap['name']; - } - - return $return; -} - - -function networkmap_db_node_to_js_node($node, &$count, &$count_item_holding_area) -{ - global $config; - - $networkmap = db_get_row('tmap', 'id', $node['id_map']); - - $networkmap['filter'] = json_decode($networkmap['filter'], true); - - // Hardcoded - $networkmap['filter']['holding_area'] = [ - 500, - 500, - ]; - - // 40 = DEFAULT NODE RADIUS - // 30 = for to align - $holding_area_max_y = ($networkmap['height'] + 30 + 40 * 2 - $networkmap['filter']['holding_area'][1] + 10 * 40); - - $item = []; - $item['id'] = $count; - - if (enterprise_installed()) { - enterprise_include_once('include/functions_pandora_networkmap.php'); - $item['id_db'] = $node['id_in_db']; - } else { - $item['id_db'] = (int) $node['id']; - } - - if ((int) $node['type'] == 0) { - $item['type'] = 0; - $item['id_agent'] = (int) $node['source_data']; - $item['id_module'] = ''; - } else if ((int) $node['type'] == 1) { - $item['type'] = 1; - $item['id_agent'] = (int) $node['style']['id_agent']; - $item['id_module'] = (int) $node['source_data']; - } else { - $item['type'] = 3; - } - - $item['fixed'] = true; - $item['x'] = (int) $node['x']; - $item['y'] = (int) $node['y']; - $item['px'] = (int) $node['x']; - $item['py'] = (int) $node['y']; - $item['z'] = (int) $node['z']; - $item['state'] = $node['state']; - $item['deleted'] = $node['deleted']; - if ($item['state'] == 'holding_area') { - // 40 = DEFAULT NODE RADIUS - // 30 = for to align - $holding_area_x = ($networkmap['width'] + 30 + 40 * 2 - $networkmap['filter']['holding_area'][0] + ($count_item_holding_area % 11) * 40); - $holding_area_y = ($networkmap['height'] + 30 + 40 * 2 - $networkmap['filter']['holding_area'][1] + (int) (($count_item_holding_area / 11)) * 40); - - if ($holding_area_max_y <= $holding_area_y) { - $holding_area_y = $holding_area_max_y; - } - - $item['x'] = $holding_area_x; - $item['y'] = $holding_area_y; - - // Increment for the next node in holding area - $count_item_holding_area++; - } - - $item['image_url'] = ''; - $item['image_width'] = 0; - $item['image_height'] = 0; - if (!empty($node['style']['image'])) { - $item['image_url'] = html_print_image( - $node['style']['image'], - true, - false, - true - ); - $image_size = getimagesize( - $config['homedir'].'/'.$node['style']['image'] - ); - $item['image_width'] = (int) $image_size[0]; - $item['image_height'] = (int) $image_size[1]; - } - - $item['raw_text'] = $node['style']['label']; - $item['text'] = io_safe_output($node['style']['label']); - $item['shape'] = $node['style']['shape']; - switch ($node['type']) { - case 0: - $color = get_status_color_networkmap($node['source_data']); - break; - - default: - // Old code - if ($node['source_data'] == -1) { - $color = '#364D1F'; - } else if ($node['source_data'] == -2) { - $color = '#364D1F'; - } else { - $color = get_status_color_networkmap($node['source_data']); - } - break; - } - - $item['color'] = $color; - $item['map_id'] = 0; - if (isset($node['id_map'])) { - $item['map_id'] = $node['id_map']; - } - - if (!isset($node['style']['id_networkmap']) || $node['style']['id_networkmap'] == '' || $node['style']['id_networkmap'] == 0) { - $item['networkmap_id'] = 0; - } else { - $item['networkmap_id'] = $node['style']['id_networkmap']; - } - - $count++; - - return $item; -} - - -function get_status_color_networkmap($id, $color=true) -{ - $status = agents_get_status($id); - - if (!$color) { - return $status; - } - - // Set node status - switch ($status) { - case 0: - $status_color = COL_NORMAL; - // Normal monitor - break; - - case 1: - $status_color = COL_CRITICAL; - // Critical monitor - break; - - case 2: - $status_color = COL_WARNING; - // Warning monitor - break; - - case 4: - $status_color = COL_ALERTFIRED; - // Alert fired - break; - - default: - $status_color = COL_UNKNOWN; - // Unknown monitor - break; - } - - return $status_color; -} - - -function networkmap_clean_relations_for_js(&$relations) -{ - do { - $cleaned = true; - - foreach ($relations as $key => $relation) { - if ($relation['id_parent_source_data'] == $relation['id_child_source_data']) { - if (($relation['child_type'] != 3) && $relation['parent_type'] != 3) { - $cleaned = false; - - if ($relation['parent_type'] == 1) { - $to_find = $relation['id_parent_source_data']; - $to_replace = $relation['id_child_source_data']; - } else if ($relation['child_type'] == 1) { - $to_find = $relation['id_child_source_data']; - $to_replace = $relation['id_parent_source_data']; - } - - // Replace and erase the links - foreach ($relations as $key2 => $relation2) { - if ($relation2['id_parent_source_data'] == $to_find) { - $relations[$key2]['id_parent_source_data'] = $to_replace; - } else if ($relation2['id_child_source_data'] == $to_find) { - $relations[$key2]['id_child_source_data'] = $to_replace; - } - } - - unset($relations[$key]); - - break; - } - } - } - } while (!$cleaned); -} - - -function networkmap_links_to_js_links($relations, $nodes_graph) -{ - $return = []; - - if (enterprise_installed()) { - enterprise_include_once('include/functions_pandora_networkmap.php'); - } - - $count = 0; - foreach ($relations as $key => $relation) { - if (($relation['parent_type'] == 1) && ($relation['child_type'] == 1)) { - $id_target_agent = agents_get_agent_id_by_module_id($relation['id_parent_source_data']); - $id_source_agent = agents_get_agent_id_by_module_id($relation['id_child_source_data']); - $id_target_module = $relation['id_parent_source_data']; - $id_source_module = $relation['id_child_source_data']; - } else if (($relation['parent_type'] == 1) && ($relation['child_type'] == 0)) { - $id_target_agent = agents_get_agent_id_by_module_id($relation['id_parent_source_data']); - $id_target_module = $relation['id_parent_source_data']; - $id_source_agent = $relation['id_child_source_data']; - } else if (($relation['parent_type'] == 0) && ($relation['child_type'] == 1)) { - $id_target_agent = $relation['id_parent_source_data']; - $id_source_module = $relation['id_child_source_data']; - $id_source_agent = agents_get_agent_id_by_module_id($relation['id_child_source_data']); - } else { - $id_target_agent = $relation['id_parent_source_data']; - $id_source_agent = $relation['id_child_source_data']; - } - - $item = []; - $item['id'] = $count; - $count++; - if (enterprise_installed()) { - $item['id_db'] = get_relation_id($relation); - } else { - $item['id_db'] = $key; - } - - $item['arrow_start'] = ''; - $item['arrow_end'] = ''; - $item['status_start'] = ''; - $item['status_end'] = ''; - $item['id_module_start'] = 0; - $item['id_agent_start'] = (int) $id_source_agent; - $item['id_module_end'] = 0; - $item['id_agent_end'] = (int) $id_target_agent; - $item['link_color'] = '#999'; - $item['target'] = -1; - $item['source'] = -1; - $item['deleted'] = $relation['deleted']; - - if (enterprise_installed()) { - $target_and_source = []; - $target_and_source = get_id_target_and_source_in_db($relation); - $item['target_id_db'] = (int) $target_and_source['target']; - $item['source_id_db'] = (int) $target_and_source['source']; - } else { - if (($relation['parent_type'] == 1) && ($relation['child_type'] == 1)) { - $item['target_id_db'] = $id_target_agent; - $item['source_id_db'] = $id_source_agent; - } else if (($relation['parent_type'] == 0) && ($relation['child_type'] == 0)) { - $item['target_id_db'] = (int) $relation['id_parent_source_data']; - $item['source_id_db'] = $id_source_agent; - } else { - $item['target_id_db'] = (int) $relation['id_parent_source_data']; - $item['source_id_db'] = (int) $relation['id_child_source_data']; - } - } - - $item['text_end'] = ''; - $item['text_start'] = ''; - - if ($relation['parent_type'] == 1) { - $item['arrow_end'] = 'module'; - $item['status_end'] = modules_get_agentmodule_status((int) $id_target_module, false, false, null); - $item['id_module_end'] = (int) $id_target_module; - $text_end = modules_get_agentmodule_name((int) $id_target_module); - if (preg_match('/(.+)_ifOperStatus$/', (string) $text_end, $matches)) { - if ($matches[1]) { - // It's ok to safe_output as it inlo goint to be user into the map line - $item['text_end'] = io_safe_output($matches[1]); - } - } - } - - if ($relation['child_type'] == 1) { - $item['arrow_start'] = 'module'; - $item['status_start'] = modules_get_agentmodule_status((int) $id_source_module, false, false, null); - $item['id_module_start'] = (int) $id_source_module; - $text_start = modules_get_agentmodule_name((int) $id_source_module); - if (preg_match('/(.+)_ifOperStatus$/', (string) $text_start, $matches)) { - if ($matches[1]) { - // It's ok to safe_output as it inlo goint to be user into the map line - $item['text_start'] = io_safe_output($matches[1]); - } - } - } - - $agent = 0; - $agent2 = 0; - - if (($relation['parent_type'] == 1) && ($relation['child_type'] == 1)) { - $mod1_status = db_get_value_filter('estado', 'tagente_estado', ['id_agente_modulo' => $relation['id_parent_source_data']]); - $mod2_status = db_get_value_filter('estado', 'tagente_estado', ['id_agente_modulo' => $relation['id_child_source_data']]); - - if (($mod1_status == AGENT_MODULE_STATUS_CRITICAL_BAD) || ($mod2_status == AGENT_MODULE_STATUS_CRITICAL_BAD)) { - $item['link_color'] = '#FC4444'; - } else if (($mod1_status == AGENT_MODULE_STATUS_WARNING) || ($mod2_status == AGENT_MODULE_STATUS_WARNING)) { - $item['link_color'] = '#FAD403'; - } - - $agent = agents_get_agent_id_by_module_id($relation['id_parent_source_data']); - $agent2 = agents_get_agent_id_by_module_id($relation['id_child_source_data']); - foreach ($nodes_graph as $key2 => $node) { - if (isset($node['id_agent'])) { - if ($node['id_agent'] == $agent) { - $agent = $node['id_db']; - } else if ($node['id_agent'] == $agent2) { - $agent2 = $node['id_db']; - } - } - } - } else if ($relation['child_type'] == 1) { - $mod1_status = db_get_value_filter('estado', 'tagente_estado', ['id_agente_modulo' => $relation['id_child_source_data']]); - - if ($mod1_status == AGENT_MODULE_STATUS_CRITICAL_BAD) { - $item['link_color'] = '#FC4444'; - } else if ($mod1_status == AGENT_MODULE_STATUS_WARNING) { - $item['link_color'] = '#FAD403'; - } - - $agent2 = agents_get_agent_id_by_module_id($relation['id_child_source_data']); - foreach ($nodes_graph as $key2 => $node) { - if (isset($node['id_agent'])) { - if ($node['id_agent'] == $relation['id_parent_source_data']) { - $agent = $node['id_db']; - } else if ($node['id_agent'] == $agent2) { - $agent2 = $node['id_db']; - } - } - } - } else if ($relation['parent_type'] == 1) { - $mod1_status = db_get_value_filter('estado', 'tagente_estado', ['id_agente_modulo' => $relation['id_parent_source_data']]); - - if ($mod1_status == AGENT_MODULE_STATUS_CRITICAL_BAD) { - $item['link_color'] = '#FC4444'; - } else if ($mod1_status == AGENT_MODULE_STATUS_WARNING) { - $item['link_color'] = '#FAD403'; - } - - $agent = agents_get_agent_id_by_module_id($relation['id_parent_source_data']); - - foreach ($nodes_graph as $key2 => $node) { - if (isset($node['id_agent'])) { - if ($node['id_agent'] == $agent) { - $agent = $node['id_db']; - } else if ($node['id_agent'] == $relation['id_child_source_data']) { - $agent2 = $node['id_db']; - } - } - } - } else if (($relation['parent_type'] == 3) && ($relation['child_type'] == 3)) { - foreach ($nodes_graph as $key2 => $node) { - if ($relation['id_parent'] == $node['id_db']) { - $agent = $node['id_db']; - } - } - - foreach ($nodes_graph as $key2 => $node) { - if ($relation['id_child'] == $node['id_db']) { - $agent2 = $node['id_db']; - } - } - } else if (($relation['parent_type'] == 3) || ($relation['child_type'] == 3)) { - if ($relation['parent_type'] == 3) { - foreach ($nodes_graph as $key2 => $node) { - if ($relation['id_parent'] == $node['id_db']) { - $agent = $node['id_db']; - } else if ($node['id_agent'] == $relation['id_child_source_data']) { - $agent2 = $node['id_db']; - } - } - } else if ($relation['child_type'] == 3) { - foreach ($nodes_graph as $key2 => $node) { - if ($relation['id_child'] == $node['id_db']) { - $agent2 = $node['id_db']; - } else if ($node['id_agent'] == $relation['id_parent_source_data']) { - $agent = $node['id_db']; - } - } - } - } else { - foreach ($nodes_graph as $key2 => $node) { - if (isset($node['id_agent'])) { - if ($node['id_agent'] == $relation['id_parent_source_data']) { - $agent = $node['id_db']; - } else if ($node['id_agent'] == $relation['id_child_source_data']) { - $agent2 = $node['id_db']; - } - } - } - } - - foreach ($nodes_graph as $node) { - if ($node['id_db'] == $agent) { - $item['target'] = $node['id']; - } else if ($node['id_db'] == $agent2) { - $item['source'] = $node['id']; - } - } - - if ((($item['target'] == -1) || ($item['source'] == -1)) && $relation['parent_type'] == 1 && $relation['child_type'] == 1) { - continue; - } - - $return[] = $item; - } - - return $return; -} - - -function networkmap_write_js_array($id, $nodes_and_relations=[], $map_dash_details=[]) -{ - global $config; - - db_clean_cache(); - - $ent_installed = (int) enterprise_installed(); - - $networkmap = db_get_row('tmap', 'id', $id); - - $networkmap['filter'] = json_decode($networkmap['filter'], true); - - // Hardcoded - $networkmap['filter']['holding_area'] = [ - 500, - 500, - ]; - - echo "\n"; - echo "////////////////////////////////////////////////////////////////////\n"; - echo "// VARS FROM THE DB\n"; - echo "////////////////////////////////////////////////////////////////////\n"; - echo "\n"; - echo "var url_background_grid = '".ui_get_full_url( - 'images/background_grid.png' - )."'\n"; - echo 'var networkmap_id = '.$id.";\n"; - - if (!empty($map_dash_details)) { - echo 'var x_offs = '.$map_dash_details['x_offs'].";\n"; - echo 'var y_offs = '.$map_dash_details['y_offs'].";\n"; - echo 'var z_dash = '.$map_dash_details['z_dash'].";\n"; - } else { - echo "var x_offs = null;\n"; - echo "var y_offs = null;\n"; - echo "var z_dash = null;\n"; - } - - echo 'var networkmap_refresh_time = 1000 * '.$networkmap['source_period'].";\n"; - echo 'var networkmap_center = [ '.$networkmap['center_x'].', '.$networkmap['center_y']."];\n"; - echo 'var networkmap_dimensions = [ '.$networkmap['width'].', '.$networkmap['height']."];\n"; - - echo 'var enterprise_installed = '.$ent_installed.";\n"; - - echo 'var node_radius = '.$networkmap['filter']['node_radius'].";\n"; - - echo 'var networkmap_holding_area_dimensions = '.json_encode($networkmap['filter']['holding_area']).";\n"; - - echo "var networkmap = {'nodes': [], 'links': []};\n"; - - $nodes = $nodes_and_relations['nodes']; - - if (empty($nodes)) { - $nodes = []; - } - - $count_item_holding_area = 0; - $count = 0; - $nodes_graph = []; - - foreach ($nodes as $key => $node) { - $style = json_decode($node['style'], true); - $node['style'] = json_decode($node['style'], true); - - // Only agents can be show - if (isset($node['type'])) { - if ($node['type'] == 1) { - continue; - } - } else { - $node['type'] = ''; - } - - $item = networkmap_db_node_to_js_node( - $node, - $count, - $count_item_holding_area - ); - if ($item['deleted']) { - continue; - } - - echo 'networkmap.nodes.push('.json_encode($item).");\n"; - $nodes_graph[$item['id']] = $item; - } - - $relations = $nodes_and_relations['relations']; - - if ($relations === false) { - $relations = []; - } - - // Clean the relations and transform the module relations into - // interfaces - networkmap_clean_relations_for_js($relations); - - $links_js = networkmap_links_to_js_links($relations, $nodes_graph); - - $array_aux = []; - foreach ($links_js as $link_js) { - if ($link_js['deleted']) { - unset($links_js[$link_js['id']]); - } - - if ($link_js['target'] == -1) { - unset($links_js[$link_js['id']]); - } - - if ($link_js['source'] == -1) { - unset($links_js[$link_js['id']]); - } - - if ($link_js['target'] == $link_js['source']) { - unset($links_js[$link_js['id']]); - } - - if ($link_js['arrow_start'] == 'module' && $link_js['arrow_end'] == 'module') { - echo 'networkmap.links.push('.json_encode($link_js).");\n"; - $array_aux[$link_js['id_agent_start']] = 1; - unset($links_js[$link_js['id']]); - } - } - - foreach ($links_js as $link_js) { - if (($link_js['id_agent_end'] === 0) && $array_aux[$link_js['id_agent_start']] === 1) { - continue; - } else { - echo 'networkmap.links.push('.json_encode($link_js).");\n"; - } - } - - echo "\n"; - echo "\n"; - - echo "////////////////////////////////////////////////////////////////////\n"; - echo "// INTERFACE STATUS COLORS\n"; - echo "////////////////////////////////////////////////////////////////////\n"; - - $module_color_status = []; - $module_color_status[] = [ - 'status_code' => AGENT_MODULE_STATUS_NORMAL, - 'color' => COL_NORMAL, - ]; - $module_color_status[] = [ - 'status_code' => AGENT_MODULE_STATUS_CRITICAL_BAD, - 'color' => COL_CRITICAL, - ]; - $module_color_status[] = [ - 'status_code' => AGENT_MODULE_STATUS_WARNING, - 'color' => COL_WARNING, - ]; - $module_color_status[] = [ - 'status_code' => AGENT_STATUS_ALERT_FIRED, - 'color' => COL_ALERTFIRED, - ]; - $module_color_status_unknown = COL_UNKNOWN; - - echo 'var module_color_status = '.json_encode($module_color_status).";\n"; - echo "var module_color_status_unknown = '".$module_color_status_unknown."';\n"; - - echo "\n"; - echo "\n"; - - echo "////////////////////////////////////////////////////////////////////\n"; - echo "// Other vars\n"; - echo "////////////////////////////////////////////////////////////////////\n"; - - echo "var translation_none = '".__('None')."';\n"; - echo "var dialog_node_edit_title = '".__('Edit node %s')."';\n"; - echo "var holding_area_title = '".__('Holding Area')."';\n"; - echo "var edit_menu = '".__('Show details and options')."';\n"; - echo "var interface_link_add = '".__('Add a interface link')."';\n"; - echo "var set_parent_link = '".__('Set parent interface')."';\n"; - echo "var set_as_children_menu = '".__('Set as children')."';\n"; - echo "var set_parent_menu = '".__('Set parent')."';\n"; - echo "var abort_relationship_menu = '".__('Abort the action of set relationship')."';\n"; - echo "var delete_menu = '".__('Delete')."';\n"; - echo "var add_node_menu = '".__('Add node')."';\n"; - echo "var set_center_menu = '".__('Set center')."';\n"; - echo "var refresh_menu = '".__('Refresh')."';\n"; - echo "var refresh_holding_area_menu = '".__('Refresh Holding area')."';\n"; - echo "var ok_button = '".__('Proceed')."';\n"; - echo "var message_to_confirm = '".__('Resetting the map will delete all customizations you have done, including manual relationships between elements, new items, etc.')."';\n"; - echo "var warning_message = '".__('WARNING')."';\n"; - echo "var ok_button = '".__('Proceed')."';\n"; - echo "var cancel_button = '".__('Cancel')."';\n"; - echo "var restart_map_menu = '".__('Restart map')."';\n"; - echo "var abort_relationship_interface = '".__('Abort the interface relationship')."';\n"; - echo "var abort_relationship_menu = '".__('Abort the action of set relationship')."';\n"; - - echo "\n"; - echo "\n"; -} - - -function networkmap_loadfile( - $id=0, - $file='', - &$relations_param, - $graph -) { - global $config; - - $height_map = db_get_value('height', 'tmap', 'id', $id); - - $networkmap_nodes = []; - - $relations = []; - - $other_file = file($file); - - // Remove the graph head - $graph = preg_replace('/^graph .*/', '', $graph); - // Cut in nodes the graph - $graph = explode(']', $graph); - - $ids = []; - foreach ($graph as $node) { - $line = str_replace("\n", ' ', $node); - - if (preg_match('/([0-9]+) \[.*tooltip.*id_module=([0-9]+)/', $line, $match) != 0) { - $ids[$match[1]] = [ - 'type' => 'module', - 'id_module' => $match[2], - ]; - } else if (preg_match('/([0-9]+) \[.*tooltip.*id_agent=([0-9]+)/', $line, $match) != 0) { - $ids[$match[1]] = [ - 'type' => 'agent', - 'id_agent' => $match[2], - ]; - } - } - - foreach ($other_file as $key => $line) { - // clean line a long spaces for one space caracter - $line = preg_replace('/[ ]+/', ' ', $line); - - $data = []; - - if (preg_match('/^node.*$/', $line) != 0) { - $items = explode(' ', $line); - $node_id = $items[1]; - $node_x = ($items[2] * 100); - // 200 is for show more big - $node_y = ($height_map - $items[3] * 100); - // 200 is for show more big - $data['id'] = $node_id; - $data['text'] = ''; - $data['image'] = ''; - $data['width'] = 10; - $data['height'] = 10; - $data['id_agent'] = 0; - - if (preg_match('/ $line_orig, - 'dest' => $line_dest, - ]; - } - } - - $relations_param = []; - - foreach ($relations as $rel) { - if (strpos($rel['orig'], 'transp_') !== false) { - // removed the transparent nodes - continue; - } - - if (strpos($rel['dest'], 'transp_') !== false) { - // removed the transparent nodes - continue; - } - - $row = [ - 'id_child' => $rel['orig'], - 'child_type' => $networkmap_nodes[$rel['orig']]['type'], - 'id_parent' => $rel['dest'], - 'parent_type' => $networkmap_nodes[$rel['dest']]['type'], - ]; - $relations_param[] = $row; - } - - return $networkmap_nodes; -} - - -function get_status_color_module_networkmap($id_agente_modulo) -{ - $status = modules_get_agentmodule_status($id_agente_modulo); - - // Set node status - switch ($status) { - case 0: - // At the moment the networkmap enterprise does not show the - // alerts. - case AGENT_MODULE_STATUS_NORMAL_ALERT: - $status_color = COL_NORMAL; - // Normal monitor - break; - - case 1: - $status_color = COL_CRITICAL; - // Critical monitor - break; - - case 2: - $status_color = COL_WARNING; - // Warning monitor - break; - - case 4: - $status_color = COL_ALERTFIRED; - // Alert fired - break; - - default: - $status_color = COL_UNKNOWN; - // Unknown monitor - break; - } - - return $status_color; -} - - -function duplicate_networkmap($id) -{ - $return = true; - - $values = db_get_row('tmap', 'id', $id); - unset($values['id']); - $free_name = false; - $values['name'] = io_safe_input(__('Copy of ')).$values['name']; - $count = 1; - while (!$free_name) { - $exist = db_get_row_filter('tmap', ['name' => $values['name']]); - if ($exist === false) { - $free_name = true; - } else { - $values['name'] = $values['name'].io_safe_input(' '.$count); - } - } - - $correct_or_id = db_process_sql_insert('tmap', $values); - if ($correct_or_id === false) { - $return = false; - } else { - if (enterprise_installed()) { - $new_id = $correct_or_id; - duplicate_map_insert_nodes_and_relations($id, $new_id); - } - } - - if ($return) { - return true; - } else { - // Clean DB. - if (enterprise_installed()) { - // Relations - delete_relations($new_id); - - // Nodes - delete_nodes($new_id); - } - - db_process_sql_delete('tmap', ['id' => $new_id]); - - return false; - } -} - - -function clean_duplicate_links($relations) -{ - if (enterprise_installed()) { - enterprise_include_once('include/functions_pandora_networkmap.php'); - } - - $segregation_links = []; - $index = 0; - $index2 = 0; - $index3 = 0; - $index4 = 0; - foreach ($relations as $rel) { - if (($rel['parent_type'] == 0) && ($rel['child_type'] == 0)) { - $segregation_links['aa'][$index] = $rel; - $index++; - } else if (($rel['parent_type'] == 1) && ($rel['child_type'] == 1)) { - $segregation_links['mm'][$index2] = $rel; - $index2++; - } else if (($rel['parent_type'] == 3) && ($rel['child_type'] == 3)) { - $segregation_links['ff'][$index4] = $rel; - $index4++; - } else { - $segregation_links['am'][$index3] = $rel; - $index3++; - } - } - - $final_links = []; - /* - ---------------------------------------------------------------- */ - /* - --------------------- Clean duplicate links -------------------- */ - // ---------------------------------------------------------------- - $duplicated = false; - $index_to_del = 0; - $index = 0; - foreach ($segregation_links['aa'] as $link) { - foreach ($segregation_links['aa'] as $link2) { - if ($link['id_parent'] == $link2['id_child'] && $link['id_child'] == $link2['id_parent']) { - if (enterprise_installed()) { - delete_link($segregation_links['aa'][$index_to_del]); - } - - unset($segregation_links['aa'][$index_to_del]); - } - - $index_to_del++; - } - - $final_links['aa'][$index] = $link; - $index++; - - $duplicated = false; - $index_to_del = 0; - } - - $duplicated = false; - $index_to_del = 0; - $index2 = 0; - foreach ($segregation_links['mm'] as $link) { - foreach ($segregation_links['mm'] as $link2) { - if ($link['id_parent'] == $link2['id_child'] && $link['id_child'] == $link2['id_parent']) { - if (enterprise_installed()) { - delete_link($segregation_links['mm'][$index_to_del]); - } - - // unset($segregation_links['mm'][$index_to_del]); - } - - $index_to_del++; - } - - $final_links['mm'][$index2] = $link; - $index2++; - - $duplicated = false; - $index_to_del = 0; - } - - $duplicated = false; - $index_to_del = 0; - $index3 = 0; - foreach ($segregation_links['ff'] as $link) { - foreach ($segregation_links['ff'] as $link2) { - if ($link['id_parent'] == $link2['id_child'] && $link['id_child'] == $link2['id_parent']) { - if (enterprise_installed()) { - delete_link($segregation_links['ff'][$index_to_del]); - } - - unset($segregation_links['ff'][$index_to_del]); - } - - $index_to_del++; - } - - $final_links['ff'][$index3] = $link; - $index3++; - - $duplicated = false; - $index_to_del = 0; - } - - $final_links['am'] = $segregation_links['am']; - - /* - ---------------------------------------------------------------- */ - /* - ----------------- AA, AM and MM links management --------------- */ - /* - ------------------ Priority: ----------------------------------- */ - /* - -------------------- 1 -> MM (module - module) ----------------- */ - /* - -------------------- 2 -> AM (agent - module) ------------------ */ - /* - -------------------- 3 -> AA (agent - agent) ------------------- */ - // ---------------------------------------------------------------- - $final_links2 = []; - $index = 0; - $l3_link = []; - $agent1 = 0; - $agent2 = 0; - foreach ($final_links['mm'] as $rel_mm) { - $module_parent = $rel_mm['id_parent_source_data']; - $module_children = $rel_mm['id_child_source_data']; - $agent1 = (int) agents_get_agent_id_by_module_id($module_parent); - $agent2 = (int) agents_get_agent_id_by_module_id($module_children); - foreach ($final_links['aa'] as $key => $rel_aa) { - $l3_link = $rel_aa; - $id_p_source_data = (int) $rel_aa['id_parent_source_data']; - $id_c_source_data = (int) $rel_aa['id_child_source_data']; - if ((($id_p_source_data == $agent1) && ($id_c_source_data == $agent2)) - || (($id_p_source_data == $agent2) && ($id_c_source_data == $agent1)) - ) { - if (enterprise_installed()) { - delete_link($final_links['aa'][$key]); - } - - unset($final_links['aa'][$key]); - } - } - } - - $final_links2['aa'] = $final_links['aa']; - $final_links2['mm'] = $final_links['mm']; - $final_links2['am'] = $final_links['am']; - $final_links2['ff'] = $final_links['ff']; - - $same_m = []; - $index = 0; - foreach ($final_links2['am'] as $rel_am) { - foreach ($final_links2['am'] as $rel_am2) { - if (($rel_am['id_child_source_data'] == $rel_am2['id_child_source_data']) - && ($rel_am['id_parent_source_data'] != $rel_am2['id_parent_source_data']) - ) { - $same_m[$index]['rel'] = $rel_am2; - $same_m[$index]['agent_parent'] = $rel_am['id_parent_source_data']; - $index++; - } - } - } - - $final_links3 = []; - $index = 0; - $l3_link = []; - $have_l3 = false; - foreach ($final_links2['aa'] as $key => $rel_aa) { - $l3_link = $rel_aa; - foreach ($same_m as $rel_am) { - if ((($rel_aa['id_parent_source_data'] == $rel_am['parent']['id_parent_source_data']) - && ($rel_aa['id_child_source_data'] == $rel_am['rel']['id_parent_source_data'])) - || (($rel_aa['id_child_source_data'] == $rel_am['parent']['id_parent_source_data']) - && ($rel_aa['id_parent_source_data'] == $rel_am['rel']['id_parent_source_data'])) - ) { - if (enterprise_installed()) { - delete_link($final_links2['aa'][$key]); - } - - unset($final_links2['aa'][$key]); - } - } - } - - $final_links3['aa'] = $final_links2['aa']; - $final_links3['mm'] = $segregation_links['mm']; - $final_links3['am'] = $segregation_links['am']; - $final_links3['ff'] = $final_links2['ff']; - - $cleaned_links = []; - foreach ($final_links3['aa'] as $link) { - $cleaned_links[] = $link; - } - - foreach ($final_links3['am'] as $link) { - $cleaned_links[] = $link; - } - - foreach ($final_links3['mm'] as $link) { - $cleaned_links[] = $link; - } - - foreach ($final_links3['ff'] as $link) { - $cleaned_links[] = $link; - } - - return $cleaned_links; -} - - -function is_in_rel_array($relations, $relation) -{ - $is_in_array = false; - foreach ($relations as $rel) { - if ($rel['id_parent_source_data'] == $relation['id_parent_source_data'] - && $rel['id_child_source_data'] == $relation['id_child_source_data'] - ) { - $is_in_array = true; - } - } - - return $is_in_array; -} - - -function map_migrated($id) -{ - $new_maps = db_get_all_rows_sql('SELECT filter FROM tmap'); - $new_map_filter = json_decode($new_maps, true); - - foreach ($new_map_filter as $filter) { - if ((isset($filter['id_migrate_map'])) && ($filter['id_migrate_map'] == $id)) { - return true; - } - } - - return false; -} - - -function migrate_older_open_maps($id) -{ - global $config; - - $old_networkmap = db_get_row_filter( - 'tnetwork_map', - ['id_networkmap' => $id] - ); - - $map_values = []; - $map_values['id_group'] = $old_networkmap['id_group']; - $map_values['id_user'] = $old_networkmap['id_user']; - $map_values['type'] = 0; - $map_values['subtype'] = 0; - $map_values['name'] = $old_networkmap['name']; - - $new_map_filter = []; - $new_map_filter['dont_show_subgroups'] = $old_networkmap['dont_show_subgroups']; - $new_map_filter['node_radius'] = 40; - $new_map_filter['id_migrate_map'] = $id; - $map_values['filter'] = json_encode($new_map_filter); - - $map_values['description'] = 'Mapa open migrado'; - $map_values['width'] = 4000; - $map_values['height'] = 4000; - $map_values['center_x'] = 2000; - $map_values['center_y'] = 2000; - $map_values['background'] = ''; - $map_values['background_options'] = 0; - $map_values['source_period'] = 60; - $map_values['source'] = 0; - $map_values['source_data'] = $old_networkmap['id_group']; - if ($old_networkmap['type'] == 'radial_dinamic') { - $map_values['generation_method'] = 6; - } else { - $map_values['generation_method'] = 4; - } - - $map_values['generated'] = 0; - - $id_new_map = db_process_sql_insert('tmap', $map_values); - - if (!$id_new_map) { - return false; - } - - return true; -} - - -function show_networkmap($id=0, $user_readonly=false, $nodes_and_relations=[], $dashboard_mode=false, $map_dash_details=[]) -{ - global $config; - $clean_relations = clean_duplicate_links($nodes_and_relations['relations']); - - $hide_minimap = ''; - - $nodes_and_relations['relations'] = $clean_relations; - - $networkmap = db_get_row('tmap', 'id', $id); - $networkmap['filter'] = json_decode($networkmap['filter'], true); - - $networkmap['filter']['l2_network_interfaces'] = 1; - - echo ''; - ui_require_css_file('jquery.contextMenu', 'include/styles/js/'); - echo ''; - echo ''; - echo '
    '; - if ($dashboard_mode) { - $hide_minimap = 'none'; - } - - echo '
    '; - echo ' - '; - - echo '
    - - - -
    '; - echo '
    '; - - echo '
    - - - -
    '; - echo ''; - - echo '
    '; - - ?> - - - - - - - - - - - - - 0], + [ + 'disabled' => 0, + 'update_module_count' => 1, + ], ['id_agente' => $agent['id_agent']] ); @@ -702,6 +708,10 @@ function planned_downtimes_stop($downtime) } } break; + + default: + // Nothing to do. + break; } $message .= ui_print_info_message( @@ -725,8 +735,6 @@ function planned_downtimes_created($values) $check_group = (bool) db_get_value('id_grupo', 'tgrupo', 'id_grupo', $values['id_group']); $check = (bool) db_get_value('name', 'tplanned_downtime', 'name', $values['name']); - $datetime_from = strtotime($values['once_date_from'].' '.$values['once_time_from']); - $datetime_to = strtotime($values['once_date_to'].' '.$values['once_time_to']); $now = time(); $result = false; @@ -735,16 +743,16 @@ function planned_downtimes_created($values) 'return' => false, 'message' => __('Not created. Error inserting data. Start time must be higher than the current time'), ]; + } else if ($values['type_execution'] == 'once' && !$config['past_planned_downtimes'] && $values['date_to'] <= $now) { + return [ + 'return' => false, + 'message' => __('Not created. Error inserting data').'. '.__('The end date must be higher than the current time'), + ]; } else if ($values['type_execution'] == 'once' && $values['date_from'] >= $values['date_to']) { return [ 'return' => false, 'message' => __('Not created. Error inserting data').'. '.__('The end date must be higher than the start date'), ]; - } else if ($values['type_execution'] == 'once' && $values['date_to'] <= $now) { - return [ - 'return' => false, - 'message' => __('Not created. Error inserting data').'. '.__('The end date must be higher than the current time'), - ]; } else if ($values['type_execution'] == 'periodically' && (($values['type_periodicity'] == 'weekly' && $values['periodically_time_from'] >= $values['periodically_time_to']) || ($values['type_periodicity'] == 'monthly' && $values['periodically_day_from'] == $values['periodically_day_to'] && $values['periodically_time_from'] >= $values['periodically_time_to'])) diff --git a/pandora_console/include/functions_reporting.php b/pandora_console/include/functions_reporting.php index 7d0028eee5..fba9d87a02 100755 --- a/pandora_console/include/functions_reporting.php +++ b/pandora_console/include/functions_reporting.php @@ -36,15 +36,16 @@ require_once $config['homedir'].'/include/functions_forecast.php'; require_once $config['homedir'].'/include/functions_ui.php'; require_once $config['homedir'].'/include/functions_netflow.php'; require_once $config['homedir'].'/include/functions_os.php'; +require_once $config['homedir'].'/include/functions_network.php'; // // CONSTANTS DEFINITIONS // // -// Priority modes +// Priority modes. define('REPORT_PRIORITY_MODE_OK', 1); define('REPORT_PRIORITY_MODE_UNKNOWN', 2); -// Status +// Status. define('REPORT_STATUS_ERR', 0); define('REPORT_STATUS_OK', 1); define('REPORT_STATUS_UNKNOWN', 2); @@ -61,7 +62,7 @@ function reporting_user_can_see_report($id_report, $id_user=null) $id_user = $config['id_user']; } - // Get Report record (to get id_group) + // Get Report record (to get id_group). $report = db_get_row('treport', 'id_report', $id_report); // Check ACL on the report to see if user has access to the report. @@ -107,6 +108,10 @@ function reporting_get_type($content) case REPORT_OLD_TYPE_SUMATORY: $content['type'] = 'sumatory'; break; + + default: + // Default. + break; } return $content['type']; @@ -142,7 +147,6 @@ function reporting_make_reporting_data( enterprise_include_once('include/functions_metaconsole.php'); $return = []; - if (!empty($report)) { $contents = $report['contents']; } else { @@ -205,7 +209,7 @@ function reporting_make_reporting_data( $server_name = $content['server_name']; // General reports with 0 period means last value - // Avoid to overwrite it by template value + // Avoid to overwrite it by template value. if (!empty($period) && ($content['type'] !== 'general' && $content['period'] != 0)) { $content['period'] = $period; } @@ -229,7 +233,7 @@ function reporting_make_reporting_data( if (in_array('label', $content['style'])) { if ($content['id_agent'] == 0) { - // Metaconsole connection + // Metaconsole connection. if ($metaconsole_on && $server_name != '') { $connection = metaconsole_get_connection($server_name); if (!metaconsole_load_external_db($connection)) { @@ -240,7 +244,7 @@ function reporting_make_reporting_data( array_push($agents_to_macro, modules_get_agentmodule_agent($graph_item['id_agent_module'])); if ($metaconsole_on) { - // Restore db connection + // Restore db connection. metaconsole_restore_db(); } } @@ -261,7 +265,7 @@ function reporting_make_reporting_data( } if (isset($content['style']['name_label'])) { - // Add macros name + // Add macros name. $items_label = []; $items_label['type'] = $content['type']; $items_label['id_agent'] = $content['id_agent']; @@ -272,11 +276,10 @@ function reporting_make_reporting_data( $metaconsole_on = is_metaconsole(); $server_name = $content['server_name']; - // Metaconsole connection + // Metaconsole connection. if ($metaconsole_on && $server_name != '') { $connection = metaconsole_get_connection($server_name); if (!metaconsole_load_external_db($connection)) { - // ui_print_error_message ("Error connecting to ".$server_name); continue; } } @@ -292,7 +295,7 @@ function reporting_make_reporting_data( $content['name'] = reporting_label_macro($items_label, $content['style']['name_label']); if ($metaconsole_on) { - // Restore db connection + // Restore db connection. metaconsole_restore_db(); } } @@ -518,16 +521,6 @@ function reporting_make_reporting_data( ); break; - case 'netflow_pie': - $report['contents'][] = reporting_netflow( - $report, - $content, - $type, - $force_width_chart, - $force_height_chart, - 'netflow_pie', - $pdf - ); break; case 'netflow_data': @@ -542,18 +535,6 @@ function reporting_make_reporting_data( ); break; - case 'netflow_statistics': - $report['contents'][] = reporting_netflow( - $report, - $content, - $type, - $force_width_chart, - $force_height_chart, - 'netflow_statistics', - $pdf - ); - break; - case 'netflow_summary': $report['contents'][] = reporting_netflow( $report, @@ -796,6 +777,18 @@ function reporting_make_reporting_data( $pdf ); break; + + case 'nt_top_n': + $report['contents'][] = reporting_nt_top_n_report( + $report, + $content, + $pdf + ); + break; + + default: + // Default. + break; } $index_content++; @@ -824,7 +817,7 @@ function reporting_SLA( $return['description'] = $content['description']; $return['date'] = reporting_get_date_text($report, $content); - // Get chart + // Get chart. reporting_set_conf_charts( $width, $height, @@ -862,7 +855,7 @@ function reporting_SLA( include_once $config['homedir'].'/include/functions_planned_downtimes.php'; $metaconsole_on = is_metaconsole(); - // checking if needed to show graph or table + // checking if needed to show graph or table. if ($content['show_graph'] == 0 || $content['show_graph'] == 1) { $show_table = 1; } else { @@ -885,11 +878,10 @@ function reporting_SLA( foreach ($slas as $sla) { $server_name = $sla['server_name']; - // Metaconsole connection + // Metaconsole connection. if ($metaconsole_on && $server_name != '') { $connection = metaconsole_get_connection($server_name); if (!metaconsole_load_external_db($connection)) { - // ui_print_error_message ("Error connecting to ".$server_name); continue; } } @@ -898,14 +890,14 @@ function reporting_SLA( || modules_is_not_init($sla['id_agent_module']) ) { if ($metaconsole_on) { - // Restore db connection + // Restore db connection. metaconsole_restore_db(); } continue; } - // controller min and max == 0 then dinamic min and max critical + // Controller min and max == 0 then dinamic min and max critical. $dinamic_text = 0; if ($sla['sla_min'] == 0 && $sla['sla_max'] == 0) { $sla['sla_min'] = null; @@ -913,7 +905,7 @@ function reporting_SLA( $dinamic_text = __('Dynamic'); } - // controller inverse interval + // Controller inverse interval. $inverse_interval = 0; if ((isset($sla['sla_max'])) && (isset($sla['sla_min']))) { if ($sla['sla_max'] < $sla['sla_min']) { @@ -925,26 +917,25 @@ function reporting_SLA( } } - // for graph slice for module-interval, if not slice=0; + // For graph slice for module-interval, if not slice=0. if ($show_graphs) { - $module_interval = modules_get_interval($sla['id_agent_module']); + $module_interval = modules_get_interval( + $sla['id_agent_module'] + ); $slice = ($content['period'] / $module_interval); } else { $slice = 1; } - // call functions sla + // Call functions sla. $sla_array = []; $sla_array = reporting_advanced_sla( $sla['id_agent_module'], ($report['datetime'] - $content['period']), $report['datetime'], $sla['sla_min'], - // min_value -> dynamic $sla['sla_max'], - // max_value -> dynamic $inverse_interval, - // inverse_interval -> dynamic [ '1' => $content['sunday'], '2' => $content['monday'], @@ -960,12 +951,12 @@ function reporting_SLA( ); if ($metaconsole_on) { - // Restore db connection + // Restore db connection. metaconsole_restore_db(); } $server_name = $sla['server_name']; - // Metaconsole connection + // Metaconsole connection. if ($metaconsole_on && $server_name != '') { $connection = metaconsole_get_connection($server_name); if (metaconsole_connect($connection) != NOERR) { @@ -974,10 +965,16 @@ function reporting_SLA( } if ($show_graphs) { - $planned_downtimes = reporting_get_planned_downtimes_intervals($sla['id_agent_module'], ($report['datetime'] - $content['period']), $report['datetime']); + $planned_downtimes = reporting_get_planned_downtimes_intervals( + $sla['id_agent_module'], + ($report['datetime'] - $content['period']), + $report['datetime'] + ); - if ((is_array($planned_downtimes)) && (count($planned_downtimes) > 0)) { - // Sort retrieved planned downtimes + if ((is_array($planned_downtimes)) + && (count($planned_downtimes) > 0) + ) { + // Sort retrieved planned downtimes. usort( $planned_downtimes, function ($a, $b) { @@ -987,16 +984,16 @@ function reporting_SLA( return 0; } - return ($a < $b) ? -1 : 1; + return ($a < $b) ? (-1) : 1; } ); - // Compress (overlapped) planned downtimes + // Compress (overlapped) planned downtimes. $npd = count($planned_downtimes); for ($i = 0; $i < $npd; $i++) { if (isset($planned_downtimes[($i + 1)])) { if ($planned_downtimes[$i]['date_to'] >= $planned_downtimes[($i + 1)]['date_from']) { - // merge + // Merge. $planned_downtimes[$i]['date_to'] = $planned_downtimes[($i + 1)]['date_to']; array_splice($planned_downtimes, ($i + 1), 1); $npd--; @@ -1009,8 +1006,17 @@ function reporting_SLA( } $data = []; - $data['agent'] = io_safe_output(modules_get_agentmodule_agent_alias($sla['id_agent_module'])); - $data['module'] = io_safe_output(modules_get_agentmodule_name($sla['id_agent_module'])); + $data['agent'] = io_safe_output( + modules_get_agentmodule_agent_alias( + $sla['id_agent_module'] + ) + ); + $data['module'] = io_safe_output( + modules_get_agentmodule_name( + $sla['id_agent_module'] + ) + ); + $data['max'] = $sla['sla_max']; $data['min'] = $sla['sla_min']; $data['sla_limit'] = $sla['sla_limit']; @@ -1044,16 +1050,17 @@ function reporting_SLA( $data['checks_unknown'] += $value_sla['checks_unknown']; $data['checks_not_init'] += $value_sla['checks_not_init']; - // generate raw data for graph + // Generate raw data for graph. if ($value_sla['time_total'] != 0) { if ($value_sla['time_error'] > 0) { - // ERR + // ERR. $raw_graph[$i]['data'] = 3; } else if ($value_sla['time_unknown'] > 0) { - // UNKNOWN + // UNKNOWN. $raw_graph[$i]['data'] = 4; - } else if ($value_sla['time_not_init'] == $value_sla['time_total']) { - // NOT INIT + } else if ($value_sla['time_not_init'] == $value_sla['time_total'] + ) { + // NOT INIT. $raw_graph[$i]['data'] = 6; } else { $raw_graph[$i]['data'] = 1; @@ -1062,7 +1069,8 @@ function reporting_SLA( $raw_graph[$i]['data'] = 7; } - $raw_graph[$i]['utimestamp'] = ($value_sla['date_to'] - $value_sla['date_from']); + $raw_graph[$i]['utimestamp'] = ( + $value_sla['date_to'] - $value_sla['date_from']); if (isset($planned_downtimes)) { foreach ($planned_downtimes as $pd) { @@ -1070,7 +1078,7 @@ function reporting_SLA( && ($value_sla['date_to'] <= $pd['date_to']) ) { $raw_graph[$i]['data'] = 5; - // in scheduled downtime + // In scheduled downtime. break; } } @@ -1079,10 +1087,15 @@ function reporting_SLA( $i++; } - $data['sla_value'] = reporting_sla_get_compliance_from_array($data); - $data['sla_fixed'] = sla_truncate($data['sla_value'], $config['graph_precision']); + $data['sla_value'] = reporting_sla_get_compliance_from_array( + $data + ); + $data['sla_fixed'] = sla_truncate( + $data['sla_value'], + $config['graph_precision'] + ); } else { - // Show only table not divider in slice for defect slice=1 + // Show only table not divider in slice for defect slice=1. $data['time_total'] = $sla_array['time_total']; $data['time_ok'] = $sla_array['time_ok']; $data['time_error'] = $sla_array['time_error']; @@ -1098,7 +1111,7 @@ function reporting_SLA( $data['sla_fixed'] = $sla_array['sla_fixed']; } - // checks whether or not it meets the SLA + // Checks whether or not it meets the SLA. if ($data['sla_value'] >= $sla['sla_limit']) { $data['sla_status'] = 1; $sla_failed = false; @@ -1107,19 +1120,19 @@ function reporting_SLA( $data['sla_status'] = 0; } - // Do not show right modules if 'only_display_wrong' is active + // Do not show right modules if 'only_display_wrong' is active. if ($content['only_display_wrong'] && $sla_failed == false) { continue; } - // find order + // Find order. $data['order'] = $data['sla_value']; if ($show_table) { $return['data'][] = $data; } - // Slice graphs calculation + // Slice graphs calculation. if ($show_graphs) { $data_init = -1; $acum = 0; @@ -1152,8 +1165,16 @@ function reporting_SLA( $array_result[$i]['real_data'] = $sum; $dataslice = []; - $dataslice['agent'] = io_safe_output(modules_get_agentmodule_agent_alias($sla['id_agent_module'])); - $dataslice['module'] = io_safe_output(modules_get_agentmodule_name($sla['id_agent_module'])); + $dataslice['agent'] = io_safe_output( + modules_get_agentmodule_agent_alias( + $sla['id_agent_module'] + ) + ); + $dataslice['module'] = io_safe_output( + modules_get_agentmodule_name( + $sla['id_agent_module'] + ) + ); $dataslice['sla_value'] = $data['sla_value']; $dataslice['order'] = $data['sla_value']; @@ -1178,24 +1199,24 @@ function reporting_SLA( } if ($metaconsole_on) { - // Restore db connection + // Restore db connection. metaconsole_restore_db(); } } if ($content['top_n'] == 2) { - // SLA items sorted descending () + // SLA items sorted descending. arsort($return['data']['']); } else if ($content['top_n'] == 1) { - // SLA items sorted ascending + // SLA items sorted ascending. asort($sla_showed_values); } - // order data for ascending or descending + // Order data for ascending or descending. if ($content['top_n'] != 0) { switch ($content['top_n']) { case 1: - // order tables + // Order tables. $temp = []; foreach ($return['data'] as $row) { $i = 0; @@ -1212,7 +1233,7 @@ function reporting_SLA( $return['data'] = $temp; - // order graphs + // Order graphs. $temp = []; foreach ($return['charts'] as $row) { $i = 0; @@ -1228,11 +1249,10 @@ function reporting_SLA( } $return['charts'] = $temp; - break; case 2: - // order tables + // Order tables. $temp = []; foreach ($return['data'] as $row) { $i = 0; @@ -1249,7 +1269,7 @@ function reporting_SLA( $return['data'] = $temp; - // order graph + // Order graph. $temp = []; foreach ($return['charts'] as $row) { $i = 0; @@ -1265,7 +1285,10 @@ function reporting_SLA( } $return['charts'] = $temp; + break; + default: + // Default. break; } } @@ -1304,7 +1327,7 @@ function reporting_event_top_n( case REPORT_TOP_N_AVG: default: - // If nothing is selected then it will be shown the average data + // If nothing is selected then it will be shown the average data. $type_top_n = __('Avg'); break; } @@ -1321,7 +1344,7 @@ function reporting_event_top_n( $return['top_n'] = $content['top_n_value']; if (empty($content['subitems'])) { - // Get all the related data + // Get all the related data. $sql = sprintf( 'SELECT id_agent_module, server_name FROM treport_content_item @@ -1334,7 +1357,7 @@ function reporting_event_top_n( $tops = $content['subitems']; } - // Get chart + // Get chart. reporting_set_conf_charts( $width, $height, @@ -1358,7 +1381,7 @@ function reporting_event_top_n( $data_top = []; foreach ($tops as $key => $row) { - // Metaconsole connection + // Metaconsole connection. $server_name = $row['server_name']; if (($config['metaconsole'] == 1) && $server_name != '' && defined('METACONSOLE')) { $connection = metaconsole_get_connection($server_name); @@ -1388,7 +1411,7 @@ function reporting_event_top_n( case REPORT_TOP_N_AVG: default: - // If nothing is selected then it will be shown the average data + // If nothing is selected then it will be shown the average data. $value = reporting_get_agentmodule_data_average($row['id_agent_module'], $content['period']); break; } @@ -1402,7 +1425,7 @@ function reporting_event_top_n( $units[$key] = $unit; } - // Restore dbconnection + // Restore dbconnection. if (($config['metaconsole'] == 1) && $server_name != '' && defined('METACONSOLE')) { metaconsole_restore_db(); } @@ -1415,21 +1438,25 @@ function reporting_event_top_n( // Order to show. switch ($order_uptodown) { - // Descending + // Descending. case 1: array_multisort($data_top, SORT_DESC, $agent_name, SORT_ASC, $module_name, SORT_ASC, $id_agent_module, SORT_ASC, $units, SORT_ASC); break; - // Ascending + // Ascending. case 2: array_multisort($data_top, SORT_ASC, $agent_name, SORT_ASC, $module_name, SORT_ASC, $id_agent_module, SORT_ASC, $units, SORT_ASC); break; - // By agent name or without selection + // By agent name or without selection. case 0: case 3: array_multisort($agent_name, SORT_ASC, $data_top, SORT_ASC, $module_name, SORT_ASC, $id_agent_module, SORT_ASC, $units, SORT_ASC); break; + + default: + // Default. + break; } array_splice($data_top, $top_n_value); @@ -1445,7 +1472,7 @@ function reporting_event_top_n( $data_top_values['id_agent_module'] = $id_agent_module; $data_top_values['units'] = $units; - // Define truncate size depends the graph width + // Define truncate size depends the graph width. $truncate_size = ($width / (4 * ($config['font_size'])) - 1); if ($order_uptodown == 1 || $order_uptodown == 2) { @@ -1571,7 +1598,7 @@ function reporting_event_top_n( $ttl ); - // Display bars graph + // Display bars graph. $return['charts']['bars'] = hbar_graph( $data_hbar, $width, @@ -1596,7 +1623,7 @@ function reporting_event_top_n( $return['resume'] = null; if ($content['show_resume'] && count($data_top_values) > 0) { - // Get the very first not null value + // Get the very first not null value. $i = 0; do { $min = $data_top_values['data_top'][$i]; @@ -1671,18 +1698,19 @@ function reporting_event_report_group( } $return['description'] = $content['description']; + $return['show_extended_events'] = $content['show_extended_events']; $return['date'] = reporting_get_date_text($report, $content); $event_filter = $content['style']; $return['show_summary_group'] = $event_filter['show_summary_group']; - // filter + // Filter. $show_summary_group = $event_filter['show_summary_group']; $filter_event_severity = json_decode($event_filter['filter_event_severity'], true); $filter_event_type = json_decode($event_filter['filter_event_type'], true); $filter_event_status = json_decode($event_filter['filter_event_status'], true); $filter_event_filter_search = $event_filter['event_filter_search']; - // graphs + // Graphs. $event_graph_by_agent = $event_filter['event_graph_by_agent']; $event_graph_by_user_validator = $event_filter['event_graph_by_user_validator']; $event_graph_by_criticity = $event_filter['event_graph_by_criticity']; @@ -1844,7 +1872,7 @@ function reporting_event_report_group( metaconsole_restore_db(); } - // total_events + // total_events. if ($return['data'] != '') { $return['total_events'] = count($return['data']); } else { @@ -1886,24 +1914,29 @@ function reporting_event_report_module( $return['title'] = $content['name']; $return['subtitle'] = agents_get_alias($content['id_agent']).' - '.io_safe_output(modules_get_agentmodule_name($content['id_agent_module'])); + $return['label'] = (isset($content['style']['label'])) ? $content['style']['label'] : ''; + if ($return['label'] != '') { + $return['label'] = reporting_label_macro($content, $return['label']); + } + if (is_metaconsole()) { metaconsole_restore_db(); } $return['description'] = $content['description']; + $return['show_extended_events'] = $content['show_extended_events']; $return['date'] = reporting_get_date_text($report, $content); - $return['label'] = (isset($content['style']['label'])) ? $content['style']['label'] : ''; $event_filter = $content['style']; $return['show_summary_group'] = $event_filter['show_summary_group']; - // filter + // Filter. $show_summary_group = $event_filter['show_summary_group']; $filter_event_severity = json_decode($event_filter['filter_event_severity'], true); $filter_event_type = json_decode($event_filter['filter_event_type'], true); $filter_event_status = json_decode($event_filter['filter_event_status'], true); $filter_event_filter_search = $event_filter['event_filter_search']; - // graphs + // Graphs. $event_graph_by_user_validator = $event_filter['event_graph_by_user_validator']; $event_graph_by_criticity = $event_filter['event_graph_by_criticity']; $event_graph_validated_vs_unvalidated = $event_filter['event_graph_validated_vs_unvalidated']; @@ -1915,7 +1948,7 @@ function reporting_event_report_module( $metaconsole_dbtable = false; } - // data events + // Data events. $data = reporting_get_module_detailed_event( $content['id_agent_module'], $content['period'], @@ -1944,7 +1977,7 @@ function reporting_event_report_module( metaconsole_restore_db(); } - // total_events + // Total_events. if ($return['data'][0]['data'] != '') { $return['total_events'] = count($return['data'][0]['data']); } else { @@ -2261,6 +2294,10 @@ function reporting_exception( $return['subtitle'] = __('Exception - Modules at critical or warning status'); $return['subtype'] = __('Modules at critical or warning status'); break; + + default: + // Default. + break; } $return['description'] = $content['description']; @@ -2271,7 +2308,7 @@ function reporting_exception( $return['resume'] = []; if (empty($content['subitems'])) { - // Get all the related data + // Get all the related data. $sql = sprintf( ' SELECT id_agent_module, server_name, operation @@ -2288,10 +2325,10 @@ function reporting_exception( if ($exceptions === false) { $return['failed'] = __('There are no Agent/Modules defined'); } else { - // Get the very first not null value + // Get the very first not null value. $i = 0; do { - // Metaconsole connection + // Metaconsole connection. $server_name = $exceptions[$i]['server_name']; if (($config['metaconsole'] == 1) && $server_name != '' && defined('METACONSOLE')) { $connection = metaconsole_get_connection($server_name); @@ -2325,12 +2362,16 @@ function reporting_exception( $content['period'] ); break; + + default: + // Default. + break; } } $i++; - // Restore dbconnection + // Restore dbconnection. if (($config['metaconsole'] == 1) && $server_name != '' && defined('METACONSOLE')) { metaconsole_restore_db(); } @@ -2342,7 +2383,7 @@ function reporting_exception( $i = 0; foreach ($exceptions as $exc) { - // Metaconsole connection + // Metaconsole connection. $server_name = $exc['server_name']; if (($config['metaconsole'] == 1) && $server_name != '' && defined('METACONSOLE')) { $connection = metaconsole_get_connection($server_name); @@ -2704,6 +2745,17 @@ function reporting_group_report($report, $content) } +/** + * Create data report event agent. + * + * @param array $report Data report. + * @param array $content Content report. + * @param string $type Type report. + * @param integer $force_width_chart Force width. + * @param integer $force_height_chart Force height. + * + * @return array Data. + */ function reporting_event_report_agent( $report, $content, @@ -2724,25 +2776,26 @@ function reporting_event_report_agent( $history = true; } - $return['title'] = $content['name']; - $return['subtitle'] = agents_get_alias($content['id_agent']); - $return['description'] = $content['description']; - $return['date'] = reporting_get_date_text($report, $content); - $return['label'] = (isset($content['style']['label'])) ? $content['style']['label'] : ''; + $return['title'] = $content['name']; + $return['subtitle'] = agents_get_alias($content['id_agent']); + $return['description'] = $content['description']; + $return['date'] = reporting_get_date_text($report, $content); + $return['show_summary_group'] = $content['style']['show_summary_group']; + $return['show_extended_events'] = $content['show_extended_events']; $style = $content['style']; - // filter - $show_summary_group = $style['show_summary_group']; - $filter_event_severity = json_decode($style['filter_event_severity'], true); - $filter_event_type = json_decode($style['filter_event_type'], true); - $filter_event_status = json_decode($style['filter_event_status'], true); + // Filter. + $show_summary_group = $style['show_summary_group']; + $filter_event_severity = json_decode($style['filter_event_severity'], true); + $filter_event_type = json_decode($style['filter_event_type'], true); + $filter_event_status = json_decode($style['filter_event_status'], true); $filter_event_filter_search = $style['event_filter_search']; - // graph - $event_graph_by_user_validator = $style['event_graph_by_user_validator']; - $event_graph_by_criticity = $style['event_graph_by_criticity']; + // Graph. + $event_graph_by_user_validator = $style['event_graph_by_user_validator']; + $event_graph_by_criticity = $style['event_graph_by_criticity']; $event_graph_validated_vs_unvalidated = $style['event_graph_validated_vs_unvalidated']; $return['data'] = reporting_get_agents_detailed_event( @@ -2787,6 +2840,13 @@ function reporting_event_report_agent( $metaconsole_dbtable = false; } + $label = (isset($content['style']['label'])) ? $content['style']['label'] : ''; + if ($label != '') { + $label = reporting_label_macro($content, $label); + } + + $return['label'] = $label; + if ($event_graph_by_user_validator) { $data_graph = events_get_count_events_validated_by_user( ['id_agent' => $content['id_agent']], @@ -2870,7 +2930,7 @@ function reporting_event_report_agent( metaconsole_restore_db(); } - // total_events + // Total events. if ($return['data'] != '') { $return['total_events'] = count($return['data']); } else { @@ -2903,7 +2963,11 @@ function reporting_historical_data($report, $content) $return['subtitle'] = $agent_name.' - '.$module_name; $return['description'] = $content['description']; $return['date'] = reporting_get_date_text($report, $content); + $return['label'] = (isset($content['style']['label'])) ? $content['style']['label'] : ''; + if ($return['label'] != '') { + $return['label'] = reporting_label_macro($content, $return['label']); + } $return['keys'] = [ __('Date'), @@ -2979,7 +3043,6 @@ function reporting_database_serialized($report, $content) $return['subtitle'] = $agent_name.' - '.$module_name; $return['description'] = $content['description']; $return['date'] = reporting_get_date_text($report, $content); - $return['label'] = (isset($content['style']['label'])) ? $content['style']['label'] : ''; $keys = []; if (isset($content['header_definition']) && ($content['header_definition'] != '')) { @@ -3005,6 +3068,11 @@ function reporting_database_serialized($report, $content) metaconsole_connect($server); } + $return['label'] = (isset($content['style']['label'])) ? $content['style']['label'] : ''; + if ($return['label'] != '') { + $return['label'] = reporting_label_macro($content, $return['label']); + } + $datelimit = ($report['datetime'] - $content['period']); $search_in_history_db = db_search_in_history_db($datelimit); @@ -3551,7 +3619,12 @@ function reporting_alert_report_agent($report, $content) $return['subtitle'] = $agent_name; $return['description'] = $content['description']; $return['date'] = reporting_get_date_text($report, $content); + $return['label'] = (isset($content['style']['label'])) ? $content['style']['label'] : ''; + if ($return['label'] != '') { + $return['label'] = reporting_label_macro($content, $return['label']); + } + $module_list = agents_get_modules($content['id_agent']); $data = []; @@ -3683,6 +3756,9 @@ function reporting_alert_report_module($report, $content) $return['description'] = $content['description']; $return['date'] = reporting_get_date_text($report, $content); $return['label'] = (isset($content['style']['label'])) ? $content['style']['label'] : ''; + if ($return['label'] != '') { + $return['label'] = reporting_label_macro($content, $return['label']); + } $data_row = []; @@ -3885,7 +3961,6 @@ function reporting_monitor_report($report, $content) $return['subtitle'] = $agent_name.' - '.$module_name; $return['description'] = $content['description']; $return['date'] = reporting_get_date_text($report, $content); - $return['label'] = (isset($content['style']['label'])) ? $content['style']['label'] : ''; if ($config['metaconsole']) { $id_meta = metaconsole_get_id_server($content['server_name']); @@ -3894,6 +3969,11 @@ function reporting_monitor_report($report, $content) metaconsole_connect($server); } + $return['label'] = (isset($content['style']['label'])) ? $content['style']['label'] : ''; + if ($return['label'] != '') { + $return['label'] = reporting_label_macro($content, $return['label']); + } + $module_name = io_safe_output( modules_get_agentmodule_name($content['id_agent_module']) ); @@ -3929,6 +4009,20 @@ function reporting_monitor_report($report, $content) } +/** + * Generates the data structure to build a netflow report. + * + * @param array $report Global report info. + * @param array $content Report item info. + * @param string $type Report type (static, dynamic, data). + * @param integer $force_width_chart Fixed width chart. + * @param integer $force_height_chart Fixed height chart. + * @param string $type_netflow One of netflow_area, netflow_data, + * netflow_summary. + * @param boolean $pdf True if a pdf report is generating. + * + * @return array Report item structure. + */ function reporting_netflow( $report, $content, @@ -3945,21 +4039,17 @@ function reporting_netflow( $return['type'] = 'netflow_area'; break; - case 'netflow_pie': - $return['type'] = 'netflow_pie'; - break; - case 'netflow_data': $return['type'] = 'netflow_data'; break; - case 'netflow_statistics': - $return['type'] = 'netflow_statistics'; - break; - case 'netflow_summary': $return['type'] = 'netflow_summary'; break; + + default: + $return['type'] = 'unknown'; + break; } if (empty($content['name'])) { @@ -3968,20 +4058,16 @@ function reporting_netflow( $content['name'] = __('Netflow Area'); break; - case 'netflow_pie': - $content['name'] = __('Netflow Pie'); + case 'netflow_summary': + $content['name'] = __('Netflow Summary'); break; case 'netflow_data': $content['name'] = __('Netflow Data'); break; - case 'netflow_statistics': - $content['name'] = __('Netflow Statistics'); - break; - - case 'netflow_summary': - $content['name'] = __('Netflow Summary'); + default: + $content['name'] = __('Unknown report'); break; } } @@ -3990,7 +4076,7 @@ function reporting_netflow( $return['description'] = $content['description']; $return['date'] = reporting_get_date_text($report, $content); - // Get chart + // Get chart. reporting_set_conf_charts( $width, $height, @@ -4008,7 +4094,7 @@ function reporting_netflow( $height = $force_height_chart; } - // Get item filters + // Get item filters. $filter = db_get_row_sql( "SELECT * FROM tnetflow_filter @@ -4033,9 +4119,17 @@ function reporting_netflow( break; case 'data': + default: + // Nothing to do. break; } + $return['subtitle'] = netflow_generate_subtitle_report( + $filter['aggregate'], + $content['top_n'], + $type_netflow + ); + return reporting_check_structure_content($return); } @@ -4387,6 +4481,9 @@ function reporting_value($report, $content, $type, $pdf=false) $return['description'] = $content['description']; $return['date'] = reporting_get_date_text($report, $content); $return['label'] = (isset($content['style']['label'])) ? $content['style']['label'] : ''; + $return['agents'] = [$content['id_agent']]; + $return['id_agent'] = $content['id_agent']; + $return['id_agent_module'] = $content['id_agent_module']; $return['agent_name'] = $agent_name; $return['module_name'] = $module_name; @@ -4880,7 +4977,9 @@ function reporting_sql($report, $content) $return['date'] = reporting_get_date_text(); if ($config['metaconsole']) { - $id_meta = metaconsole_get_id_server($content['server_name']); + $id_meta = metaconsole_get_id_server( + $content['server_name'] + ); $server = metaconsole_get_connection_by_id($id_meta); metaconsole_connect($server); @@ -4889,22 +4988,40 @@ function reporting_sql($report, $content) if ($content['treport_custom_sql_id'] != 0) { switch ($config['dbtype']) { case 'mysql': - $sql = io_safe_output(db_get_value_filter('`sql`', 'treport_custom_sql', ['id' => $content['treport_custom_sql_id']])); + $sql = io_safe_output( + db_get_value_filter( + '`sql`', + 'treport_custom_sql', + ['id' => $content['treport_custom_sql_id']] + ) + ); break; case 'postgresql': - $sql = io_safe_output(db_get_value_filter('"sql"', 'treport_custom_sql', ['id' => $content['treport_custom_sql_id']])); + $sql = io_safe_output( + db_get_value_filter( + '"sql"', + 'treport_custom_sql', + ['id' => $content['treport_custom_sql_id']] + ) + ); break; case 'oracle': - $sql = io_safe_output(db_get_value_filter('sql', 'treport_custom_sql', ['id' => $content['treport_custom_sql_id']])); + $sql = io_safe_output( + db_get_value_filter( + 'sql', + 'treport_custom_sql', + ['id' => $content['treport_custom_sql_id']] + ) + ); break; } } else { $sql = io_safe_output($content['external_source']); } - // Do a security check on SQL coming from the user + // Do a security check on SQL coming from the user. $sql = check_sql($sql); $return['sql'] = $sql; @@ -4919,7 +5036,9 @@ function reporting_sql($report, $content) } if ($content['id_rc'] != null) { - $historical_db = db_get_value_sql('SELECT historical_db from treport_content where id_rc ='.$content['id_rc']); + $historical_db = db_get_value_sql( + 'SELECT historical_db from treport_content where id_rc ='.$content['id_rc'] + ); } else { $historical_db = $content['historical_db']; } @@ -4974,11 +5093,16 @@ function sla_truncate($num, $accurancy=2) } -// -// Aux: check value limits -// -// Returns if the data is in a valid range or not -// +/** + * SLA check value. + * + * @param integer $value Value. + * @param integer $min Treshold min SLA. + * @param boolean $max Treshold max SLA. + * @param boolean $inverse_interval Treshold inverse SLA. + * + * @return boolean Returns the interval in downtime (false if no matches). + */ function sla_check_value($value, $min, $max, $inverse_interval=0) { if (!isset($inverse_interval)) { @@ -4986,12 +5110,12 @@ function sla_check_value($value, $min, $max, $inverse_interval=0) } if ((!isset($max)) && (!isset($min))) { - // disabled thresholds + // Disabled thresholds. return true; } if ($max == $min) { - // equal + // Equal. if ($value == $max) { return ($inverse_interval == 0) ? true : false; } @@ -5000,7 +5124,7 @@ function sla_check_value($value, $min, $max, $inverse_interval=0) } if (!isset($max)) { - // greater or equal than min + // Greater or equal than min. if ($value >= $min) { return ($inverse_interval == 0) ? true : false; } @@ -5009,7 +5133,7 @@ function sla_check_value($value, $min, $max, $inverse_interval=0) } if (!isset($min)) { - // smaller or equal than max + // Smaller or equal than max. if ($value <= $max) { return ($inverse_interval == 0) ? true : false; } @@ -5026,20 +5150,25 @@ function sla_check_value($value, $min, $max, $inverse_interval=0) /** - * SLA downtime worktime + * SLA downtime worktime. * - * Check (if needed) if the range specified by wt_start and wt_end is downtime + * Check (if needed) if the range specified by wt_start and wt_end is downtime. * - * Only used for inclusive downtimes calculation (from sla_fixed_worktime) + * Only used for inclusive downtimes calculation (from sla_fixed_worktime). * - * @param integer $wt_start start of the range - * @param integer $wt_end end of the range - * @param hash $planned_downtimes array with the planned downtimes (ordered and merged) + * @param integer $wt_start Start of the range. + * @param integer $wt_end End of the range. + * @param boolean $inclusive_downtimes Boolean. + * @param array $planned_downtimes Array with the planned downtimes (ordered and merged). * - * @return integer returns the interval in downtime (false if no matches) + * @return integer Returns the interval in downtime (false if no matches). */ -function sla_downtime_worktime($wt_start, $wt_end, $inclusive_downtimes=1, $planned_downtimes=null) -{ +function sla_downtime_worktime( + $wt_start, + $wt_end, + $inclusive_downtimes=1, + $planned_downtimes=null +) { if ((!isset($planned_downtimes)) || (!is_array($planned_downtimes))) { return false; } @@ -5053,6 +5182,7 @@ function sla_downtime_worktime($wt_start, $wt_end, $inclusive_downtimes=1, $plan } $rt = false; + foreach ($planned_downtimes as $pd) { if (($wt_start >= $pd['date_from']) && ($wt_start <= $pd['date_to']) @@ -5074,7 +5204,7 @@ function sla_downtime_worktime($wt_start, $wt_end, $inclusive_downtimes=1, $plan && ($wt_end > $pd['date_to']) ) { // ..[..start..]..end.. - $rt = ($wt_end - $pd['date_to']); + $rt = ($pd['date_to'] - $wt_start); break; } else if (($wt_start >= $pd['date_to']) && ($wt_end >= $pd['date_to']) @@ -5098,29 +5228,44 @@ function sla_downtime_worktime($wt_start, $wt_end, $inclusive_downtimes=1, $plan * As worktime is order (older ... newer) the idx works as flag to identify * last range checked, in order to improve the algorythm performance. * - * @param integer $wt_start start of the range - * @param integer $wt_end end of the range - * @param hash $worktime hash containing the valid intervals - * @param hash $planned_downtimes array with the planned downtimes (ordered and merged) - * @param integer $inclusive_downtimes In downtime as OK (1) or ignored (0) - * @param integer $idx last ranges checked + * @param integer $wt_start Start of the range. + * @param integer $wt_end End of the range. + * @param array $worktime Hash containing the valid intervals. + * @param array $planned_downtimes Array with the planned downtimes (ordered and merged). + * @param integer $inclusive_downtimes In downtime as OK (1) or ignored (0). + * @param integer $idx Last ranges checked. + * + * @return array */ -function sla_fixed_worktime($wt_start, $wt_end, $worktime=null, $planned_downtimes=null, $inclusive_downtimes=1, $idx=0) -{ +function sla_fixed_worktime( + $wt_start, + $wt_end, + $worktime=null, + $planned_downtimes=null, + $inclusive_downtimes=1, + $idx=0 +) { $return = []; - // Accept all ranges by default + // Accept all ranges by default. $return['wt_valid'] = 1; $return['interval'] = ($wt_end - $wt_start); - if ((!isset($wt_start)) || (!isset($wt_end)) || ($wt_start > $wt_end) || ($wt_start > time())) { + if ((!isset($wt_start)) || (!isset($wt_end)) + || ($wt_start > $wt_end) || ($wt_start > time()) + ) { $return['wt_valid'] = 0; $return['interval'] = 0; } - // No exclusions defined, entire worktime is valid + // No exclusions defined, entire worktime is valid. if ((!isset($worktime) || (!is_array($worktime)))) { - $time_in_downtime = sla_downtime_worktime($wt_start, $wt_end, $inclusive_downtimes, $planned_downtimes); + $time_in_downtime = sla_downtime_worktime( + $wt_start, + $wt_end, + $inclusive_downtimes, + $planned_downtimes + ); if ($time_in_downtime != false) { $return['wt_in_downtime'] = 1; $return['downtime_interval'] = $time_in_downtime; @@ -5130,7 +5275,7 @@ function sla_fixed_worktime($wt_start, $wt_end, $worktime=null, $planned_downtim return $return; } - // Check exceptions + // Check exceptions. $total = count($worktime); $return['idx'] = $idx; @@ -5144,10 +5289,15 @@ function sla_fixed_worktime($wt_start, $wt_end, $worktime=null, $planned_downtim $wt = $worktime[$i]; if ($start_fixed == 1) { - // Intervals greater than 1 DAY + // Intervals greater than 1 DAY. if ($wt_end < $wt['date_from']) { // Case G: ..end..[..].. - $time_in_downtime = sla_downtime_worktime($wt_start, $wt_end, $inclusive_downtimes, $planned_downtimes); + $time_in_downtime = sla_downtime_worktime( + $wt_start, + $wt_end, + $inclusive_downtimes, + $planned_downtimes + ); if ($time_in_downtime != false) { $return['wt_in_downtime'] = 1; $return['downtime_interval'] = $time_in_downtime; @@ -5163,9 +5313,14 @@ function sla_fixed_worktime($wt_start, $wt_end, $worktime=null, $planned_downtim && ($wt_end <= $wt['date_to']) ) { // Case H: ..[..end..].. - // add last slice + // add last slice. $return['interval'] += ($wt_end - $wt['date_from']); - $time_in_downtime = sla_downtime_worktime($wt['date_from'], $wt_end, $inclusive_downtimes, $planned_downtimes); + $time_in_downtime = sla_downtime_worktime( + $wt['date_from'], + $wt_end, + $inclusive_downtimes, + $planned_downtimes + ); if ($time_in_downtime != false) { $return['wt_in_downtime'] = 1; $return['downtime_interval'] = $time_in_downtime; @@ -5179,9 +5334,14 @@ function sla_fixed_worktime($wt_start, $wt_end, $worktime=null, $planned_downtim && ($wt_end > $wt['date_to']) ) { // Case H: ..[..]..end.. - // Add current slice and continue checking + // Add current slice and continue checking. $return['interval'] += ($wt['date_to'] - $wt['date_from']); - $time_in_downtime = sla_downtime_worktime($wt['date_from'], $wt['date_to'], $inclusive_downtimes, $planned_downtimes); + $time_in_downtime = sla_downtime_worktime( + $wt['date_from'], + $wt['date_to'], + $inclusive_downtimes, + $planned_downtimes + ); if ($time_in_downtime != false) { $return['wt_in_downtime'] = 1; $return['downtime_interval'] = $time_in_downtime; @@ -5205,7 +5365,12 @@ function sla_fixed_worktime($wt_start, $wt_end, $worktime=null, $planned_downtim // Case B: ...start..[..end..]...... $return['wt_valid'] = 1; $return['interval'] = ($wt_end - $wt['date_from']); - $time_in_downtime = sla_downtime_worktime($wt['date_from'], $wt_end, $inclusive_downtimes, $planned_downtimes); + $time_in_downtime = sla_downtime_worktime( + $wt['date_from'], + $wt_end, + $inclusive_downtimes, + $planned_downtimes + ); if ($time_in_downtime != false) { $return['wt_in_downtime'] = 1; $return['downtime_interval'] = $time_in_downtime; @@ -5222,7 +5387,12 @@ function sla_fixed_worktime($wt_start, $wt_end, $worktime=null, $planned_downtim ) { // Case C: ...[..start..end..]...... $return['wt_valid'] = 1; - $time_in_downtime = sla_downtime_worktime($wt_start, $wt_end, $inclusive_downtimes, $planned_downtimes); + $time_in_downtime = sla_downtime_worktime( + $wt_start, + $wt_end, + $inclusive_downtimes, + $planned_downtimes + ); if ($time_in_downtime != false) { $return['wt_in_downtime'] = 1; $return['downtime_interval'] = $time_in_downtime; @@ -5238,7 +5408,12 @@ function sla_fixed_worktime($wt_start, $wt_end, $worktime=null, $planned_downtim ) { // Case D: ...[..start..]...end..... $return['interval'] = ($wt['date_to'] - $wt_start); - $time_in_downtime = sla_downtime_worktime($wt_start, $wt['date_to'], $inclusive_downtimes, $planned_downtimes); + $time_in_downtime = sla_downtime_worktime( + $wt_start, + $wt['date_to'], + $inclusive_downtimes, + $planned_downtimes + ); if ($time_in_downtime != false) { $return['wt_in_downtime'] = 1; $return['downtime_interval'] = $time_in_downtime; @@ -5247,10 +5422,11 @@ function sla_fixed_worktime($wt_start, $wt_end, $worktime=null, $planned_downtim $return['wt_valid'] = 1; $start_fixed = 1; - // we must check if 'end' is greater than the next valid worktime range start time - // unless is the last one + // We must check if 'end' is greater than the next valid + // worktime range start time unless is the last one. if (($i + 1) == $total) { - // if there's no more worktime ranges to check return the accumulated + // If there's no more worktime ranges + // to check return the accumulated. return $return; } } @@ -5261,7 +5437,12 @@ function sla_fixed_worktime($wt_start, $wt_end, $worktime=null, $planned_downtim // Case E: ...start...[...]...end... $return['wt_valid'] = 1; $return['interval'] = ($wt['date_to'] - $wt['date_from']); - $time_in_downtime = sla_downtime_worktime($wt['date_from'], $wt['date_to'], $inclusive_downtimes, $planned_downtimes); + $time_in_downtime = sla_downtime_worktime( + $wt['date_from'], + $wt['date_to'], + $inclusive_downtimes, + $planned_downtimes + ); if ($time_in_downtime != false) { $return['wt_in_downtime'] = 1; $return['downtime_interval'] = $time_in_downtime; @@ -5269,10 +5450,10 @@ function sla_fixed_worktime($wt_start, $wt_end, $worktime=null, $planned_downtim } if (($wt_end - $wt_start) < SECONDS_1DAY) { - // Interval is less than 1 day + // Interval is less than 1 day. return $return; } else { - // Interval greater than 1 day, split valid worktimes + // Interval greater than 1 day, split valid worktimes. $start_fixed = 1; } } @@ -5281,9 +5462,9 @@ function sla_fixed_worktime($wt_start, $wt_end, $worktime=null, $planned_downtim && ($wt_end > $wt['date_to']) ) { // Case F: ...[....]..start...end... - // Invalid, check next worktime hole + // Invalid, check next worktime hole. $return['wt_valid'] = 0; - // and remove current one + // And remove current one. $return['idx'] = ($i + 1); } } @@ -5298,19 +5479,19 @@ function sla_fixed_worktime($wt_start, $wt_end, $worktime=null, $planned_downtim /** * Advanced SLA result with summary * - * @param integer $id_agent_module id_agent_module - * @param integer $time_from Time start - * @param integer $time_to time end - * @param integer $min_value minimum value for OK status - * @param integer $max_value maximum value for OK status - * @param integer $inverse_interval inverse interval (range) for OK status - * @param hash $daysWeek Days of active work times (M-T-W-T-V-S-S) - * @param integer $timeFrom Start of work time, in each day - * @param integer $timeTo End of work time, in each day - * @param integer $slices Number of reports (time division) - * @param integer $inclusive_downtimes In downtime as OK (1) or ignored (0) + * @param integer $id_agent_module Id_agent_module. + * @param integer $time_from Time start. + * @param integer $time_to Time end. + * @param integer $min_value Minimum value for OK status. + * @param integer $max_value Maximum value for OK status. + * @param integer $inverse_interval Inverse interval (range) for OK status. + * @param array $daysWeek Days of active work times (M-T-W-T-V-S-S). + * @param integer $timeFrom Start of work time, in each day. + * @param integer $timeTo End of work time, in each day. + * @param integer $slices Number of reports (time division). + * @param integer $inclusive_downtimes In downtime as OK (1) or ignored (0). * - * @return array Returns a hash with the calculated data + * @return array Returns a hash with the calculated data. */ function reporting_advanced_sla( $id_agent_module, @@ -5326,9 +5507,8 @@ function reporting_advanced_sla( $inclusive_downtimes=1 ) { // In content: - // - // [time_from, time_to] => Worktime - // week's days => flags to manage workdays + // Example: [time_from, time_to] => Worktime + // week's days => flags to manage workdays. if (!isset($id_agent_module)) { return false; } @@ -5338,13 +5518,13 @@ function reporting_advanced_sla( } if ((!isset($min_value)) && (!isset($max_value))) { - // Infer availability range based on the critical thresholds + // Infer availability range based on the critical thresholds. $agentmodule_info = modules_get_agentmodule($id_agent_module); - // take in mind: the "inverse" critical threshold + // Take in mind: the "inverse" critical threshold. $min_value = $agentmodule_info['min_critical']; $max_value = $agentmodule_info['max_critical']; - $inverse_interval = $agentmodule_info['critical_inverse'] == 0 ? 1 : 0; + $inverse_interval = ($agentmodule_info['critical_inverse'] == 0) ? 1 : 0; if ((!isset($min_value)) || ($min_value == 0)) { $min_value = null; @@ -5361,31 +5541,34 @@ function reporting_advanced_sla( if ((!isset($min_value)) && (!isset($max_value))) { if (($agentmodule_info['id_tipo_modulo'] == '2') - // generic_proc + // Generic_proc. || ($agentmodule_info['id_tipo_modulo'] == '6') - // remote_icmp_proc + // Remote_icmp_proc. || ($agentmodule_info['id_tipo_modulo'] == '9') - // remote_tcp_proc + // Remote_tcp_proc. || ($agentmodule_info['id_tipo_modulo'] == '18') - // remote_snmp_proc + // Remote_snmp_proc. || ($agentmodule_info['id_tipo_modulo'] == '21') - // async_proc + // Async_proc. || ($agentmodule_info['id_tipo_modulo'] == '31') ) { - // web_proc - // Boolean values are OK if they're different from 0 + // Web_proc + // boolean values are OK if they're different from 0. $max_value = 0; $min_value = 0; $inverse_interval = 1; + } else if ($agentmodule_info['id_tipo_modulo'] == '100') { + $max_value = 0.9; + $min_value = 0; } } } - // By default show last day + // By default show last day. $datetime_to = time(); $datetime_from = ($datetime_to - SECONDS_1DAY); - // Or apply specified range + // Or apply specified range. if ((isset($time_to) && isset($time_from)) && ($time_to > $time_from)) { $datetime_to = $time_to; $datetime_from = $time_from; @@ -5399,7 +5582,11 @@ function reporting_advanced_sla( $datetime_from = $time_from; } - $uncompressed_data = db_uncompress_module_data($id_agent_module, $datetime_from, $datetime_to); + $uncompressed_data = db_uncompress_module_data( + $id_agent_module, + $datetime_from, + $datetime_to + ); if (is_array($uncompressed_data)) { $n_pools = count($uncompressed_data); @@ -5408,10 +5595,14 @@ function reporting_advanced_sla( } } - $planned_downtimes = reporting_get_planned_downtimes_intervals($id_agent_module, $datetime_from, $datetime_to); + $planned_downtimes = reporting_get_planned_downtimes_intervals( + $id_agent_module, + $datetime_from, + $datetime_to + ); if ((is_array($planned_downtimes)) && (count($planned_downtimes) > 0)) { - // Sort retrieved planned downtimes + // Sort retrieved planned downtimes. usort( $planned_downtimes, function ($a, $b) { @@ -5421,16 +5612,16 @@ function reporting_advanced_sla( return 0; } - return ($a < $b) ? -1 : 1; + return ($a < $b) ? (-1) : 1; } ); - // Compress (overlapped) planned downtimes + // Compress (overlapped) planned downtimes. $npd = count($planned_downtimes); for ($i = 0; $i < $npd; $i++) { if (isset($planned_downtimes[($i + 1)])) { if ($planned_downtimes[$i]['date_to'] >= $planned_downtimes[($i + 1)]['date_from']) { - // merge + // Merge. $planned_downtimes[$i]['date_to'] = $planned_downtimes[($i + 1)]['date_to']; array_splice($planned_downtimes, ($i + 1), 1); $npd--; @@ -5449,9 +5640,8 @@ function reporting_advanced_sla( // data // array // utimestamp - // datos - // - // Build exceptions + // datos. + // Build exceptions. $worktime = null; if (((isset($daysWeek)) @@ -5462,22 +5652,22 @@ function reporting_advanced_sla( $n = 0; if (!isset($daysWeek)) { - // init + // Init. $daysWeek = [ '1' => 1, - // sunday" + // Sunday. '2' => 1, - // monday + // Monday. '3' => 1, - // tuesday + // Tuesday. '4' => 1, - // wednesday + // Wednesday. '5' => 1, - // thursday + // Thursday. '6' => 1, - // friday + // Friday. '7' => 1, - // saturday + // Saturday. ]; } @@ -5488,10 +5678,10 @@ function reporting_advanced_sla( } if (($n == count($daysWeek)) && ($timeFrom == $timeTo)) { - // Ignore custom ranges + // Ignore custom ranges. $worktime = null; } else { - // get only first day + // Get only first day. $date_start = strtotime(date('Y/m/d', $datetime_from)); $date_end = strtotime(date('Y/m/d', $datetime_to)); @@ -5512,25 +5702,31 @@ function reporting_advanced_sla( $timeTo = '00:00:00'; } - // timeFrom (seconds) + // TimeFrom (seconds). sscanf($timeFrom, '%d:%d:%d', $hours, $minutes, $seconds); $secondsFrom = ($hours * 3600 + $minutes * 60 + $seconds); - // timeTo (seconds) + // TimeTo (seconds). sscanf($timeTo, '%d:%d:%d', $hours, $minutes, $seconds); $secondsTo = ($hours * 3600 + $minutes * 60 + $seconds); - // Apply planned downtime exceptions (fix matrix) + // Apply planned downtime exceptions (fix matrix). while ($t_day <= $date_end) { if ($daysWeek[(date('w', $t_day) + 1)] == 1) { - $wt_start = strtotime(date('Y/m/d H:i:s', ($t_day + $secondsFrom))); - $wt_end = strtotime(date('Y/m/d H:i:s', ($t_day + $secondsTo))); + $wt_start = strtotime( + date('Y/m/d H:i:s', ($t_day + $secondsFrom)) + ); + $wt_end = strtotime( + date('Y/m/d H:i:s', ($t_day + $secondsTo)) + ); if ($timeFrom == $timeTo) { $wt_end += SECONDS_1DAY; } - // Check if in planned downtime if exclusive downtimes - if (($inclusive_downtimes == 0) && (is_array($planned_downtimes))) { + // Check if in planned downtime if exclusive downtimes. + if (($inclusive_downtimes == 0) + && (is_array($planned_downtimes)) + ) { $start_fixed = 0; $n_planned_downtimes = count($planned_downtimes); @@ -5539,7 +5735,8 @@ function reporting_advanced_sla( $last_pd = end($planned_downtimes); if ($wt_start > $last_pd['date_to']) { - // There's no more planned downtimes, accept remaining range + // There's no more planned downtimes, + // accept remaining range. $worktime[$i] = []; $worktime[$i]['date_from'] = $wt_start; $worktime[$i]['date_to'] = $wt_end; @@ -5549,10 +5746,10 @@ function reporting_advanced_sla( $pd = $planned_downtimes[$i_planned_downtimes]; if ($start_fixed == 1) { - // Interval greater than found planned downtime + // Interval greater than found planned downtime. if ($wt_end < $pd['date_from']) { $worktime[$i] = []; - // wt_start already fixed + // Wt_start already fixed. $worktime[$i]['date_from'] = $wt_start; $worktime[$i]['date_to'] = $wt_end; $i++; @@ -5563,7 +5760,7 @@ function reporting_advanced_sla( && ( $wt_end <= $pd['date_to'] ) ) { $worktime[$i] = []; - // wt_start already fixed + // Wt_start already fixed. $worktime[$i]['date_from'] = $wt_start; $worktime[$i]['date_to'] = $pd['date_from']; $i++; @@ -5572,13 +5769,14 @@ function reporting_advanced_sla( if ($wt_end > $pd['date_to']) { $worktime[$i] = []; - // wt_start already fixed + // Wt_start already fixed. $worktime[$i]['date_from'] = $wt_start; $worktime[$i]['date_to'] = $pd['date_from']; $i++; $start_fixed = 0; - // Search following planned downtimes, we're still on work time! + // Search following planned downtimes, + // we're still on work time!. $wt_start = $pd['date_from']; } } @@ -5586,7 +5784,7 @@ function reporting_advanced_sla( if (( $wt_start < $pd['date_from']) && ( $wt_end < $pd['date_from']) ) { - // Out of planned downtime: Add worktime + // Out of planned downtime: Add worktime. $worktime[$i] = []; $worktime[$i]['date_from'] = $wt_start; $worktime[$i]['date_to'] = $wt_end; @@ -5608,7 +5806,7 @@ function reporting_advanced_sla( if (( $wt_start >= $pd['date_from']) && ( $wt_end <= $pd['date_to']) ) { - // All worktime in downtime, ignore + // All worktime in downtime, ignore. break; } @@ -5635,8 +5833,11 @@ function reporting_advanced_sla( $start_fixed = 1; } - if (($start_fixed == 1) && (($i_planned_downtimes + 1) == $n_planned_downtimes)) { - // There's no more planned downtimes, accept remaining range + if (($start_fixed == 1) + && (($i_planned_downtimes + 1) == $n_planned_downtimes) + ) { + // There's no more planned downtimes, + // accept remaining range. $worktime[$i] = []; $worktime[$i]['date_from'] = $wt_start; $worktime[$i]['date_to'] = $wt_end; @@ -5646,7 +5847,7 @@ function reporting_advanced_sla( } } } else { - // No planned downtimes scheduled + // No planned downtimes scheduled. $worktime[$i] = []; $worktime[$i]['date_from'] = $wt_start; $worktime[$i]['date_to'] = $wt_end; @@ -5655,9 +5856,9 @@ function reporting_advanced_sla( } $t_day = strtotime(' + 1 days', $t_day); - } //end while - } //end if - } //end if + } + } + } // DEBUG // print "
    Umcompressed data debug:\n";
    @@ -5668,23 +5869,29 @@ function reporting_advanced_sla(
         // }
         // }
         // print "
    "; - // Initialization + // Initialization. $global_return = []; $wt_check['idx'] = 0; $last_pool_id = 0; $last_item_id = 0; - // Support to slices + // Support to slices. $global_datetime_from = $datetime_from; $global_datetime_to = $datetime_to; $range = (($datetime_to - $datetime_from) / $slices); - // Analysis begins + // Analysis begins. for ($count = 0; $count < $slices; $count++) { - // use strtotime based on local timezone to avoid datetime conversions - $datetime_from = strtotime(' + '.($count * $range).' seconds', $global_datetime_from); - $datetime_to = strtotime(' + '.(($count + 1) * $range).' seconds', $global_datetime_from); + // Use strtotime based on local timezone to avoid datetime conversions. + $datetime_from = strtotime( + ' + '.($count * $range).' seconds', + $global_datetime_from + ); + $datetime_to = strtotime( + ' + '.(($count + 1) * $range).' seconds', + $global_datetime_from + ); if ((!isset($datetime_from)) || ($datetime_from === false)) { $datetime_from = ($global_datetime_from + ($count * $range)); @@ -5695,7 +5902,7 @@ function reporting_advanced_sla( } $return = []; - // timing + // Timing. $time_total = 0; $time_in_ok = 0; $time_in_error = 0; @@ -5704,7 +5911,7 @@ function reporting_advanced_sla( $time_in_down = 0; $time_out = 0; - // checks + // Checks. $bad_checks = 0; $ok_checks = 0; $not_init_checks = 0; @@ -5716,7 +5923,7 @@ function reporting_advanced_sla( for ($pool_index = $last_pool_id; $pool_index < $n_pools; $pool_index++) { $pool = $uncompressed_data[$pool_index]; - // check limits + // Check limits. if (isset($uncompressed_data[($pool_index + 1)])) { $next_pool = $uncompressed_data[($pool_index + 1)]; } else { @@ -5729,36 +5936,37 @@ function reporting_advanced_sla( $pool['next_utimestamp'] = $global_datetime_to; } - // update last pool checked: avoid repetition + // Update last pool checked: avoid repetition. $last_pool_id = $pool_index; if ($datetime_from > $pool['utimestamp']) { - // Skip pool + // Skip pool. continue; } - // Test if need to acquire current pool - if ((($datetime_from <= $pool['utimestamp']) && ($datetime_to >= $pool['next_utimestamp'])) + // Test if need to acquire current pool. + if ((($datetime_from <= $pool['utimestamp']) + && ($datetime_to >= $pool['next_utimestamp'])) || ($datetime_to > $pool['utimestamp']) ) { - // Acquire pool to this slice + // Acquire pool to this slice. $nitems_in_pool = count($pool['data']); for ($i = 0; $i < $nitems_in_pool; $i++) { $current_data = $pool['data'][$i]; if (($i + 1) >= $nitems_in_pool) { - // if pool exceded, check next pool timestamp + // If pool exceded, check next pool timestamp. $next_data = $next_pool; } else { - // pool not exceded, check next item + // Pool not exceded, check next item. $next_data = $pool['data'][($i + 1)]; } if (isset($next_data['utimestamp'])) { - // check next mark time in current pool + // Check next mark time in current pool. $next_timestamp = $next_data['utimestamp']; } else { - // check last time -> datetime_to + // Check last time -> datetime_to. if (!isset($next_pool)) { $next_timestamp = $global_datetime_to; } else { @@ -5766,12 +5974,20 @@ function reporting_advanced_sla( } } - // Effective time limits for current data + // Effective time limits for current data. $wt_start = $current_data['utimestamp']; $wt_end = $next_timestamp; - // Remove time spent not in planning (and in planned downtime if needed) - $wt_check = sla_fixed_worktime($wt_start, $wt_end, $worktime, $planned_downtimes, $inclusive_downtimes, $wt_check['idx']); + // Remove time spent not in planning + // (and in planned downtime if needed). + $wt_check = sla_fixed_worktime( + $wt_start, + $wt_end, + $worktime, + $planned_downtimes, + $inclusive_downtimes, + $wt_check['idx'] + ); $time_interval = $wt_check['interval']; if (($wt_check['wt_valid'] == 1)) { @@ -5779,9 +5995,17 @@ function reporting_advanced_sla( if ($time_interval > 0) { $total_checks++; - if ((isset($current_data['datos'])) && ($current_data['datos'] !== false)) { - // not unknown nor not init values - if (sla_check_value($current_data['datos'], $min_value, $max_value, $inverse_interval)) { + if ((isset($current_data['datos'])) + && ($current_data['datos'] !== false) + ) { + // Not unknown nor not init values. + if (sla_check_value( + $current_data['datos'], + $min_value, + $max_value, + $inverse_interval + ) + ) { $ok_checks++; $time_in_ok += $time_interval; } else { @@ -5801,7 +6025,8 @@ function reporting_advanced_sla( if ($inclusive_downtimes == 1) { if ($wt_check['wt_in_downtime']) { - // Add downtime interval as OK in inclusion mode + // Add downtime interval as + // OK in inclusion mode. $total_checks++; $ok_checks++; $time_total += $wt_check['downtime_interval']; @@ -5814,24 +6039,23 @@ function reporting_advanced_sla( $time_out += $wt_check['downtime_interval']; } - // ignore worktime, is in an invalid period: + // Ignore worktime, is in an invalid period: // scheduled downtimes in exclusion mode - // not 24x7 sla's + // not 24x7 sla's. } - } //end for - } //end if - else { + } + } else { break; } - } //end for + } } else { - // If monitor in not-init status => no data to show + // If monitor in not-init status => no data to show. $time_in_not_init = ($datetime_to - $datetime_from); $time_total += $time_in_not_init; $not_init_checks++; } - // Timing + // Timing. $return['time_total'] = $time_total; $return['time_ok'] = $time_in_ok; $return['time_error'] = $time_in_error; @@ -5840,25 +6064,28 @@ function reporting_advanced_sla( $return['time_downtime'] = $time_in_down; $return['time_out'] = $time_out; - // # Checks + // Checks. $return['checks_total'] = $total_checks; $return['checks_ok'] = $ok_checks; $return['checks_error'] = $bad_checks; $return['checks_unknown'] = $unknown_checks; $return['checks_not_init'] = $not_init_checks; - // SLA + // SLA. $return['SLA'] = reporting_sla_get_compliance_from_array($return); - $return['SLA_fixed'] = sla_truncate($return['SLA'], $config['graph_precision']); + $return['SLA_fixed'] = sla_truncate( + $return['SLA'], + $config['graph_precision'] + ); - // Time ranges + // Time ranges. $return['date_from'] = $datetime_from; $return['date_to'] = $datetime_to; if ($slices > 1) { array_push($global_return, $return); } - } //end for + } if ($slices > 1) { return $global_return; @@ -6113,6 +6340,19 @@ function reporting_availability($report, $content, $date=false, $time=false) $return['resume']['avg'] = $avg; $return['resume']['max_text'] = $max_text; $return['resume']['max'] = $max; + $return['fields'] = []; + $return['fields']['total_time'] = $content['total_time']; + $return['fields']['time_failed'] = $content['time_failed']; + $return['fields']['time_in_ok_status'] = $content['time_in_ok_status']; + $return['fields']['time_in_unknown_status'] = $content['time_in_unknown_status']; + $return['fields']['time_of_not_initialized_module'] = $content['time_of_not_initialized_module']; + $return['fields']['time_of_downtime'] = $content['time_of_downtime']; + $return['fields']['total_checks'] = $content['total_checks']; + $return['fields']['checks_failed'] = $content['checks_failed']; + $return['fields']['checks_in_ok_status'] = $content['checks_in_ok_status']; + $return['fields']['unknown_checks'] = $content['unknown_checks']; + $return['fields']['agent_max_value'] = $content['agent_max_value']; + $return['fields']['agent_min_value'] = $content['agent_min_value']; return reporting_check_structure_content($return); } @@ -6794,7 +7034,6 @@ function reporting_general($report, $content) if (!is_numeric($data_res[$index])) { $return['data'][$ag_name][$mod_name] = $data_res[$index]; } else { - hd($data_res[$index], true); $return['data'][$ag_name][$mod_name] = format_for_graph($data_res[$index], 2).' '.$unit; } } @@ -7076,6 +7315,7 @@ function reporting_custom_graph( 'modules_series' => $graphs[0]['modules_series'], 'id_graph' => $id_graph, 'type_report' => $type_report, + 'labels' => $content['style']['label'], ]; $return['chart'] = graphic_combined_module( @@ -7136,6 +7376,7 @@ function reporting_simple_graph( $report, $content ); + $label = (isset($content['style']['label'])) ? $content['style']['label'] : ''; if ($label != '') { $label = reporting_label_macro($content, $label); @@ -7147,7 +7388,7 @@ function reporting_simple_graph( $return['chart'] = ''; - // Get chart + // Get chart. reporting_set_conf_charts($width, $height, $only_image, $type, $content, $ttl); if (!empty($force_width_chart)) { @@ -7287,6 +7528,21 @@ function reporting_check_structure_content($report) $report['date']['to'] = ''; } + if (!isset($report['fields'])) { + $return['fields']['total_time'] = ''; + $return['fields']['time_failed'] = ''; + $return['fields']['time_in_ok_status'] = ''; + $return['fields']['time_in_unknown_status'] = ''; + $return['fields']['time_of_not_initialized_module'] = ''; + $return['fields']['time_of_downtime'] = ''; + $return['fields']['total_checks'] = ''; + $return['fields']['checks_failed'] = ''; + $return['fields']['checks_in_ok_status'] = ''; + $return['fields']['unknown_checks'] = ''; + $return['fields']['agent_max_value'] = ''; + $return['fields']['agent_min_value'] = ''; + } + return $report; } @@ -7582,6 +7838,7 @@ function reporting_get_agents_detailed_event( 'criticity' => $e['criticity'], 'validated_by' => $e['id_usuario'], 'timestamp' => $e['timestamp_rep'], + 'id_evento' => $e['id_evento'], ]; } else { $return_data[] = [ @@ -7591,6 +7848,7 @@ function reporting_get_agents_detailed_event( 'criticity' => $e['criticity'], 'validated_by' => $e['id_usuario'], 'timestamp' => $e['timestamp'], + 'id_evento' => $e['id_evento'], ]; } } @@ -7613,11 +7871,11 @@ function reporting_get_agents_detailed_event( foreach ($events as $eventRow) { foreach ($eventRow as $k => $event) { - // First pass along the class of this row + // First pass along the class of this row. $table->cellclass[$k][1] = $table->cellclass[$k][2] = $table->cellclass[$k][4] = $table->cellclass[$k][5] = $table->cellclass[$k][6] = get_priority_class($event['criticity']); $data = []; - // Colored box + // Colored box. switch ($event['estado']) { case 0: $img_st = 'images/star.png'; @@ -9132,15 +9390,34 @@ function reporting_get_agent_module_info($id_agent) $return = []; $return['last_contact'] = 0; - // Last agent contact + // Last agent contact. $return['status'] = STATUS_AGENT_NO_DATA; - $return['status_img'] = ui_print_status_image(STATUS_AGENT_NO_DATA, __('Agent without data'), true); + $return['status_img'] = ui_print_status_image( + STATUS_AGENT_NO_DATA, + __('Agent without data'), + true + ); $return['alert_status'] = 'notfired'; $return['alert_value'] = STATUS_ALERT_NOT_FIRED; - $return['alert_img'] = ui_print_status_image(STATUS_ALERT_NOT_FIRED, __('Alert not fired'), true); - $return['agent_group'] = agents_get_agent_group($id_agent); + $return['alert_img'] = ui_print_status_image( + STATUS_ALERT_NOT_FIRED, + __('Alert not fired'), + true + ); - if (!check_acl($config['id_user'], $return['agent_group'], 'AR')) { + $return['agent_group'] = ''; + // Important agents_get_all_groups_agent check secondary groups. + $id_all_groups = agents_get_all_groups_agent($id_agent); + if (isset($id_all_groups) && is_array($id_all_groups)) { + foreach ($id_all_groups as $value) { + if (check_acl($config['id_user'], $value, 'AR')) { + $return['agent_group'] = $value; + } + } + } + + // If $return['agent_group'] is empty no access. + if ($return['agent_group'] == '') { return $return; } @@ -9153,7 +9430,7 @@ function reporting_get_agent_module_info($id_agent) $now = get_system_time(); - // Get modules status for this agent + // Get modules status for this agent. $agent = db_get_row('tagente', 'id_agente', $id_agent); $return['total_count'] = $agent['total_count']; @@ -9167,28 +9444,52 @@ function reporting_get_agent_module_info($id_agent) if ($return['total_count'] > 0) { if ($return['critical_count'] > 0) { $return['status'] = STATUS_AGENT_CRITICAL; - $return['status_img'] = ui_print_status_image(STATUS_AGENT_CRITICAL, __('At least one module in CRITICAL status'), true); + $return['status_img'] = ui_print_status_image( + STATUS_AGENT_CRITICAL, + __('At least one module in CRITICAL status'), + true + ); } else if ($return['warning_count'] > 0) { $return['status'] = STATUS_AGENT_WARNING; - $return['status_img'] = ui_print_status_image(STATUS_AGENT_WARNING, __('At least one module in WARNING status'), true); + $return['status_img'] = ui_print_status_image( + STATUS_AGENT_WARNING, + __('At least one module in WARNING status'), + true + ); } else if ($return['unknown_count'] > 0) { $return['status'] = STATUS_AGENT_DOWN; - $return['status_img'] = ui_print_status_image(STATUS_AGENT_DOWN, __('At least one module is in UKNOWN status'), true); + $return['status_img'] = ui_print_status_image( + STATUS_AGENT_DOWN, + __('At least one module is in UKNOWN status'), + true + ); } else { $return['status'] = STATUS_AGENT_OK; - $return['status_img'] = ui_print_status_image(STATUS_AGENT_OK, __('All Monitors OK'), true); + $return['status_img'] = ui_print_status_image( + STATUS_AGENT_OK, + __('All Monitors OK'), + true + ); } } - // Alert not fired is by default + // Alert not fired is by default. if ($return['fired_count'] > 0) { $return['alert_status'] = 'fired'; - $return['alert_img'] = ui_print_status_image(STATUS_ALERT_FIRED, __('Alert fired'), true); + $return['alert_img'] = ui_print_status_image( + STATUS_ALERT_FIRED, + __('Alert fired'), + true + ); $return['alert_value'] = STATUS_ALERT_FIRED; } else if (groups_give_disabled_group($return['agent_group'])) { $return['alert_status'] = 'disabled'; $return['alert_value'] = STATUS_ALERT_DISABLED; - $return['alert_img'] = ui_print_status_image(STATUS_ALERT_DISABLED, __('Alert disabled'), true); + $return['alert_img'] = ui_print_status_image( + STATUS_ALERT_DISABLED, + __('Alert disabled'), + true + ); } return $return; @@ -9198,13 +9499,23 @@ function reporting_get_agent_module_info($id_agent) /** * Print tiny statistics of the status of one agent, group, etc. * - * @param mixed Array with the counts of the total modules, normal modules, critical modules, warning modules, unknown modules and fired alerts - * @param bool return or echo flag + * @param mixed $counts_info Array with the counts of the total modules, + * normal modules, critical modules, warning modules, unknown modules and + * fired alerts. + * @param boolean $return Return or echo flag. + * @param string $type agent or modules or ??. + * @param string $separator Sepearator (classic view). + * @param boolean $modern Use modern interfaces or old one. * - * @return string html formatted tiny stats of modules/alerts of an agent + * @return string HTML formatted tiny stats of modules/alerts of an agent. */ -function reporting_tiny_stats($counts_info, $return=false, $type='agent', $separator=':', $strict_user=false) -{ +function reporting_tiny_stats( + $counts_info, + $return=false, + $type='agent', + $separator=':', + $modern=false +) { global $config; $out = ''; @@ -9321,37 +9632,74 @@ function reporting_tiny_stats($counts_info, $return=false, $type='agent', $separ $out .= html_print_div($params, true); } - // If total count is less than 0, is an error. Never show negative numbers + // If total count is less than 0, is an error. Never show negative numbers. if ($total_count < 0) { $total_count = 0; } - $out .= ''.''.$total_count.''; - if (isset($fired_count) && $fired_count > 0) { - $out .= ' '.$separator.' '.$fired_count.''; - } + if ($modern === true) { + $out .= '
    '; + // $out .=''.$total_count.$separator.''; + if (isset($fired_count) && $fired_count > 0) { + $out .= '
    '; + $out .= ''.$fired_count.'
    '; + } - if (isset($critical_count) && $critical_count > 0) { - $out .= ' '.$separator.' '.$critical_count.''; - } + if (isset($critical_count) && $critical_count > 0) { + $out .= '
    '; + $out .= ''.$critical_count.'
    '; + } - if (isset($warning_count) && $warning_count > 0) { - $out .= ' '.$separator.' '.$warning_count.''; - } + if (isset($warning_count) && $warning_count > 0) { + $out .= '
    '; + $out .= ''.$warning_count.'
    '; + } - if (isset($unknown_count) && $unknown_count > 0) { - $out .= ' '.$separator.' '.$unknown_count.''; - } + if (isset($unknown_count) && $unknown_count > 0) { + $out .= '
    '; + $out .= ''.$unknown_count.'
    '; + } - if (isset($not_init_count) && $not_init_count > 0) { - $out .= ' '.$separator.' '.$not_init_count.''; - } + if (isset($not_init_count) && $not_init_count > 0) { + $out .= '
    '; + $out .= ''.$not_init_count.'
    '; + } - if (isset($normal_count) && $normal_count > 0) { - $out .= ' '.$separator.' '.$normal_count.''; - } + if (isset($normal_count) && $normal_count > 0) { + $out .= '
    '; + $out .= ''.$normal_count.'
    '; + } - $out .= '
    '; + $out .= '
    '; + } else { + // Classic ones. + $out .= ''.$total_count.''; + if (isset($fired_count) && $fired_count > 0) { + $out .= ' '.$separator.' '.$fired_count.''; + } + + if (isset($critical_count) && $critical_count > 0) { + $out .= ' '.$separator.' '.$critical_count.''; + } + + if (isset($warning_count) && $warning_count > 0) { + $out .= ' '.$separator.' '.$warning_count.''; + } + + if (isset($unknown_count) && $unknown_count > 0) { + $out .= ' '.$separator.' '.$unknown_count.''; + } + + if (isset($not_init_count) && $not_init_count > 0) { + $out .= ' '.$separator.' '.$not_init_count.''; + } + + if (isset($normal_count) && $normal_count > 0) { + $out .= ' '.$separator.' '.$normal_count.''; + } + + $out .= ''; + } if ($return) { return $out; @@ -11284,33 +11632,95 @@ function reporting_sla_is_ignored_from_array($sla_array) * * @return integer Status */ -function reporting_sla_get_status_period($sla_times, $priority_mode=REPORT_PRIORITY_MODE_OK) -{ - if ($sla_times['time_error'] > 0) { +function reporting_sla_get_status_period( + $sla, + $priority_mode=REPORT_PRIORITY_MODE_OK +) { + if ($sla['time_error'] > 0) { return REPORT_STATUS_ERR; } - if ($priority_mode == REPORT_PRIORITY_MODE_OK && $sla_times['time_ok'] > 0) { + if ($priority_mode == REPORT_PRIORITY_MODE_OK && $sla['time_ok'] > 0) { return REPORT_STATUS_OK; } - if ($sla_times['time_out'] > 0) { + if ($sla['time_out'] > 0) { return REPORT_STATUS_IGNORED; } - if ($sla_times['time_downtime'] > 0) { + if ($sla['time_downtime'] > 0) { return REPORT_STATUS_DOWNTIME; } - if ($sla_times['time_unknown'] > 0) { + if ($sla['time_unknown'] > 0) { return REPORT_STATUS_UNKNOWN; } - if ($sla_times['time_not_init'] > 0) { + if ($sla['time_not_init'] > 0) { return REPORT_STATUS_NOT_INIT; } - if ($sla_times['time_ok'] > 0) { + if ($sla['time_ok'] > 0) { + return REPORT_STATUS_OK; + } + + return REPORT_STATUS_IGNORED; +} + + +/** + * @brief Given a period, get the SLA status + * of the period compare with sla_limit. + * + * @param Array An array with all times to calculate the SLA. + * @param int Limit SLA pass for user. + * Only used for monthly, weekly And hourly report. + * + * @return integer Status + */ +function reporting_sla_get_status_period_compliance( + $sla, + $sla_limit +) { + global $config; + + $time_compliance = ( + $sla['time_ok'] + $sla['time_unknown'] + $sla['time_downtime'] + ); + + $time_total_working = ( + $time_compliance + $sla['time_error'] + ); + + $time_compliance = ($time_compliance == 0) ? 0 : (($time_compliance / $time_total_working) * 100); + + if ($sla['time_error'] > 0 && ($time_compliance < $sla_limit)) { + return REPORT_STATUS_ERR; + } + + if ($priority_mode == REPORT_PRIORITY_MODE_OK + && $sla['time_ok'] > 0 && ($time_compliance >= $sla_limit) + ) { + return REPORT_STATUS_OK; + } + + if ($sla['time_out'] > 0 && ($time_compliance < $sla_limit)) { + return REPORT_STATUS_IGNORED; + } + + if ($sla['time_downtime'] > 0 && ($time_compliance < $sla_limit)) { + return REPORT_STATUS_DOWNTIME; + } + + if ($sla['time_unknown'] > 0 && ($time_compliance < $sla_limit)) { + return REPORT_STATUS_UNKNOWN; + } + + if ($sla['time_not_init'] > 0 && ($time_compliance < $sla_limit)) { + return REPORT_STATUS_NOT_INIT; + } + + if ($sla['time_ok'] > 0 && ($time_compliance >= $sla_limit)) { return REPORT_STATUS_OK; } @@ -11336,3 +11746,62 @@ function reporting_translate_sla_status_for_graph($status) ]; return $sts[$status]; } + + +/** + * Print header to report pdf and add page break + * + * @param string $title Title of report. + * @param string $description Description of report. + * + * @return html Return table of header. + */ +function reporting_header_table_for_pdf($title='', $description='') +{ + $result_pdf .= ''; + $result_pdf .= ''; + $result_pdf .= ''; + $result_pdf .= '
    '; + $result_pdf .= $title; + $result_pdf .= ''; + $result_pdf .= '
    '; + $result_pdf .= $description; + $result_pdf .= '
    '; + + return $result_pdf; +} + + +/** + * Build the required data to build network traffic top N report + * + * @param int Period (time window). + * @param array Information about the item of report. + * @param bool Pdf or not + * + * @return array With report presentation info and report data. + */ +function reporting_nt_top_n_report($period, $content, $pdf) +{ + $return = []; + $return['type'] = 'nt_top_n'; + $return['title'] = $content['name']; + $return['description'] = $content['description']; + + // Get the data sent and received + $return['data'] = []; + $start_time = ($period['datetime'] - (int) $content['period']); + $return['data']['send'] = network_matrix_get_top( + $content['top_n_value'], + true, + $start_time, + $period['datetime'] + ); + $return['data']['recv'] = network_matrix_get_top( + $content['top_n_value'], + false, + $start_time, + $period['datetime'] + ); + return $return; +} diff --git a/pandora_console/include/functions_reporting_html.php b/pandora_console/include/functions_reporting_html.php index 54f81e32bc..10bef8631f 100644 --- a/pandora_console/include/functions_reporting_html.php +++ b/pandora_console/include/functions_reporting_html.php @@ -1,25 +1,32 @@ '.' - - - - - '; + $html = '
    '.__('Generated').': '.$date_today.'
    '.__('Report date').':
    + + + + + '; if (isset($report['period'])) { if (is_numeric($report['datetime']) && is_numeric($report['period'])) { $html .= ''; @@ -119,10 +126,10 @@ function html_do_report_info($report) } $html .= ' - - - -
    '.__('Generated').': '.$date_today.'
    '.__('Report date').': '.date($config['date_format'], ($report['datetime'] - $report['period'])).'
    '.__('Description').': '.io_safe_output($report['description']).'
    '.'
    '; + + '.__('Description').': '.io_safe_output($report['description']).' + + '.''; echo $html; } @@ -153,8 +160,6 @@ function reporting_html_print_report($report, $mini=false, $report_info=1) $label = ''; } - // $aux = explode("-",$item['subtitle']); - // $item['subtitle'] = db_get_value ("alias","tagente","nombre",$item['agent_name']) .' -'. $aux[1]; reporting_html_header( $table, $mini, @@ -177,6 +182,7 @@ function reporting_html_print_report($report, $mini=false, $report_info=1) switch ($item['type']) { case 'availability': + default: reporting_html_availability($table, $item); break; @@ -265,21 +271,7 @@ function reporting_html_print_report($report, $mini=false, $report_info=1) break; case 'netflow_area': - reporting_html_graph($table, $item); - break; - - case 'netflow_pie': - reporting_html_graph($table, $item); - break; - case 'netflow_data': - reporting_html_graph($table, $item); - break; - - case 'netflow_statistics': - reporting_html_graph($table, $item); - break; - case 'netflow_summary': reporting_html_graph($table, $item); break; @@ -289,13 +281,7 @@ function reporting_html_print_report($report, $mini=false, $report_info=1) break; case 'sql_graph_vbar': - reporting_html_sql_graph($table, $item); - break; - case 'sql_graph_hbar': - reporting_html_sql_graph($table, $item); - break; - case 'sql_graph_pie': reporting_html_sql_graph($table, $item); break; @@ -367,6 +353,10 @@ function reporting_html_print_report($report, $mini=false, $report_info=1) reporting_enterprise_html_SLA_monthly($table, $item, $mini); break; + case 'nt_top_n': + reporting_html_nt_top_n($table, $item, $mini); + break; + case 'SLA_weekly': reporting_enterprise_html_SLA_weekly($table, $item, $mini); break; @@ -380,7 +370,11 @@ function reporting_html_print_report($report, $mini=false, $report_info=1) break; case 'module_histogram_graph': - reporting_enterprise_html_module_histogram_graph($table, $item, $mini); + reporting_enterprise_html_module_histogram_graph( + $table, + $item, + $mini + ); break; } @@ -397,9 +391,27 @@ function reporting_html_print_report($report, $mini=false, $report_info=1) } -function reporting_html_SLA($table, $item, $mini) +/** + * Function to print to HTML SLA report. + * + * @param object $table Head table or false if it comes from pdf. + * @param array $item Items data. + * @param boolean $mini If true or false letter mini. + * @param boolean $pdf If it comes from pdf. + * + * @return html + */ +function reporting_html_SLA($table, $item, $mini, $pdf=0) { - $style = db_get_value('style', 'treport_content', 'id_rc', $item['id_rc']); + $return_pdf = ''; + + $style = db_get_value( + 'style', + 'treport_content', + 'id_rc', + $item['id_rc'] + ); + $style = json_decode(io_safe_output($style), true); $same_agent_in_resume = ''; @@ -423,7 +435,9 @@ function reporting_html_SLA($table, $item, $mini) $table->data['sla']['cell'] = $item['failed']; } else { if (!empty($item['planned_downtimes'])) { - $downtimes_table = reporting_html_planned_downtimes_table($item['planned_downtimes']); + $downtimes_table = reporting_html_planned_downtimes_table( + $item['planned_downtimes'] + ); if (!empty($downtimes_table)) { $table->colspan['planned_downtime']['cell'] = 3; @@ -459,7 +473,12 @@ function reporting_html_SLA($table, $item, $mini) $table1->headstyle[4] = 'text-align: right'; $table1->headstyle[5] = 'text-align: right'; - // second_table for time globals + $table1->style = []; + $table1->style[0] = 'page-break-before: always;'; + + $table1->rowstyle = []; + + // Second_table for time globals. $table2 = new stdClass(); $table2->width = '99%'; @@ -490,7 +509,7 @@ function reporting_html_SLA($table, $item, $mini) $table2->headstyle[5] = 'text-align: right'; $table2->headstyle[6] = 'text-align: right'; - // third_table for time globals + // Third_table for time globals. $table3 = new stdClass(); $table3->width = '99%'; @@ -520,15 +539,19 @@ function reporting_html_SLA($table, $item, $mini) foreach ($item['data'] as $sla) { if (isset($sla)) { - $the_first_men_time = get_agent_first_time(io_safe_output($sla['agent'])); - - // first_table + // First_table. $row = []; $row[] = $sla['agent']; $row[] = $sla['module']; if (is_numeric($sla['dinamic_text'])) { - $row[] = sla_truncate($sla['max'], $config['graph_precision']).' / '.sla_truncate($sla['min'], $config['graph_precision']); + $row[] = sla_truncate( + $sla['max'], + $config['graph_precision'] + ).' / '.sla_truncate( + $sla['min'], + $config['graph_precision'] + ); } else { $row[] = $sla['dinamic_text']; } @@ -541,56 +564,73 @@ function reporting_html_SLA($table, $item, $mini) } else if (reporting_sla_is_ignored_from_array($sla)) { $row[] = ''.__('N/A').''; $row[] = ''.__('No data').''; - // Normal calculation + // Normal calculation. } else if ($sla['sla_status']) { - $row[] = ''.sla_truncate($sla['sla_value'], $config['graph_precision']).'%'.''; + $row[] = ''.sla_truncate($sla['sla_value'], $config['graph_precision']).'%'; $row[] = ''.__('OK').''; } else { - $row[] = ''.sla_truncate($sla['sla_value'], $config['graph_precision']).'%'.''; + $row[] = ''.sla_truncate($sla['sla_value'], $config['graph_precision']).'%'; $row[] = ''.__('Fail').''; } - // second table for time globals + // Second table for time globals. $row2 = []; $row2[] = $sla['agent'].' -- ['.$sla['module'].']'; if ($sla['time_total'] != 0) { - $row2[] = human_time_description_raw($sla['time_total']); + $row2[] = human_time_description_raw( + $sla['time_total'] + ); } else { $row2[] = '--'; } if ($sla['time_error'] != 0) { - $row2[] = ''.human_time_description_raw($sla['time_error'], true).''; + $row2[] = ''.human_time_description_raw( + $sla['time_error'], + true + ).''; } else { $row2[] = '--'; } if ($sla['time_ok'] != 0) { - $row2[] = ''.human_time_description_raw($sla['time_ok'], true).''; + $row2[] = ''.human_time_description_raw( + $sla['time_ok'], + true + ).''; } else { $row2[] = '--'; } if ($sla['time_unknown'] != 0) { - $row2[] = ''.human_time_description_raw($sla['time_unknown'], true).''; + $row2[] = ''.human_time_description_raw( + $sla['time_unknown'], + true + ).''; } else { $row2[] = '--'; } if ($sla['time_not_init'] != 0) { - $row2[] = ''.human_time_description_raw($sla['time_not_init'], true).''; + $row2[] = ''.human_time_description_raw( + $sla['time_not_init'], + true + ).''; } else { $row2[] = '--'; } if ($sla['time_downtime'] != 0) { - $row2[] = ''.human_time_description_raw($sla['time_downtime'], true).''; + $row2[] = ''.human_time_description_raw( + $sla['time_downtime'], + true + ).''; } else { $row2[] = '--'; } - // third table for checks globals + // Third table for checks globals. $row3 = []; $row3[] = $sla['agent'].' -- ['.$sla['module'].']'; $row3[] = $sla['checks_total']; @@ -598,18 +638,52 @@ function reporting_html_SLA($table, $item, $mini) $row3[] = ''.$sla['checks_ok'].''; $row3[] = ''.$sla['checks_unknown'].''; + $table1->rowstyle[] = 'page-break-before: always;'; $table1->data[] = $row; $table2->data[] = $row2; $table3->data[] = $row3; } } - $table->colspan['sla']['cell'] = 2; - $table->data['sla']['cell'] = html_print_table($table1, true); - $table->colspan['time_global']['cell'] = 2; - $table->data['time_global']['cell'] = html_print_table($table2, true); - $table->colspan['checks_global']['cell'] = 2; - $table->data['checks_global']['cell'] = html_print_table($table3, true); + if ($pdf === 0) { + $table->colspan['sla']['cell'] = 2; + $table->data['sla']['cell'] = html_print_table( + $table1, + true + ); + $table->colspan['time_global']['cell'] = 2; + $table->data['time_global']['cell'] = html_print_table( + $table2, + true + ); + $table->colspan['checks_global']['cell'] = 2; + $table->data['checks_global']['cell'] = html_print_table( + $table3, + true + ); + } else { + $table1->title = $item['title']; + $table1->titleclass = 'title_table_pdf'; + $table1->titlestyle = 'text-align:left;'; + $return_pdf .= html_print_table( + $table1, + true + ); + $table2->title = $item['title']; + $table2->titleclass = 'title_table_pdf'; + $table2->titlestyle = 'text-align:left;'; + $return_pdf .= html_print_table( + $table2, + true + ); + $table3->title = $item['title']; + $table3->titleclass = 'title_table_pdf'; + $table3->titlestyle = 'text-align:left;'; + $return_pdf .= html_print_table( + $table3, + true + ); + } } else { $table->colspan['error']['cell'] = 3; $table->data['error']['cell'] = __('There are no Agent/Modules defined'); @@ -630,10 +704,23 @@ function reporting_html_SLA($table, $item, $mini) ]; } - $table->colspan['charts']['cell'] = 2; - $table->data['charts']['cell'] = html_print_table($table1, true); + if ($pdf === 0) { + $table->colspan['charts']['cell'] = 2; + $table->data['charts']['cell'] = html_print_table( + $table1, + true + ); + } else { + $table1->title = $item['title']; + $table1->titleclass = 'title_table_pdf'; + $table1->titlestyle = 'text-align:left;'; + $return_pdf .= html_print_table( + $table1, + true + ); + } - // table_legend_graphs; + // Table_legend_graphs. $table1 = new stdClass(); $table1->width = '99%'; $table1->data = []; @@ -668,18 +755,46 @@ function reporting_html_SLA($table, $item, $mini) $table1->size[11] = '15%'; $table1->data[0][11] = ''.__('Ignore time').''; - $table->colspan['legend']['cell'] = 2; - $table->data['legend']['cell'] = html_print_table($table1, true); + if ($pdf === 0) { + $table->colspan['legend']['cell'] = 2; + $table->data['legend']['cell'] = html_print_table( + $table1, + true + ); + } else { + $return_pdf .= html_print_table( + $table1, + true + ); + } } } + + if ($pdf !== 0) { + return $return_pdf; + } } -function reporting_html_top_n($table, $item) +/** + * Function to print html report top N. + * + * @param object $table Head table or false if it comes from pdf. + * @param array $item Items data. + * @param boolean $pdf If it comes from pdf. + * + * @return html + */ +function reporting_html_top_n($table, $item, $pdf=0) { + $return_pdf = ''; if (!empty($item['failed'])) { - $table->colspan['top_n']['cell'] = 3; - $table->data['top_n']['cell'] = $item['failed']; + if ($pdf !== 0) { + $return_pdf .= $item['failed']; + } else { + $table->colspan['top_n']['cell'] = 3; + $table->data['top_n']['cell'] = $item['failed']; + } } else { $table1 = new stdClass(); $table1->width = '99%'; @@ -710,16 +825,31 @@ function reporting_html_top_n($table, $item) } $table->colspan['top_n']['cell'] = 3; - $table->data['top_n']['cell'] = html_print_table($table1, true); + if ($pdf !== 0) { + $table1->title = $item['title']; + $table1->titleclass = 'title_table_pdf'; + $table1->titlestyle = 'text-align:left;'; + $return_pdf .= html_print_table($table1, true); + } else { + $table->data['top_n']['cell'] = html_print_table($table1, true); + } if (!empty($item['charts']['pie'])) { - $table->colspan['char_pie']['cell'] = 3; - $table->data['char_pie']['cell'] = $item['charts']['pie']; + if ($pdf !== 0) { + $return_pdf .= $item['charts']['pie']; + } else { + $table->colspan['char_pie']['cell'] = 3; + $table->data['char_pie']['cell'] = $item['charts']['pie']; + } } if (!empty($item['charts']['bars'])) { - $table->colspan['char_bars']['cell'] = 3; - $table->data['char_bars']['cell'] = $item['charts']['bars']; + if ($pdf !== 0) { + $return_pdf .= $item['charts']['bars']; + } else { + $table->colspan['char_bars']['cell'] = 3; + $table->data['char_bars']['cell'] = $item['charts']['bars']; + } } if (!empty($item['resume'])) { @@ -749,16 +879,30 @@ function reporting_html_top_n($table, $item) $row[] = $item['resume']['max']['formated_value']; $table1->data[] = $row; - $table->colspan['resume']['cell'] = 3; - $table->data['resume']['cell'] = html_print_table($table1, true); + if ($pdf !== 0) { + $table1->title = $item['title']; + $table1->titleclass = 'title_table_pdf'; + $table1->titlestyle = 'text-align:left;'; + $return_pdf .= html_print_table($table1, true); + } else { + $table->colspan['resume']['cell'] = 3; + $table->data['resume']['cell'] = html_print_table($table1, true); + } } } + + if ($pdf !== 0) { + return $return_pdf; + } } function reporting_html_event_report_group($table, $item, $pdf=0) { global $config; + + $show_extended_events = $item['show_extended_events']; + if ($item['total_events']) { $table1 = new stdClass(); $table1->width = '99%'; @@ -794,7 +938,7 @@ function reporting_html_event_report_group($table, $item, $pdf=0) } foreach ($item['data'] as $k => $event) { - // First pass along the class of this row + // First pass along the class of this row. if ($item['show_summary_group']) { $table1->cellclass[$k][1] = $table1->cellclass[$k][2] = $table1->cellclass[$k][4] = $table1->cellclass[$k][5] = $table1->cellclass[$k][6] = $table1->cellclass[$k][7] = get_priority_class($event['criticity']); } else { @@ -803,7 +947,7 @@ function reporting_html_event_report_group($table, $item, $pdf=0) $data = []; - // Colored box + // Colored box. switch ($event['estado']) { case 0: $img_st = 'images/star.png'; @@ -866,16 +1010,25 @@ function reporting_html_event_report_group($table, $item, $pdf=0) } array_push($table1->data, $data); + + if ($show_extended_events == 1 && events_has_extended_info($event['id_evento'])) { + $extended_events = events_get_extended_events($event['id_evento']); + + foreach ($extended_events as $extended_event) { + $extended_data = []; + + $extended_data[] = "".io_safe_output($extended_event['description'])."".date($config['date_format'], $extended_event['utimestamp']).''; + array_push($table1->data, $extended_data); + } + } } if ($pdf) { $table0 = new stdClass(); $table0->width = '99%'; - $table0->class = 'table-beauty'; $table0->data['count_row']['count'] = 'Total events: '.$item['total_events']; $pdf_export = html_print_table($table0, true); - $table1->class = 'table-beauty'; $pdf_export .= html_print_table($table1, true); $pdf_export .= '
    '; } else { @@ -891,7 +1044,6 @@ function reporting_html_event_report_group($table, $item, $pdf=0) $table1->data[0][0] = $item['chart']['by_agent']; if ($pdf) { - $table1->class = 'table-beauty'; $pdf_export .= html_print_table($table1, true); $pdf_export .= '
    '; } else { @@ -909,7 +1061,6 @@ function reporting_html_event_report_group($table, $item, $pdf=0) $table1->data[0][0] = $item['chart']['by_user_validator']; if ($pdf) { - $table1->class = 'table-beauty'; $pdf_export .= html_print_table($table1, true); $pdf_export .= '
    '; } else { @@ -927,7 +1078,6 @@ function reporting_html_event_report_group($table, $item, $pdf=0) $table1->data[0][0] = $item['chart']['by_criticity']; if ($pdf) { - $table1->class = 'table-beauty'; $pdf_export .= html_print_table($table1, true); $pdf_export .= '
    '; } else { @@ -945,7 +1095,6 @@ function reporting_html_event_report_group($table, $item, $pdf=0) $table1->data[0][0] = $item['chart']['validated_vs_unvalidated']; if ($pdf) { - $table1->class = 'table-beauty'; $pdf_export .= html_print_table($table1, true); $pdf_export .= '
    '; } else { @@ -962,7 +1111,6 @@ function reporting_html_event_report_group($table, $item, $pdf=0) if ($pdf) { $table0 = new stdClass(); $table0->width = '99%'; - $table0->class = 'table-beauty'; $table0->data['count_row']['count'] = 'Total events: '.$item['total_events']; $pdf_export = html_print_table($table0, true); @@ -975,6 +1123,9 @@ function reporting_html_event_report_group($table, $item, $pdf=0) function reporting_html_event_report_module($table, $item, $pdf=0) { global $config; + + $show_extended_events = $item['show_extended_events']; + $show_summary_group = $item['show_summary_group']; if ($item['total_events']) { if (!empty($item['failed'])) { @@ -1018,9 +1169,10 @@ function reporting_html_event_report_module($table, $item, $pdf=0) $table1->cellclass[$i][1] = $table1->cellclass[$i][3] = $table1->cellclass[$i][4] = get_priority_class($event['criticity']); } - // Colored box + // Colored box. switch ($event['estado']) { case 0: + default: $img_st = 'images/star.png'; $title_st = __('New event'); break; @@ -1057,17 +1209,26 @@ function reporting_html_event_report_module($table, $item, $pdf=0) } $table1->data[] = $data; + + if ($show_extended_events == 1 && events_has_extended_info($event['id_evento'])) { + $extended_events = events_get_extended_events($event['id_evento']); + + foreach ($extended_events as $extended_event) { + $extended_data = []; + + $extended_data[] = "".io_safe_output($extended_event['description'])."".date($config['date_format'], $extended_event['utimestamp']).''; + array_push($table1->data, $extended_data); + } + } } } if ($pdf) { $table0 = new stdClass(); $table0->width = '99%'; - $table0->class = 'table-beauty'; $table0->data['count_row']['count'] = 'Total events: '.$item['total_events']; $pdf_export = html_print_table($table0, true); - $table1->class = 'table-beauty'; $pdf_export .= html_print_table($table1, true); $pdf_export .= '
    '; } else { @@ -1083,7 +1244,6 @@ function reporting_html_event_report_module($table, $item, $pdf=0) $table1->data[0][0] = $item['chart']['by_agent']; if ($pdf) { - $table1->class = 'table-beauty'; $pdf_export .= html_print_table($table1, true); $pdf_export .= '
    '; } else { @@ -1101,7 +1261,6 @@ function reporting_html_event_report_module($table, $item, $pdf=0) $table1->data[0][0] = $item['chart']['by_user_validator']; if ($pdf) { - $table1->class = 'table-beauty'; $pdf_export .= html_print_table($table1, true); $pdf_export .= '
    '; } else { @@ -1119,7 +1278,6 @@ function reporting_html_event_report_module($table, $item, $pdf=0) $table1->data[0][0] = $item['chart']['by_criticity']; if ($pdf) { - $table1->class = 'table-beauty'; $pdf_export .= html_print_table($table1, true); $pdf_export .= '
    '; } else { @@ -1137,7 +1295,6 @@ function reporting_html_event_report_module($table, $item, $pdf=0) $table1->data[0][0] = $item['chart']['validated_vs_unvalidated']; if ($pdf) { - $table1->class = 'table-beauty'; $pdf_export .= html_print_table($table1, true); $pdf_export .= '
    '; } else { @@ -1156,7 +1313,6 @@ function reporting_html_event_report_module($table, $item, $pdf=0) if ($pdf) { $table0 = new stdClass(); $table0->width = '99%'; - $table0->class = 'table-beauty'; $table0->data['count_row']['count'] = 'Total events: '.$item['total_events']; $pdf_export = html_print_table($table0, true); @@ -1166,18 +1322,34 @@ function reporting_html_event_report_module($table, $item, $pdf=0) } -function reporting_html_inventory_changes($table, $item) +/** + * Print in html inventory changes reports + * + * @param object $table Head table or false if it comes from pdf. + * @param array $item Items data. + * @param boolean $pdf Print pdf true or false. + * + * @return html + */ +function reporting_html_inventory_changes($table, $item, $pdf=0) { + $return_pdf = ''; if (!empty($item['failed'])) { - $table->colspan['failed']['cell'] = 3; - $table->cellstyle['failed']['cell'] = 'text-align: center;'; - $table->data['failed']['cell'] = $item['failed']; + if ($pdf === 0) { + $table->colspan['failed']['cell'] = 3; + $table->cellstyle['failed']['cell'] = 'text-align: center;'; + $table->data['failed']['cell'] = $item['failed']; + } else { + $return_pdf .= $item['failed']; + } } else { foreach ($item['data'] as $module_item) { - $table1 = null; + $table1 = new stdClass(); $table1->width = '99%'; + $table1->cellstyle = []; - $table1->cellstyle[0][0] = $table1->cellstyle[0][1] = 'background: #373737; color: #FFF;'; + $table1->cellstyle[0][0] = 'background: #373737; color: #FFF;'; + $table1->cellstyle[0][1] = 'background: #373737; color: #FFF;'; $table1->data[0][0] = $module_item['agent']; $table1->data[0][1] = $module_item['module']; @@ -1190,7 +1362,10 @@ function reporting_html_inventory_changes($table, $item) $table1->colspan[2][0] = 2; if (count($module_item['added'])) { - $table1->data = array_merge($table1->data, $module_item['added']); + $table1->data = array_merge( + $table1->data, + $module_item['added'] + ); } $table1->cellstyle[(3 + count($module_item['added']))][0] = 'background: #373737; color: #FFF; text-align: center;'; @@ -1198,25 +1373,59 @@ function reporting_html_inventory_changes($table, $item) $table1->colspan[(3 + count($module_item['added']))][0] = 2; if (count($module_item['deleted'])) { - $table1->data = array_merge($table1->data, $module_item['deleted']); + $table1->data = array_merge( + $table1->data, + $module_item['deleted'] + ); } - $table->colspan[$module_item['agent'].'_'.$module_item['module']]['cell'] = 3; - $table->data[$module_item['agent'].'_'.$module_item['module']]['cell'] = html_print_table($table1, true); + if ($pdf === 0) { + $table->colspan[$module_item['agent'].'_'.$module_item['module']]['cell'] = 3; + $table->data[$module_item['agent'].'_'.$module_item['module']]['cell'] = html_print_table( + $table1, + true + ); + } else { + $table1->title = $item['title']; + $table1->titleclass = 'title_table_pdf'; + $table1->titlestyle = 'text-align:left;'; + $return_pdf .= html_print_table( + $table1, + true + ); + } } } + + if ($pdf !== 0) { + return $return_pdf; + } } -function reporting_html_inventory($table, $item) +/** + * Print in html inventory reportd + * + * @param object $table Head table or false if it comes from pdf. + * @param array $item Items data. + * @param boolean $pdf Print pdf true or false. + * + * @return html + */ +function reporting_html_inventory($table, $item, $pdf=0) { + $return_pdf = ''; if (!empty($item['failed'])) { - $table->colspan['failed']['cell'] = 3; - $table->cellstyle['failed']['cell'] = 'text-align: center;'; - $table->data['failed']['cell'] = $item['failed']; + if ($pdf === 0) { + $table->colspan['failed']['cell'] = 3; + $table->cellstyle['failed']['cell'] = 'text-align: center;'; + $table->data['failed']['cell'] = $item['failed']; + } else { + $return_pdf .= $item['failed']; + } } else { foreach ($item['data'] as $module_item) { - $table1 = null; + $table1 = new stdClass(); $table1->width = '99%'; $first = reset($module_item['data']); @@ -1226,12 +1435,12 @@ function reporting_html_inventory($table, $item) $table1->data[0][0] = $module_item['agent_name']; if ($count_columns == 1) { $table1->colspan[0][0] = ($count_columns + 1); - // + columm date } else { $table1->colspan[0][0] = $count_columns; } - $table1->cellstyle[1][0] = $table1->cellstyle[1][1] = 'background: #373737; color: #FFF;'; + $table1->cellstyle[1][0] = 'background: #373737; color: #FFF;'; + $table1->cellstyle[1][1] = 'background: #373737; color: #FFF;'; $table1->data[1][0] = $module_item['name']; if (($count_columns - 1) > 0) { $table1->colspan[1][0] = ($count_columns - 1); @@ -1247,19 +1456,46 @@ function reporting_html_inventory($table, $item) $table1->data[2] = array_keys($first); if (($count_columns - 1) == 0) { $table1->colspan[2][0] = ($count_columns + 1); - // + columm date; } - $table1->data = array_merge($table1->data, $module_item['data']); + $table1->data = array_merge( + $table1->data, + $module_item['data'] + ); - $table->colspan[$module_item['name'].'_'.$module_item['id_agente']]['cell'] = 3; - $table->data[$module_item['name'].'_'.$module_item['id_agente']]['cell'] = html_print_table($table1, true); + if ($pdf === 0) { + $table->colspan[$module_item['name'].'_'.$module_item['id_agente']]['cell'] = 3; + $table->data[$module_item['name'].'_'.$module_item['id_agente']]['cell'] = html_print_table( + $table1, + true + ); + } else { + $table1->title = $item['title']; + $table1->titleclass = 'title_table_pdf'; + $table1->titlestyle = 'text-align:left;'; + $return_pdf .= html_print_table( + $table1, + true + ); + } } } + if ($pdf !== 0) { + return $return_pdf; + } } +/** + * Print in html the agent / module report + * showing the status of these modules. + * + * @param object $table Head table or false if it comes from pdf. + * @param array $item Items data. + * + * @return void + */ function reporting_html_agent_module($table, $item) { $table->colspan['agent_module']['cell'] = 3; @@ -1329,11 +1565,12 @@ function reporting_html_agent_module($table, $item) $table_data .= "".$file_name.''; foreach ($row['modules'] as $module_name => $module) { - if (is_null($module)) { + if ($module === null) { $table_data .= ""; } else { $table_data .= ""; switch ($module) { + default: case AGENT_STATUS_NORMAL: $table_data .= ui_print_status_image( 'module_ok.png', @@ -1464,12 +1701,26 @@ function reporting_html_agent_module($table, $item) } -function reporting_html_exception($table, $item) +/** + * Function to print to HTML Exception report. + * + * @param object $table Head table or false if it comes from pdf. + * @param array $item Items data. + * @param boolean $pdf If it comes from pdf. + * + * @return html + */ +function reporting_html_exception($table, $item, $pdf=0) { + $return_pdf = ''; if (!empty($item['failed'])) { - $table->colspan['group_report']['cell'] = 3; - $table->cellstyle['group_report']['cell'] = 'text-align: center;'; - $table->data['group_report']['cell'] = $item['failed']; + if ($pdf !== 0) { + $return_pdf .= $item['failed']; + } else { + $table->colspan['group_report']['cell'] = 3; + $table->cellstyle['group_report']['cell'] = 'text-align: center;'; + $table->data['group_report']['cell'] = $item['failed']; + } } else { $table1 = new stdClass(); $table1->width = '99%'; @@ -1504,18 +1755,30 @@ function reporting_html_exception($table, $item) $table1->data[] = $row; } - $table->colspan['data']['cell'] = 3; - $table->cellstyle['data']['cell'] = 'text-align: center;'; - $table->data['data']['cell'] = html_print_table($table1, true); + if ($pdf !== 0) { + $table1->title = $item['title']; + $table1->titleclass = 'title_table_pdf'; + $table1->titlestyle = 'text-align:left;'; + $return_pdf .= html_print_table($table1, true); + } else { + $table->colspan['data']['cell'] = 3; + $table->cellstyle['data']['cell'] = 'text-align: center;'; + $table->data['data']['cell'] = html_print_table($table1, true); + } if (!empty($item['chart'])) { - $table->colspan['chart_pie']['cell'] = 3; - $table->cellstyle['chart_pie']['cell'] = 'text-align: center;'; - $table->data['chart_pie']['cell'] = $item['chart']['pie']; + if ($pdf !== 0) { + $return_pdf .= $item['chart']['pie']; + $return_pdf .= $item['chart']['hbar']; + } else { + $table->colspan['chart_pie']['cell'] = 3; + $table->cellstyle['chart_pie']['cell'] = 'text-align: center;'; + $table->data['chart_pie']['cell'] = $item['chart']['pie']; - $table->colspan['chart_hbar']['cell'] = 3; - $table->cellstyle['chart_hbar']['cell'] = 'text-align: center;'; - $table->data['chart_hbar']['cell'] = $item['chart']['hbar']; + $table->colspan['chart_hbar']['cell'] = 3; + $table->cellstyle['chart_hbar']['cell'] = 'text-align: center;'; + $table->data['chart_hbar']['cell'] = $item['chart']['hbar']; + } } if (!empty($item['resume'])) { @@ -1544,68 +1807,94 @@ function reporting_html_exception($table, $item) 'max' => $item['resume']['max']['formated_value'], ]; - $table->colspan['resume']['cell'] = 3; - $table->cellstyle['resume']['cell'] = 'text-align: center;'; - $table->data['resume']['cell'] = html_print_table($table1, true); + if ($pdf !== 0) { + $table1->title = $item['title']; + $table1->titleclass = 'title_table_pdf'; + $table1->titlestyle = 'text-align:left;'; + $return_pdf .= html_print_table($table1, true); + } else { + $table->colspan['resume']['cell'] = 3; + $table->cellstyle['resume']['cell'] = 'text-align: center;'; + $table->data['resume']['cell'] = html_print_table($table1, true); + } } } + + if ($pdf !== 0) { + return $return_pdf; + } } -function reporting_html_group_report($table, $item) +/** + * Function to print to HTML group report. + * + * @param object $table Head table or false if it comes from pdf. + * @param array $item Items data. + * @param boolean $pdf If it comes from pdf. + * + * @return html + */ +function reporting_html_group_report($table, $item, $pdf=0) { global $config; $table->colspan['group_report']['cell'] = 3; $table->cellstyle['group_report']['cell'] = 'text-align: center;'; - $table->data['group_report']['cell'] = " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ".__('Total')."
    ".__('Unknown')."
    ".__('Agents')."
    ".$item['data']['group_stats']['total_agents']."
    ".$item['data']['group_stats']['agents_unknown']."
    ".__('Total')."
    ".__('Normal')."
    ".__('Critical')."
    ".__('Warning')."
    ".__('Unknown')."
    ".__('Not init')."
    ".__('Monitors')."
    ".$item['data']['group_stats']['monitor_checks']."
    ".$item['data']['group_stats']['monitor_ok']."
    ".$item['data']['group_stats']['monitor_critical']."
    ".$item['data']['group_stats']['monitor_warning']."
    ".$item['data']['group_stats']['monitor_unknown']."
    ".$item['data']['group_stats']['monitor_not_init']."
    ".__('Defined')."
    ".__('Fired')."
    ".__('Alerts')."
    ".$item['data']['group_stats']['monitor_alerts']."
    ".$item['data']['group_stats']['monitor_alerts_fired']."
    ".__('Last %s', human_time_description_raw($item['date']['period']))."
    ".__('Events')."
    ".$item['data']['count_events'].'
    '; + $data = " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ".__('Total')."".__('Unknown')."
    ".__('Agents')."".$item['data']['group_stats']['total_agents']."".$item['data']['group_stats']['agents_unknown']."
    ".__('Total')."".__('Normal')."".__('Critical')."".__('Warning')."".__('Unknown')."".__('Not init')."
    ".__('Monitors')."".$item['data']['group_stats']['monitor_checks']."".$item['data']['group_stats']['monitor_ok']."".$item['data']['group_stats']['monitor_critical']."".$item['data']['group_stats']['monitor_warning']."".$item['data']['group_stats']['monitor_unknown']."".$item['data']['group_stats']['monitor_not_init']."
    ".__('Defined')."".__('Fired')."
    ".__('Alerts')."".$item['data']['group_stats']['monitor_alerts']."".$item['data']['group_stats']['monitor_alerts_fired']."
    ".__('Last %s', human_time_description_raw($item['date']['period']))."
    ".__('Events')."".$item['data']['count_events'].'
    '; + + $table->data['group_report']['cell'] = $data; + + if ($pdf !== 0) { + return $data; + } } @@ -1613,6 +1902,8 @@ function reporting_html_event_report_agent($table, $item, $pdf=0) { global $config; + $show_extended_events = $item['show_extended_events']; + if ($item['total_events'] != 0) { $table1 = new stdClass(); $table1->width = '99%'; @@ -1643,9 +1934,10 @@ function reporting_html_event_report_agent($table, $item, $pdf=0) } $data = []; - // Colored box + // Colored box. switch ($event['status']) { case 0: + default: $img_st = 'images/star.png'; $title_st = __('New event'); break; @@ -1681,7 +1973,7 @@ function reporting_html_event_report_agent($table, $item, $pdf=0) false, true ); - // $data[] = $event['event_type']; + $data[] = events_print_type_img($event['type'], true); $data[] = get_priority_name($event['criticity']); @@ -1699,16 +1991,25 @@ function reporting_html_event_report_agent($table, $item, $pdf=0) } array_push($table1->data, $data); + + if ($show_extended_events == 1 && events_has_extended_info($event['id_evento'])) { + $extended_events = events_get_extended_events($event['id_evento']); + + foreach ($extended_events as $extended_event) { + $extended_data = []; + + $extended_data[] = "".io_safe_output($extended_event['description'])."".date($config['date_format'], $extended_event['utimestamp']).''; + array_push($table1->data, $extended_data); + } + } } if ($pdf) { $table0 = new stdClass(); $table0->width = '99%'; - $table0->class = 'table-beauty'; $table0->data['count_row']['count'] = 'Total events: '.$item['total_events']; $pdf_export = html_print_table($table0, true); - $table1->class = 'table-beauty'; $pdf_export .= html_print_table($table1, true); $pdf_export .= '
    '; } else { @@ -1725,7 +2026,6 @@ function reporting_html_event_report_agent($table, $item, $pdf=0) $table1->data[0][0] = $item['chart']['by_user_validator']; if ($pdf) { - $table1->class = 'table-beauty'; $pdf_export .= html_print_table($table1, true); $pdf_export .= '
    '; } else { @@ -1743,7 +2043,6 @@ function reporting_html_event_report_agent($table, $item, $pdf=0) $table1->data[0][0] = $item['chart']['by_criticity']; if ($pdf) { - $table1->class = 'table-beauty'; $pdf_export .= html_print_table($table1, true); $pdf_export .= '
    '; } else { @@ -1761,7 +2060,6 @@ function reporting_html_event_report_agent($table, $item, $pdf=0) $table1->data[0][0] = $item['chart']['validated_vs_unvalidated']; if ($pdf) { - $table1->class = 'table-beauty'; $pdf_export .= html_print_table($table1, true); $pdf_export .= '
    '; } else { @@ -1778,7 +2076,6 @@ function reporting_html_event_report_agent($table, $item, $pdf=0) if ($pdf) { $table0 = new stdClass(); $table0->width = '99%'; - $table0->class = 'table-beauty'; $table0->data['count_row']['count'] = 'Total events: '.$item['total_events']; $pdf_export = html_print_table($table0, true); @@ -1788,7 +2085,16 @@ function reporting_html_event_report_agent($table, $item, $pdf=0) } -function reporting_html_historical_data($table, $item) +/** + * Function to print to HTML historical data report. + * + * @param object $table Head table or false if it comes from pdf. + * @param array $item Items data. + * @param boolean $pdf If it comes from pdf. + * + * @return html + */ +function reporting_html_historical_data($table, $item, $pdf=0) { global $config; @@ -1815,13 +2121,40 @@ function reporting_html_historical_data($table, $item) $table1->data[] = $row; } - $table->colspan['database_serialized']['cell'] = 3; - $table->cellstyle['database_serialized']['cell'] = 'text-align: center;'; - $table->data['database_serialized']['cell'] = html_print_table($table1, true); + if ($pdf === 0) { + $table->colspan['database_serialized']['cell'] = 3; + $table->cellstyle['database_serialized']['cell'] = 'text-align: center;'; + $table->data['database_serialized']['cell'] = html_print_table( + $table1, + true + ); + } else { + $table1->title = $item['title']; + $table1->titleclass = 'title_table_pdf'; + $table1->titlestyle = 'text-align:left;'; + return html_print_table( + $table1, + true + ); + } } -function reporting_html_database_serialized($table, $item) +/** + * It displays an item in the table format report from + * the data stored within the table named 'tagente_datos_stringin' + * the Pandora FMS Database. + * For it, the agent should serialize the data separating + * them with a line-separating character and another + * which separates the fields. All lines should contain all fields. + * + * @param object $table Head table or false if it comes from pdf. + * @param array $item Items data. + * @param boolean $pdf If it comes from pdf. + * + * @return html + */ +function reporting_html_database_serialized($table, $item, $pdf=0) { $table1 = new stdClass(); $table1->width = '100%'; @@ -1841,40 +2174,92 @@ function reporting_html_database_serialized($table, $item) } } - $table->colspan['database_serialized']['cell'] = 3; - $table->cellstyle['database_serialized']['cell'] = 'text-align: center;'; - $table->data['database_serialized']['cell'] = html_print_table($table1, true); + if ($pdf === 0) { + $table->colspan['database_serialized']['cell'] = 3; + $table->cellstyle['database_serialized']['cell'] = 'text-align: center;'; + $table->data['database_serialized']['cell'] = html_print_table( + $table1, + true + ); + } else { + $table1->title = $item['title']; + $table1->titleclass = 'title_table_pdf'; + $table1->titlestyle = 'text-align:left;'; + return html_print_table( + $table1, + true + ); + } } -function reporting_html_group_configuration($table, $item) +/** + * Shows the data of a group and the agents that are part of them. + * + * @param object $table Head table or false if it comes from pdf. + * @param array $item Items data. + * @param boolean $pdf If it comes from pdf. + * + * @return html + */ +function reporting_html_group_configuration($table, $item, $pdf=0) { - $table1 = new stdClass(); - $table1->width = '100%'; - $table1->head = []; - $table1->data = []; $cell = ''; foreach ($item['data'] as $agent) { - $table2 = new stdClass(); - $table2->width = '100%'; - $table2->data = []; - reporting_html_agent_configuration($table2, ['data' => $agent]); - - $cell .= html_print_table($table2, true); + if ($pdf === 0) { + $table2 = new stdClass(); + $table2->width = '100%'; + $table2->data = []; + reporting_html_agent_configuration( + $table2, + ['data' => $agent], + $pdf + ); + $cell .= html_print_table( + $table2, + true + ); + } else { + $cell .= reporting_html_agent_configuration( + false, + ['data' => $agent], + $pdf, + $item['title'] + ); + } } - $table->colspan['group_configuration']['cell'] = 3; - $table->cellstyle['group_configuration']['cell'] = 'text-align: center;'; - $table->data['group_configuration']['cell'] = $cell; + if ($pdf === 0) { + $table->colspan['group_configuration']['cell'] = 3; + $table->cellstyle['group_configuration']['cell'] = 'text-align: center;'; + $table->data['group_configuration']['cell'] = $cell; + } else { + return $cell; + } } -function reporting_html_network_interfaces_report($table, $item, $pdf=false) +/** + * This type of report element will generate the interface graphs + * of all those devices that belong to the selected group. + * + * @param object $table Head table or false if it comes from pdf. + * @param array $item Items data. + * @param boolean $pdf If it comes from pdf. + * + * @return html + */ +function reporting_html_network_interfaces_report($table, $item, $pdf=0) { + $return_pdf = ''; if (!empty($item['failed'])) { - $table->colspan['interfaces']['cell'] = 3; - $table->cellstyle['interfaces']['cell'] = 'text-align: left;'; - $table->data['interfaces']['cell'] = $item['failed']; + if ($pdf === 0) { + $table->colspan['interfaces']['cell'] = 3; + $table->cellstyle['interfaces']['cell'] = 'text-align: left;'; + $table->data['interfaces']['cell'] = $item['failed']; + } else { + $return_pdf .= $item['failed']; + } } else { foreach ($item['data'] as $agent) { $table_agent = new StdCLass(); @@ -1887,9 +2272,6 @@ function reporting_html_network_interfaces_report($table, $item, $pdf=false) $table_agent->style[0] = 'text-align: center'; $table_agent->data['interfaces'] = ''; - if ($pdf) { - $return_pdf .= __('Agent').' '.$agent['agent']; - } foreach ($agent['interfaces'] as $interface) { $table_interface = new StdClass(); @@ -1921,22 +2303,35 @@ function reporting_html_network_interfaces_report($table, $item, $pdf=false) $table_interface->cellstyle['graph'][0] = 'text-align: center;'; } - if ($pdf) { - $table_interface->class = 'table-beauty'; - $return_pdf .= html_print_table($table_interface, true); + if ($pdf !== 0) { + $table_interface->title = $item['title'].' '.__('Agents').': '.$agent['agent']; + $table_interface->titleclass = 'title_table_pdf'; + $table_interface->titlestyle = 'text-align:left;'; + $table_interface->styleTable = 'page-break-inside:avoid;'; + + $return_pdf .= html_print_table( + $table_interface, + true + ); } - $table_agent->data['interfaces'] .= html_print_table($table_interface, true); + $table_agent->data['interfaces'] .= html_print_table( + $table_interface, + true + ); $table_agent->colspan[$interface_name][0] = 3; } $id = uniqid(); $table->colspan[$id][0] = 3; - $table->data[$id] = html_print_table($table_agent, true); + $table->data[$id] = html_print_table( + $table_agent, + true + ); } } - if ($pdf) { + if ($pdf !== 0) { return $return_pdf; } } @@ -1957,7 +2352,11 @@ function reporting_html_alert_report($table, $item, $pdf=0) $table1->valign = []; if ($item['data'] == null) { - $table->data['alerts']['cell'] = ui_print_empty_data(__('No alerts defined'), '', true); + $table->data['alerts']['cell'] = ui_print_empty_data( + __('No alerts defined'), + '', + true + ); return true; } @@ -1989,7 +2388,7 @@ function reporting_html_alert_report($table, $item, $pdf=0) $row['fired'] = ''; foreach ($alert['actions'] as $action) { if ($action['name'] == '') { - // Removed from retrieved hash + // Removed from retrieved hash. continue; } @@ -2006,7 +2405,7 @@ function reporting_html_alert_report($table, $item, $pdf=0) $row['tfired'] .= '
    '.$fired.'
    '."\n"; } - // Skip first td's to avoid repeat the agent and module names + // Skip first td's to avoid repeat the agent and module names. $table1->data[] = $row; if ($td > 1) { for ($i = 0; $i < $td; $i++) { @@ -2019,12 +2418,25 @@ function reporting_html_alert_report($table, $item, $pdf=0) $table->data['alerts']['cell'] = html_print_table($table1, true); if ($pdf) { - $table1->class = 'table-beauty pdf_alert_table'; + $table1->class = 'pdf_alert_table'; return html_print_table($table1, true); } } +/** + * This type of report element allows custom graphs to be defined + * for use in reports. + * These graphs will be created using SQL code entered by the user. + * This SQL code should always return a variable called "label" + * for the text labels or name of the elements to be displayed + * and a field called "value" to store the numerical value to be represented. + * + * @param object $table Parameters table. + * @param array $item Items data. + * + * @return void + */ function reporting_html_sql_graph($table, $item) { $table->colspan['chart']['cell'] = 3; @@ -2033,7 +2445,18 @@ function reporting_html_sql_graph($table, $item) } -function reporting_html_monitor_report($table, $item, $mini) +/** + * It shows the percentage of time a module has been + * right or wrong within a predefined period. + * + * @param object $table Parameters table. + * @param array $item Items data. + * @param boolean $mini True or flase. + * @param integer $pdf Values 0 or 1. + * + * @return mixed + */ +function reporting_html_monitor_report($table, $item, $mini, $pdf=0) { global $config; @@ -2055,16 +2478,50 @@ function reporting_html_monitor_report($table, $item, $mini) $table1->data['data']['unknown'] .= __('Unknown').'

    '; } else { $table1->data['data']['ok'] = '

    '; - $table1->data['data']['ok'] .= html_print_image('images/module_ok.png', true).' '.__('OK').': '.remove_right_zeros(number_format($item['data']['ok']['formated_value'], $config['graph_precision'])).' %

    '; + $table1->data['data']['ok'] .= html_print_image( + 'images/module_ok.png', + true + ).' '.__('OK').': '.remove_right_zeros( + number_format( + $item['data']['ok']['formated_value'], + $config['graph_precision'] + ) + ).' %

    '; $table1->data['data']['fail'] = '

    '; - $table1->data['data']['fail'] .= html_print_image('images/module_critical.png', true).' '.__('Not OK').': '.remove_right_zeros(number_format($item['data']['fail']['formated_value'], $config['graph_precision'])).' % '.'

    '; + $table1->data['data']['fail'] .= html_print_image( + 'images/module_critical.png', + true + ).' '.__('Not OK').': '.remove_right_zeros( + number_format( + $item['data']['fail']['formated_value'], + $config['graph_precision'] + ) + ).' % '.'

    '; } - $table->data['module']['cell'] = html_print_table($table1, true); + if ($pdf === 0) { + $table->data['module']['cell'] = html_print_table( + $table1, + true + ); + } else { + return html_print_table( + $table1, + true + ); + } } +/** + * Print report html. + * + * @param object $table Parameters table. + * @param array $item Items data. + * + * @return mixed + */ function reporting_html_graph($table, $item) { $table->colspan['chart']['cell'] = 3; @@ -2073,16 +2530,38 @@ function reporting_html_graph($table, $item) } +/** + * Print report prediction date. + * + * @param object $table Parameters table. + * @param array $item Items data. + * @param boolean $mini True or False. + * + * @return mixed + */ function reporting_html_prediction_date($table, $item, $mini) { reporting_html_value($table, $item, $mini, true); } -function reporting_html_agent_configuration(&$table, $item) -{ - $table->colspan['agent']['cell'] = 3; - $table->cellstyle['agent']['cell'] = 'text-align: left;'; +/** + * Shows the data of agents and modules. + * + * @param object $table Head table or false if it comes from pdf. + * @param array $item Items data. + * @param boolean $pdf If it comes from pdf. + * @param string $title Show title pdf. + * + * @return html + */ +function reporting_html_agent_configuration( + $table, + $item, + $pdf=0, + $title='' +) { + $return_pdf = ''; $table1 = new stdClass(); $table1->width = '99%'; @@ -2094,6 +2573,7 @@ function reporting_html_agent_configuration(&$table, $item) $table1->head['description'] = __('Description'); $table1->head['status'] = __('Status'); $table1->data = []; + $row = []; $row['name'] = $item['data']['name']; $row['group'] = $item['data']['group_icon']; @@ -2107,13 +2587,32 @@ function reporting_html_agent_configuration(&$table, $item) } $table1->data[] = $row; - $table->data['agent']['cell'] = html_print_table($table1, true); - $table->colspan['modules']['cell'] = 3; - $table->cellstyle['modules']['cell'] = 'text-align: left;'; + if ($pdf === 0) { + $table->colspan['agent']['cell'] = 3; + $table->cellstyle['agent']['cell'] = 'text-align: left;'; + $table->data['agent']['cell'] = html_print_table( + $table1, + true + ); + } else { + $return_pdf .= html_print_table( + $table1, + true + ); + } + + if ($pdf === 0) { + $table->colspan['modules']['cell'] = 3; + $table->cellstyle['modules']['cell'] = 'text-align: left;'; + } if (empty($item['data']['modules'])) { - $table->data['modules']['cell'] = __('Empty modules'); + if ($pdf === 0) { + $table->data['modules']['cell'] = __('Empty modules'); + } else { + $return_pdf .= __('Empty modules'); + } } else { $table1->width = '99%'; $table1->head = []; @@ -2157,7 +2656,25 @@ function reporting_html_agent_configuration(&$table, $item) $table1->data[] = $row; } - $table->data['modules']['cell'] = html_print_table($table1, true); + if ($pdf === 0) { + $table->data['modules']['cell'] = html_print_table($table1, true); + } else { + if ($title !== '') { + $item['title'] = $title; + } + + $table1->title = $item['title'].' '.__('Agent').': '.$item['data']['name']; + $table1->titleclass = 'title_table_pdf'; + $table1->titlestyle = 'text-align:left;'; + $return_pdf .= html_print_table( + $table1, + true + ); + } + } + + if ($pdf !== 0) { + return $return_pdf; } } @@ -2235,13 +2752,29 @@ function reporting_html_value(&$table, $item, $mini, $only_value=false, $check_e } -function reporting_html_increment(&$table, $item) +/** + * Show a brief analysis in which the variation of the value + * of the indicated module is indicated. + * + * @param string $table Reference table in pdf a false. + * @param array $item Parameters for item pdf. + * @param boolean $pdf Send pdf. + * + * @return html + */ +function reporting_html_increment($table, $item, $pdf=0) { global $config; + $return_pdf = ''; + if (isset($item['data']['error'])) { - $table->colspan['error']['cell'] = 3; - $table->data['error']['cell'] = $item['data']['message']; + if ($pdf === 0) { + $table->colspan['error']['cell'] = 3; + $table->data['error']['cell'] = $item['data']['message']; + } else { + $return_pdf .= $item['data']['message']; + } } else { $table1 = new stdClass(); $table1->width = '99%'; @@ -2290,9 +2823,17 @@ function reporting_html_increment(&$table, $item) $table1->data[] = $table1_row; - $data = []; - $data[0] = html_print_table($table1, true); - array_push($table->data, $data); + if ($pdf === 0) { + $data = []; + $data[0] = html_print_table($table1, true); + array_push($table->data, $data); + } else { + $return_pdf = html_print_table($table1, true); + } + } + + if ($pdf !== 0) { + return $return_pdf; } } @@ -2302,15 +2843,15 @@ function reporting_html_url(&$table, $item, $key) $table->colspan['data']['cell'] = 3; $table->cellstyle['data']['cell'] = 'text-align: left;'; $table->data['data']['cell'] = ' - '; - // TODO: make this dynamic and get the height if the iframe to resize this item + '; + // TODO: make this dynamic and get the height if the iframe to resize this item. $table->data['data']['cell'] .= ' - '; + '; } @@ -2322,10 +2863,30 @@ function reporting_html_text(&$table, $item) } -function reporting_html_availability(&$table, $item) +/** + * Report availability + * + * @param string $table Reference table in pdf a false. + * @param array $item Parameters for item pdf. + * @param boolean $pdf Send pdf. + * + * @return html + */ +function reporting_html_availability($table, $item, $pdf=0) { - $style = db_get_value('style', 'treport_content', 'id_rc', $item['id_rc']); - $style = json_decode(io_safe_output($style), true); + $retun_pdf = ''; + + $style = db_get_value( + 'style', + 'treport_content', + 'id_rc', + $item['id_rc'] + ); + + $style = json_decode( + io_safe_output($style), + true + ); $same_agent_in_resume = ''; global $config; @@ -2338,39 +2899,69 @@ function reporting_html_availability(&$table, $item) $table1->head = []; $table1->head[0] = __('Agent'); // HACK it is saved in show_graph field. - // Show interfaces instead the modules + // Show interfaces instead the modules. if ($item['kind_availability'] == 'address') { $table1->head[1] = __('IP Address'); } else { $table1->head[1] = __('Module'); } - $table1->head[2] = __('Total time'); - $table1->head[3] = __('Time failed'); - $table1->head[4] = __('Time OK'); - $table1->head[5] = __('Time Uknown'); - $table1->head[6] = __('Time Not Init Module'); - $table1->head[7] = __('Time Downtime'); + if ($item['fields']['total_time']) { + $table1->head[2] = __('Total time'); + } else { + $table1->head[2] = __(''); + } + + if ($item['fields']['time_failed']) { + $table1->head[3] = __('Time failed'); + } else { + $table1->head[3] = __(''); + } + + if ($item['fields']['time_in_ok_status']) { + $table1->head[4] = __('Time OK'); + } else { + $table1->head[4] = __(''); + } + + if ($item['fields']['time_in_unknown_status']) { + $table1->head[5] = __('Time Unknown'); + } else { + $table1->head[5] = __(''); + } + + if ($item['fields']['time_of_not_initialized_module']) { + $table1->head[6] = __('Time Not Init Module'); + } else { + $table1->head[6] = __(''); + } + + if ($item['fields']['time_of_downtime']) { + $table1->head[7] = __('Time Downtime'); + } else { + $table1->head[7] = __(''); + } + $table1->head[8] = __('% Ok'); $table1->headstyle = []; $table1->headstyle[0] = 'text-align: left'; $table1->headstyle[1] = 'text-align: left'; - $table1->headstyle[2] = 'text-align: right'; - $table1->headstyle[3] = 'text-align: right'; - $table1->headstyle[4] = 'text-align: right'; - $table1->headstyle[5] = 'text-align: right'; - $table1->headstyle[6] = 'text-align: right'; + $table1->headstyle[2] = 'text-align: center'; + $table1->headstyle[3] = 'text-align: center'; + $table1->headstyle[4] = 'text-align: center'; + $table1->headstyle[5] = 'text-align: center'; + $table1->headstyle[6] = 'text-align: center'; $table1->headstyle[7] = 'text-align: right'; $table1->headstyle[8] = 'text-align: right'; $table1->style[0] = 'text-align: left'; $table1->style[1] = 'text-align: left'; - $table1->style[2] = 'text-align: right'; - $table1->style[3] = 'text-align: right'; - $table1->style[4] = 'text-align: right'; - $table1->style[5] = 'text-align: right'; - $table1->style[6] = 'text-align: right'; + $table1->style[2] = 'text-align: center'; + $table1->style[3] = 'text-align: center'; + $table1->style[4] = 'text-align: center'; + $table1->style[5] = 'text-align: center'; + $table1->style[6] = 'text-align: center'; $table1->style[7] = 'text-align: right'; $table1->style[8] = 'text-align: right'; @@ -2381,18 +2972,37 @@ function reporting_html_availability(&$table, $item) $table2->head = []; $table2->head[0] = __('Agent'); // HACK it is saved in show_graph field. - // Show interfaces instead the modules + // Show interfaces instead the modules. if ($item['kind_availability'] == 'address') { $table2->head[1] = __('IP Address'); } else { $table2->head[1] = __('Module'); } - $table2->head[2] = __('Total checks'); - $table2->head[3] = __('Checks failed'); - $table2->head[4] = __('Checks OK'); - $table2->head[5] = __('Checks Uknown'); - // $table2->head[6] = __('% Ok'); + if ($item['fields']['total_checks']) { + $table2->head[2] = __('Total checks'); + } else { + $table2->head[2] = __(''); + } + + if ($item['fields']['checks_failed']) { + $table2->head[3] = __('Checks failed'); + } else { + $table2->head[3] = __(''); + } + + if ($item['fields']['checks_in_ok_status']) { + $table2->head[4] = __('Checks OK'); + } else { + $table2->head[4] = __(''); + } + + if ($item['fields']['unknown_checks']) { + $table2->head[5] = __('Checks Uknown'); + } else { + $table2->head[5] = __(''); + } + $table2->headstyle = []; $table2->headstyle[0] = 'text-align: left'; $table2->headstyle[1] = 'text-align: left'; @@ -2400,66 +3010,110 @@ function reporting_html_availability(&$table, $item) $table2->headstyle[3] = 'text-align: right'; $table2->headstyle[4] = 'text-align: right'; $table2->headstyle[5] = 'text-align: right'; - // $table2->headstyle[6] = 'text-align: right'; + $table2->style[0] = 'text-align: left'; $table2->style[1] = 'text-align: left'; $table2->style[2] = 'text-align: right'; $table2->style[3] = 'text-align: right'; $table2->style[4] = 'text-align: right'; $table2->style[5] = 'text-align: right'; - // $table2->style[6] = 'text-align: right'; - foreach ($item['data'] as $row) { - $the_first_men_time = get_agent_first_time(io_safe_output($row['agent'])); + foreach ($item['data'] as $row) { $table_row = []; $table_row[] = $row['agent']; $table_row[] = $row['availability_item']; - if ($row['time_total'] != 0) { - $table_row[] = human_time_description_raw($row['time_total'], true); - } else { + if ($row['time_total'] != 0 && $item['fields']['total_time']) { + $table_row[] = human_time_description_raw( + $row['time_total'], + true + ); + } else if ($row['time_total'] == 0 && $item['fields']['total_time']) { $table_row[] = '--'; - } + } else { + $table_row[] = ''; + }; - if ($row['time_error'] != 0) { - $table_row[] = human_time_description_raw($row['time_error'], true); - } else { + if ($row['time_error'] != 0 && $item['fields']['time_failed']) { + $table_row[] = human_time_description_raw( + $row['time_error'], + true + ); + } else if ($row['time_error'] == 0 && $item['fields']['time_failed']) { $table_row[] = '--'; - } + } else { + $table_row[] = ''; + }; - if ($row['time_ok'] != 0) { - $table_row[] = human_time_description_raw($row['time_ok'], true); - } else { + if ($row['time_ok'] != 0 && $item['fields']['time_in_ok_status']) { + $table_row[] = human_time_description_raw( + $row['time_ok'], + true + ); + } else if ($row['time_ok'] == 0 && $item['fields']['time_in_ok_status']) { $table_row[] = '--'; - } + } else { + $table_row[] = ''; + }; - if ($row['time_unknown'] != 0) { - $table_row[] = human_time_description_raw($row['time_unknown'], true); - } else { + if ($row['time_unknown'] != 0 && $item['fields']['time_in_unknown_status']) { + $table_row[] = human_time_description_raw( + $row['time_unknown'], + true + ); + } else if ($row['time_unknown'] == 0 && $item['fields']['time_in_unknown_status']) { $table_row[] = '--'; - } + } else { + $table_row[] = ''; + }; - if ($row['time_not_init'] != 0) { - $table_row[] = human_time_description_raw($row['time_not_init'], true); - } else { + if ($row['time_not_init'] != 0 && $item['fields']['time_of_not_initialized_module']) { + $table_row[] = human_time_description_raw( + $row['time_not_init'], + true + ); + } else if ($row['time_not_init'] == 0 && $item['fields']['time_of_not_initialized_module']) { $table_row[] = '--'; - } + } else { + $table_row[] = ''; + }; - if ($row['time_downtime'] != 0) { - $table_row[] = human_time_description_raw($row['time_downtime'], true); - } else { + if ($row['time_downtime'] != 0 && $item['fields']['time_of_downtime']) { + $table_row[] = human_time_description_raw( + $row['time_downtime'], + true + ); + } else if ($row['time_downtime'] == 0 && $item['fields']['time_of_downtime']) { $table_row[] = '--'; - } + } else { + $table_row[] = ''; + }; $table_row[] = ''.sla_truncate($row['SLA'], $config['graph_precision']).'%'; $table_row2 = []; $table_row2[] = $row['agent']; $table_row2[] = $row['availability_item']; - $table_row2[] = $row['checks_total']; - $table_row2[] = $row['checks_error']; - $table_row2[] = $row['checks_ok']; - $table_row2[] = $row['checks_unknown']; + if ($item['fields']['total_checks']) { + $table_row2[] = $row['checks_total']; + } else { + $table_row2[] = ''; + }; + if ($item['fields']['checks_failed']) { + $table_row2[] = $row['checks_error']; + } else { + $table_row2[] = ''; + }; + if ($item['fields']['checks_in_ok_status']) { + $table_row2[] = $row['checks_ok']; + } else { + $table_row2[] = ''; + }; + if ($item['fields']['unknown_checks']) { + $table_row2[] = $row['checks_unknown']; + } else { + $table_row2[] = ''; + }; $table1->data[] = $table_row; $table2->data[] = $table_row2; @@ -2469,22 +3123,36 @@ function reporting_html_availability(&$table, $item) $table->data['error']['cell'] = __('There are no Agent/Modules defined'); } - $table->colspan[1][0] = 2; - $table->colspan[2][0] = 2; - $data = []; - $data[0] = html_print_table($table1, true); - array_push($table->data, $data); + if ($pdf === 0) { + $table->colspan[1][0] = 2; + $table->colspan[2][0] = 2; + $data = []; + $data[0] = html_print_table($table1, true); + array_push($table->data, $data); + } else { + $table1->title = $item['title']; + $table1->titleclass = 'title_table_pdf'; + $table1->titlestyle = 'text-align:left;'; + $return_pdf .= html_print_table($table1, true); + } if ($item['resume']['resume']) { - $data2 = []; - $data2[0] = html_print_table($table2, true); - array_push($table->data, $data2); + if ($pdf === 0) { + $data2 = []; + $data2[0] = html_print_table($table2, true); + array_push($table->data, $data2); + } else { + $table2->title = $item['title']; + $table2->titleclass = 'title_table_pdf'; + $table2->titlestyle = 'text-align:left;'; + $return_pdf .= html_print_table($table2, true); + } } if ($item['resume']['resume'] && !empty($item['data'])) { $table1->width = '99%'; $table1->data = []; - if ((strpos($item['resume']['min_text'], $same_agent_in_resume) === false)) { + if (empty($same_agent_in_resume) || (strpos($item['resume']['min_text'], $same_agent_in_resume) === false)) { $table1->head = []; $table1->head['max_text'] = __('Agent max value'); $table1->head['max'] = __('Max Value'); @@ -2508,27 +3176,73 @@ function reporting_html_availability(&$table, $item) $table1->data[] = [ 'max_text' => $item['resume']['max_text'], - 'max' => sla_truncate($item['resume']['max'], $config['graph_precision']).'%', + 'max' => sla_truncate( + $item['resume']['max'], + $config['graph_precision'] + ).'%', 'min_text' => $item['resume']['min_text'], - 'min' => sla_truncate($item['resume']['min'], $config['graph_precision']).'%', + 'min' => sla_truncate( + $item['resume']['min'], + $config['graph_precision'] + ).'%', 'avg' => ''.sla_truncate($item['resume']['avg'], $config['graph_precision']).'%', ]; + if ($item['fields']['agent_max_value'] == false) { + $table1->head['max_text'] = ''; + $table1->data[0]['max_text'] = ''; + $table1->head['max'] = ''; + $table1->data[0]['max'] = ''; + } - $table->colspan[3][0] = 3; - $data = []; - $data[0] = html_print_table($table1, true); - array_push($table->data, $data); + if ($item['fields']['agent_min_value'] == false) { + $table1->head['min_text'] = ''; + $table1->data[0]['min_text'] = ''; + $table1->head['min'] = ''; + $table1->data[0]['min'] = ''; + } + + if ($pdf === 0) { + $table->colspan[3][0] = 3; + $data = []; + $data[0] = html_print_table( + $table1, + true + ); + array_push($table->data, $data); + } else { + $table1->title = $item['title']; + $table1->titleclass = 'title_table_pdf'; + $table1->titlestyle = 'text-align:left;'; + $return_pdf .= html_print_table( + $table1, + true + ); + } } } + + if ($pdf !== 0) { + return $return_pdf; + } } -function reporting_html_availability_graph(&$table, $item, $pdf=0) +/** + * The availability report shows in detail the reached + * status of a module in a given time interval. + * + * @param string $table Reference table in pdf a false. + * @param array $item Parameters for item pdf. + * @param boolean $pdf Send pdf. + * + * @return html + */ +function reporting_html_availability_graph($table, $item, $pdf=0) { global $config; $metaconsole_on = is_metaconsole(); - if ($metaconsole_on) { + if ($metaconsole_on !== false) { $hack_metaconsole = '../../'; } else { $hack_metaconsole = ''; @@ -2570,7 +3284,10 @@ function reporting_html_availability_graph(&$table, $item, $pdf=0) break; } - $sla_value = sla_truncate($chart['sla_value'], $config['graph_precision']).'%'; + $sla_value = sla_truncate( + $chart['sla_value'], + $config['graph_precision'] + ).'%'; $checks_resume = '('.$chart['checks_ok'].'/'.$chart['checks_total'].')'; } @@ -2578,11 +3295,14 @@ function reporting_html_availability_graph(&$table, $item, $pdf=0) $table1->data[0][1] = $chart['chart']; $table1->data[0][2] = "".$sla_value.''; $table1->data[0][3] = $checks_resume; - $tables_chart .= html_print_table($table1, true); + $tables_chart .= html_print_table( + $table1, + true + ); } if ($item['type'] == 'availability_graph') { - // table_legend_graphs; + // Table_legend_graphs. $table2 = new stdClass(); $table2->width = '99%'; $table2->data = []; @@ -2618,22 +3338,61 @@ function reporting_html_availability_graph(&$table, $item, $pdf=0) $table2->data[0][11] = ''.__('Ignore time').''; } - $table->colspan['charts']['cell'] = 2; - $table->data['charts']['cell'] = $tables_chart; - $table->colspan['legend']['cell'] = 2; - $table->data['legend']['cell'] = html_print_table($table2, true); - - if ($pdf) { - return $tables_chart.'
    '.html_print_table($table2, true); + if ($pdf !== 0) { + $tables_chart .= html_print_table( + $table2, + true + ); + return $tables_chart; + } else { + $table->colspan['charts']['cell'] = 2; + $table->data['charts']['cell'] = $tables_chart; + $table->colspan['legend']['cell'] = 2; + $table->data['legend']['cell'] = html_print_table( + $table2, + true + ); } } -function reporting_html_general(&$table, $item) +/** + * Function for first time data agent. + * + * @param string $agent_name Agent name. + * + * @return array + */ +function get_agent_first_time($agent_name) { + $id = agents_get_agent_id($agent_name, true); + + $utimestamp = db_get_all_rows_sql( + 'SELECT min(utimestamp) FROM tagente_datos WHERE id_agente_modulo IN + (SELECT id_agente_modulo FROM tagente_modulo WHERE id_agente = '.$id.')' + ); + $utimestamp = $utimestamp[0]['utimestamp']; + + return $utimestamp; +} + + +/** + * Function to print to HTML General report. + * + * @param object $table Head table or false if it comes from pdf. + * @param array $item Items data. + * @param boolean $pdf If it comes from pdf. + * + * @return html + */ +function reporting_html_general($table, $item, $pdf=0) +{ + $return_pdf = ''; if (!empty($item['data'])) { $data_in_same_row = $item['show_in_same_row']; switch ($item['subtype']) { + default: case REPORT_GENERAL_NOT_GROUP_BY_AGENT: if (!$data_in_same_row) { $table1 = new stdClass(); @@ -2652,14 +3411,14 @@ function reporting_html_general(&$table, $item) $table1->style[2] = 'text-align: left'; $table1->style[3] = 'text-align: left'; - // Begin - Order by agent + // Begin - Order by agent. foreach ($item['data'] as $key => $row) { $aux[$key] = $row['agent']; } array_multisort($aux, SORT_ASC, $item['data']); - // End - Order by agent + // End - Order by agent. foreach ($item['data'] as $row) { if ($row['id_module_type'] == 6 || $row['id_module_type'] == 9 || $row['id_module_type'] == 18 || $row['id_module_type'] == 2) { $row['formated_value'] = round($row['formated_value'], 0, PHP_ROUND_HALF_DOWN); @@ -2723,7 +3482,6 @@ function reporting_html_general(&$table, $item) } } break; - case REPORT_GENERAL_GROUP_BY_AGENT: $list_modules = []; foreach ($item['data'] as $modules) { @@ -2754,12 +3512,23 @@ function reporting_html_general(&$table, $item) break; } - $table->colspan['data']['cell'] = 3; - $table->cellstyle['data']['cell'] = 'text-align: center;'; - $table->data['data']['cell'] = html_print_table($table1, true); + if ($pdf !== 0) { + $table1->title = $item['title']; + $table1->titleclass = 'title_table_pdf'; + $table1->titlestyle = 'text-align:left;'; + $return_pdf .= html_print_table($table1, true); + } else { + $table->colspan['data']['cell'] = 3; + $table->cellstyle['data']['cell'] = 'text-align: center;'; + $table->data['data']['cell'] = html_print_table($table1, true); + } } else { - $table->colspan['error']['cell'] = 3; - $table->data['error']['cell'] = __('There are no Agent/Modules defined'); + if ($pdf !== 0) { + $return_pdf .= __('There are no Agent/Modules defined'); + } else { + $table->colspan['error']['cell'] = 3; + $table->data['error']['cell'] = __('There are no Agent/Modules defined'); + } } if ($item['resume'] && !empty($item['data'])) { @@ -2789,34 +3558,44 @@ function reporting_html_general(&$table, $item) $table_summary->data[0][3] = $item['max']['agent'].' - '.$item['max']['module']; $table_summary->data[0][4] = $item['max']['formated_value']; - $table->colspan['summary_title']['cell'] = 3; - $table->data['summary_title']['cell'] = ''.__('Summary').''; - $table->colspan['summary_table']['cell'] = 3; - $table->data['summary_table']['cell'] = html_print_table($table_summary, true); + if ($pdf !== 0) { + $return_pdf .= html_print_table($table_summary, true); + } else { + $table->colspan['summary_title']['cell'] = 3; + $table->data['summary_title']['cell'] = ''.__('Summary').''; + $table->colspan['summary_table']['cell'] = 3; + $table->data['summary_table']['cell'] = html_print_table( + $table_summary, + true + ); + } + } + + if ($pdf !== 0) { + return $return_pdf; } } -function get_agent_first_time($agent_name) -{ - $id = agents_get_agent_id($agent_name, true); - - $utimestamp = db_get_all_rows_sql( - 'SELECT utimestamp FROM tagente_datos WHERE id_agente_modulo IN - (SELECT id_agente_modulo FROM tagente_modulo WHERE id_agente = '.$id.') - ORDER BY utimestamp ASC LIMIT 1' - ); - $utimestamp = $utimestamp[0]['utimestamp']; - - return $utimestamp; -} - - -function reporting_html_sql(&$table, $item) +/** + * Function to print to HTML query sql. + * + * @param object $table Head table or false if it comes from pdf. + * @param array $item Items data. + * @param boolean $pdf If it comes from pdf. + * + * @return html + */ +function reporting_html_sql($table, $item, $pdf=0) { + $return_pdf = ''; if (!$item['correct']) { - $table->colspan['error']['cell'] = 3; - $table->data['error']['cell'] = $item['error']; + if ($pdf === 0) { + $table->colspan['error']['cell'] = 3; + $table->data['error']['cell'] = $item['error']; + } else { + $return_pdf .= $item['error']; + } } else { $first = true; @@ -2825,10 +3604,10 @@ function reporting_html_sql(&$table, $item) $table2->width = '100%'; foreach ($item['data'] as $row) { - if ($first) { + if ($first === true) { $first = false; - // Print the header + // Print the header. foreach ($row as $key => $value) { $table2->head[] = $key; } @@ -2837,18 +3616,44 @@ function reporting_html_sql(&$table, $item) $table2->data[] = $row; } - $table->colspan['data']['cell'] = 3; - $table->cellstyle['data']['cell'] = 'text-align: center;'; - $table->data['data']['cell'] = html_print_table($table2, true); + if ($pdf === 0) { + $table->colspan['data']['cell'] = 3; + $table->cellstyle['data']['cell'] = 'text-align: center;'; + $table->data['data']['cell'] = html_print_table( + $table2, + true + ); + } else { + $table2->title = $item['title']; + $table2->titleclass = 'title_table_pdf'; + $table2->titlestyle = 'text-align:left;'; + $return_pdf .= html_print_table( + $table2, + true + ); + } + } + + if ($pdf !== 0) { + return $return_pdf; } } +/** + * Function for stats. + * + * @param array $data Array item. + * @param integer $graph_width Items data. + * @param integer $graph_height If it comes from pdf. + * + * @return html + */ function reporting_get_stats_summary($data, $graph_width, $graph_height) { global $config; - // Alerts table + // Alerts table. $table_sum = html_get_predefined_table(); $tdata = []; @@ -2868,25 +3673,33 @@ function reporting_get_stats_summary($data, $graph_width, $graph_height) $table_sum->cellstyle[count($table_sum->data)][2] = 'text-align: center;'; if ($data['monitor_checks'] > 0) { - // Fixed width non interactive charts + // Fixed width non interactive charts. $status_chart_width = $graph_width; - $tdata[0] = '
    '.'
    '.graph_agent_status(false, $graph_width, $graph_height, true, true).'
    '.'
    '; + $tdata[0] = '
    '.graph_agent_status(false, $graph_width, $graph_height, true, true).'
    '; } else { - $tdata[2] = html_print_image('images/image_problem_area_small.png', true, ['width' => $graph_width]); + $tdata[2] = html_print_image( + 'images/image_problem_area_small.png', + true, + ['width' => $graph_width] + ); } if ($data['monitor_alerts'] > 0) { $tdata[2] = '
    '.graph_alert_status($data['monitor_alerts'], $data['monitor_alerts_fired'], $graph_width, $graph_height, true, true).'
    '; } else { - $tdata[2] = html_print_image('images/image_problem_area_small.png', true, ['width' => $graph_width]); + $tdata[2] = html_print_image( + 'images/image_problem_area_small.png', + true, + ['width' => $graph_width] + ); } $table_sum->rowclass[] = ''; $table_sum->data[] = $tdata; $output = '
    - '.__('Summary').''.html_print_table($table_sum, true).'
    '; + '.__('Summary').''.html_print_table($table_sum, true).''; return $output; } @@ -2898,10 +3711,11 @@ function reporting_get_stats_summary($data, $graph_width, $graph_height) * It construct a table object with all the events happened in a group * during a period of time. * - * @param int Group id to get the report. - * @param int Period of time to get the report. - * @param int Beginning date of the report - * @param int Flag to return or echo the report table (echo by default). + * @param integer $id_group Group id to get the report. + * @param integer $period Period of time to get the report. + * @param integer $date Beginning date of the report. + * @param boolean $return Flag to return or echo the + * report table (echo by default). * * @return object A table object */ @@ -2934,7 +3748,7 @@ function reporting_event_reporting($id_group, $period, $date=0, $return=false) } $data[1] = $event['evento']; - $data[2] = $event['id_usuario'] != '0' ? $event['id_usuario'] : ''; + $data[2] = ($event['id_usuario'] != '0') ? $event['id_usuario'] : ''; $data[3] = $event['timestamp']; array_push($table->data, $data); } @@ -2950,8 +3764,9 @@ function reporting_event_reporting($id_group, $period, $date=0, $return=false) /** * Get a table report from a alerts fired array. * - * @param array Alerts fired array. - * @see function get_alerts_fired () + * @param array $alerts_fired Alerts fired array. + * + * @see function get_alerts_fired () * * @return object A table object with a report of the fired alerts. */ @@ -2966,7 +3781,7 @@ function reporting_get_fired_alerts_table($alerts_fired) $alert_module = alerts_get_alert_agent_module($id_alert); $template = alerts_get_alert_template($id_alert); - // Add alerts fired to $agents_fired_alerts indexed by id_agent + // Add alerts fired to $agents_fired_alerts indexed by id_agent. $id_agent = db_get_value( 'id_agente', 'tagente_modulo', @@ -3012,8 +3827,9 @@ function reporting_get_fired_alerts_table($alerts_fired) /** * Get a report table with all the monitors down. * - * @param array An array with all the monitors down - * @see function modules_get_monitors_down() + * @param array $monitors_down An array with all the monitors down. + * + * @see Function modules_get_monitors_down(). * * @return object A table object with a monitors down report. */ @@ -3027,7 +3843,7 @@ function reporting_get_monitors_down_table($monitors_down) $agents = []; if ($monitors_down) { foreach ($monitors_down as $monitor) { - // Add monitors fired to $agents_fired_alerts indexed by id_agent + // Add monitors fired to $agents_fired_alerts indexed by id_agent. $id_agent = $monitor['id_agente']; if (!isset($agents[$id_agent])) { $agents[$id_agent] = []; @@ -3067,8 +3883,8 @@ function reporting_get_monitors_down_table($monitors_down) * * It shows the number of agents and no more things right now. * - * @param int Group to get the report - * @param bool Flag to return or echo the report (by default). + * @param integer $id_group Group to get the report. + * @param boolean $return Flag to return or echo the report (by default). * * @return HTML string with group report */ @@ -3088,9 +3904,10 @@ function reporting_print_group_reporting($id_group, $return=false) /** * Get a report table of the fired alerts group by agents. * - * @param int Agent id to generate the report. - * @param int Period of time of the report. - * @param int Beginning date of the report in UNIX time (current date by default). + * @param integer $id_agent Agent id to generate the report. + * @param integer $period Period of time of the report. + * @param integer $date Beginning date of the report in + * UNIX time (current date by default). * * @return object A table object with the alert reporting.. */ @@ -3123,6 +3940,7 @@ function reporting_get_agent_alerts_table($id_agent, $period=0, $date=0) switch ($template['type']) { case 'regex': + default: if ($template['matches_value']) { $data[2] = '≃ "'.$template['value'].'"'; } else { @@ -3133,23 +3951,19 @@ function reporting_get_agent_alerts_table($id_agent, $period=0, $date=0) case 'equal': case 'not_equal': $data[2] = $template['value']; - break; case 'max-min': $data[2] = __('Min.').': '.$template['min_value'].' '; $data[2] .= __('Max.').': '.$template['max_value'].' '; - break; case 'max': $data[2] = $template['max_value']; - break; case 'min': $data[2] = $template['min_value']; - break; } @@ -3167,9 +3981,10 @@ function reporting_get_agent_alerts_table($id_agent, $period=0, $date=0) /** * Get a report of monitors in an agent. * - * @param int Agent id to get the report - * @param int Period of time of the report. - * @param int Beginning date of the report in UNIX time (current date by default). + * @param integer $id_agent Agent id to get the report. + * @param integer $period Period of time of the report. + * @param integer $date Beginning date of the report in UNIX time + * (current date by default). * * @return object A table object with the report. */ @@ -3187,7 +4002,11 @@ function reporting_get_agent_monitors_table($id_agent, $period=0, $date=0) } foreach ($monitors as $monitor) { - $downs = modules_get_monitor_downs_in_period($monitor['id_agente_modulo'], $period, $date); + $downs = modules_get_monitor_downs_in_period( + $monitor['id_agente_modulo'], + $period, + $date + ); if (! $downs) { continue; } @@ -3199,7 +4018,11 @@ function reporting_get_agent_monitors_table($id_agent, $period=0, $date=0) $data[0] = $monitor['nombre']; } - $data[1] = modules_get_last_down_timestamp_in_period($monitor['id_agente_modulo'], $period, $date); + $data[1] = modules_get_last_down_timestamp_in_period( + $monitor['id_agente_modulo'], + $period, + $date + ); array_push($table->data, $data); } @@ -3210,9 +4033,10 @@ function reporting_get_agent_monitors_table($id_agent, $period=0, $date=0) /** * Get a report of all the modules in an agent. * - * @param int Agent id to get the report. - * @param int Period of time of the report - * @param int Beginning date of the report in UNIX time (current date by default). + * @param integer $id_agent Agent id to get the report. + * @param integer $period Period of time of the report. + * @param integer $date Beginning date of the report in UNIX time + * (current date by default). * * @return object */ @@ -3244,19 +4068,24 @@ function reporting_get_agent_modules_table($id_agent, $period=0, $date=0) /** * Get a detailed report of an agent * - * @param int Agent to get the report. - * @param int Period of time of the desired report. - * @param int Beginning date of the report in UNIX time (current date by default). - * @param bool Flag to return or echo the report (by default). + * @param integer $id_agent Agent to get the report. + * @param integer $period Period of time of the desired report. + * @param integer $date Beginning date of the report in UNIX time + * (current date by default). + * @param boolean $return Flag to return or echo the report (by default). * * @return string */ -function reporting_get_agent_detailed($id_agent, $period=0, $date=0, $return=false) -{ +function reporting_get_agent_detailed( + $id_agent, + $period=0, + $date=0, + $return=false +) { $output = ''; $n_a_string = __('N/A(*)'); - // Show modules in agent + // Show modules in agent. $output .= '
    '; $output .= '

    '.__('Agent').' - '.agents_get_alias($id_agent).'

    '; $output .= '

    '.__('Modules').'

    '; @@ -3264,17 +4093,17 @@ function reporting_get_agent_detailed($id_agent, $period=0, $date=0, $return=fal $table_modules->width = '99%'; $output .= html_print_table($table_modules, true); - // Show alerts in agent + // Show alerts in agent. $table_alerts = reporting_get_agent_alerts_table($id_agent, $period, $date); $table_alerts->width = '99%'; - if (sizeof($table_alerts->data)) { + if (count($table_alerts->data)) { $output .= '

    '.__('Alerts').'

    '; $output .= html_print_table($table_alerts, true); } - // Show monitor status in agent (if any) + // Show monitor status in agent (if any). $table_monitors = reporting_get_agent_monitors_table($id_agent, $period, $date); - if (sizeof($table_monitors->data) == 0) { + if (count($table_monitors->data) == 0) { $output .= '
    '; if (! $return) { echo $output; @@ -3467,12 +4296,12 @@ function reporting_get_agents_by_status($data, $graph_width=250, $graph_height=1 if (!defined('METACONSOLE')) { $agents_data = '
    - '.__('Agents by status').''.html_print_table($table_agent, true).'
    '; + '.__('Agents by status').''.html_print_table($table_agent, true).''; } else { $table_agent->style = []; $table_agent->class = 'tactical_view'; $agents_data = '
    - '.__('Agents by status').''.html_print_table($table_agent, true).'
    '; + '.__('Agents by status').''.html_print_table($table_agent, true).''; } return $agents_data; @@ -3495,7 +4324,7 @@ function reporting_get_total_agents_and_monitors($data, $graph_width=250, $graph $total_data[3] = $total_module <= 0 ? '-' : $total_module; $table_total->data[] = $total_data; $total_agent_module = '
    - '.__('Total agents and monitors').''.html_print_table($table_total, true).'
    '; + '.__('Total agents and monitors').''.html_print_table($table_total, true).''; return $total_agent_module; } @@ -3514,12 +4343,12 @@ function reporting_get_total_servers($num_servers) if (!defined('METACONSOLE')) { $node_overview = '
    - '.__('Node overview').''.html_print_table($table_node, true).'
    '; + '.__('Node overview').''.html_print_table($table_node, true).''; } else { $table_node->style = []; $table_node->class = 'tactical_view'; $node_overview = '
    - '.__('Node overview').''.html_print_table($table_node, true).'
    '; + '.__('Node overview').''.html_print_table($table_node, true).''; } return $node_overview; @@ -3563,7 +4392,7 @@ function reporting_get_events($data, $links=false) if (!defined('METACONSOLE')) { $event_view = '
    - '.__('Events by severity').''.html_print_table($table_events, true).'
    '; + '.__('Events by severity').''.html_print_table($table_events, true).''; } else { $table_events->class = 'tactical_view'; $table_events->styleTable = 'text-align:center;'; @@ -3573,7 +4402,7 @@ function reporting_get_events($data, $links=false) $table_events->size[3] = '10%'; $event_view = '
    - '.__('Important Events by Criticity').''.html_print_table($table_events, true).'
    '; + '.__('Important Events by Criticity').''.html_print_table($table_events, true).''; } return $event_view; @@ -3605,9 +4434,9 @@ function reporting_get_last_activity() case 'mysql': $sql = sprintf( 'SELECT id_usuario,accion,fecha,ip_origen,descripcion,utimestamp - FROM tsesion - WHERE (`utimestamp` > UNIX_TIMESTAMP(NOW()) - '.SECONDS_1WEEK.") - AND `id_usuario` = '%s' ORDER BY `utimestamp` DESC LIMIT 5", + FROM tsesion + WHERE (`utimestamp` > UNIX_TIMESTAMP(NOW()) - '.SECONDS_1WEEK.") + AND `id_usuario` = '%s' ORDER BY `utimestamp` DESC LIMIT 5", $config['id_user'] ); break; @@ -3615,9 +4444,9 @@ function reporting_get_last_activity() case 'postgresql': $sql = sprintf( "SELECT \"id_usuario\", accion, fecha, \"ip_origen\", descripcion, utimestamp - FROM tsesion - WHERE (\"utimestamp\" > ceil(date_part('epoch', CURRENT_TIMESTAMP)) - ".SECONDS_1WEEK.") - AND \"id_usuario\" = '%s' ORDER BY \"utimestamp\" DESC LIMIT 5", + FROM tsesion + WHERE (\"utimestamp\" > ceil(date_part('epoch', CURRENT_TIMESTAMP)) - ".SECONDS_1WEEK.") + AND \"id_usuario\" = '%s' ORDER BY \"utimestamp\" DESC LIMIT 5", $config['id_user'] ); break; @@ -3625,9 +4454,9 @@ function reporting_get_last_activity() case 'oracle': $sql = sprintf( "SELECT id_usuario, accion, fecha, ip_origen, descripcion, utimestamp - FROM tsesion - WHERE ((utimestamp > ceil((sysdate - to_date('19700101000000','YYYYMMDDHH24MISS')) * (".SECONDS_1DAY.')) - '.SECONDS_1WEEK.") - AND id_usuario = '%s') AND rownum <= 10 ORDER BY utimestamp DESC", + FROM tsesion + WHERE ((utimestamp > ceil((sysdate - to_date('19700101000000','YYYYMMDDHH24MISS')) * (".SECONDS_1DAY.')) - '.SECONDS_1WEEK.") + AND id_usuario = '%s') AND rownum <= 10 ORDER BY utimestamp DESC", $config['id_user'] ); break; @@ -3793,7 +4622,7 @@ function reporting_get_event_histogram($events, $text_header_event=false) [], true, $ttl, - false, + true, false ); @@ -3805,7 +4634,7 @@ function reporting_get_event_histogram($events, $text_header_event=false) if (!defined('METACONSOLE')) { if (!$text_header_event) { $event_graph = '
    - '.$text_header_event.''.html_print_table($table, true).'
    '; + '.$text_header_event.''.html_print_table($table, true).''; } else { $table->class = 'noclass'; $event_graph = html_print_table($table, true); @@ -3903,9 +4732,9 @@ function reporting_get_event_histogram_meta($width) $time_condition = 'utimestamp > '.$bottom.' AND utimestamp < '.$top; $sql = sprintf( 'SELECT criticity,utimestamp - FROM tmetaconsole_event - WHERE %s %s %s - ORDER BY criticity DESC', + FROM tmetaconsole_event + WHERE %s %s %s + ORDER BY criticity DESC', $time_condition, $groups_condition, $status_condition @@ -3989,7 +4818,7 @@ function reporting_get_event_histogram_meta($width) if (!$text_header_event) { $event_graph = '
    - '.$text_header_event.''.html_print_table($table, true).'
    '; + '.$text_header_event.''.html_print_table($table, true).''; } else { $table->class = 'noclass'; $event_graph = html_print_table($table, true); @@ -3999,6 +4828,65 @@ function reporting_get_event_histogram_meta($width) } +/** + * Print network traffic data into top n tables + * (one for received data and another for sent) + * + * @param stdClass Table class to paint the report + * @param array Associative array with info about + * @param bool Unused + */ +function reporting_html_nt_top_n($table, $item, $mini) +{ + // Prepare the table + $table_top = new stdClass(); + $table_top->cellpadding = 0; + $table_top->cellspacing = 0; + $table_top->width = '100%'; + $table_top->class = 'databox data'; + $table_top->cellpadding = 0; + $table_top->cellspacing = 0; + $table_top->width = '100%'; + $table_top->class = 'databox data'; + $table_top->head['host'] = __('Agent'); + $table_top->head['bytes'] = __('Kilobytes'); + $table_top->head['pkts'] = __('Packages'); + + // Build the table for sent packages + if (empty($item['data']['send'])) { + $table->data['send_title'] = '

    '.__('No network traffic sent data').'

    '; + } else { + foreach ($item['data']['send'] as $s_item) { + $table_top->data[] = [ + 'host' => $s_item['host'], + 'bytes' => remove_right_zeros(number_format(($s_item['sum_bytes'] / 1024), $config['graph_precision'])), + 'pkts' => remove_right_zeros(number_format($s_item['sum_pkts'], $config['graph_precision'])), + ]; + } + + $table->data['send_title'] = '

    '.__('Network traffic sent').'

    '; + $table->data['send'] = html_print_table($table_top, true); + } + + // Reset the table and build the table for received packages + $table_top->data = []; + if (empty($item['data']['send'])) { + $table->data['recv_title'] = '

    '.__('No network traffic received data').'

    '; + } else { + foreach ($item['data']['recv'] as $s_item) { + $table_top->data[] = [ + 'host' => $s_item['host'], + 'bytes' => remove_right_zeros(number_format(($s_item['sum_bytes'] / 1024), $config['graph_precision'])), + 'pkts' => remove_right_zeros(number_format($s_item['sum_pkts'], $config['graph_precision'])), + ]; + } + + $table->data['recv_title'] = '

    '.__('Network traffic received').'

    '; + $table->data['recv'] = html_print_table($table_top, true); + } +} + + function reporting_html_planned_downtimes_table($planned_downtimes) { global $config; @@ -4014,7 +4902,10 @@ function reporting_html_planned_downtimes_table($planned_downtimes) $table = new StdClass(); $table->width = '99%'; - $table->title = __('This SLA has been affected by the following planned downtimes'); + $table->title = __('This SLA has been affected by the following planned downtimes').ui_print_help_tip( + __('If the duration of the planned downtime is less than 5 minutes it will not be represented in the graph'), + true + ); $table->head = []; $table->head[0] = __('Name'); $table->head[1] = __('Description'); @@ -4026,7 +4917,7 @@ function reporting_html_planned_downtimes_table($planned_downtimes) if ($for_pdf) { $table->titlestyle = 'background: #373737; color: #FFF; display: table-cell; font-size: 12px; border: 1px solid grey'; - $table->class = 'table_sla table_beauty'; + $table->class = 'table_sla'; for ($i = 0; $i < count($table->head); $i++) { $table->headstyle[$i] = 'background: #666; color: #FFF; display: table-cell; font-size: 11px; border: 1px solid grey'; diff --git a/pandora_console/include/functions_reporting_xml.php b/pandora_console/include/functions_reporting_xml.php index d1b28ac2a0..91e3288d83 100644 --- a/pandora_console/include/functions_reporting_xml.php +++ b/pandora_console/include/functions_reporting_xml.php @@ -11,10 +11,10 @@ // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -require_once 'include/functions_modules.php'; -require_once 'include/functions_events.php'; -require_once 'include/functions_groups.php'; -require_once 'include/functions_netflow.php'; +require_once __DIR__.'/functions_modules.php'; +require_once __DIR__.'/functions_events.php'; +require_once __DIR__.'/functions_groups.php'; +require_once __DIR__.'/functions_netflow.php'; enterprise_include_once('include/functions_metaconsole.php'); @@ -31,7 +31,7 @@ function reporting_xml_get_report($report, $filename, $return=false) unset($report['private']); unset($report['custom_logo']); // ---------------------------------------------------------------------- - // change agent name + // change agent name. if (count($report['contents']) > 0) { for ($i = 0; $i < count($report['contents']); $i++) { $aux = explode('-', $report['contents'][$i]['subtitle']); @@ -44,16 +44,18 @@ function reporting_xml_get_report($report, $filename, $return=false) $xml = preg_replace('/(<[^>]+>)(<[^>]+>)(<[^>]+>)/', "$1\n$2\n$3", $xml); $xml = preg_replace('/(<[^>]+>)(<[^>]+>)/', "$1\n$2", $xml); - // Return if is marked to return + // Return if is marked to return. if ($return) { return $xml; } - // Download if marked to download - header('Content-Type: application/xml; charset=UTF-8'); - header('Content-Disposition: attachment; filename="'.$filename.'.xml"'); + // Download if marked to download. + if ($filename !== false) { + header('Content-Type: application/xml; charset=UTF-8'); + header('Content-Disposition: attachment; filename="'.$filename.'.xml"'); + } - // Clean the output buffer + // Clean the output buffer. ob_clean(); echo $xml; diff --git a/pandora_console/include/functions_reports.php b/pandora_console/include/functions_reports.php index fd68aa0da2..0bf1f8fe70 100755 --- a/pandora_console/include/functions_reports.php +++ b/pandora_console/include/functions_reports.php @@ -867,18 +867,10 @@ function reports_get_report_types($template=false, $not_editor=false) 'optgroup' => __('Netflow'), 'name' => __('Netflow area chart'), ]; - $types['netflow_pie'] = [ - 'optgroup' => __('Netflow'), - 'name' => __('Netflow pie chart'), - ]; $types['netflow_data'] = [ 'optgroup' => __('Netflow'), 'name' => __('Netflow data table'), ]; - $types['netflow_statistics'] = [ - 'optgroup' => __('Netflow'), - 'name' => __('Netflow statistics table'), - ]; $types['netflow_summary'] = [ 'optgroup' => __('Netflow'), 'name' => __('Netflow summary table'), @@ -892,5 +884,10 @@ function reports_get_report_types($template=false, $not_editor=false) ]; } + $types['nt_top_n'] = [ + 'optgroup' => __('Network traffic'), + 'name' => __('Network Traffic Top N'), + ]; + return $types; } diff --git a/pandora_console/include/functions_servers.php b/pandora_console/include/functions_servers.php index 3081e076b6..0850dcbfac 100644 --- a/pandora_console/include/functions_servers.php +++ b/pandora_console/include/functions_servers.php @@ -1,22 +1,33 @@ __('Recon server')]); + case SERVER_TYPE_DISCOVERY: + $server['img'] = html_print_image('images/recon.png', true, ['title' => __('Discovery server')]); $server['type'] = 'recon'; $id_modulo = 0; break; @@ -589,11 +652,11 @@ function servers_get_info($id_server=-1) $server['lag'] = 0; $server['module_lag'] = 0; } - // Recon server - else if ($server['server_type'] == SERVER_TYPE_RECON) { + // Discovery server + else if ($server['server_type'] == SERVER_TYPE_DISCOVERY) { $server['name'] = ''.$server['name'].''; - // Total jobs running on this recon server + // Total jobs running on this Discovery server $server['modules'] = db_get_sql( 'SELECT COUNT(id_rt) FROM trecon_task @@ -921,3 +984,67 @@ function servers_get_status($id_server) $serverinfo = servers_get_info($id_server); return $serverinfo[$id_server]; } + + +/** + * Return server name based on identifier. + * + * @param integer $server Server identifier. + * + * @return string Server name + */ +function servers_get_server_string_name(int $server) +{ + switch ($server) { + case SERVER_TYPE_DATA: + return __('Data server'); + + case SERVER_TYPE_NETWORK: + return __('Network server'); + + case SERVER_TYPE_SNMP: + return __('SNMP server'); + + case SERVER_TYPE_ENTERPRISE_ICMP: + return __('Enterprise ICMP server'); + + case SERVER_TYPE_ENTERPRISE_SNMP: + return __('Enterprise SNMP server'); + + case SERVER_TYPE_PLUGIN: + return __('Plugin server'); + + case SERVER_TYPE_PREDICTION: + return __('Prediction Server'); + + case SERVER_TYPE_WMI: + return __('WMI server'); + + case SERVER_TYPE_WEB: + return __('Web server'); + + case SERVER_TYPE_EXPORT: + return __('Export server'); + + case SERVER_TYPE_INVENTORY: + return __('Inventory server'); + + case SERVER_TYPE_EVENT: + return __('Event server'); + + case SERVER_TYPE_DISCOVERY: + return __('Discovery server'); + + case SERVER_TYPE_SYSLOG: + return __('Syslog server'); + + case SERVER_TYPE_WUX: + return __('WUX server'); + + case SERVER_TYPE_ENTERPRISE_SATELLITE: + return __('Satellite'); + + default: + return __('N/A'); + } +} diff --git a/pandora_console/include/functions_snmp_browser.php b/pandora_console/include/functions_snmp_browser.php index 57bc416c76..ca2b2d055b 100644 --- a/pandora_console/include/functions_snmp_browser.php +++ b/pandora_console/include/functions_snmp_browser.php @@ -1,125 +1,240 @@ id_name)) or filters filtered + * Generates a Tree with given $tree information. * - * @param tree string SNMP tree returned by snmp_broser_get_tree. - * @param id string Level ID. Do not set, used for recursion. - * @param depth string Branch depth. Do not set, used for recursion. + * Selects all netflow filters (array (id_name => id_name)) or filters filtered + * Used also in Cloud Wizard. + * + * @param string $tree SNMP tree returned by snmp_broser_get_tree. + * @param string $id Level ID. Do not set, used for recursion. + * @param string $depth Branch depth. Do not set, used for recursion. + * @param integer $last Last. + * @param array $last_array Last_array. + * @param string $sufix Sufix. + * @param array $checked Checked. + * @param boolean $descriptive_ids Descriptive_ids. + * @param string $previous_id Previous_id. + * + * @return string HTML code with complete tree. */ -function snmp_browser_print_tree($tree, $id=0, $depth=0, $last=0, $last_array=[]) -{ +function snmp_browser_get_html_tree( + $tree, + $id=0, + $depth=0, + $last=0, + $last_array=[], + $sufix=false, + $checked=[], + $descriptive_ids=false, + $previous_id='' +) { static $url = false; - // Get the base URL for images + $output = ''; + + // Get the base URL for images. if ($url === false) { $url = ui_get_full_url('operation/tree', false, false, false); } - // Leaf + // Leaf. if (empty($tree['__LEAVES__'])) { - return; + return ''; } $count = 0; - $total = (sizeof(array_keys($tree['__LEAVES__'])) - 1); + $total = (count(array_keys($tree['__LEAVES__'])) - 1); $last_array[$depth] = $last; if ($depth > 0) { - echo " +
  • Id of the user who fires the response: _current_user_
  • +

    Custom fields

    diff --git a/pandora_console/include/help/es/help_alert_config.php b/pandora_console/include/help/es/help_alert_config.php index 3c6d0b8e53..ec219d87ca 100644 --- a/pandora_console/include/help/es/help_alert_config.php +++ b/pandora_console/include/help/es/help_alert_config.php @@ -54,6 +54,7 @@ Además de las macros de módulo definidas, las siguientes macros están disponi
  • _event_extra_id_ : (Solo alertas de evento) Id extra.
  • _event_id_: (Solo alertas de evento) Id del evento que disparó la alerta.
  • _event_text_severity_: (Solo alertas de evento) Prioridad en texto de el evento que dispara la alerta (Maintenance, Informational, Normal Minor, Warning, Major, Critical).
  • +
  • _eventTimestamp_: Timestamp en el que se creo el evento.
  • _field1_: Campo 1 definido por el usuario.
  • _field2_: Campo 2 definido por el usuario.
  • _field3_: Campo 3 definido por el usuario.
  • diff --git a/pandora_console/include/help/es/help_alert_macros.php b/pandora_console/include/help/es/help_alert_macros.php index de420b31c7..75e627f19a 100644 --- a/pandora_console/include/help/es/help_alert_macros.php +++ b/pandora_console/include/help/es/help_alert_macros.php @@ -37,6 +37,7 @@ Además de las macros de módulo definidas, las siguientes macros están disponi
  • _event_extra_id_ : (Solo alertas de evento) Id extra.
  • _event_id_: (Solo alertas de evento) Id del evento que disparó la alerta.
  • _event_text_severity_:(Solo alertas de evento) Prioridad en texto de el evento que dispara la alerta (Maintenance, Informational, Normal Minor, Warning, Major, Critical).
  • +
  • _eventTimestamp_: Timestamp en el que se creo el evento.
  • _field1_: Campo 1 definido por el usuario.
  • _field2_: Campo 2 definido por el usuario.
  • _field3_: Campo 3 definido por el usuario.
  • diff --git a/pandora_console/include/help/es/help_column_macros.php b/pandora_console/include/help/es/help_column_macros.php new file mode 100644 index 0000000000..b34ede1555 --- /dev/null +++ b/pandora_console/include/help/es/help_column_macros.php @@ -0,0 +1,13 @@ + +

    Macros de módulos

    + +

    +Las siguientes macros están disponibles: +

    +
      +
    • _agentcustomfield_n_: Campo personalizado número n del agente (eg. _agentcustomfield_9_).
    • +
    diff --git a/pandora_console/include/help/es/help_custom_logo.php b/pandora_console/include/help/es/help_custom_logo.php index 2f39432fd7..53b814f25b 100644 --- a/pandora_console/include/help/es/help_custom_logo.php +++ b/pandora_console/include/help/es/help_custom_logo.php @@ -1,15 +1,12 @@ -

    Logo de Cliente (Marca comunitaria de empresa)

    - -Esta opción se utiliza para poder desplegar su propio logo en la cabecera de . Puede utilizar cualquier tipo de gráfica en formato PNG. Hay una ancho/alto para cualquier imagen desplegada aquí de 206x47 píxeles. +

    Logo (Marca de empresa)

    +Esta opción sirve para poder subir su propio logo, que estará visible en el menú de . Este logo será visible cuando el menú esté desplegado.

    - -Suba su logo de marca de empresa utilizando el directorio /images/custom_logo directory. - - - +La imagen debe tener el formato PNG y un tamaño de 215x60 pixeles. +

    +Debe subir su logo al directorio /images/custom_logo. diff --git a/pandora_console/include/help/es/help_custom_logo_collapsed.php b/pandora_console/include/help/es/help_custom_logo_collapsed.php new file mode 100644 index 0000000000..05fabf5318 --- /dev/null +++ b/pandora_console/include/help/es/help_custom_logo_collapsed.php @@ -0,0 +1,12 @@ + +

    Logo (Marca de empresa)

    + +Esta opción sirve para poder subir su propio logo, que estará visible en el menú de . Este logo será visible cuando el menú esté plegado. +

    +La imagen debe tener el formato PNG y un tamaño de 60x60 pixeles. +

    +Debe subir su logo al directorio /images/custom_logo. diff --git a/pandora_console/include/help/es/help_response_macros.php b/pandora_console/include/help/es/help_response_macros.php index adc43b4f48..5a860f1548 100644 --- a/pandora_console/include/help/es/help_response_macros.php +++ b/pandora_console/include/help/es/help_response_macros.php @@ -33,6 +33,7 @@ Las macros aceptadas son las siguientes:
  • Nombre del módulo asociado al evento: _module_name_
  • Usuario propietario del evento: _owner_user_
  • Id del usuario: _user_id_
  • +
  • Id del usuario que ejecuta la respuesta: _current_user_
  • Campos personalizados

    diff --git a/pandora_console/include/help/ja/help_alert_config.php b/pandora_console/include/help/ja/help_alert_config.php index 21e12b1baf..b606b1571f 100644 --- a/pandora_console/include/help/ja/help_alert_config.php +++ b/pandora_console/include/help/ja/help_alert_config.php @@ -53,6 +53,7 @@ email アクションを設定するには、_field1_ (送信先アドレス)、
  • _event_extra_id_: (イベントアラートのみ) 拡張 ID
  • _event_id_ : (イベントアラートのみ) アラート発生元のイベントID
  • _event_text_severity_ : (イベントアラートのみ) イベント(アラートの発生元)のテキストでの重要度 (Maintenance, Informational, Normal Minor, Warning, Major, Critical)
  • +
  • _eventTimestamp_: Timestamp in which the event was created.
  • _field1_ : ユーザ定義フィールド1
  • _field2_ : ユーザ定義フィールド2
  • _field3_ : ユーザ定義フィールド3
  • diff --git a/pandora_console/include/help/ja/help_alert_macros.php b/pandora_console/include/help/ja/help_alert_macros.php index 73ca00126e..36ff609741 100644 --- a/pandora_console/include/help/ja/help_alert_macros.php +++ b/pandora_console/include/help/ja/help_alert_macros.php @@ -37,6 +37,7 @@
  • _event_extra_id_: (Only event alerts) Extra id.
  • _event_id_ : (イベントアラートのみ) アラート発生元のイベントID
  • _event_text_severity_ : (イベントアラートのみ) イベント(アラートの発生元)のテキストでの重要度 (Maintenance, Informational, Normal Minor, Warning, Major, Critical)
  • +
  • _eventTimestamp_: Timestamp in which the event was created.
  • _field1_ : ユーザ定義フィールド1
  • _field2_ : ユーザ定義フィールド2
  • _field3_ : ユーザ定義フィールド3
  • diff --git a/pandora_console/include/help/ja/help_column_macros.php b/pandora_console/include/help/ja/help_column_macros.php new file mode 100644 index 0000000000..9d925b1193 --- /dev/null +++ b/pandora_console/include/help/ja/help_column_macros.php @@ -0,0 +1,15 @@ + +

    モジュールマクロ

    + +

    +次のマクロが利用できます: +

    +
      +
    • _agentcustomfield_n_ : エージェントカスタムフィールド番号n (例: _agentcustomfield_9_).
    • +
    +

    +

    diff --git a/pandora_console/include/help/ja/help_custom_logo.php b/pandora_console/include/help/ja/help_custom_logo.php index f9863b7e15..6e0a7823a6 100644 --- a/pandora_console/include/help/ja/help_custom_logo.php +++ b/pandora_console/include/help/ja/help_custom_logo.php @@ -5,8 +5,8 @@ ?>

    カスタムロゴ

    -ここに指定した画像ファイルを、オリジナルロゴとして のヘッダーに表示することができます。 -表示可能な画像ファイルは PNG 形式です。 -画像サイズは、206x47ピクセルに修正されます。 +This option allows uploading your own logo, which will be visible in the menu. This logo will be visible when the menu is expanded.

    -カスタムロゴは、ファイルマネージャを使って /images/custom_logo ディレクトリへアップロードしてください。 +The image must have PNG format and a size of 215x60 pixels. +

    +You must upload your logo to the /images/custom_logo directory. diff --git a/pandora_console/include/help/ja/help_custom_logo_collapsed.php b/pandora_console/include/help/ja/help_custom_logo_collapsed.php new file mode 100644 index 0000000000..53630fceda --- /dev/null +++ b/pandora_console/include/help/ja/help_custom_logo_collapsed.php @@ -0,0 +1,13 @@ + +

    カスタムロゴ

    + +This option allows uploading your own logo, which will be visible in the menu. This logo will be visible when the menu is collapsed. +

    +The image must have PNG format and a size of 60x60 pixels. +

    +You must upload your logo to the /images/custom_logo directory. + diff --git a/pandora_console/include/help/ja/help_recontask.php b/pandora_console/include/help/ja/help_recontask.php index 790c2cdb48..182b249653 100644 --- a/pandora_console/include/help/ja/help_recontask.php +++ b/pandora_console/include/help/ja/help_recontask.php @@ -12,7 +12,7 @@ 検出タスクの名前です。フィルターやテンプレートとは異なり、タスクを区別しやすい説明を入れるだけです。

    -自動検出サーバ(Recon server)
    +自動検出サーバ(Discovery server)
    タスクを割り当てる自動検出サーバです。複数の自動検出サーバがある場合は、自動検出タスクをどのサーバで実行するかを選択します。

    diff --git a/pandora_console/include/help/ja/help_response_macros.php b/pandora_console/include/help/ja/help_response_macros.php index 1aa60b38a4..8beebc7a8d 100644 --- a/pandora_console/include/help/ja/help_response_macros.php +++ b/pandora_console/include/help/ja/help_response_macros.php @@ -32,6 +32,7 @@
  • Event associated module name: _module_name_
  • Event owner user: _owner_user_
  • User ID: _user_id_
  • +
  • Id of the user who fires the response: _current_user_
  • Custom fields

    diff --git a/pandora_console/include/javascript/functions_pandora_networkmap.js b/pandora_console/include/javascript/functions_pandora_networkmap.js index 4c9f5b61b7..c2335903d7 100644 --- a/pandora_console/include/javascript/functions_pandora_networkmap.js +++ b/pandora_console/include/javascript/functions_pandora_networkmap.js @@ -1,5 +1,49 @@ +/* global jQuery */ +/* global $ */ +/* global context_minimap */ +/* global minimap_w */ +/* global minimap_h */ +/* global minimap_relation */ +/* global graph */ +/* global translation */ +/* global scale */ +/* global width_svg */ +/* global height_svg */ +/* global networkmap_dimensions */ +/* global node_radius */ +/* global holding_area_dimensions */ +/* global networkmap_id */ +/* global enterprise_installed */ +/* global force */ +/* global layer_graph_nodes */ +/* global layer_graph_links */ +/* global ellipsize */ +/* global d3 */ +/* global dialog_node_edit_title */ +/* global click_menu_position_svg */ +/* global show_labels:true */ +/* global show_minimap:true */ +/* global layer_graph */ +/* global zoom_obj */ +/* global disabled_drag_zoom */ +/* global scale:true */ +/* global link */ +/* global siblingCount:true */ +/* global xRotation:true */ +/* global largeArc:true */ +/* global node */ + +/* exported delete_link */ +/* exported update_fictional_node */ +/* exported update_node_name */ +/* exported change_shape */ +/* exported add_agent_node_from_the_filter_group */ +/* exported hide_labels */ +/* exported toggle_minimap */ +/* exported over_node */ + function draw_minimap() { - //Clean the canvas + // Clean the canvas. context_minimap.clearRect(0, 0, minimap_w, minimap_h); context_minimap.beginPath(); @@ -20,6 +64,9 @@ function draw_minimap() { jQuery.each(graph.nodes, function(key, value) { if (typeof value == "undefined") return; + var center_orig_x; + var center_orig_y; + context_minimap.beginPath(); //Paint the item if (graph.nodes.length > 100) { @@ -36,7 +83,7 @@ function draw_minimap() { context_minimap.arc(center_orig_x, center_orig_y, 2, 0, Math.PI * 2, false); //Check if the pandora point - if (value.id_agent == -1) { + if (value.type == 2) { context_minimap.fillStyle = "#364D1F"; } else { context_minimap.fillStyle = "#000"; @@ -96,11 +143,11 @@ function inner_minimap_box(param_x, param_y) { return false; } -function set_center(id, event) { - pos_x = width_svg / 2 - translation[0] / scale; - pos_y = height_svg / 2 - translation[1] / scale; - +function set_center(id) { + var pos_x = width_svg / 2 - translation[0] / scale; + var pos_y = height_svg / 2 - translation[1] / scale; var params = []; + params.push("set_center=1"); params.push("id=" + id); params.push("x=" + pos_x); @@ -111,11 +158,7 @@ function set_center(id, event) { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), - success: function(data) { - if (data["correct"]) { - } - } + url: "ajax.php" }); } @@ -164,7 +207,7 @@ function delete_link( data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { if (data["correct"]) { var found = -1; @@ -222,7 +265,7 @@ function update_fictional_node(id_db_node) { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { if (data["correct"]) { $("#dialog_node_edit").dialog("close"); @@ -262,7 +305,7 @@ function update_node_name(id_db_node) { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { if (data["correct"]) { $("#dialog_node_edit").dialog("close"); @@ -308,13 +351,13 @@ function change_shape(id_db_node) { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { $("#shape_icon_in_progress").css("display", "none"); if (data["correct"]) { $("#shape_icon_correct").css("display", ""); - count = graph.nodes.length; + var count = graph.nodes.length; jQuery.each(graph.nodes, function(i, element) { if (element.id_db == id_db_node) { @@ -585,7 +628,7 @@ function update_link(row_index, id_link) { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { $(".edit_icon_progress_" + row_index).css("display", "none"); @@ -607,12 +650,10 @@ function update_link(row_index, id_link) { "']" ).prop("selected", true); - var id = ""; var index = -1; $.each(graph.links, function(j, link) { if (link["id_db"] == id_link) { index = j; - id = String(id_link); } }); @@ -706,7 +747,7 @@ function move_to_networkmap(node) { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { if (data["correct"]) { window.location = @@ -726,6 +767,7 @@ function edit_node(data_node, dblClick) { //Only select one node var selection = d3.selectAll(".node_selected"); + var id; if (selection[0].length == 1) { edit_node = selection[0].pop(); @@ -746,12 +788,12 @@ function edit_node(data_node, dblClick) { .select(edit_node) .attr("id") .replace("id_node_", ""); - id_networkmap_lenght = networkmap_id.toString().length; - id_node_length = id.length - id_networkmap_lenght; + var id_networkmap_lenght = networkmap_id.toString().length; + var id_node_length = id.length - id_networkmap_lenght; id = id.substring(0, id_node_length); - node_selected = graph.nodes[id]; + var node_selected = graph.nodes[id]; - selected_links = get_relations(node_selected); + var selected_links = get_relations(node_selected); $( "select[name='shape'] option[value='" + node_selected.shape + "']" @@ -779,7 +821,7 @@ function edit_node(data_node, dblClick) { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { $("#node_details-0-1").html( '"; } } else { - for (address in data["adressess"]) { + for (var address in data["adressess"]) { addresses += address + "
    "; } } @@ -826,7 +868,7 @@ function edit_node(data_node, dblClick) { ); // It doesn't eval the possible XSS so it's ok $("#dialog_node_edit").dialog("open"); - if (node_selected.id_agent == undefined || node_selected.id_agent == -2) { + if (node_selected.id_agent == undefined || node_selected.type == 3) { //Fictional node $("#node_options-fictional_node_name").css("display", ""); $("input[name='edit_name_fictional_node']").val(node_selected.text); // It doesn't eval the possible XSS so it's ok @@ -868,7 +910,7 @@ function get_interface_data_to_table(node_selected, selected_links) { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { if (data.length == 0) { $("#interface_information") @@ -880,10 +922,11 @@ function get_interface_data_to_table(node_selected, selected_links) { ); } else { jQuery.each(data, function(j, interface) { + var interf_graph; if (interface["graph"] == "") { - var interf_graph = "--"; + interf_graph = "--"; } else { - var interf_graph = interface["graph"]; + interf_graph = interface["graph"]; } $("#interface_information") .find("tbody") @@ -955,7 +998,7 @@ function load_interfaces(selected_links) { type: "POST", async: true, cache: false, - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { if (data["correct"]) { $( @@ -1075,7 +1118,7 @@ function add_node() { } function add_agent_node_from_the_filter_group() { - agents = $("select[name='agents_filter_group']").val(); + var agents = $("select[name='agents_filter_group']").val(); add_agent_node(agents); } @@ -1122,7 +1165,7 @@ function add_agent_node(agents) { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { if (data["correct"]) { $("#agent_name").val(""); @@ -1210,24 +1253,17 @@ function add_agent_node(agents) { var temp_node = {}; temp_node["id"] = graph.nodes.length; - temp_node["id_db"] = data["id_node"]; - temp_node["id_agent"] = data["id_agent"]; + temp_node["id_db"] = graph.nodes.length; + temp_node["id_agent"] = id_agent; temp_node["id_module"] = ""; - temp_node["px"] = data["x"]; - temp_node["py"] = data["y"]; - temp_node["x"] = data["x"]; - temp_node["y"] = data["y"]; + temp_node["px"] = x; + temp_node["py"] = y; + temp_node["x"] = x; + temp_node["y"] = y; temp_node["z"] = 0; temp_node["fixed"] = true; temp_node["type"] = 0; - temp_node["color"] = data["status"]; - temp_node["shape"] = data["shape"]; - temp_node["text"] = data["text"]; - temp_node["image_url"] = data["image_url"]; - temp_node["image_width"] = data["width"]; - temp_node["image_height"] = data["height"]; - temp_node["map_id"] = data["map_id"]; - temp_node["state"] = data["state"]; + temp_node["map_id"] = networkmap_id; graph.nodes.push(temp_node); } @@ -1248,7 +1284,7 @@ function hide_labels_function() { $("#hide_labels_" + networkmap_id + " > a").attr("title", "Show Labels"); $("#hide_labels_" + networkmap_id + " > a > img").attr( "src", - "images/icono_pintar.png" + window.location.origin + "/pandora_console/images/icono_pintar.png" ); d3.selectAll(".node_text").style("display", "none"); @@ -1261,7 +1297,7 @@ function show_labels_function() { $("#hide_labels_" + networkmap_id + " > a").attr("title", "Hide Labels"); $("#hide_labels_" + networkmap_id + " > a > img").attr( "src", - "images/icono_borrar.png" + window.location.origin + "/pandora_console/images//icono_borrar.png" ); d3.selectAll(".node_text").style("display", ""); @@ -1320,9 +1356,10 @@ function delete_nodes() { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { if (data["correct"]) { + var found = -1; do { found = -1; jQuery.each(graph.links, function(i, element) { @@ -1600,7 +1637,7 @@ function set_positions_graph() { } function over_node(d) { - over = d3.select("#id_node_" + d.id + networkmap_id).classed("node_over"); + var over = d3.select("#id_node_" + d.id + networkmap_id).classed("node_over"); in_a_node = !in_a_node; @@ -1644,7 +1681,8 @@ function clear_selection() { function update_networkmap() { if (enterprise_installed) { node.each(function(d) { - if (d.id_agent != -1) { + // Do not update Pandora FMS node. + if (d.type != 2) { var params = []; params.push("update_node_color=1"); params.push("id=" + d.id_db); @@ -1656,7 +1694,7 @@ function update_networkmap() { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { d3.select( "#id_node_" + d.id + networkmap_id + " .node_shape" @@ -1668,7 +1706,7 @@ function update_networkmap() { link.each(function(d) { if (d.id_module_start != 0 || d.id_module_end != 0) { - if (d.id_module_start != 0) { + if (d.id_module_start && d.id_module_start > 0) { var params = []; params.push("module_get_status=1"); params.push("page=operation/agentes/pandora_networkmap.view"); @@ -1677,7 +1715,7 @@ function update_networkmap() { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { d3.selectAll(".id_module_start_" + d.id_module_start).attr( "marker-start", @@ -1691,7 +1729,7 @@ function update_networkmap() { }); } - if (d.id_module_end != 0) { + if (d.id_module_end && d.id_module_end > 0) { var params = []; params.push("module_get_status=1"); params.push("page=operation/agentes/pandora_networkmap.view"); @@ -1700,7 +1738,7 @@ function update_networkmap() { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { d3.selectAll(".id_module_end_" + d.id_module_end).attr( "marker-end", @@ -1859,7 +1897,7 @@ function show_menu(item, data) { icon: "interface_link_children", disabled: function() { if (enterprise_installed) { - if (data.type == 3) { + if (data.type == 3 || data.type == 2) { return true; } else { return false; @@ -1929,7 +1967,7 @@ function show_menu(item, data) { icon: "interface_link_parent", disabled: function() { if (enterprise_installed) { - if (data.type == 3) { + if (data.type == 3 || data.type == 2) { return true; } else { return false; @@ -2015,7 +2053,8 @@ function show_menu(item, data) { }; } - if (data.id_agent != -1) { + // Avoid deletion if Pandora FMS node. + if (data.type != 2) { items_list["delete"] = { name: delete_menu, icon: "delete", @@ -2141,21 +2180,25 @@ function show_menu(item, data) { }; } - $.contextMenu("destroy"); - $.contextMenu({ - disabled: false, - selector: "#networkconsole_" + networkmap_id, - // define the elements of the menu - items: items_list - }); + if (typeof $.contextMenu == "function") { + $.contextMenu("destroy"); + $.contextMenu({ + disabled: false, + selector: "#networkconsole_" + networkmap_id, + // define the elements of the menu + items: items_list + }); + } break; } //Force to show in the mouse position - $("#networkconsole_" + networkmap_id).contextMenu({ - x: mouse[0], - y: mouse[1] - }); + if (typeof $("#networkconsole_" + networkmap_id).contextMenu == "function") { + $("#networkconsole_" + networkmap_id).contextMenu({ + x: mouse[0], + y: mouse[1] + }); + } } function add_interface_link(data_parent) { @@ -2205,7 +2248,7 @@ function add_interface_link(data_parent) { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { var parent_name = data_parent.text; var child_name = child_data.text; @@ -2250,32 +2293,32 @@ function add_interface_link_js() { cancel_set_parent_interface(); $("#dialog_interface_link").dialog("close"); - source_value = $("#interface_source_select").val(); - source_text = $("#interface_source_select") + var source_value = $("#interface_source_select").val(); + var source_text = $("#interface_source_select") .find("option:selected") .text(); - target_value = $("#interface_target_select").val(); - target_text = $("#interface_target_select") + var target_value = $("#interface_target_select").val(); + var target_text = $("#interface_target_select") .find("option:selected") .text(); - var params = []; - params.push("add_interface_relation=1"); - params.push("id=" + networkmap_id); - params.push("source_value=" + source_value); - params.push("target_value=" + target_value); - params.push("source_text=" + source_text); - params.push("target_text=" + target_text); - params.push("page=enterprise/operation/agentes/pandora_networkmap.view"); - jQuery.ajax({ - data: params.join("&"), + data: { + page: "enterprise/operation/agentes/pandora_networkmap.view", + add_interface_relation: 1, + id: networkmap_id, + source_value: source_value, + target_value: target_value, + source_text: source_text, + target_text: target_text + }, dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { if (data["correct"]) { var temp_link = {}; + temp_link["id"] = graph.links.length; temp_link["status_start"] = "0"; temp_link["status_end"] = "0"; @@ -2284,8 +2327,9 @@ function add_interface_link_js() { if (data["type_source"] == 1) { temp_link["arrow_start"] = "module"; temp_link["id_module_start"] = source_value; - temp_link["status_start"] = data["status"]; - temp_link["link_color"] = data["status"] == "1" ? "#FC4444" : "#999"; + temp_link["status_start"] = data["status_start"]; + temp_link["link_color"] = + data["status_start"] == "1" ? "#FC4444" : "#999"; } else { temp_link["arrow_start"] = ""; temp_link["id_agent_start"] = source_value; @@ -2294,8 +2338,9 @@ function add_interface_link_js() { if (data["type_target"] == 1) { temp_link["arrow_end"] = "module"; temp_link["id_module_end"] = target_value; - temp_link["status_end"] = data["status"]; - temp_link["link_color"] = data["status"] == "1" ? "#FC4444" : "#999"; + temp_link["status_end"] = data["status_end"]; + temp_link["link_color"] = + data["status_end"] == "1" ? "#FC4444" : "#999"; } else { temp_link["arrow_end"] = ""; temp_link["id_agent_end"] = target_value; @@ -2325,8 +2370,8 @@ function add_interface_link_js() { } function refresh_holding_area() { - holding_pos_x = d3.select("#holding_area_" + networkmap_id).attr("x"); - holding_pos_y = d3.select("#holding_area_" + networkmap_id).attr("y"); + var holding_pos_x = d3.select("#holding_area_" + networkmap_id).attr("x"); + var holding_pos_y = d3.select("#holding_area_" + networkmap_id).attr("y"); var pos_x = parseInt(holding_pos_x) + parseInt(node_radius); var pos_y = parseInt(holding_pos_y) + parseInt(node_radius); @@ -2342,7 +2387,7 @@ function refresh_holding_area() { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { if (data["correct"]) { window.holding_area = data["holding_area"]; @@ -2510,28 +2555,29 @@ function proceed_to_restart_map() { text: ok_button, click: function() { $(this).dialog("close"); - var new_elements = []; - new_elements[0] = $("#text-name").val(); - new_elements[1] = $("#id_group").val(); - new_elements[2] = $("#text-node_radius").val(); - new_elements[3] = $("#textarea_description").val(); - new_elements[4] = $("input[name=source]:checked").val(); - if (new_elements[4] == "group") { - new_elements[5] = $("#checkbox-dont_show_subgroups").is(":checked"); - } else if (new_elements[4] == "recon_task") { - new_elements[5] = $("#recon_task_id").val(); - } else { - new_elements[5] = $("#text-ip_mask").val(); - } - new_elements[6] = $("#method").val(); - new_elements[7] = $("#text-pos_x").val(); - new_elements[8] = $("#text-pos_y").val(); - new_elements[9] = $("#text-scale_z").val(); - new_elements[10] = $("#text-node_sep").val(); - new_elements[11] = $("#text-mindist").val(); - new_elements[12] = $("#text-rank_sep").val(); - new_elements[13] = $("#text-kval").val(); - reset_map_from_form(new_elements); + var data = { + params: { + name: $("#text-name").val(), + id_group: $("#id_group").val(), + node_radius: $("#text-node_radius").val(), + description: $("#textarea_description").val(), + source: $("input[name=source]:checked").val(), + dont_show_subgroups: $("#checkbox-dont_show_subgroups").is( + ":checked" + ), + recon_task_id: $("#recon_task_id").val(), + ip_mask: $("#text-ip_mask").val(), + generation_method: $("#method").val(), + pos_x: $("#text-pos_x").val(), + pos_y: $("#text-pos_y").val(), + scale_z: $("#text-scale_z").val(), + node_sep: $("#text-node_sep").val(), + mindist: $("#text-mindist").val(), + rank_sep: $("#text-rank_sep").val(), + kval: $("#text-kval").val() + } + }; + reset_map_from_form(data); } }, { @@ -2551,31 +2597,29 @@ function proceed_to_restart_map() { data: params.join("&"), dataType: "html", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { - $("#restart_map_form").html(data); - $("#restart_map_form").dialog("open"); + $("#restart_map_form") + .html(data) + .dialog("open"); } }); } function reset_map_from_form(new_elements) { - var params = []; - params.push("reset_map=1"); - params.push("map_id=" + networkmap_id); - params.push("elems[]=" + new_elements); - params.push("page=enterprise/operation/agentes/pandora_networkmap.view"); + var data = new_elements; + data.map_id = networkmap_id; + data.reset_map = 1; + data.page = "enterprise/operation/agentes/pandora_networkmap.view"; jQuery.ajax({ - data: params.join("&"), + data: data, dataType: "json", type: "POST", - url: (action = "ajax.php"), - success: function(data) { - if (!data["error"]) { - window.location = - "index.php?sec=network&sec2=operation/agentes/pandora_networkmap&tab=view&id_networkmap=" + - networkmap_id; - } + url: "ajax.php", + success: function(d) { + window.location = + "index.php?sec=network&sec2=operation/agentes/pandora_networkmap&tab=view&id_networkmap=" + + networkmap_id; } }); } @@ -2636,7 +2680,7 @@ function set_parent(parent_data) { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { if (data["correct"]) { //Add the relationship and paint @@ -2727,23 +2771,25 @@ function init_drag_and_drop() { var selection = d3.selectAll(".node_selected"); if (enterprise_installed) { - holding_pos_x = d3.select("#holding_area_" + networkmap_id).attr("x"); - holding_pos_y = d3.select("#holding_area_" + networkmap_id).attr("y"); + var holding_pos_x = d3 + .select("#holding_area_" + networkmap_id) + .attr("x"); + var holding_pos_y = d3 + .select("#holding_area_" + networkmap_id) + .attr("y"); delete d.raw_text; selection.each(function(d) { - var params = []; - params.push("update_node=1"); - params.push("node=" + JSON.stringify(d)); - params.push("x=" + holding_pos_x); - params.push("y=" + holding_pos_y); - params.push( - "page=enterprise/operation/agentes/pandora_networkmap.view" - ); jQuery.ajax({ - data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", + data: { + node: JSON.stringify(d), + x: holding_pos_x, + y: holding_pos_y, + update_node: 1, + page: "enterprise/operation/agentes/pandora_networkmap.view" + }, success: function(data) { if (d.state == "holding_area") { //It is out the holding area @@ -2777,7 +2823,7 @@ function init_drag_and_drop() { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { if (data["correct"]) { $("#open_version_dialog").dialog(); @@ -2840,7 +2886,7 @@ function add_fictional_node() { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { if (data["correct"]) { $("#dialog_node_add").dialog("close"); @@ -2909,6 +2955,13 @@ function init_graph(parameter_object) { window.height_svg = $(window).height() - $("#menu_tab_frame_view").height() - 20; // 20 of margin } + if (!window.height_svg) { + window.height_svg = $("#networkconsole_" + networkmap_id).height(); + } + + if (typeof parameter_object.font_size != "undefined") { + window.font_size = parameter_object.font_size; + } window.refresh_period = 5 * 1000; //milliseconds if (typeof parameter_object.refresh_period != "undefined") { @@ -3922,6 +3975,10 @@ function draw_elements_graph() { var font_size = node_radius / 1.5; + if (typeof window.font_size != "undefined") { + font_size = window.font_size; + } + node_temp .append("text") .attr("class", "node_text") @@ -3991,7 +4048,7 @@ function choose_group_for_show_agents() { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "ajax.php"), + url: "ajax.php", success: function(data) { if (data["correct"]) { $("#agents_filter_group").html(""); @@ -4013,162 +4070,6 @@ function choose_group_for_show_agents() { '" ); $("#spinner_group").css("display", "none"); - function show_networkmap_node(id_agent_param, refresh_state) { - id_agent = id_agent_param; - - canvas = $("#node_info"); - context_popup = canvas[0].getContext("2d"); - - dirty_popup = true; - self.setInterval("check_popup_modification()", 1000 / 30); - - $("#node_info").mousemove(function(event) { - var x = event.pageX - $("#node_info").offset().left; - var y = event.pageY - $("#node_info").offset().top; - - module_inner = inner_module(x, y); - - if (module_inner != null) { - document.body.style.cursor = "pointer"; - } else { - document.body.style.cursor = "default"; - } - }); - - $("#node_info").mousedown(function(event) { - var x = event.pageX - $("#node_info").offset().left; - var y = event.pageY - $("#node_info").offset().top; - - if (module_inner != null) { - show_tooltip(module_inner, x, y); - } - - event.stopPropagation(); - return false; - }); - - $("#node_info").mouseup(function(event) { - var x = event.pageX - $("#node_info").offset().left; - var y = event.pageY - $("#node_info").offset().top; - - drag = false; - drag_x = 0; - drag_y = 0; - dirty_popup = true; - - document.body.style.cursor = "default"; - - module_inner = null; - - event.stopPropagation(); - return false; - }); - - $("#node_info").mouseout(function(event) { - var x = event.pageX - $("#node_info").offset().left; - var y = event.pageY - $("#node_info").offset().top; - - drag = false; - drag_x = 0; - drag_y = 0; - dirty_popup = true; - - document.body.style.cursor = "default"; - - module_inner = null; - - event.stopPropagation(); - return false; - }); - - $(window).resize(function() { - function show_networkmap_node(id_agent_param, refresh_state) { - id_agent = id_agent_param; - - canvas = $("#node_info"); - context_popup = canvas[0].getContext("2d"); - - dirty_popup = true; - self.setInterval("check_popup_modification()", 1000 / 30); - - $("#node_info").mousemove(function(event) { - var x = event.pageX - $("#node_info").offset().left; - var y = event.pageY - $("#node_info").offset().top; - - module_inner = inner_module(x, y); - - if (module_inner != null) { - document.body.style.cursor = "pointer"; - } else { - document.body.style.cursor = "default"; - } - }); - - $("#node_info").mousedown(function(event) { - var x = event.pageX - $("#node_info").offset().left; - var y = event.pageY - $("#node_info").offset().top; - - if (module_inner != null) { - show_tooltip(module_inner, x, y); - } - - event.stopPropagation(); - return false; - }); - - $("#node_info").mouseup(function(event) { - var x = event.pageX - $("#node_info").offset().left; - var y = event.pageY - $("#node_info").offset().top; - - drag = false; - drag_x = 0; - drag_y = 0; - dirty_popup = true; - - document.body.style.cursor = "default"; - - module_inner = null; - - event.stopPropagation(); - return false; - }); - - $("#node_info").mouseout(function(event) { - var x = event.pageX - $("#node_info").offset().left; - var y = event.pageY - $("#node_info").offset().top; - - drag = false; - drag_x = 0; - drag_y = 0; - dirty_popup = true; - - document.body.style.cursor = "default"; - - module_inner = null; - - event.stopPropagation(); - return false; - }); - - $(window).resize(function() { - pos_scroll = Math.floor( - $("#content_node_info").width() / 2 - ); - - $("#content_node_info").scrollLeft(pos_scroll); - - dirty_popup = true; - check_popup_modification(); - }); - } - pos_scroll = Math.floor($("#content_node_info").width() / 2); - - $("#content_node_info").scrollLeft(pos_scroll); - - dirty_popup = true; - check_popup_modification(); - }); - } } } }); @@ -4213,7 +4114,7 @@ function get_status_node() { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "../../../ajax.php"), + url: "../../../ajax.php", success: function(data) { if (data["correct"]) { color_status_node = data["status_agent"]; @@ -4235,7 +4136,7 @@ function get_status_module() { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "../../../ajax.php"), + url: "../../../ajax.php", success: function(data) { if (data["correct"]) { modules[data["id"]].status_color = data["status_color"]; @@ -4333,7 +4234,7 @@ function show_tooltip_content(id) { data: params.join("&"), dataType: "json", type: "POST", - url: (action = "../../../ajax.php"), + url: "../../../ajax.php", success: function(data) { if (data["correct"]) { $("#tooltip").html(data["content"]); @@ -4353,7 +4254,7 @@ function show_tooltip(id, x, y) { jQuery.ajax({ data: params1.join("&"), type: "POST", - url: (action = "../../../ajax.php"), + url: "../../../ajax.php", success: function(data) { $("#tooltip").html(data); $("#tooltip").css("display", ""); diff --git a/pandora_console/include/javascript/jquery.pandora.js b/pandora_console/include/javascript/jquery.pandora.js index bd0da308c4..9e0b3447af 100644 --- a/pandora_console/include/javascript/jquery.pandora.js +++ b/pandora_console/include/javascript/jquery.pandora.js @@ -163,12 +163,21 @@ $(document).ready (function () { background: "black" }, open: function() { - setTimeout(function(){ - $("#spinner_ok").hide(); + var remaining = 30; + + // Timeout counter. + var count = function() { + if (remaining > 0) { + $("#license_error_remaining").text(remaining); + remaining -= 1; + } else { + $("#license_error_remaining").hide(); $("#ok_buttom").show(); - }, - 30000 - ); + clearInterval(count); + } + } + + setInterval(count, 1000); } }); diff --git a/pandora_console/include/javascript/pandora.js b/pandora_console/include/javascript/pandora.js index 37a9987812..351531a5e9 100644 --- a/pandora_console/include/javascript/pandora.js +++ b/pandora_console/include/javascript/pandora.js @@ -33,9 +33,21 @@ function winopeng_var(url, wid, width, height) { status = wid; } -function open_help(help_id, home_url, id_user) { +function open_help(url) { + if (!navigator.onLine) { + alert( + "The help system could not be started. Please, check your network connection." + ); + return; + } + if (url == "") { + alert( + "The help system is currently under maintenance. Sorry for the inconvenience." + ); + return; + } open( - home_url + "general/pandora_help.php?id=" + help_id + "&id_user=" + id_user, + url, "pandorahelp", "width=650,height=500,status=0,toolbar=0,menubar=0,scrollbars=1,location=0" ); @@ -503,6 +515,14 @@ function module_changed_by_multiple_modules(event, id_module, selected) { selection_mode = "common"; } + var tags_selected = []; + + var tags_to_search = $("#tags").val(); + if (tags_to_search != null) { + if (tags_to_search[0] != -1) { + tags_selected = tags_to_search; + } + } jQuery.post( "ajax.php", { @@ -510,7 +530,8 @@ function module_changed_by_multiple_modules(event, id_module, selected) { get_agents_json_for_multiple_modules: 1, status_module: status_module, "module_name[]": idModules, - selection_mode: selection_mode + selection_mode: selection_mode, + tags: tags_selected }, function(data) { $("#agents").append( @@ -1205,7 +1226,7 @@ function paint_qrcode(text, where, width, height) { text: text, width: width, height: height, - colorDark: "#3B6941", + colorDark: "#343434", colorLight: "#ffffff", correctLevel: QRCode.CorrectLevel.M }); @@ -1739,7 +1760,9 @@ function round_with_decimals(value, multiplier) { if (typeof multiplier === "undefined") multiplier = 1; // Return non numeric types without modification - if (typeof value !== "number") return value; + if (typeof value !== "number" || Number.isNaN(value)) { + return value; + } if (value * multiplier == 0) return 0; if (Math.abs(value) * multiplier >= 1) { diff --git a/pandora_console/include/javascript/pandora_alerts.js b/pandora_console/include/javascript/pandora_alerts.js index 41f8d20ad8..1c72d13cf3 100644 --- a/pandora_console/include/javascript/pandora_alerts.js +++ b/pandora_console/include/javascript/pandora_alerts.js @@ -19,8 +19,14 @@ function parse_alert_command(command, classs) { var regex = new RegExp(field, "gi"); - command = command.replace(regex, $(this).val()); + if ($(this).css("-webkit-text-security") == "disc") { + var hidden_character = "*"; + var hidden_string = hidden_character.repeat($(this).val().length); + command = command.replace(regex, hidden_string); + } else { + command = command.replace(regex, $(this).val()); + } nfield++; }); diff --git a/pandora_console/include/javascript/pandora_events.js b/pandora_console/include/javascript/pandora_events.js index 8fbef6b03d..1f1ff42c3f 100644 --- a/pandora_console/include/javascript/pandora_events.js +++ b/pandora_console/include/javascript/pandora_events.js @@ -241,6 +241,7 @@ function show_massive_response_dialog( }, close: function(event, ui) { $(".chk_val").prop("checked", false); + $("#event_response_command_window").dialog("close"); }, width: response["modal_width"], height: response["modal_height"] @@ -364,9 +365,9 @@ function get_event_name(event_id, meta, history) { function add_row_param(id_table, param) { $("#" + id_table).append( - '' + + '' + param + - ' 1 || response_params[0] != "") { for (i = 0; i < response_params.length; i++) { - target = target.replace( - "_" + response_params[i] + "_", - $("#" + response_params[i]).val() - ); + if (!response_command) { + target = target.replace( + "_" + response_params[i] + "_", + $("#" + response_params[i]).val() + ); + } else { + target = target.replace( + "_" + response_params[i] + "_", + response_command[response_params[i] + "-" + i] + ); + } } } @@ -459,10 +471,6 @@ function perform_response_massive(target, response_id, out_iterator) { $("#response_loading_command_" + out_iterator).show(); $("#response_out_" + out_iterator).html(""); - var finished = 0; - var time = Math.round(+new Date() / 1000); - var timeout = time + 10; - var params = []; params.push("page=include/ajax/events"); params.push("perform_event_response=1"); @@ -487,7 +495,7 @@ function perform_response_massive(target, response_id, out_iterator) { return false; } -// Change the status of an event to new, in process or validated +// Change the status of an event to new, in process or validated. function event_change_status(event_ids) { var ajax_file = $("#hidden-ajax_file").val(); @@ -681,3 +689,53 @@ function show_events_group_agent(id_insert, id_agent, server_id) { } }); } + +function show_event_response_command_dialog(id, response, total_checked) { + var ajax_file = $("#hidden-ajax_file").val(); + + var params = []; + params.push("page=include/ajax/events"); + params.push("get_table_response_command=1"); + params.push("event_response_id=" + id); + + jQuery.ajax({ + data: params.join("&"), + type: "POST", + url: (action = ajax_file), + dataType: "html", + success: function(data) { + $("#event_response_command_window") + .hide() + .empty() + .append(data) + .dialog({ + resizable: true, + draggable: true, + modal: false, + open: function() { + $("#response_loading_dialog").hide(); + $("#button-submit_event_response").show(); + }, + width: 600, + height: 300 + }) + .show(); + + $("#submit-enter_command").on("click", function(e) { + e.preventDefault(); + var response_command = []; + + $(".response_command_input").each(function() { + response_command[$(this).attr("name")] = $(this).val(); + }); + + check_massive_response_event( + id, + response, + total_checked, + response_command + ); + }); + } + }); +} diff --git a/pandora_console/include/javascript/pandora_modules.js b/pandora_console/include/javascript/pandora_modules.js index 135c8811de..0487923b38 100644 --- a/pandora_console/include/javascript/pandora_modules.js +++ b/pandora_console/include/javascript/pandora_modules.js @@ -1,3 +1,8 @@ +/* + global $ + global jQuery +*/ + /* Modules ids to check types */ var id_modules_icmp = Array(6, 7); var id_modules_tcp = Array(8, 9, 10, 11); @@ -95,6 +100,7 @@ function configure_modules_form() { $("#text-unit").attr("value", ""); $("#checkbox-critical_inverse").attr("value", 0); $("#checkbox-warning_inverse").attr("value", 0); + $("#checkbox-ff_type").attr("value", 0); $("#textarea_critical_instructions").attr("value", ""); $("#textarea_warning_instructions").attr("value", ""); $("#textarea_unknown_instructions").attr("value", ""); @@ -177,16 +183,23 @@ function configure_modules_form() { "value", data["min_ff_event"] == 0 ? 0 : data["min_ff_event"] ); + + if (data["ff_type"] != 0) { + $("#checkbox-ff_type").prop("checked", 1); + } else { + $("#checkbox-ff_type").prop("checked", 0); + } + $("#text-post_process").attr( "value", data["post_process"] == 0 ? 0 : data["post_process"] ); $("#text-unit").attr("value", data["unit"] == "" ? "" : data["unit"]); $("#checkbox-critical_inverse").prop( - "checked", + "uncheck", data["critical_inverse"] ); - $("#checkbox-warning_inverse").prop("checked", data["warning_inverse"]); + $("#checkbox-warning_inverse").prop("uncheck", data["warning_inverse"]); $("#component_loading").hide(); $("#id_module_type").change(); if ($("#id_category").is("select")) { @@ -413,6 +426,12 @@ function configure_modules_form() { data["min_ff_event_critical"] == 0 ? 0 : data["min_ff_event_critical"] ); + if (data["ff_type"] != 0) { + $("#checkbox-ff_type").prop("checked", 1); + } else { + $("#checkbox-ff_type").prop("checked", 0); + } + // Shows manual input if post_process field is setted if (data["post_process"] != 0) { $("#post_process_manual").show(); @@ -834,12 +853,10 @@ function add_macro_field(macro, row_model_id) { $("#" + row_id) .children() .eq(1) - .children() .attr("id", "text-" + macro_macro); $("#" + row_id) .children() .eq(1) - .children() .attr("name", macro_macro); macro_field_hide = false; @@ -859,13 +876,11 @@ function add_macro_field(macro, row_model_id) { $("#" + row_id) .children() .eq(1) - .children() .attr("type", "password"); } $("#" + row_id) .children() .eq(1) - .children() .val(macro_value); $("#" + row_id).show(); @@ -1121,3 +1136,90 @@ function delete_macro(num) { // Do not decrease the macro counter or new macros may overlap existing ones! } + +function get_explanation_recon_script(id, id_rt, url) { + var xhrManager = function() { + var manager = {}; + + manager.tasks = []; + + manager.addTask = function(xhr) { + manager.tasks.push(xhr); + }; + + manager.stopTasks = function() { + while (manager.tasks.length > 0) manager.tasks.pop().abort(); + }; + + return manager; + }; + + var taskManager = new xhrManager(); + + // Stop old ajax tasks. + taskManager.stopTasks(); + + // Show the spinners. + $("#textarea_explanation").hide(); + $("#spinner_layout").show(); + + var xhr = jQuery.ajax({ + data: { + page: "enterprise/include/ajax/hostDevices.ajax", + get_explanation: 1, + id: id, + id_rt: id_rt + }, + url: url, + type: "POST", + dataType: "text", + complete: function(xhr, textStatus) { + $("#spinner_layout").hide(); + }, + success: function(data, textStatus, xhr) { + $("#textarea_explanation").val(data); + $("#textarea_explanation").show(); + }, + error: function(xhr, textStatus, errorThrown) { + console.log(errorThrown); + } + }); + + taskManager.addTask(xhr); + + // Delete all the macro fields. + $(".macro_field").remove(); + $("#spinner_recon_script").show(); + + var xhr = jQuery.ajax({ + data: { + page: "enterprise/include/ajax/hostDevices.ajax", + get_recon_script_macros: 1, + id: id, + id_rt: id_rt + }, + url: url, + type: "POST", + dataType: "json", + complete: function(xhr, textStatus) { + $("#spinner_recon_script").hide(); + forced_title_callback(); + }, + success: function(data, textStatus, xhr) { + if (data.array !== null) { + $("#hidden-macros").val(data.base64); + + jQuery.each(data.array, function(i, macro) { + if (macro.desc != "") { + add_macro_field(macro, "table_recon-macro"); + } + }); + } + }, + error: function(xhr, textStatus, errorThrown) { + console.log(errorThrown); + } + }); + + taskManager.addTask(xhr); +} diff --git a/pandora_console/include/javascript/pandora_snmp_browser.js b/pandora_console/include/javascript/pandora_snmp_browser.js index eb4cc80f2e..ee75eac71f 100644 --- a/pandora_console/include/javascript/pandora_snmp_browser.js +++ b/pandora_console/include/javascript/pandora_snmp_browser.js @@ -164,6 +164,7 @@ function snmpGet(oid) { var snmp3_privacy_method = $("#snmp3_browser_privacy_method").val(); var snmp3_privacy_pass = $("#password-snmp3_browser_privacy_pass").val(); var ajax_url = $("#hidden-ajax_url").val(); + var server_to_exec = $("#server_to_exec").val(); // Check for a custom action var custom_action = $("#hidden-custom_action").val(); @@ -183,6 +184,7 @@ function snmpGet(oid) { "snmp3_browser_auth_pass=" + snmp3_auth_pass, "snmp3_browser_privacy_method=" + snmp3_privacy_method, "snmp3_browser_privacy_pass=" + snmp3_privacy_pass, + "server_to_exec=" + server_to_exec, "action=" + "snmpget", "custom_action=" + custom_action, "page=operation/snmpconsole/snmp_browser" diff --git a/pandora_console/include/javascript/pandora_taskList.js b/pandora_console/include/javascript/pandora_taskList.js new file mode 100644 index 0000000000..75d95df026 --- /dev/null +++ b/pandora_console/include/javascript/pandora_taskList.js @@ -0,0 +1,109 @@ +/* + global $ + global jQuery +*/ + +/** + * Function for create modal with progress task + * and recalculate 3 second. + * @param {int} id + * @param {string} name + */ +function progress_task_list(id, title) { + var timeoutRef = null; + var xhr = null; + var $elem = $("#progress_task_" + id); + + $elem + .hide() + .empty() + .dialog({ + title: title, + autoOpen: false, + modal: false, + resizable: false, + draggable: false, + closeOnEscape: true, + width: 800, + height: 600, + close: function() { + if (xhr != null) xhr.abort(); + if (timeoutRef != null) clearTimeout(timeoutRef); + } + }); + + // Function var. + var handleFetchTaskList = function(err, data) { + if (err) { + // TODO: Show info about the problem. + } + + $elem.html(data.html); + if (!$elem.dialog("isOpen")) $elem.dialog("open"); + + if (data.status != -1) { + timeoutRef = setTimeout(function() { + xhr = fetchTaskList(id, handleFetchTaskList); + }, 3000); + } + }; + + xhr = fetchTaskList(id, handleFetchTaskList); +} + +/** + * Function that performs ajax request to return + * the progress of the task. + * @param {int} id Id task. + * @param {function} callback Function callback. + */ +function fetchTaskList(id, callback) { + return jQuery.ajax({ + data: { + page: "include/ajax/task_list.ajax", + progress_task_discovery: 1, + id: id + }, + type: "POST", + url: "ajax.php", + dataType: "json", + success: function(data) { + callback(null, data); + }, + error: function() { + callback(new Error("cannot fetch the list")); + } + }); +} + +function show_map(id, name) { + $("#map_task") + .empty() + .hide() + .append("

    Loading map

    ") + .dialog({ + title: "Task: " + name, + resizable: true, + draggable: true, + modal: false, + width: 1280, + height: 700 + }) + .show(); + + jQuery.ajax({ + data: { + page: "include/ajax/task_list.ajax", + showmap: 1, + id: id + }, + type: "POST", + url: "ajax.php", + dataType: "html", + success: function(data) { + $("#map_task") + .empty() + .append(data); + } + }); +} diff --git a/pandora_console/include/javascript/pandora_visual_console.js b/pandora_console/include/javascript/pandora_visual_console.js index 06209e092f..b78270f3dc 100755 --- a/pandora_console/include/javascript/pandora_visual_console.js +++ b/pandora_console/include/javascript/pandora_visual_console.js @@ -1,3 +1,265 @@ +// TODO: Add Artica ST header. +/* globals jQuery, VisualConsole, AsyncTaskManager */ + +/* + * ********************* + * * New VC functions. * + * ********************* + */ + +/** + * Generate a Visual Console client. + * @param {HTMLElement} container Node which will be used to contain the VC. + * @param {object} props VC container properties. + * @param {object[]} items List of item definitions. + * @param {string | null} baseUrl Base URL to perform API requests. + * @param {number | null} updateInterval Time in milliseconds between VC updates. + * @param {function | null} onUpdate Callback which will be execuded when the Visual Console. + * is updated. It will receive two arguments with the old and the new Visual Console's + * data structure. + * @return {VisualConsole | null} The Visual Console instance or a null value. + */ +// eslint-disable-next-line no-unused-vars +function createVisualConsole( + container, + props, + items, + baseUrl, + updateInterval, + onUpdate +) { + if (container == null || props == null || items == null) return null; + if (baseUrl == null) baseUrl = ""; + + var visualConsole = null; + var asyncTaskManager = new AsyncTaskManager(); + + function updateVisualConsole(visualConsoleId, updateInterval, tts) { + if (tts == null) tts = 0; // Time to start. + + asyncTaskManager.add( + "visual-console", + function(done) { + var abortable = loadVisualConsoleData( + baseUrl, + visualConsoleId, + function(error, data) { + if (error) { + console.log( + "[ERROR]", + "[VISUAL-CONSOLE-CLIENT]", + "[API]", + error.message + ); + done(); + return; + } + + // Replace Visual Console. + if (data != null && data.props != null && data.items != null) { + try { + var props = + typeof data.props === "string" + ? JSON.parse(data.props) + : data.props; + var items = + typeof data.items === "string" + ? JSON.parse(data.items) + : data.items; + + var prevProps = visualConsole.props; + // Update the data structure. + visualConsole.props = props; + // Update the items. + visualConsole.updateElements(items); + // Emit the VC update event. + if (onUpdate) onUpdate(prevProps, visualConsole.props); + } catch (ignored) {} // eslint-disable-line no-empty + + done(); + } + } + ); + + return { + cancel: function() { + abortable.abort(); + } + }; + }, + updateInterval + ); + + asyncTaskManager.add("visual-console-start", function(done) { + var ref = setTimeout(function() { + asyncTaskManager.init("visual-console"); + done(); + }, tts); + + return { + cancel: function() { + clearTimeout(ref); + } + }; + }); + + if (tts > 0) { + // Wait to start the fetch interval. + asyncTaskManager.init("visual-console-start"); + } else { + // Start the fetch interval immediately. + asyncTaskManager.init("visual-console"); + } + } + + // Initialize the Visual Console. + try { + visualConsole = new VisualConsole(container, props, items); + // VC Item clicked. + visualConsole.onClick(function(e) { + // Override the link to another VC if it isn't on remote console. + if ( + e.data && + e.data.linkedLayoutId != null && + e.data.linkedLayoutId > 0 && + e.data.link != null && + e.data.link.length > 0 && + (e.data.linkedLayoutAgentId == null || e.data.linkedLayoutAgentId === 0) + ) { + // Stop the current link behavior. + e.nativeEvent.preventDefault(); + // Fetch and update the old VC with the new. + updateVisualConsole(e.data.linkedLayoutId, updateInterval); + } + }); + + if (updateInterval != null && updateInterval > 0) { + // Start an interval to update the Visual Console. + updateVisualConsole(props.id, updateInterval, updateInterval); + } + } catch (error) { + console.log("[ERROR]", "[VISUAL-CONSOLE-CLIENT]", error.message); + } + + return { + visualConsole: visualConsole, + changeUpdateInterval: function(updateInterval) { + if (updateInterval != null && updateInterval > 0) { + updateVisualConsole( + visualConsole.props.id, + updateInterval, + updateInterval + ); + } else { + // Update interval disabled. Cancel possible pending tasks. + asyncTaskManager.cancel("visual-console"); + asyncTaskManager.cancel("visual-console-start"); + } + } + }; +} + +/** + * Fetch a Visual Console's structure and its items. + * @param {string} baseUrl Base URL to build the API path. + * @param {number} vcId Identifier of the Visual Console. + * @param {function} callback Function to be executed on request success or fail. + * On success, the function will receive an object with the next properties: + * - `props`: object with the Visual Console's data structure. + * - `items`: array of data structures of the Visual Console's items. + * @return {Object} Cancellable. Object which include and .abort([statusText]) function. + */ +// eslint-disable-next-line no-unused-vars +function loadVisualConsoleData(baseUrl, vcId, callback) { + // var apiPath = baseUrl + "/include/rest-api"; + var apiPath = baseUrl + "/ajax.php"; + var vcJqXHR = null; + var itemsJqXHR = null; + + // Initialize the final result. + var result = { + props: null, + items: null + }; + + // Cancel the ajax requests. + var abort = function(textStatus) { + if (textStatus == null) textStatus = "abort"; + + // -- XMLHttpRequest.readyState -- + // Value State Description + // 0 UNSENT Client has been created. open() not called yet. + // 4 DONE The operation is complete. + + if (vcJqXHR.readyState !== 0 && vcJqXHR.readyState !== 4) + vcJqXHR.abort(textStatus); + if (itemsJqXHR.readyState !== 0 && itemsJqXHR.readyState !== 4) + itemsJqXHR.abort(textStatus); + }; + + // Check if the required data is complete. + var checkResult = function() { + return result.props !== null && result.items !== null; + }; + + // Failed request handler. + var handleFail = function(jqXHR, textStatus, errorThrown) { + abort(); + // Manually aborted or not. + if (textStatus === "abort") { + callback(); + } else { + var error = new Error(errorThrown); + error.request = jqXHR; + callback(error); + } + }; + + // Curried function which handle success. + var handleSuccess = function(key) { + // Actual request handler. + return function(data) { + result[key] = data; + if (checkResult()) callback(null, result); + }; + }; + + // Visual Console container request. + vcJqXHR = jQuery + // .get(apiPath + "/visual-consoles/" + vcId, null, "json") + .get( + apiPath, + { + page: "include/rest-api/index", + getVisualConsole: 1, + visualConsoleId: vcId + }, + "json" + ) + .done(handleSuccess("props")) + .fail(handleFail); + // Visual Console items request. + itemsJqXHR = jQuery + // .get(apiPath + "/visual-consoles/" + vcId + "/items", null, "json") + .get( + apiPath, + { + page: "include/rest-api/index", + getVisualConsoleItems: 1, + visualConsoleId: vcId + }, + "json" + ) + .done(handleSuccess("items")) + .fail(handleFail); + + // Abortable. + return { + abort: abort + }; +} + +// TODO: Delete the functions below when you can. /************************************** These functions require jQuery library **************************************/ diff --git a/pandora_console/include/javascript/timezonepicker/README.md b/pandora_console/include/javascript/timezonepicker/README.md new file mode 100644 index 0000000000..fdaf77e099 --- /dev/null +++ b/pandora_console/include/javascript/timezonepicker/README.md @@ -0,0 +1,189 @@ +# timezonepicker + +A jQuery and ImageMap based timezone picker. + +This library only works with pre-built imagemaps generated from +http://timezonepicker.com. + +## Features + +- Simple implementation, lightweight footprint (160KB, 40KB gzipped). +- Includes 440+ clickable areas. +- HTML5 Geolocation to identify timezone. +- Islands include padding to increase ease of selection. +- Country mapping can be used to set timezone and country at the same time. +- Timezone highlighting on rollover (thanks to [jQuery maphilight](http://davidlynch.org/projects/maphilight/docs/)) + +## Usage + +Basic call using all defaults: + +```javascript +$("#img-with-usemap-attr").timezonePicker(); +``` + +A few simple options: + +```javascript +$("#img-with-usemap-attr").timezonePicker({ + pin: ".timezone-pin", + fillColor: "FFCCCC" +}); +``` + +## Options + +As pulled from the set of defaults. + +```javascript +$.fn.timezonePicker.defaults = { + // Selector for the pin that should be used. This selector only works in the + // immediate parent of the image map img tag. + pin: ".timezone-pin", + // Specify a URL for the pin image instead of using a DOM element. + pinUrl: null, + // Preselect a particular timezone. + timezone: null, + // Pass through options to the jQuery maphilight plugin. + maphilight: true, + // Selector for the select list, textfield, or hidden to update upon click. + target: null, + // Selector for the select list, textfield, or hidden to update upon click + // with the specified country. + countryTarget: null, + // If changing the country should use the first timezone within that country. + countryGuess: true, + // A list of country guess exceptions. These should only be needed if a + // country spans multiple timezones. + countryGuesses: { + AU: "Australia/Sydney", + BR: "America/Sao_Paulo", + CA: "America/Toronto", + CN: "Asia/Shanghai", + ES: "Europe/Madrid", + MX: "America/Mexico_City", + RU: "Europe/Moscow", + US: "America/New_York" + }, + // If this map should automatically adjust its size if scaled. Note that + // this can be very expensive computationally and will likely have a delay + // on resize. The maphilight library also is incompatible with this setting + // and will be disabled. + responsive: false, + // A function to be called upon timezone change + // timezoneName, countryName, and offset will be passed as arguments + changeHandler: null, + + // Default options passed along to the maphilight plugin. + fade: false, + stroke: true, + strokeColor: "FFFFFF", + strokeOpacity: 0.4, + fillColor: "FFFFFF", + fillOpacity: 0.4, + groupBy: "data-offset" +}; +``` + +## Additional methods + +After creating a timezone picker from an image tag, you can execute additional +commands on the image map with these methods: + +```javascript +// Query the user's browser for the current location and set timezone from that. +$("#img-with-usemap-attr").timezonePicker("detectTimezone"); + +// The detectTimezone method may also provide event callbacks. +$("#img-with-usemap-attr").timezonePicker("detectTimezone", { + success: successCallback, + error: errorCallback, + complete: completeCallback // Called on both success or failure. +}); + +// Set the active timezone to some value programatically. +$("#img-with-usemap-attr").timezonePicker("updateTimezone", "America/New_York"); + +// Resize the image map coordinates to match an adjusted size of the image. +// Note that this option does not work well and is very slow. Not recommended. +$("#img-with-usemap-attr").timezonePicker("resize"); +``` + +## Building new definition files + +The definition files are used to determine the polygons and rectangles used to +generate the resulting imagemap. Note this should rarely be necessary for normal +users as the timezone picker project will rebuild the shape files after updates +to the timezone database. + +1. Download latest shape file "tz_world" from + http://efele.net/maps/tz/world/. + + wget http://efele.net/maps/tz/world/tz_world.zip + unzip tz_world.zip + +2. Install PostGIS, which provides the shp2pgsql executable. + http://postgis.refractions.net/download/ + + For Mac OS X, I installed PostGres, GDAL Complete, and PostGIS binaries from + http://www.kyngchaos.com/software:postgres + + Then add psql and shp2pgsql to your $PATH variable in your shell profile. + export PATH=/usr/local/pgsql-9.1/bin:$PATH + +3. Convert the tz_world.shp file into SQL: + + ``` + cd world + shp2pgsql tz_world.shp timezones > tz_world.sql + ``` + +4. Create a temporary database and import the SQL file. + + ``` + psql -U postgres -c "CREATE DATABASE timezones" -d template1 + ``` + + And import the PostGIS functions into the database. + + ``` + psql -U postgres -d timezones -f /usr/local/pgsql-9.1/share/contrib/postgis-2.0/postgis.sql + + psql -U postgres -d timezones < tz_world.sql + ``` + +5. Export the data as text in a simplified format. + + ``` + psql -U postgres -d timezones -t -A -c " + + SELECT tzid, ST_AsText(ST_Simplify(ST_SnapToGrid(geom, 0.001), 0.3)) FROM timezones + + WHERE (ST_Area(geom) > 3 OR (gid IN ( + + SELECT MAX(gid) FROM timezones WHERE ST_Area(geom) <= 3 AND tzid NOT IN ( + + SELECT tzid FROM timezones WHERE ST_Area(geom) > 3 + + ) group by tzid ORDER BY MAX(ST_AREA(geom)) + + ))) AND tzid != 'uninhabited'; + + " > tz_world.txt + ``` + + And a special export for Islands that are hard to select otherwise. + + ``` + psql -U postgres -d timezones -t -A -c " + SELECT tzid, ST_Expand(ST_Extent(geom), GREATEST(3 - ST_Area(ST_Extent(geom)), 0)) FROM timezones + + WHERE ST_Area(geom) < 3 AND (tzid LIKE 'Pacific/%' OR tzid LIKE 'Indian/%' OR tzid LIKE 'Atlantic/%') GROUP BY tzid ORDER BY tzid; + " > tz_islands.txt + ``` + +## LICENSE + +Copyright 2011-2013 Nathan Haug + +Released under the MIT License. diff --git a/pandora_console/include/javascript/timezonepicker/images/blue-marble-1280.jpg b/pandora_console/include/javascript/timezonepicker/images/blue-marble-1280.jpg new file mode 100644 index 0000000000..9fa8633d88 Binary files /dev/null and b/pandora_console/include/javascript/timezonepicker/images/blue-marble-1280.jpg differ diff --git a/pandora_console/include/javascript/timezonepicker/images/custom.php b/pandora_console/include/javascript/timezonepicker/images/custom.php new file mode 100644 index 0000000000..bd15772119 --- /dev/null +++ b/pandora_console/include/javascript/timezonepicker/images/custom.php @@ -0,0 +1,66 @@ + 'png', + 'blue-marble' => 'jpg', + 'living' => 'jpg', + 'night-electric' => 'jpg', +]; +$width = isset($_GET['w']) ? min((int) $_GET['w'], 1280) : 600; +$height = round($width / 2); + +if (isset($_GET['base']) && isset($bases[$_GET['base']])) { + $base = $_GET['base']; + $extension = $bases[$_GET['base']]; +} else { + $base = reset(array_keys($bases)); + $extension = reset($bases); +} + +$source = $base.'-1280.'.$extension; +$open_extension = str_replace('jpg', 'jpeg', $extension); +$open_func = 'imagecreatefrom'.$open_extension; + +$im = $open_func($source); +if (!$im) { + return false; +} + +list($original_width, $original_height) = getimagesize($source); + +$res = imagecreatetruecolor($width, $height); +if ($extension == 'png') { + $transparency = imagecolorallocatealpha($res, 0, 0, 0, 127); + imagealphablending($res, false); + imagefilledrectangle($res, 0, 0, $width, $height, $transparency); + imagealphablending($res, true); + imagesavealpha($res, true); +} else if ($extension == 'gif') { + // If we have a specific transparent color. + $transparency_index = imagecolortransparent($im); + if ($transparency_index >= 0) { + // Get the original image's transparent color's RGB values. + $transparent_color = imagecolorsforindex($im, $transparency_index); + // Allocate the same color in the new image resource. + $transparency_index = imagecolorallocate($res, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']); + // Completely fill the background of the new image with allocated color. + imagefill($res, 0, 0, $transparency_index); + // Set the background color for new image to transparent. + imagecolortransparent($res, $transparency_index); + // Find number of colors in the images palette. + $number_colors = imagecolorstotal($im); + // Convert from true color to palette to fix transparency issues. + imagetruecolortopalette($res, true, $number_colors); + } +} + +imagecopyresampled($res, $im, 0, 0, 0, 0, $width, $height, $original_width, $original_height); + +header('Content-Type: image/'.$extension); +header('Cache-Control: public, max-age: 3600'); + +$close_function = 'image'.$open_extension; +$close_function($res); + +imagedestroy($res); +imagedestroy($im); diff --git a/pandora_console/include/javascript/timezonepicker/images/gray-1280.png b/pandora_console/include/javascript/timezonepicker/images/gray-1280.png new file mode 100644 index 0000000000..538abc41e8 Binary files /dev/null and b/pandora_console/include/javascript/timezonepicker/images/gray-1280.png differ diff --git a/pandora_console/include/javascript/timezonepicker/images/gray-400.png b/pandora_console/include/javascript/timezonepicker/images/gray-400.png new file mode 100644 index 0000000000..631dd24628 Binary files /dev/null and b/pandora_console/include/javascript/timezonepicker/images/gray-400.png differ diff --git a/pandora_console/include/javascript/timezonepicker/images/gray-600.png b/pandora_console/include/javascript/timezonepicker/images/gray-600.png new file mode 100644 index 0000000000..fa00ca74f9 Binary files /dev/null and b/pandora_console/include/javascript/timezonepicker/images/gray-600.png differ diff --git a/pandora_console/include/javascript/timezonepicker/images/gray-800.png b/pandora_console/include/javascript/timezonepicker/images/gray-800.png new file mode 100644 index 0000000000..a59d22fbe8 Binary files /dev/null and b/pandora_console/include/javascript/timezonepicker/images/gray-800.png differ diff --git a/pandora_console/include/javascript/timezonepicker/images/living-1280.jpg b/pandora_console/include/javascript/timezonepicker/images/living-1280.jpg new file mode 100644 index 0000000000..3f216faaf9 Binary files /dev/null and b/pandora_console/include/javascript/timezonepicker/images/living-1280.jpg differ diff --git a/pandora_console/include/javascript/timezonepicker/images/map-outlines.psd b/pandora_console/include/javascript/timezonepicker/images/map-outlines.psd new file mode 100644 index 0000000000..490622a2fa Binary files /dev/null and b/pandora_console/include/javascript/timezonepicker/images/map-outlines.psd differ diff --git a/pandora_console/include/javascript/timezonepicker/images/night-electric-1280.jpg b/pandora_console/include/javascript/timezonepicker/images/night-electric-1280.jpg new file mode 100644 index 0000000000..b763a659ab Binary files /dev/null and b/pandora_console/include/javascript/timezonepicker/images/night-electric-1280.jpg differ diff --git a/pandora_console/include/javascript/timezonepicker/images/pin.png b/pandora_console/include/javascript/timezonepicker/images/pin.png new file mode 100644 index 0000000000..ad9b970de3 Binary files /dev/null and b/pandora_console/include/javascript/timezonepicker/images/pin.png differ diff --git a/pandora_console/include/javascript/timezonepicker/includes/parser.inc b/pandora_console/include/javascript/timezonepicker/includes/parser.inc new file mode 100644 index 0000000000..698c940752 --- /dev/null +++ b/pandora_console/include/javascript/timezonepicker/includes/parser.inc @@ -0,0 +1,167 @@ + 1280 ? 600 : (int) $_GET['w']; +$map_height = round($map_width / 2); +$timezones = timezone_picker_parse_files($map_width, $map_height, 'tz_world.txt', 'tz_islands.txt'); + +header('Content-Type: application/json'); +header('Cache-Control: public, max-age: 3600'); + +print json_encode($timezones, (JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT)); diff --git a/pandora_console/include/javascript/timezonepicker/lib/jquery.maphilight.min.js b/pandora_console/include/javascript/timezonepicker/lib/jquery.maphilight.min.js new file mode 100644 index 0000000000..0f93346263 --- /dev/null +++ b/pandora_console/include/javascript/timezonepicker/lib/jquery.maphilight.min.js @@ -0,0 +1,564 @@ +(function(root, factory) { + if (typeof define === "function" && define.amd) { + define(["jquery"], factory); + } else { + factory(root.jQuery); + } +})(this, function($) { + var has_VML, + has_canvas, + create_canvas_for, + add_shape_to, + clear_canvas, + shape_from_area, + canvas_style, + hex_to_decimal, + css3color, + is_image_loaded, + options_from_area; + + has_canvas = !!document.createElement("canvas").getContext; + + // VML: more complex + has_VML = (function() { + var a = document.createElement("div"); + a.innerHTML = ''; + var b = a.firstChild; + b.style.behavior = "url(#default#VML)"; + return b ? typeof b.adj == "object" : true; + })(); + + if (!(has_canvas || has_VML)) { + $.fn.maphilight = function() { + return this; + }; + return; + } + + if (has_canvas) { + hex_to_decimal = function(hex) { + return Math.max(0, Math.min(parseInt(hex, 16), 255)); + }; + css3color = function(color, opacity) { + return ( + "rgba(" + + hex_to_decimal(color.substr(0, 2)) + + "," + + hex_to_decimal(color.substr(2, 2)) + + "," + + hex_to_decimal(color.substr(4, 2)) + + "," + + opacity + + ")" + ); + }; + create_canvas_for = function(img) { + var c = $( + '' + ).get(0); + c.getContext("2d").clearRect(0, 0, $(img).width(), $(img).height()); + return c; + }; + var draw_shape = function(context, shape, coords, x_shift, y_shift) { + x_shift = x_shift || 0; + y_shift = y_shift || 0; + + context.beginPath(); + if (shape == "rect") { + // x, y, width, height + context.rect( + coords[0] + x_shift, + coords[1] + y_shift, + coords[2] - coords[0], + coords[3] - coords[1] + ); + } else if (shape == "poly") { + context.moveTo(coords[0] + x_shift, coords[1] + y_shift); + for (i = 2; i < coords.length; i += 2) { + context.lineTo(coords[i] + x_shift, coords[i + 1] + y_shift); + } + } else if (shape == "circ") { + // x, y, radius, startAngle, endAngle, anticlockwise + context.arc( + coords[0] + x_shift, + coords[1] + y_shift, + coords[2], + 0, + Math.PI * 2, + false + ); + } + context.closePath(); + }; + add_shape_to = function(canvas, shape, coords, options, name) { + var i, + context = canvas.getContext("2d"); + + // Because I don't want to worry about setting things back to a base state + + // Shadow has to happen first, since it's on the bottom, and it does some clip / + // fill operations which would interfere with what comes next. + if (options.shadow) { + context.save(); + if (options.shadowPosition == "inside") { + // Cause the following stroke to only apply to the inside of the path + draw_shape(context, shape, coords); + context.clip(); + } + + // Redraw the shape shifted off the canvas massively so we can cast a shadow + // onto the canvas without having to worry about the stroke or fill (which + // cannot have 0 opacity or width, since they're what cast the shadow). + var x_shift = canvas.width * 100; + var y_shift = canvas.height * 100; + draw_shape(context, shape, coords, x_shift, y_shift); + + context.shadowOffsetX = options.shadowX - x_shift; + context.shadowOffsetY = options.shadowY - y_shift; + context.shadowBlur = options.shadowRadius; + context.shadowColor = css3color( + options.shadowColor, + options.shadowOpacity + ); + + // Now, work out where to cast the shadow from! It looks better if it's cast + // from a fill when it's an outside shadow or a stroke when it's an interior + // shadow. Allow the user to override this if they need to. + var shadowFrom = options.shadowFrom; + if (!shadowFrom) { + if (options.shadowPosition == "outside") { + shadowFrom = "fill"; + } else { + shadowFrom = "stroke"; + } + } + if (shadowFrom == "stroke") { + context.strokeStyle = "rgba(0,0,0,1)"; + context.stroke(); + } else if (shadowFrom == "fill") { + context.fillStyle = "rgba(0,0,0,1)"; + context.fill(); + } + context.restore(); + + // and now we clean up + if (options.shadowPosition == "outside") { + context.save(); + // Clear out the center + draw_shape(context, shape, coords); + context.globalCompositeOperation = "destination-out"; + context.fillStyle = "rgba(0,0,0,1);"; + context.fill(); + context.restore(); + } + } + + context.save(); + + draw_shape(context, shape, coords); + + // fill has to come after shadow, otherwise the shadow will be drawn over the fill, + // which mostly looks weird when the shadow has a high opacity + if (options.fill) { + context.fillStyle = css3color(options.fillColor, options.fillOpacity); + context.fill(); + } + // Likewise, stroke has to come at the very end, or it'll wind up under bits of the + // shadow or the shadow-background if it's present. + if (options.stroke) { + context.strokeStyle = css3color( + options.strokeColor, + options.strokeOpacity + ); + context.lineWidth = options.strokeWidth; + context.stroke(); + } + + context.restore(); + + if (options.fade) { + $(canvas) + .css("opacity", 0) + .animate({ opacity: 1 }, 100); + } + }; + clear_canvas = function(canvas) { + canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height); + }; + } else { + // ie executes this code + create_canvas_for = function(img) { + return $( + '' + ).get(0); + }; + add_shape_to = function(canvas, shape, coords, options, name) { + var fill, stroke, opacity, e; + for (var i in coords) { + coords[i] = parseInt(coords[i], 10); + } + fill = + ''; + stroke = options.stroke + ? 'strokeweight="' + + options.strokeWidth + + '" stroked="t" strokecolor="#' + + options.strokeColor + + '"' + : 'stroked="f"'; + opacity = ''; + if (shape == "rect") { + e = $( + '' + ); + } else if (shape == "poly") { + e = $( + '' + ); + } else if (shape == "circ") { + e = $( + '' + ); + } + e.get(0).innerHTML = fill + opacity; + $(canvas).append(e); + }; + clear_canvas = function(canvas) { + // jquery1.8 + ie7 + var $html = $("
    " + canvas.innerHTML + "
    "); + $html.children("[name=highlighted]").remove(); + canvas.innerHTML = $html.html(); + }; + } + + shape_from_area = function(area) { + var i, + coords = area.getAttribute("coords").split(","); + for (i = 0; i < coords.length; i++) { + coords[i] = parseFloat(coords[i]); + } + return [ + area + .getAttribute("shape") + .toLowerCase() + .substr(0, 4), + coords + ]; + }; + + options_from_area = function(area, options) { + var $area = $(area); + return $.extend( + {}, + options, + $.metadata ? $area.metadata() : false, + $area.data("maphilight") + ); + }; + + is_image_loaded = function(img) { + if (!img.complete) { + return false; + } // IE + if (typeof img.naturalWidth != "undefined" && img.naturalWidth === 0) { + return false; + } // Others + return true; + }; + + canvas_style = { + position: "absolute", + left: 0, + top: 0, + padding: 0, + border: 0 + }; + + var ie_hax_done = false; + $.fn.maphilight = function(opts) { + opts = $.extend({}, $.fn.maphilight.defaults, opts); + + if (!has_canvas && !ie_hax_done) { + $(window).ready(function() { + document.namespaces.add("v", "urn:schemas-microsoft-com:vml"); + var style = document.createStyleSheet(); + var shapes = [ + "shape", + "rect", + "oval", + "circ", + "fill", + "stroke", + "imagedata", + "group", + "textbox" + ]; + $.each(shapes, function() { + style.addRule( + "v\\:" + this, + "behavior: url(#default#VML); antialias:true" + ); + }); + }); + ie_hax_done = true; + } + + return this.each(function() { + var img, + wrap, + options, + map, + canvas, + canvas_always, + highlighted_shape, + usemap; + img = $(this); + + if (!is_image_loaded(this)) { + // If the image isn't fully loaded, this won't work right. Try again later. + return window.setTimeout(function() { + img.maphilight(opts); + }, 200); + } + + options = $.extend( + {}, + opts, + $.metadata ? img.metadata() : false, + img.data("maphilight") + ); + + // jQuery bug with Opera, results in full-url#usemap being returned from jQuery's attr. + // So use raw getAttribute instead. + usemap = img.get(0).getAttribute("usemap"); + + if (!usemap) { + return; + } + + map = $('map[name="' + usemap.substr(1) + '"]'); + + if (!(img.is('img,input[type="image"]') && usemap && map.length > 0)) { + return; + } + + if (img.hasClass("maphilighted")) { + // We're redrawing an old map, probably to pick up changes to the options. + // Just clear out all the old stuff. + var wrapper = img.parent(); + img.insertBefore(wrapper); + wrapper.remove(); + $(map).unbind(".maphilight"); + } + + wrap = $("
    ").css({ + display: "block", + backgroundImage: 'url("' + this.src + '")', + backgroundSize: "contain", + position: "relative", + padding: 0, + width: this.width, + height: this.height + }); + if (options.wrapClass) { + if (options.wrapClass === true) { + wrap.addClass($(this).attr("class")); + } else { + wrap.addClass(options.wrapClass); + } + } + // Firefox has a bug that prevents tabbing into the image map if + // we set opacity of the image to 0, but very nearly 0 works! + img + .before(wrap) + .css("opacity", 0.0000000001) + .css(canvas_style) + .remove(); + if (has_VML) { + img.css("filter", "Alpha(opacity=0)"); + } + wrap.append(img); + + canvas = create_canvas_for(this); + $(canvas).css(canvas_style); + canvas.height = this.height; + canvas.width = this.width; + + $(map) + .bind("alwaysOn.maphilight", function() { + // Check for areas with alwaysOn set. These are added to a *second* canvas, + // which will get around flickering during fading. + if (canvas_always) { + clear_canvas(canvas_always); + } + if (!has_canvas) { + $(canvas).empty(); + } + $(map) + .find("area[coords]") + .each(function() { + var shape, area_options; + area_options = options_from_area(this, options); + if (area_options.alwaysOn) { + if (!canvas_always && has_canvas) { + canvas_always = create_canvas_for(img[0]); + $(canvas_always).css(canvas_style); + canvas_always.width = img[0].width; + canvas_always.height = img[0].height; + img.before(canvas_always); + } + area_options.fade = area_options.alwaysOnFade; // alwaysOn shouldn't fade in initially + shape = shape_from_area(this); + if (has_canvas) { + add_shape_to( + canvas_always, + shape[0], + shape[1], + area_options, + "" + ); + } else { + add_shape_to(canvas, shape[0], shape[1], area_options, ""); + } + } + }); + }) + .trigger("alwaysOn.maphilight") + .bind("mouseover.maphilight focusin.maphilight", function(e) { + var shape, + area_options, + area = e.target; + area_options = options_from_area(area, options); + if (!area_options.neverOn && !area_options.alwaysOn) { + shape = shape_from_area(area); + add_shape_to( + canvas, + shape[0], + shape[1], + area_options, + "highlighted" + ); + if (area_options.groupBy) { + var areas; + // two ways groupBy might work; attribute and selector + if (/^[a-zA-Z][\-a-zA-Z]+$/.test(area_options.groupBy)) { + areas = map.find( + "area[" + + area_options.groupBy + + '="' + + $(area).attr(area_options.groupBy) + + '"]' + ); + } else { + areas = map.find(area_options.groupBy); + } + var first = area; + areas.each(function() { + if (this != first) { + var subarea_options = options_from_area(this, options); + if (!subarea_options.neverOn && !subarea_options.alwaysOn) { + var shape = shape_from_area(this); + add_shape_to( + canvas, + shape[0], + shape[1], + subarea_options, + "highlighted" + ); + } + } + }); + } + // workaround for IE7, IE8 not rendering the final rectangle in a group + if (!has_canvas) { + $(canvas).append(""); + } + } + }) + .bind("mouseout.maphilight focusout.maphilight", function(e) { + clear_canvas(canvas); + }); + + img.before(canvas); // if we put this after, the mouseover events wouldn't fire. + + img.addClass("maphilighted"); + }); + }; + $.fn.maphilight.defaults = { + fill: true, + fillColor: "000000", + fillOpacity: 0.2, + stroke: true, + strokeColor: "ff0000", + strokeOpacity: 1, + strokeWidth: 1, + fade: true, + alwaysOn: false, + neverOn: false, + groupBy: false, + wrapClass: true, + // plenty of shadow: + shadow: false, + shadowX: 0, + shadowY: 0, + shadowRadius: 6, + shadowColor: "000000", + shadowOpacity: 0.8, + shadowPosition: "outside", + shadowFrom: false + }; +}); diff --git a/pandora_console/include/javascript/timezonepicker/lib/jquery.timezone-picker.js b/pandora_console/include/javascript/timezonepicker/lib/jquery.timezone-picker.js new file mode 100644 index 0000000000..f2134f47a0 --- /dev/null +++ b/pandora_console/include/javascript/timezonepicker/lib/jquery.timezone-picker.js @@ -0,0 +1,382 @@ +(function($) { + // We only support a single instance per call, so these variables are available + // for all subsequent calls. + var methods = {}; + var opts = {}; + var selectedTimezone = null; + var imgElement = null; + var mapElement = null; + var $pin = null; + + // Gets called upon timezone change. + // The expected method signature is changeHandler(timezoneName, countryName, offset). + var changeHandler = null; + + methods.init = function(initOpts) { + var $origCall = this; + + // Set the instance options. + opts = $.extend({}, $.fn.timezonePicker.defaults, initOpts); + selectedTimezone = opts.timezone; + + changeHandler = opts.changeHandler; + + return $origCall.each(function(index, item) { + imgElement = item; + mapElement = document.getElementsByName( + imgElement.useMap.replace(/^#/, "") + )[0]; + + // Wrap the img tag in a relatively positioned DIV for the pin. + $(imgElement) + .wrap('
    ') + .parent() + .css({ + position: "relative", + width: $(imgElement).width() + "px" + }); + + // Add the pin. + if (opts.pinUrl) { + $pin = $('') + .appendTo(imgElement.parentNode) + .css("display", "none"); + } else if (opts.pin) { + $pin = $(imgElement) + .parent() + .parent() + .find(opts.pin) + .appendTo(imgElement.parentNode) + .css("display", "none"); + } + + // Main event handler when a timezone is clicked. + $(mapElement) + .find("area") + .click(function() { + var areaElement = this; + // Enable the pin adjustment. + if ($pin) { + $pin.css("display", "block"); + var pinCoords = $(areaElement) + .attr("data-pin") + .split(","); + var pinWidth = parseInt($pin.width() / 2); + var pinHeight = $pin.height(); + + $pin.css({ + position: "absolute", + left: pinCoords[0] - pinWidth + "px", + top: pinCoords[1] - pinHeight + "px" + }); + } + + var timezoneName = $(areaElement).attr("data-timezone"); + var countryName = $(areaElement).attr("data-country"); + var offset = $(areaElement).attr("data-offset"); + + // Call the change handler + if (typeof changeHandler === "function") { + changeHandler(timezoneName, countryName, offset); + } + + // Update the target select list. + if (opts.target) { + if (timezoneName) $(opts.target).val(timezoneName); + } + if (opts.countryTarget) { + if (countryName) $(opts.countryTarget).val(countryName); + } + + return false; + }); + + // Adjust the timezone if the target changes. + if (opts.target) { + $(opts.target).bind("change", function() { + $origCall.timezonePicker("updateTimezone", $(this).val()); + }); + } + + // Adjust the timezone if the countryTarget changes. + if (opts.countryTarget && opts.countryGuess) { + $(opts.countryTarget).bind("change", function() { + var countryCode = $(this).val(); + if (opts.countryGuesses[countryCode]) { + $(mapElement) + .find( + 'area[data-timezone="' + opts.countryGuesses[countryCode] + '"]' + ) + .click(); + } else { + $(mapElement) + .find("area[data-country=" + countryCode + "]:first") + .click(); + } + }); + } + + // This is very expensive, so only run if enabled. + if (opts.responsive) { + var resizeTimeout = null; + $(window).resize(function() { + if (resizeTimeout) { + clearTimeout(resizeTimeout); + } + resizeTimeout = setTimeout(function() { + $origCall.timezonePicker("resize"); + }, 200); + }); + } + + // Give the page a slight time to load before selecting the default + // timezone on the map. + setTimeout(function() { + if ( + opts.responsive && + parseInt(imgElement.width) !== + parseInt(imgElement.getAttribute("width")) + ) { + $origCall.timezonePicker("resize"); + } else if (opts.maphilight && $.fn.maphilight) { + $(imgElement).maphilight(opts); + } + if (opts.target) { + $(opts.target).triggerHandler("change"); + } + }, 500); + }); + }; + + /** + * Update the currently selected timezone and update the pin location. + */ + methods.updateTimezone = function(newTimezone) { + selectedTimezone = newTimezone; + $pin.css("display", "none"); + $(mapElement) + .find("area") + .each(function(m, areaElement) { + if (areaElement.getAttribute("data-timezone") === selectedTimezone) { + $(areaElement).triggerHandler("click"); + return false; + } + }); + + return this; + }; + + /** + * Use browser geolocation to update the currently selected timezone and update the pin location. + */ + methods.detectLocation = function(detectOpts) { + var detectDefaults = { + success: undefined, + error: undefined, + complete: undefined + }; + detectOpts = $.extend(detectDefaults, detectOpts); + + if (navigator.geolocation) { + navigator.geolocation.getCurrentPosition(showPosition, handleErrors); + } + + function showPosition(position) { + var $imgElement = $(imgElement); + var imageXY = convertXY( + position.coords.latitude, + position.coords.longitude, + $imgElement.width(), + $imgElement.height() + ); + + $(mapElement) + .find("area") + .each(function(m, areaElement) { + var coords = areaElement.getAttribute("coords").split(","); + var shape = areaElement.getAttribute("shape"); + var poly = []; + for (var n = 0; n < coords.length / 2; n++) { + poly[n] = [coords[n * 2], coords[n * 2 + 1]]; + } + + if ( + (shape === "poly" && isPointInPoly(poly, imageXY[0], imageXY[1])) || + (shape === "rect" && isPointInRect(coords, imageXY[0], imageXY[1])) + ) { + $(areaElement).triggerHandler("click", detectOpts["success"]); + return false; + } + }); + if (detectOpts["complete"]) { + detectOpts["complete"](position); + } + } + + function handleErrors(error) { + if (detectOpts["error"]) { + detectOpts["error"](error); + } + if (detectOpts["complete"]) { + detectOpts["complete"](error); + } + } + + // Converts lat and long into X,Y coodinates on a Equirectangular map. + function convertXY(latitude, longitude, map_width, map_height) { + var x = Math.round((longitude + 180) * (map_width / 360)); + var y = Math.round((latitude * -1 + 90) * (map_height / 180)); + return [x, y]; + } + + // Do a dual-check here to ensure accuracy. Ray-tracing algorithm gives us the + // basic idea of if we're in a polygon, but may be inaccurate if the ray goes + // through a single point exactly at its vertex. We double check positives + // against a bounding box, ensuring the item is actually in that area. + function isPointInPoly(poly, x, y) { + var inside = false; + var bbox = [1000000, 1000000, -1000000, -1000000]; + for (var i = 0, j = poly.length - 1; i < poly.length; j = i++) { + var xi = poly[i][0], + yi = poly[i][1]; + var xj = poly[j][0], + yj = poly[j][1]; + bbox[0] = Math.min(bbox[0], xi); + bbox[1] = Math.min(bbox[1], yi); + bbox[2] = Math.max(bbox[2], xi); + bbox[3] = Math.max(bbox[3], yi); + + var intersect = + yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi; + if (intersect) inside = !inside; + } + + return inside && isPointInRect(bbox, x, y); + } + + // Simple check if a point is in between two X/Y coordinates. Input may be + // any two points, with a box made between them. + function isPointInRect(rect, x, y) { + // Adjust so we're always going top-left to lower-right. + rect = [ + Math.min(rect[0], rect[2]), + Math.min(rect[1], rect[3]), + Math.max(rect[0], rect[2]), + Math.max(rect[1], rect[3]) + ]; + return x >= rect[0] && x <= rect[2] && y >= rect[1] && y <= rect[2]; + } + + return this; + }; + + /** + * Experimental method to rewrite the imagemap based on new image dimensions. + * + * This does not resize the image itself, it recalculates the imagemap to match + * the current dimensions of the image. + */ + methods.resize = function() { + $(mapElement) + .find("area") + .each(function(m, areaElement) { + // Save the original coordinates for further resizing. + if (!areaElement.originalCoords) { + areaElement.originalCoords = { + timezone: areaElement.getAttribute("data-timezone"), + country: areaElement.getAttribute("data-country"), + coords: areaElement.getAttribute("coords"), + pin: areaElement.getAttribute("data-pin") + }; + } + var rescale = imgElement.width / imgElement.getAttribute("width"); + + // Adjust the image size. + $(imgElement) + .parent() + .css({ + width: $(imgElement).width() + "px" + }); + + // Adjust the coords attribute. + var originalCoords = areaElement.originalCoords.coords.split(","); + var newCoords = new Array(); + for (var j = 0; j < originalCoords.length; j++) { + newCoords[j] = Math.round(parseInt(originalCoords[j]) * rescale); + } + areaElement.setAttribute("coords", newCoords.join(",")); + + // Adjust the pin coordinates. + var pinCoords = areaElement.originalCoords.pin.split(","); + pinCoords[0] = Math.round(parseInt(pinCoords[0]) * rescale); + pinCoords[1] = Math.round(parseInt(pinCoords[1]) * rescale); + areaElement.setAttribute("data-pin", pinCoords.join(",")); + + // Fire the change handler on the target. + if (opts.target) { + $(opts.target).triggerHandler("change"); + } + }); + + return this; + }; + + $.fn.timezonePicker = function(method) { + // Method calling logic. + if (methods[method]) { + return methods[method].apply( + this, + Array.prototype.slice.call(arguments, 1) + ); + } else if (typeof method === "object" || !method) { + return methods.init.apply(this, arguments); + } else { + $.error("Method " + method + " does not exist on jQuery.timezonePicker"); + } + }; + + $.fn.timezonePicker.defaults = { + // Selector for the pin that should be used. This selector only works in the + // immediate parent of the image map img tag. + pin: ".timezone-pin", + // Specify a URL for the pin image instead of using a DOM element. + pinUrl: null, + // Preselect a particular timezone. + timezone: null, + // Pass through options to the jQuery maphilight plugin. + maphilight: true, + // Selector for the select list, textfield, or hidden to update upon click. + target: null, + // Selector for the select list, textfield, or hidden to update upon click + // with the specified country. + countryTarget: null, + // If changing the country should use the first timezone within that country. + countryGuess: true, + // A list of country guess exceptions. These should only be needed if a + // country spans multiple timezones. + countryGuesses: { + AU: "Australia/Sydney", + BR: "America/Sao_Paulo", + CA: "America/Toronto", + CN: "Asia/Shanghai", + ES: "Europe/Madrid", + MX: "America/Mexico_City", + RU: "Europe/Moscow", + US: "America/New_York" + }, + // If this map should automatically adjust its size if scaled. Note that + // this can be very expensive computationally and will likely have a delay + // on resize. The maphilight library also is incompatible with this setting + // and will be disabled. + responsive: false, + + // Default options passed along to the maphilight plugin. + fade: false, + stroke: true, + strokeColor: "FFFFFF", + strokeOpacity: 0.4, + fillColor: "FFFFFF", + fillOpacity: 0.4, + groupBy: "data-offset" + }; +})(jQuery); diff --git a/pandora_console/include/javascript/timezonepicker/lib/jquery.timezone-picker.min.js b/pandora_console/include/javascript/timezonepicker/lib/jquery.timezone-picker.min.js new file mode 100644 index 0000000000..fd4e7efc5c --- /dev/null +++ b/pandora_console/include/javascript/timezonepicker/lib/jquery.timezone-picker.min.js @@ -0,0 +1 @@ +(function($){var methods={};var opts={};var selectedTimzone=null;var imgElement=null;var mapElement=null;var $pin=null;var changeHandler=null;methods.init=function(initOpts){var $origCall=this;opts=$.extend({},$.fn.timezonePicker.defaults,initOpts);selectedTimzone=opts.timezone;changeHandler=opts.changeHandler;return $origCall.each(function(index,item){imgElement=item;mapElement=document.getElementsByName(imgElement.useMap.replace(/^#/,""))[0];$(imgElement).wrap('
    ').parent().css({position:"relative",width:$(imgElement).width()+"px"});if(opts.pinUrl){$pin=$('').appendTo(imgElement.parentNode).css("display","none")}else if(opts.pin){$pin=$(imgElement).parent().parent().find(opts.pin).appendTo(imgElement.parentNode).css("display","none")}$(mapElement).find("area").click(function(){var areaElement=this;if($pin){$pin.css("display","block");var pinCoords=$(areaElement).attr("data-pin").split(",");var pinWidth=parseInt($pin.width()/2);var pinHeight=$pin.height();$pin.css({position:"absolute",left:pinCoords[0]-pinWidth+"px",top:pinCoords[1]-pinHeight+"px"})}var timezoneName=$(areaElement).attr("data-timezone");var countryName=$(areaElement).attr("data-country");var offset=$(areaElement).attr("data-offset");if(typeof changeHandler==="function"){changeHandler(timezoneName,countryName,offset)}if(opts.target){if(timezoneName)$(opts.target).val(timezoneName)}if(opts.countryTarget){if(countryName)$(opts.countryTarget).val(countryName)}return false});if(opts.target){$(opts.target).bind("change",function(){$origCall.timezonePicker("updateTimezone",$(this).val())})}if(opts.countryTarget&&opts.countryGuess){$(opts.countryTarget).bind("change",function(){var countryCode=$(this).val();if(opts.countryGuesses[countryCode]){$(mapElement).find('area[data-timezone="'+opts.countryGuesses[countryCode]+'"]').click()}else{$(mapElement).find("area[data-country="+countryCode+"]:first").click()}})}if(opts.responsive){var resizeTimeout=null;$(window).resize(function(){if(resizeTimeout){clearTimeout(resizeTimeout)}resizeTimeout=setTimeout(function(){$origCall.timezonePicker("resize")},200)})}setTimeout(function(){if(opts.responsive&&parseInt(imgElement.width)!==parseInt(imgElement.getAttribute("width"))){$origCall.timezonePicker("resize")}else if(opts.maphilight&&$.fn.maphilight){$(imgElement).maphilight(opts)}if(opts.target){$(opts.target).triggerHandler("change")}},500)})};methods.updateTimezone=function(newTimezone){selectedTimzone=newTimezone;$pin.css("display","none");$(mapElement).find("area").each(function(m,areaElement){if(areaElement.getAttribute("data-timezone")===selectedTimzone){$(areaElement).triggerHandler("click");return false}});return this};methods.detectLocation=function(detectOpts){var detectDefaults={success:undefined,error:undefined,complete:undefined};detectOpts=$.extend(detectDefaults,detectOpts);if(navigator.geolocation){navigator.geolocation.getCurrentPosition(showPosition,handleErrors)}function showPosition(position){var $imgElement=$(imgElement);var imageXY=convertXY(position.coords.latitude,position.coords.longitude,$imgElement.width(),$imgElement.height());$(mapElement).find("area").each(function(m,areaElement){var coords=areaElement.getAttribute("coords").split(",");var shape=areaElement.getAttribute("shape");var poly=[];for(var n=0;ny!=yj>y&&x<(xj-xi)*(y-yi)/(yj-yi)+xi;if(intersect)inside=!inside}return inside&&isPointInRect(bbox,x,y)}function isPointInRect(rect,x,y){rect=[Math.min(rect[0],rect[2]),Math.min(rect[1],rect[3]),Math.max(rect[0],rect[2]),Math.max(rect[1],rect[3])];return x>=rect[0]&&x<=rect[2]&&y>=rect[1]&&y<=rect[2]}return this};methods.resize=function(){$(mapElement).find("area").each(function(m,areaElement){if(!areaElement.originalCoords){areaElement.originalCoords={timezone:areaElement.getAttribute("data-timezone"),country:areaElement.getAttribute("data-country"),coords:areaElement.getAttribute("coords"),pin:areaElement.getAttribute("data-pin")}}var rescale=imgElement.width/imgElement.getAttribute("width");$(imgElement).parent().css({width:$(imgElement).width()+"px"});var originalCoords=areaElement.originalCoords.coords.split(",");var newCoords=new Array;for(var j=0;j"); - $counters.addClass("tree-node-counters"); - - if (typeof counters.total != "undefined" && counters.total >= 0) { - var $totalCounter = $("
    "); - $totalCounter - .addClass("tree-node-counter") - .addClass("total") - .html(counters.total); - - _processNodeCounterTitle($totalCounter, type, "total"); - - // Open the parentheses - $counters.append(" ("); - - $counters.append($totalCounter); + if (type == "services") { + var $counters = $("
    "); + $counters.addClass("tree-node-counters"); if ( - typeof counters.alerts != "undefined" && - counters.alerts > 0 + counters.total_services + + counters.total_agents + + counters.total_modules > + 0 ) { - var $firedCounter = $("
    "); - $firedCounter - .addClass("tree-node-counter") - .addClass("alerts") - .addClass("orange") - .html(counters.alerts); + // Open the parentheses + $counters.append(" ("); - _processNodeCounterTitle($firedCounter, type, "alerts"); + if ( + typeof counters.total_services != "undefined" && + counters.total_services >= 0 + ) { + var $servicesCounter = $("
    "); + $servicesCounter + .addClass("tree-node-counter") + .addClass("total") + .html(counters.total_services); - $counters.append(" : ").append($firedCounter); + _processNodeCounterTitle( + $servicesCounter, + type, + "total_services" + ); + + $counters.append($servicesCounter); + } else { + var $servicesCounter = $("
    "); + $servicesCounter + .addClass("tree-node-counter") + .addClass("total") + .html("0"); + + _processNodeCounterTitle( + $servicesCounter, + type, + "total_services" + ); + + $counters.append($servicesCounter); + } + + if ( + typeof counters.total_agents != "undefined" && + counters.total_agents > 0 + ) { + var $agentsCounter = $("
    "); + $agentsCounter + .addClass("tree-node-counter") + .html(counters.total_agents); + + _processNodeCounterTitle( + $agentsCounter, + type, + "total_agents" + ); + + $counters.append(" : ").append($agentsCounter); + } else { + var $agentsCounter = $("
    "); + $agentsCounter + .addClass("tree-node-counter") + .addClass("total") + .html("0"); + + _processNodeCounterTitle( + $agentsCounter, + type, + "total_agents" + ); + + $counters.append(" : ").append($agentsCounter); + } + + if ( + typeof counters.total_modules != "undefined" && + counters.total_modules > 0 + ) { + var $modulesCounter = $("
    "); + $modulesCounter + .addClass("tree-node-counter") + .addClass("total") + .html(counters.total_modules); + + _processNodeCounterTitle( + $modulesCounter, + type, + "total_modules" + ); + + $counters.append(" : ").append($modulesCounter); + } else { + var $modulesCounter = $("
    "); + $modulesCounter + .addClass("tree-node-counter") + .addClass("total") + .html("0"); + + _processNodeCounterTitle( + $modulesCounter, + type, + "total_modules" + ); + + $counters.append(" : ").append($modulesCounter); + } + + // Close the parentheses + $counters.append(")"); + + hasCounters = true; } - if ( - typeof counters.critical != "undefined" && - counters.critical > 0 - ) { - var $criticalCounter = $("
    "); - $criticalCounter + } else { + var $counters = $("
    "); + $counters.addClass("tree-node-counters"); + + if (typeof counters.total != "undefined" && counters.total >= 0) { + var $totalCounter = $("
    "); + $totalCounter .addClass("tree-node-counter") - .addClass("critical") - .addClass("red") - .html(counters.critical); + .addClass("total") + .html(counters.total); - _processNodeCounterTitle($criticalCounter, type, "critical"); + _processNodeCounterTitle($totalCounter, type, "total"); - $counters.append(" : ").append($criticalCounter); - } - if ( - typeof counters.warning != "undefined" && - counters.warning > 0 - ) { - var $warningCounter = $("
    "); - $warningCounter - .addClass("tree-node-counter") - .addClass("warning") - .addClass("yellow") - .html(counters.warning); + // Open the parentheses + $counters.append(" ("); - _processNodeCounterTitle($warningCounter, type, "warning"); + $counters.append($totalCounter); - $counters.append(" : ").append($warningCounter); - } - if ( - typeof counters.unknown != "undefined" && - counters.unknown > 0 - ) { - var $unknownCounter = $("
    "); - $unknownCounter - .addClass("tree-node-counter") - .addClass("unknown") - .addClass("grey") - .html(counters.unknown); + if ( + typeof counters.alerts != "undefined" && + counters.alerts > 0 + ) { + var $firedCounter = $("
    "); + $firedCounter + .addClass("tree-node-counter") + .addClass("alerts") + .addClass("orange") + .html(counters.alerts); - _processNodeCounterTitle($unknownCounter, type, "unknown"); + _processNodeCounterTitle($firedCounter, type, "alerts"); - $counters.append(" : ").append($unknownCounter); - } - if ( - typeof counters.not_init != "undefined" && - counters.not_init > 0 - ) { - var $notInitCounter = $("
    "); - $notInitCounter - .addClass("tree-node-counter") - .addClass("not_init") - .addClass("blue") - .html(counters.not_init); + $counters.append(" : ").append($firedCounter); + } + if ( + typeof counters.critical != "undefined" && + counters.critical > 0 + ) { + var $criticalCounter = $("
    "); + $criticalCounter + .addClass("tree-node-counter") + .addClass("critical") + .addClass("red") + .html(counters.critical); - _processNodeCounterTitle($notInitCounter, type, "not_init"); + _processNodeCounterTitle($criticalCounter, type, "critical"); - $counters.append(" : ").append($notInitCounter); - } - if (typeof counters.ok != "undefined" && counters.ok > 0) { - var $okCounter = $("
    "); - $okCounter - .addClass("tree-node-counter") - .addClass("ok") - .addClass("green") - .html(counters.ok); + $counters.append(" : ").append($criticalCounter); + } + if ( + typeof counters.warning != "undefined" && + counters.warning > 0 + ) { + var $warningCounter = $("
    "); + $warningCounter + .addClass("tree-node-counter") + .addClass("warning") + .addClass("yellow") + .html(counters.warning); - _processNodeCounterTitle($okCounter, type, "ok"); + _processNodeCounterTitle($warningCounter, type, "warning"); - $counters.append(" : ").append($okCounter); + $counters.append(" : ").append($warningCounter); + } + if ( + typeof counters.unknown != "undefined" && + counters.unknown > 0 + ) { + var $unknownCounter = $("
    "); + $unknownCounter + .addClass("tree-node-counter") + .addClass("unknown") + .addClass("grey") + .html(counters.unknown); + + _processNodeCounterTitle($unknownCounter, type, "unknown"); + + $counters.append(" : ").append($unknownCounter); + } + if ( + typeof counters.not_init != "undefined" && + counters.not_init > 0 + ) { + var $notInitCounter = $("
    "); + $notInitCounter + .addClass("tree-node-counter") + .addClass("not_init") + .addClass("blue") + .html(counters.not_init); + + _processNodeCounterTitle($notInitCounter, type, "not_init"); + + $counters.append(" : ").append($notInitCounter); + } + if (typeof counters.ok != "undefined" && counters.ok > 0) { + var $okCounter = $("
    "); + $okCounter + .addClass("tree-node-counter") + .addClass("ok") + .addClass("green") + .html(counters.ok); + + _processNodeCounterTitle($okCounter, type, "ok"); + + $counters.append(" : ").append($okCounter); + } } // Close the parentheses @@ -436,7 +570,120 @@ var TreeController = { $content.append($alertImage); } - $content.append(element.alias); + + // Events by agent + if (element.showEventsBtn == 1) { + if (typeof element.eventAgent != "undefined") { + $content.append( + '' + ); + var $eventImage = $( + ' ' + ); + $eventImage.addClass("agent-alerts-fired"); + $eventImage + .click(function(e) { + e.preventDefault(); + + document + .getElementById( + "hiddenAgentsEventsForm-" + element.eventAgent + ) + .submit(); + }) + .css("cursor", "pointer"); + + $content.append($eventImage); + } + } + + $content.append(" " + element.alias); + break; + case "services": + if ( + typeof element.statusImageHTML != "undefined" && + element.statusImageHTML.length > 0 + ) { + var $statusImage = $(element.statusImageHTML); + $statusImage.addClass("agent-status"); + + $content.append($statusImage); + } + + var $serviceDetailImage = $( + ' ' + ); + + if (typeof element.serviceDetail != "undefined") { + $serviceDetailImage + .click(function(e) { + e.preventDefault(); + + window.location.href = element.serviceDetail; + }) + .css("cursor", "pointer"); + + $content.append($serviceDetailImage); + } + + $content.append(" " + element.name); + + break; + case "modules": + if ( + typeof element.statusImageHTML != "undefined" && + element.statusImageHTML.length > 0 + ) { + var $statusImage = $(element.statusImageHTML); + $statusImage.addClass("agent-status"); + + $content.append($statusImage); + } + + // Events by module + if (element.showEventsBtn == 1) { + if (typeof element.eventModule != "undefined") { + $content.append( + '' + ); + var $moduleImage = $( + ' ' + ); + $moduleImage + .click(function(e) { + e.preventDefault(); + + document + .getElementById( + "hiddenModulesEventsForm-" + element.eventModule + ) + .submit(); + }) + .css("cursor", "pointer"); + + $content.append($moduleImage); + } + } + + $content.append(" " + element.name); break; case "module": // Status image @@ -500,9 +747,11 @@ var TreeController = { } } else { try { - winopeng( + winopeng_var( element.moduleGraph.url, - element.moduleGraph.handle + element.moduleGraph.handle, + 1000, + 650 ); } catch (error) { // console.log(error); @@ -617,6 +866,19 @@ var TreeController = { } $content.append(element.name); break; + case "services": + // Status image + if ( + typeof element.statusImageHTML != "undefined" && + element.statusImageHTML.length > 0 + ) { + var $statusImage = $(element.statusImageHTML); + $statusImage.addClass("agent-status"); + + $content.append($statusImage); + } + $content.append(element.name); + break; default: $content.append(element.name); break; @@ -820,14 +1082,16 @@ var TreeController = { } controller.recipient.empty(); - controller.recipient.html( - "
    " + - controller.foundMessage + - ": " + - controller.tree.length + - "
    " + - "
    " - ); + if (controller.tree.length !== undefined) { + controller.recipient.html( + "
    " + + controller.foundMessage + + ": " + + controller.tree.length + + "
    " + + "
    " + ); + } var $children = _processGroup(this.recipient, this.tree, true); $children.show(); diff --git a/pandora_console/include/javascript/update_manager.js b/pandora_console/include/javascript/update_manager.js index a091b9c504..bab4ef2aae 100644 --- a/pandora_console/include/javascript/update_manager.js +++ b/pandora_console/include/javascript/update_manager.js @@ -1,3 +1,7 @@ +/* + globals $, jQuery +*/ + var correct_install_progress = true; function form_upload(homeurl) { @@ -322,20 +326,20 @@ function install_package(package, homeurl) { }); var dialog_accept_package_mr_fail_text = - "
    "; + "
    "; dialog_accept_package_mr_fail_text = dialog_accept_package_mr_fail_text + - "
    "; + "

    INFO

    "; dialog_accept_package_mr_fail_text = dialog_accept_package_mr_fail_text + - "

    INFO

    "; - dialog_accept_package_mr_fail_text = - dialog_accept_package_mr_fail_text + - "

    " + + "

    " + mr_not_accepted_code_yes + "

    "; + dialog_accept_package_mr_fail_text = + dialog_accept_package_mr_fail_text + + "
    "; dialog_accept_package_mr_fail_text = dialog_accept_package_mr_fail_text + "
    "; @@ -393,20 +397,21 @@ function install_package(package, homeurl) { ] }); - var dialog_success_pkg_text = "
    "; + var dialog_success_pkg_text = + "
    "; dialog_success_pkg_text = dialog_success_pkg_text + - "
    "; + "

    SUCCESS

    "; dialog_success_pkg_text = dialog_success_pkg_text + - "

    SUCCESS

    "; - dialog_success_pkg_text = - dialog_success_pkg_text + - "

    " + + "

    " + package_success + "

    "; + dialog_success_pkg_text = + dialog_success_pkg_text + + "
    "; dialog_success_pkg_text = dialog_success_pkg_text + "
    "; @@ -452,20 +457,21 @@ function install_package(package, homeurl) { ] }); - var dialog_error_pkg_text = "
    "; + var dialog_error_pkg_text = + "
    "; dialog_error_pkg_text = dialog_error_pkg_text + - "
    "; + "

    ERROR

    "; dialog_error_pkg_text = dialog_error_pkg_text + - "

    ERROR

    "; - dialog_error_pkg_text = - dialog_error_pkg_text + - "

    " + + "

    " + package_error + "

    "; + dialog_error_pkg_text = + dialog_error_pkg_text + + "
    "; dialog_error_pkg_text = dialog_error_pkg_text + "
    "; @@ -529,20 +535,21 @@ function install_package(package, homeurl) { ] }); - var dialog_cancel_pkg_text = "
    "; + var dialog_cancel_pkg_text = + "
    "; dialog_cancel_pkg_text = dialog_cancel_pkg_text + - "
    "; + "

    INFO

    "; dialog_cancel_pkg_text = dialog_cancel_pkg_text + - "

    INFO

    "; - dialog_cancel_pkg_text = - dialog_cancel_pkg_text + - "

    " + + "

    " + package_cancel + "

    "; + dialog_cancel_pkg_text = + dialog_cancel_pkg_text + + "
    "; dialog_cancel_pkg_text = dialog_cancel_pkg_text + "
    "; @@ -567,20 +574,21 @@ function install_package(package, homeurl) { ] }); - var dialog_bad_message_text = "
    "; + var dialog_bad_message_text = + "
    "; dialog_bad_message_text = dialog_bad_message_text + - "
    "; + "

    ERROR

    "; dialog_bad_message_text = dialog_bad_message_text + - "

    ERROR

    "; - dialog_bad_message_text = - dialog_bad_message_text + - "

    " + + "

    " + bad_mr_file + "

    "; + dialog_bad_message_text = + dialog_bad_message_text + + "
    "; dialog_bad_message_text = dialog_bad_message_text + "
    "; @@ -612,20 +620,21 @@ function install_package(package, homeurl) { ] }); - var dialog_success_mr_text = "
    "; + var dialog_success_mr_text = + "
    "; dialog_success_mr_text = dialog_success_mr_text + - "
    "; + "

    SUCCESS

    "; dialog_success_mr_text = dialog_success_mr_text + - "

    SUCCESS

    "; - dialog_success_mr_text = - dialog_success_mr_text + - "

    " + + "

    " + mr_success + "

    "; + dialog_success_mr_text = + dialog_success_mr_text + + "
    "; dialog_success_mr_text = dialog_success_mr_text + "
    "; @@ -680,20 +689,21 @@ function install_package(package, homeurl) { ] }); - var dialog_success_pkg_text = "
    "; + var dialog_success_pkg_text = + "
    "; dialog_success_pkg_text = dialog_success_pkg_text + - "
    "; + "

    SUCCESS

    "; dialog_success_pkg_text = dialog_success_pkg_text + - "

    SUCCESS

    "; - dialog_success_pkg_text = - dialog_success_pkg_text + - "

    " + + "

    " + package_success + "

    "; + dialog_success_pkg_text = + dialog_success_pkg_text + + "
    "; dialog_success_pkg_text = dialog_success_pkg_text + "
    "; @@ -739,20 +749,21 @@ function install_package(package, homeurl) { ] }); - var dialog_error_pkg_text = "
    "; + var dialog_error_pkg_text = + "
    "; dialog_error_pkg_text = dialog_error_pkg_text + - "
    "; + "

    ERROR

    "; dialog_error_pkg_text = dialog_error_pkg_text + - "

    ERROR

    "; - dialog_error_pkg_text = - dialog_error_pkg_text + - "

    " + + "

    " + package_error + "

    "; + dialog_error_pkg_text = + dialog_error_pkg_text + + "
    "; dialog_error_pkg_text = dialog_error_pkg_text + "
    "; @@ -810,20 +821,21 @@ function install_package(package, homeurl) { ] }); - var dialog_error_mr_text = "
    "; + var dialog_error_mr_text = + "
    "; dialog_error_mr_text = dialog_error_mr_text + - "
    "; + "

    ERROR

    "; dialog_error_mr_text = dialog_error_mr_text + - "

    ERROR

    "; - dialog_error_mr_text = - dialog_error_mr_text + - "

    " + + "

    " + mr_error + "

    "; + dialog_error_mr_text = + dialog_error_mr_text + + "
    "; dialog_error_mr_text = dialog_error_mr_text + "
    "; @@ -870,20 +882,21 @@ function install_package(package, homeurl) { ] }); - var dialog_cancel_mr_text = "
    "; + var dialog_cancel_mr_text = + "
    "; dialog_cancel_mr_text = dialog_cancel_mr_text + - "
    "; + "

    INFO

    "; dialog_cancel_mr_text = dialog_cancel_mr_text + - "

    INFO

    "; - dialog_cancel_mr_text = - dialog_cancel_mr_text + - "

    " + + "

    " + mr_cancel + "

    "; + dialog_cancel_mr_text = + dialog_cancel_mr_text + + "
    "; dialog_cancel_mr_text = dialog_cancel_mr_text + "
    "; @@ -906,34 +919,33 @@ function install_package(package, homeurl) { ] }); - $("button:contains(Apply MR)").attr("id", "apply_rr_button"); + $("button:contains(Apply MR)") + .attr("id", "apply_rr_button") + .addClass("success_button"); $("button:contains(Cancel)").attr("id", "cancel_rr_button"); - var dialog_have_mr_text = "
    "; + var dialog_have_mr_text = "
    "; dialog_have_mr_text = dialog_have_mr_text + - "
    "; - dialog_have_mr_text = - dialog_have_mr_text + - "

    " + + "

    " + mr_available_header + - "

    "; + "

    "; + dialog_have_mr_text = + dialog_have_mr_text + "

    " + text1_mr_file + "

    "; dialog_have_mr_text = dialog_have_mr_text + - "

    " + - text1_mr_file + - "

    "; - dialog_have_mr_text = - dialog_have_mr_text + - "

    " + + "

    " + text2_mr_file + - "" + + '' + text3_mr_file + "" + text4_mr_file + "

    "; + dialog_have_mr_text = + dialog_have_mr_text + + "
    "; dialog_have_mr_text = dialog_have_mr_text + "
    "; $("#mr_dialog2").html(dialog_have_mr_text); @@ -988,20 +1000,21 @@ function install_package(package, homeurl) { ] }); - var dialog_success_pkg_text = "
    "; + var dialog_success_pkg_text = + "
    "; dialog_success_pkg_text = dialog_success_pkg_text + - "
    "; + "

    SUCCESS

    "; dialog_success_pkg_text = dialog_success_pkg_text + - "

    SUCCESS

    "; - dialog_success_pkg_text = - dialog_success_pkg_text + - "

    " + + "

    " + package_success + "

    "; + dialog_success_pkg_text = + dialog_success_pkg_text + + "
    "; dialog_success_pkg_text = dialog_success_pkg_text + "
    "; @@ -1043,20 +1056,20 @@ function install_package(package, homeurl) { ] }); - var dialog_error_pkg_text = "
    "; + var dialog_error_pkg_text = "
    "; dialog_error_pkg_text = dialog_error_pkg_text + - "
    "; + "

    ERROR

    "; dialog_error_pkg_text = dialog_error_pkg_text + - "

    ERROR

    "; - dialog_error_pkg_text = - dialog_error_pkg_text + - "

    " + + "

    " + package_error + "

    "; + dialog_error_pkg_text = + dialog_error_pkg_text + + "
    "; dialog_error_pkg_text = dialog_error_pkg_text + "
    "; $("#error_pkg").html(dialog_error_pkg_text); @@ -1120,20 +1133,16 @@ function install_package(package, homeurl) { ] }); - var dialog_cancel_pkg_text = "
    "; + var dialog_cancel_pkg_text = "
    "; + dialog_cancel_pkg_text = + dialog_cancel_pkg_text + "

    INFO

    "; + dialog_cancel_pkg_text = + dialog_cancel_pkg_text + "

    " + package_cancel + "

    "; dialog_cancel_pkg_text = dialog_cancel_pkg_text + - "
    "; - dialog_cancel_pkg_text = - dialog_cancel_pkg_text + - "

    INFO

    "; - dialog_cancel_pkg_text = - dialog_cancel_pkg_text + - "

    " + - package_cancel + - "

    "; + "images/icon_info_mr.png'>
    "; dialog_cancel_pkg_text = dialog_cancel_pkg_text + "
    "; $("#cancel_pkg").html(dialog_cancel_pkg_text); @@ -1210,22 +1219,18 @@ function install_package(package, homeurl) { ] }); - var dialog_text = "
    "; + var dialog_text = "
    "; dialog_text = dialog_text + - "
    "; - dialog_text = - dialog_text + - "

    " + + "

    " + text1_package_file + - "

    "; + "

    "; + dialog_text = dialog_text + "

    " + text2_package_file + "

    "; dialog_text = dialog_text + - "

    " + - text2_package_file + - "

    "; + "
    "; dialog_text = dialog_text + "
    "; $("#pkg_apply_dialog").html(dialog_text); @@ -1246,11 +1251,11 @@ function check_install_package(package, homeurl) { data: parameters, dataType: "json", success: function(data) { - // Print the updated files and take the scroll to the bottom - $("#log_zone").html(data.info); + // Print the updated files and take the scroll to the bottom. + $("#log_zone").append(data.info); $("#log_zone").scrollTop($("#log_zone").prop("scrollHeight")); - // Change the progress bar + // Change the progress bar. if ( $("#form-offline_update ul") .find("li") @@ -1271,14 +1276,19 @@ function check_install_package(package, homeurl) { .trigger("change"); } - // The class loading is present until the update ends + // The class loading is present until the update ends. var isInstalling = $("#form-offline_update ul") .find("li") .hasClass("loading"); if (data.progress < 100 && isInstalling) { - // Recursive call to check the update status + // Recursive call to check the update status. check_install_package(package, homeurl); } + + if (!isInstalling) { + //Check if exist remove files. + delete_desired_files(homeurl); + } } }); } @@ -1513,20 +1523,20 @@ function install_free_package_prev_step(package, version, homeurl) { }); var dialog_accept_package_mr_fail_text = - "
    "; + "
    "; dialog_accept_package_mr_fail_text = dialog_accept_package_mr_fail_text + - "
    "; + "

    INFO

    "; dialog_accept_package_mr_fail_text = dialog_accept_package_mr_fail_text + - "

    INFO

    "; - dialog_accept_package_mr_fail_text = - dialog_accept_package_mr_fail_text + - "

    " + + "

    " + mr_not_accepted_code_yes + "

    "; + dialog_accept_package_mr_fail_text = + dialog_accept_package_mr_fail_text + + "
    "; dialog_accept_package_mr_fail_text = dialog_accept_package_mr_fail_text + "
    "; @@ -1607,20 +1617,21 @@ function install_free_package_prev_step(package, version, homeurl) { ] }); - var dialog_cancel_pkg_text = "
    "; + var dialog_cancel_pkg_text = + "
    "; dialog_cancel_pkg_text = dialog_cancel_pkg_text + - "
    "; + "

    INFO

    "; dialog_cancel_pkg_text = dialog_cancel_pkg_text + - "

    INFO

    "; - dialog_cancel_pkg_text = - dialog_cancel_pkg_text + - "

    " + + "

    " + package_cancel + "

    "; + dialog_cancel_pkg_text = + dialog_cancel_pkg_text + + "
    "; dialog_cancel_pkg_text = dialog_cancel_pkg_text + "
    "; @@ -1637,20 +1648,21 @@ function install_free_package_prev_step(package, version, homeurl) { ] }); - var dialog_bad_message_text = "
    "; + var dialog_bad_message_text = + "
    "; dialog_bad_message_text = dialog_bad_message_text + - "
    "; + "

    ERROR

    "; dialog_bad_message_text = dialog_bad_message_text + - "

    ERROR

    "; - dialog_bad_message_text = - dialog_bad_message_text + - "

    " + + "

    " + bad_mr_file + "

    "; + dialog_bad_message_text = + dialog_bad_message_text + + "
    "; dialog_bad_message_text = dialog_bad_message_text + "
    "; @@ -1682,20 +1694,21 @@ function install_free_package_prev_step(package, version, homeurl) { ] }); - var dialog_success_mr_text = "
    "; + var dialog_success_mr_text = + "
    "; dialog_success_mr_text = dialog_success_mr_text + - "
    "; + "

    SUCCESS

    "; dialog_success_mr_text = dialog_success_mr_text + - "

    SUCCESS

    "; - dialog_success_mr_text = - dialog_success_mr_text + - "

    " + + "

    " + mr_success + "

    "; + dialog_success_mr_text = + dialog_success_mr_text + + "
    "; dialog_success_mr_text = dialog_success_mr_text + "
    "; @@ -1765,20 +1778,21 @@ function install_free_package_prev_step(package, version, homeurl) { ] }); - var dialog_error_mr_text = "
    "; + var dialog_error_mr_text = + "
    "; dialog_error_mr_text = dialog_error_mr_text + - "
    "; + "

    ERROR

    "; dialog_error_mr_text = dialog_error_mr_text + - "

    ERROR

    "; - dialog_error_mr_text = - dialog_error_mr_text + - "

    " + + "

    " + mr_error + "

    "; + dialog_error_mr_text = + dialog_error_mr_text + + "
    "; dialog_error_mr_text = dialog_error_mr_text + "
    "; @@ -1818,20 +1832,21 @@ function install_free_package_prev_step(package, version, homeurl) { ] }); - var dialog_cancel_mr_text = "
    "; + var dialog_cancel_mr_text = + "
    "; dialog_cancel_mr_text = dialog_cancel_mr_text + - "
    "; + "

    INFO

    "; dialog_cancel_mr_text = dialog_cancel_mr_text + - "

    INFO

    "; - dialog_cancel_mr_text = - dialog_cancel_mr_text + - "

    " + + "

    " + mr_cancel + "

    "; + dialog_cancel_mr_text = + dialog_cancel_mr_text + + "
    "; dialog_cancel_mr_text = dialog_cancel_mr_text + "
    "; @@ -1846,34 +1861,33 @@ function install_free_package_prev_step(package, version, homeurl) { ] }); - $("button:contains(Apply MR)").attr("id", "apply_rr_button"); + $("button:contains(Apply MR)") + .attr("id", "apply_rr_button") + .addClass("success_button"); $("button:contains(Cancel)").attr("id", "cancel_rr_button"); - var dialog_have_mr_text = "
    "; + var dialog_have_mr_text = "
    "; dialog_have_mr_text = dialog_have_mr_text + - "
    "; - dialog_have_mr_text = - dialog_have_mr_text + - "

    " + + "

    " + mr_available_header + - "

    "; + "

    "; + dialog_have_mr_text = + dialog_have_mr_text + "

    " + text1_mr_file + "

    "; dialog_have_mr_text = dialog_have_mr_text + - "

    " + - text1_mr_file + - "

    "; - dialog_have_mr_text = - dialog_have_mr_text + - "

    " + + "

    " + text2_mr_file + - "" + + '' + text3_mr_file + "" + text4_mr_file + "

    "; + dialog_have_mr_text = + dialog_have_mr_text + + "
    "; dialog_have_mr_text = dialog_have_mr_text + "
    "; $("#mr_dialog2").html(dialog_have_mr_text); @@ -1941,20 +1955,16 @@ function install_free_package_prev_step(package, version, homeurl) { ] }); - var dialog_cancel_pkg_text = "
    "; + var dialog_cancel_pkg_text = "
    "; + dialog_cancel_pkg_text = + dialog_cancel_pkg_text + "

    INFO

    "; + dialog_cancel_pkg_text = + dialog_cancel_pkg_text + "

    " + package_cancel + "

    "; dialog_cancel_pkg_text = dialog_cancel_pkg_text + - "
    "; - dialog_cancel_pkg_text = - dialog_cancel_pkg_text + - "

    INFO

    "; - dialog_cancel_pkg_text = - dialog_cancel_pkg_text + - "

    " + - package_cancel + - "

    "; + "images/icon_info_mr.png'>
    "; dialog_cancel_pkg_text = dialog_cancel_pkg_text + "
    "; $("#cancel_pkg").html(dialog_cancel_pkg_text); @@ -1968,22 +1978,18 @@ function install_free_package_prev_step(package, version, homeurl) { ] }); - var dialog_text = "
    "; + var dialog_text = "
    "; dialog_text = dialog_text + - "
    "; - dialog_text = - dialog_text + - "

    " + + "

    " + text1_package_file + - "

    "; + "

    "; + dialog_text = dialog_text + "

    " + text2_package_file + "

    "; dialog_text = dialog_text + - "

    " + - text2_package_file + - "

    "; + "
    "; dialog_text = dialog_text + "
    "; $("#pkg_apply_dialog").html(dialog_text); @@ -2030,20 +2036,16 @@ function install_free_package(package, version, homeurl) { ] }); - var dialog_error_pkg_text = "
    "; + var dialog_error_pkg_text = "
    "; + dialog_error_pkg_text = + dialog_error_pkg_text + "

    ERROR

    "; + dialog_error_pkg_text = + dialog_error_pkg_text + "

    " + data["message"] + "

    "; dialog_error_pkg_text = dialog_error_pkg_text + - "
    "; - dialog_error_pkg_text = - dialog_error_pkg_text + - "

    ERROR

    "; - dialog_error_pkg_text = - dialog_error_pkg_text + - "

    " + - data["message"] + - "

    "; + "images/icon_error_mr.png'>
    "; dialog_error_pkg_text = dialog_error_pkg_text + "
    "; $("#error_pkg").html(dialog_error_pkg_text); @@ -2083,20 +2085,17 @@ function install_free_package(package, version, homeurl) { ] }); - var dialog_success_pkg_text = "
    "; + var dialog_success_pkg_text = "
    "; dialog_success_pkg_text = dialog_success_pkg_text + - "

    SUCCESS

    "; + dialog_success_pkg_text = + dialog_success_pkg_text + "

    " + data["message"] + "

    "; + dialog_success_pkg_text = + dialog_success_pkg_text + + "
    "; - dialog_success_pkg_text = - dialog_success_pkg_text + - "

    SUCCESS

    "; - dialog_success_pkg_text = - dialog_success_pkg_text + - "

    " + - data["message"] + - "

    "; + "images/icon_success_mr.png'>
    "; dialog_success_pkg_text = dialog_success_pkg_text + "
    "; $("#success_pkg").html(dialog_success_pkg_text); @@ -2133,20 +2132,16 @@ function install_free_package(package, version, homeurl) { ] }); - var dialog_error_pkg_text = "
    "; + var dialog_error_pkg_text = "
    "; + dialog_error_pkg_text = + dialog_error_pkg_text + "

    ERROR

    "; + dialog_error_pkg_text = + dialog_error_pkg_text + "

    " + data["message"] + "

    "; dialog_error_pkg_text = dialog_error_pkg_text + - "
    "; - dialog_error_pkg_text = - dialog_error_pkg_text + - "

    ERROR

    "; - dialog_error_pkg_text = - dialog_error_pkg_text + - "

    " + - data["message"] + - "

    "; + "images/icon_error_mr.png'>
    "; dialog_error_pkg_text = dialog_error_pkg_text + "
    "; $("#error_pkg").html(dialog_error_pkg_text); @@ -2184,20 +2179,16 @@ function install_free_package(package, version, homeurl) { ] }); - var dialog_error_pkg_text = "
    "; + var dialog_error_pkg_text = "
    "; + dialog_error_pkg_text = + dialog_error_pkg_text + "

    ERROR

    "; + dialog_error_pkg_text = + dialog_error_pkg_text + "

    " + data["message"] + "

    "; dialog_error_pkg_text = dialog_error_pkg_text + - "
    "; - dialog_error_pkg_text = - dialog_error_pkg_text + - "

    ERROR

    "; - dialog_error_pkg_text = - dialog_error_pkg_text + - "

    " + - data["message"] + - "

    "; + "images/icon_error_mr.png'>
    "; dialog_error_pkg_text = dialog_error_pkg_text + "
    "; $("#error_pkg").html(dialog_error_pkg_text); @@ -2237,13 +2228,7 @@ function apply_minor_release(n_mr, pkg, ent, off, homeurl) { $("#mr_dialog2").html(data); error["error"] = true; } else { - $("#mr_dialog2").append( - "

    - " + - applying_mr + - " #" + - mr + - "

    " - ); + $("#mr_dialog2").append("

    - " + applying_mr + " #" + mr + "

    "); } } }); @@ -2290,3 +2275,107 @@ function remove_rr_file_to_extras(homeurl) { success: function(data) {} }); } + +/** + * Function delete files desired and add extras/delete_files.txt. + * + * @param string homeurl Url. + */ +function delete_desired_files(homeurl) { + var home_url = typeof homeurl !== "undefined" ? homeurl + "/" : ""; + + var parameters = { + page: "include/ajax/update_manager.ajax", + delete_desired_files: 1 + }; + + jQuery.ajax({ + data: parameters, + type: "POST", + url: home_url + "ajax.php", + dataType: "json", + success: function(data) { + var translation = data.translation; + // Print the deleted files. + // Print title. + $("#log_zone").append( + "

    " + + translation.title + + ":

    " + ); + $.each(data.status_list, function(key, value) { + var log_zone_line_class = "log_zone_line "; + var msg = ""; + switch (value.status) { + case -1: + //Not exits file. + msg = translation.not_file; + break; + case 0: + //File or directory deleted successfully. + if (value.type === "f") { + log_zone_line_class += ""; + } else { + log_zone_line_class += "bolder"; + } + + msg = value.path; + break; + case 1: + //Problem delete file or directory. + if (value.type === "f") { + log_zone_line_class += "log_zone_line_error"; + } else { + log_zone_line_class += "log_zone_line_error bolder"; + } + + msg = value.path + " ( " + translation.not_deleted + " ) "; + break; + case 2: + //Not found file or directory. + if (value.type === "f") { + log_zone_line_class += "log_zone_line_error"; + } else { + log_zone_line_class += "log_zone_line_error bolder"; + } + + msg = value.path + " ( " + translation.not_found + " ) "; + break; + case 3: + //Don`t read file deleet_files.txt. + log_zone_line_class += "log_zone_line_error bolder"; + msg = translation.not_read; + break; + case 4: + //"deleted" folder could not be created. + log_zone_line_class += "log_zone_line_error bolder"; + msg = value.path + " ( " + translation.folder_deleted_f + " ) "; + break; + case 5: + //"deleted" folder was created. + log_zone_line_class += "bolder"; + msg = translation.folder_deleted_t; + break; + case 6: + //The "delete files" could not be the "delete" folder. + log_zone_line_class += "log_zone_line_error bolder"; + msg = value.path + " ( " + translation.move_file_f + " ) "; + break; + case 7: + //The "delete files" is moved to the "delete" folder. + log_zone_line_class += "bolder"; + msg = translation.move_file_d; + break; + default: + // It can not come without state. + break; + } + + //Print line. + $("#log_zone").append( + "" + msg + "
    " + ); + }); + } + }); +} diff --git a/pandora_console/include/languages/en_GB.mo b/pandora_console/include/languages/en_GB.mo index f585765553..4b915e98e8 100644 Binary files a/pandora_console/include/languages/en_GB.mo and b/pandora_console/include/languages/en_GB.mo differ diff --git a/pandora_console/include/languages/en_GB.po b/pandora_console/include/languages/en_GB.po index 3eab48be5d..c6e833bc32 100644 --- a/pandora_console/include/languages/en_GB.po +++ b/pandora_console/include/languages/en_GB.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: pandora-fms\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-03-14 10:58+0100\n" -"PO-Revision-Date: 2018-12-07 12:05+0000\n" -"Last-Translator: Vanessa \n" +"PO-Revision-Date: 2019-03-25 16:10+0000\n" +"Last-Translator: Zarzuelo \n" "Language-Team: English (United Kingdom) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2018-12-07 12:16+0000\n" -"X-Generator: Launchpad (build 18831)\n" +"X-Launchpad-Export-Date: 2019-03-25 16:24+0000\n" +"X-Generator: Launchpad (build 18910)\n" "Language: en_GB\n" #: ../../extensions/agents_alerts.php:55 @@ -23480,7 +23480,7 @@ msgstr "Only avg, min and max are displayed by default" #: ../../enterprise/include/functions_reporting_pdf.php:1746 #: ../../enterprise/include/functions_reporting_pdf.php:2149 msgid "Fail" -msgstr "Error" +msgstr "Fail" #: ../../include/functions_config.php:602 msgid "Display lateral menus with left click" @@ -36481,8 +36481,8 @@ msgstr "" #: ../../enterprise/load_enterprise.php:584 #, php-format msgid "" -"License out of limits

    " -"This node has a metaconsole license and it allows %d agents and you have %d " +"Out of license limits

    " +"This node has a Metaconsole license that allows %d agents, and you have %d " "agents cached." msgstr "" "License expired

    This " @@ -36492,20 +36492,21 @@ msgstr "" #: ../../enterprise/load_enterprise.php:592 #, php-format msgid "" -"License out of limits

    " -"This license allows %d agents and you have %d agents configured." +"Out of license limits

    " +"This node has a Metaconsole license that allows %d agents, and you have %d " +"agents configured." msgstr "" "License expired

    This " -"license allows %d agents and you have %d agents configured." +"license allows %d agents, and you have %d agents configured." #: ../../enterprise/load_enterprise.php:597 #, php-format msgid "" -"License out of limits

    " +"Out of license limits

    " "This license allows %d modules and you have %d modules configured." msgstr "" -"License expired

    This " -"license allows %d modules and you have %d modules configured." +"Out of license limits

    This " +"license allows %d modules, and you have %d modules configured." #: ../../enterprise/load_enterprise.php:604 msgid "" diff --git a/pandora_console/include/rest-api/index.php b/pandora_console/include/rest-api/index.php new file mode 100644 index 0000000000..10f87488c7 --- /dev/null +++ b/pandora_console/include/rest-api/index.php @@ -0,0 +1,49 @@ + $visualConsoleId]); + $visualConsoleData = $visualConsole->toArray(); + $groupId = $visualConsoleData['groupId']; + + // ACL. + $aclRead = check_acl($config['id_user'], $groupId, 'VR'); + $aclWrite = check_acl($config['id_user'], $groupId, 'VW'); + $aclManage = check_acl($config['id_user'], $groupId, 'VM'); + + if (!$aclRead && !$aclWrite && !$aclManage) { + db_pandora_audit( + 'ACL Violation', + 'Trying to access visual console without group access' + ); + exit; + } + + echo $visualConsole; +} else if ($getVisualConsoleItems === true) { + $vcItems = VisualConsole::getItemsFromDB($visualConsoleId, $aclUserGroups); + echo '['.implode($vcItems, ',').']'; +} + +exit; diff --git a/pandora_console/include/rest-api/models/CachedModel.php b/pandora_console/include/rest-api/models/CachedModel.php new file mode 100644 index 0000000000..e4cf65b15a --- /dev/null +++ b/pandora_console/include/rest-api/models/CachedModel.php @@ -0,0 +1,116 @@ + 0) { + // Obtain the item's data from cache. + $cachedData = static::fetchCachedData($filter); + if ($cachedData === null) { + $userId = (static::$indexCacheByUser === true) ? $config['id_user'] : null; + + // Delete expired data cache. + static::clearCachedData( + [ + 'vc_item_id' => $filter['id'], + 'vc_id' => $filter['id_layout'], + 'user_id' => $userId, + ] + ); + // Obtain the item's data from the database. + $data = static::fetchDataFromDB($filter); + // Save the item's data in cache. + static::saveCachedData( + [ + 'vc_item_id' => $filter['id'], + 'vc_id' => $filter['id_layout'], + 'user_id' => $userId, + 'expiration' => $filter['cache_expiration'], + ], + $data + ); + } else { + $data = $cachedData; + } + } else { + $data = static::fetchDataFromDB($filter); + } + + return static::fromArray($data); + } + + +} diff --git a/pandora_console/include/rest-api/models/Model.php b/pandora_console/include/rest-api/models/Model.php new file mode 100644 index 0000000000..78ef90468e --- /dev/null +++ b/pandora_console/include/rest-api/models/Model.php @@ -0,0 +1,231 @@ +validateData($unknownData); + $this->data = $this->decode($unknownData); + // Sort alphabetically. + ksort($this->data, (SORT_NATURAL | SORT_FLAG_CASE)); + } + + + /** + * Instance the class with the unknown input data. + * + * @param array $data Unknown data structure. + * + * @return self Instance of the model. + */ + public static function fromArray(array $data) + { + // The reserved word static refers to the invoked class at runtime. + return new static($data); + } + + + /** + * Obtain a data structure from the database using a filter. + * + * @param array $filter Filter to retrieve the modeled element. + * + * @return array The modeled element data structure stored into the DB. + * @throws \Exception When the data cannot be retrieved from the DB. + * + * @abstract + */ + abstract protected static function fetchDataFromDB(array $filter); + + + /** + * Obtain a model's instance from the database using a filter. + * + * @param array $filter Filter to retrieve the modeled element. + * + * @return self A modeled element's instance. + */ + public static function fromDB(array $filter): self + { + // The reserved word static refers to the invoked class at runtime. + return static::fromArray(static::fetchDataFromDB($filter)); + } + + + /** + * JSON representation of the model. + * + * @return string + */ + public function toArray(): array + { + return $this->data; + } + + + /** + * JSON representation of the model. + * + * @return string + */ + public function toJson(): string + { + return \json_encode($this->data); + } + + + /** + * Text representation of the model. + * + * @return string + */ + public function __toString(): string + { + return $this->toJson(); + } + + + /* + * ------------- + * - UTILITIES - + * ------------- + */ + + + /** + * From a unknown value, it will try to extract a valid boolean value. + * + * @param mixed $value Unknown input. + * + * @return boolean Valid boolean value. + */ + protected static function parseBool($value): bool + { + if (\is_bool($value) === true) { + return $value; + } else if (\is_numeric($value) === true) { + return $value > 0; + } else if (\is_string($value) === true) { + return $value === '1' || $value === 'true'; + } else { + return false; + } + } + + + /** + * Return a not empty string or a default value from a unknown value. + * + * @param mixed $val Input value. + * @param mixed $def Default value. + * + * @return mixed A valid string (not empty) extracted from the input + * or the default value. + */ + protected static function notEmptyStringOr($val, $def) + { + return (\is_string($val) === true && strlen($val) > 0) ? $val : $def; + } + + + /** + * Return a valid integer or a default value from a unknown value. + * + * @param mixed $val Input value. + * @param mixed $def Default value. + * + * @return mixed A valid int extracted from the input or the default value. + */ + protected static function parseIntOr($val, $def) + { + return (is_numeric($val) === true) ? (int) $val : $def; + } + + + /** + * Return a valid float or a default value from a unknown value. + * + * @param mixed $val Input value. + * @param mixed $def Default value. + * + * @return mixed A valid float extracted from the input or the + * default value. + */ + protected static function parseFloatOr($val, $def) + { + return (is_numeric($val) === true) ? (float) $val : $def; + } + + + /** + * Get a value from a dictionary from a possible pool of keys. + * + * @param array $dict Input array. + * @param array $keys Possible keys. + * + * @return mixed The first value found with the pool of keys or null. + */ + protected static function issetInArray(array $dict, array $keys) + { + foreach ($keys as $key => $value) { + if (isset($dict[$value]) === true) { + return $dict[$value]; + } + } + + return null; + } + + +} diff --git a/pandora_console/include/rest-api/models/VisualConsole/Container.php b/pandora_console/include/rest-api/models/VisualConsole/Container.php new file mode 100644 index 0000000000..ad1f34a2ff --- /dev/null +++ b/pandora_console/include/rest-api/models/VisualConsole/Container.php @@ -0,0 +1,377 @@ + (int) $data['id'], + 'name' => $data['name'], + 'groupId' => static::extractGroupId($data), + 'backgroundImage' => static::extractBackgroundImage($data), + 'backgroundColor' => static::extractBackgroundColor($data), + 'isFavorite' => static::extractFavorite($data), + 'width' => (int) $data['width'], + 'height' => (int) $data['height'], + 'backgroundURL' => static::extractBackgroundUrl($data), + 'relationLineWidth' => (int) $data['relationLineWidth'], + ]; + } + + + /** + * Extract a group Id value. + * + * @param array $data Unknown input data structure. + * + * @return integer Valid identifier of a group. + * + * @throws \InvalidArgumentException When a valid group Id can't be found. + */ + private static function extractGroupId(array $data): int + { + $groupId = static::parseIntOr( + static::issetInArray($data, ['id_group', 'groupId']), + null + ); + + if ($groupId === null || $groupId < 0) { + throw new \InvalidArgumentException( + 'the group Id property is required and should be integer' + ); + } + + return $groupId; + } + + + /** + * Extract a image name value. + * + * @param array $data Unknown input data structure. + * + * @return mixed String representing the image name (not empty) or null. + */ + private static function extractBackgroundImage(array $data) + { + $backgroundImage = static::notEmptyStringOr( + static::issetInArray($data, ['background', 'backgroundURL']), + null + ); + + return ($backgroundImage === 'None.png') ? null : $backgroundImage; + } + + + /** + * Extract a image url value. + * + * @param array $data Unknown input data structure. + * + * @return mixed String representing the image url (not empty) or null. + */ + private static function extractBackgroundUrl(array $data) + { + return static::notEmptyStringOr( + static::issetInArray($data, ['backgroundURL']), + null + ); + } + + + /** + * Extract a background color value. + * + * @param array $data Unknown input data structure. + * + * @return mixed String representing the color (not empty) or null. + */ + private static function extractBackgroundColor(array $data) + { + return static::notEmptyStringOr( + static::issetInArray( + $data, + [ + 'backgroundColor', + 'background_color', + ] + ), + null + ); + } + + + /** + * Extract the "is favorite" switch value. + * + * @param array $data Unknown input data structure. + * + * @return boolean If the item is favorite or not. + */ + private static function extractFavorite(array $data): bool + { + return static::parseBool( + static::issetInArray($data, ['is_favourite', 'isFavorite']) + ); + } + + + /** + * Obtain a container data structure from the database using a filter. + * + * @param array $filter Filter of the Visual Console. + * + * @return self A Visual Console Container instance. + * @throws \Exception When the data cannot be retrieved from the DB. + * + * @override Model::fetchDataFromDB. + */ + protected static function fetchDataFromDB(array $filter) + { + // Due to this DB call, this function cannot be unit tested without + // a proper mock. + $row = \db_get_row_filter('tlayout', $filter); + + if ($row === false) { + throw new \Exception('error fetching the data from the DB'); + } + + // Load side libraries. + global $config; + include_once $config['homedir'].'/include/functions_io.php'; + include_once $config['homedir'].'/include/functions_ui.php'; + + // Clean HTML entities. + $row = \io_safe_output($row); + + $row['relationLineWidth'] = (int) $config['vc_line_thickness']; + + $backgroundUrl = static::extractBackgroundUrl($row); + $backgroundImage = static::extractBackgroundImage($row); + + if ($backgroundUrl === null && $backgroundImage !== null) { + $row['backgroundURL'] = ui_get_full_url( + 'images/console/background/'.$backgroundImage, + false, + false, + false + ); + } + + return \io_safe_output($row); + } + + + /** + * Obtain a item's class. + * + * @param integer $type Type of the item of the Visual Console. + * + * @return mixed A reference to the item's class. + */ + public static function getItemClass(int $type) + { + switch ($type) { + case STATIC_GRAPH: + return Items\StaticGraph::class; + + case MODULE_GRAPH: + return Items\ModuleGraph::class; + + case SIMPLE_VALUE: + case SIMPLE_VALUE_MAX: + case SIMPLE_VALUE_MIN: + case SIMPLE_VALUE_AVG: + return Items\SimpleValue::class; + + case PERCENTILE_BAR: + case PERCENTILE_BUBBLE: + case CIRCULAR_PROGRESS_BAR: + case CIRCULAR_INTERIOR_PROGRESS_BAR: + return Items\Percentile::class; + + case LABEL: + return Items\Label::class; + + case ICON: + return Items\Icon::class; + + // Enterprise item. It may not exist. + case SERVICE: + return \class_exists('\Enterprise\Models\VisualConsole\Items\Service') ? \Enterprise\Models\VisualConsole\Items\Service::class : Item::class; + + case GROUP_ITEM: + return Items\Group::class; + + case BOX_ITEM: + return Items\Box::class; + + case LINE_ITEM: + return Items\Line::class; + + case AUTO_SLA_GRAPH: + return Items\EventsHistory::class; + + case DONUT_GRAPH: + return Items\DonutGraph::class; + + case BARS_GRAPH: + return Items\BarsGraph::class; + + case CLOCK: + return Items\Clock::class; + + case COLOR_CLOUD: + return Items\ColorCloud::class; + + default: + return Item::class; + } + } + + + /** + * Obtain a list of items which belong to the Visual Console. + * + * @param integer $layoutId Identifier of the Visual Console. + * @param array $groupsFilter Groups can access user. + * + * @return array A list of items. + * @throws \Exception When the data cannot be retrieved from the DB. + */ + public static function getItemsFromDB( + int $layoutId, + array $groupsFilter=[] + ): array { + // Default filter. + $filter = ['id_layout' => $layoutId]; + $fields = [ + 'id', + 'type', + 'cache_expiration', + 'id_layout', + ]; + + // Override the filter if the groups filter is not empty. + if (count($groupsFilter) > 0) { + // Filter group for elements groups. + $filter = []; + $filter[] = \db_format_array_where_clause_sql( + [ + 'id_layout' => $layoutId, + 'element_group' => $groupsFilter, + ] + ); + + // Filter groups for type groups. + // Only true condition if type is GROUP_ITEM. + $filter[] = '('.\db_format_array_where_clause_sql( + [ + 'type' => GROUP_ITEM, + 'id_group' => $groupsFilter, + ] + ).')'; + } + + $rows = \db_get_all_rows_filter( + 'tlayout_data', + $filter, + $fields, + 'OR' + ); + + if ($rows === false) { + $rows = []; + } + + $items = []; + + foreach ($rows as $data) { + $itemId = (int) $data['id']; + $class = static::getItemClass((int) $data['type']); + + try { + array_push($items, $class::fromDB($data)); + } catch (\Throwable $e) { + // TODO: Log this? + } + } + + return $items; + } + + +} diff --git a/pandora_console/include/rest-api/models/VisualConsole/Item.php b/pandora_console/include/rest-api/models/VisualConsole/Item.php new file mode 100644 index 0000000000..617b48e517 --- /dev/null +++ b/pandora_console/include/rest-api/models/VisualConsole/Item.php @@ -0,0 +1,1190 @@ + (int) $data['id'], + 'type' => (int) $data['type'], + 'label' => static::extractLabel($data), + 'labelPosition' => static::extractLabelPosition($data), + 'isLinkEnabled' => static::extractIsLinkEnabled($data), + 'isOnTop' => static::extractIsOnTop($data), + 'parentId' => static::extractParentId($data), + 'aclGroupId' => static::extractAclGroupId($data), + 'width' => (int) $data['width'], + 'height' => (int) $data['height'], + 'x' => static::extractX($data), + 'y' => static::extractY($data), + ]; + + if (static::$useLinkedModule === true) { + $decodedData = array_merge( + $decodedData, + static::extractLinkedModule($data) + ); + } else if (static::$useLinkedAgent === true) { + $decodedData = array_merge( + $decodedData, + static::extractLinkedAgent($data) + ); + } + + if (static::$useLinkedVisualConsole === true) { + $decodedData = array_merge( + $decodedData, + static::extractLinkedVisualConsole($data) + ); + } + + if (static::$useHtmlOutput === true) { + $decodedData['encodedHtml'] = static::extractEncodedHtml($data); + } + + // Conditionally add the item link. + if ($decodedData['isLinkEnabled'] === true) { + $decodedData['link'] = static::notEmptyStringOr( + static::issetInArray($data, ['link']), + null + ); + } + + return $decodedData; + } + + + /** + * Extract x y axis value. + * + * @param array $data Unknown input data structure. + * + * @return integer Valid x axis position of the item. + */ + private static function extractX(array $data): int + { + return static::parseIntOr( + static::issetInArray($data, ['x', 'pos_x']), + 0 + ); + } + + + /** + * Extract a y axis value. + * + * @param array $data Unknown input data structure. + * + * @return integer Valid y axis position of the item. + */ + private static function extractY(array $data): int + { + return static::parseIntOr( + static::issetInArray($data, ['y', 'pos_y']), + 0 + ); + } + + + /** + * Extract a group Id (for ACL) value. + * + * @param array $data Unknown input data structure. + * + * @return integer Valid identifier of a group. + */ + private static function extractAclGroupId(array $data) + { + return static::parseIntOr( + static::issetInArray($data, ['id_group', 'aclGroupId']), + null + ); + } + + + /** + * Extract a parent Id value. + * + * @param array $data Unknown input data structure. + * + * @return integer Valid identifier of the item's parent. + */ + private static function extractParentId(array $data) + { + return static::parseIntOr( + static::issetInArray($data, ['parentId', 'parent_item']), + null + ); + } + + + /** + * Extract the "is on top" switch value. + * + * @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 the "is link enabled" switch value. + * + * @param array $data Unknown input data structure. + * + * @return boolean If the item has the link enabled or not. + */ + private static function extractIsLinkEnabled(array $data): bool + { + return static::parseBool( + static::issetInArray($data, ['isLinkEnabled', 'enable_link']) + ); + } + + + /** + * Extract a label value. + * + * @param array $data Unknown input data structure. + * + * @return mixed String representing the label (not empty) or null. + */ + private static function extractLabel(array $data) + { + return static::notEmptyStringOr( + static::issetInArray($data, ['label']), + null + ); + } + + + /** + * Extract a label position value. + * + * @param array $data Unknown input data structure. + * + * @return mixed One string of up|right|left|down. down by default. + */ + private static function extractLabelPosition(array $data): string + { + $labelPosition = static::notEmptyStringOr( + static::issetInArray($data, ['labelPosition', 'label_position']), + null + ); + + switch ($labelPosition) { + case 'up': + case 'right': + case 'left': + return $labelPosition; + + default: + return 'down'; + } + } + + + /** + * Extract an agent Id value. + * + * @param array $data Unknown input data structure. + * + * @return integer Valid identifier of an agent. + */ + private static function extractAgentId(array $data) + { + return static::parseIntOr( + static::issetInArray($data, ['agentId', 'id_agent', 'id_agente']), + null + ); + } + + + /** + * Extract an module Id value. + * + * @param array $data Unknown input data structure. + * + * @return integer Valid identifier of a module. + */ + private static function extractModuleId(array $data) + { + return static::parseIntOr( + static::issetInArray( + $data, + [ + 'moduleId', + 'id_agente_modulo', + 'id_modulo', + ] + ), + null + ); + } + + + /** + * Extract an metaconsole node Id value. + * + * @param array $data Unknown input data structure. + * + * @return integer Valid identifier of a metaconsole node. + */ + private static function extractMetaconsoleId(array $data) + { + return static::parseIntOr( + static::issetInArray($data, ['metaconsoleId', 'id_metaconsole']), + null + ); + } + + + /** + * Extract the values of a linked agent. + * + * @param array $data Unknown input data structure. + * + * @return array Data structure of the linked agent info. + * + * @example [ + * 'metaconsoleId' => 1, + * 'agentId' => 2, + * 'agentName' => 'Foo', + * ] + * @example [ + * 'agentId' => 20, + * 'agentName' => 'Bar', + * ] + * @example [ + * 'agentId' => null, + * 'agentName' => null, + * ] + */ + protected static function extractLinkedAgent(array $data): array + { + $agentData = []; + + // We should add the metaconsole Id if we can. + $metaconsoleId = static::extractMetaconsoleId($data); + if ($metaconsoleId !== null && $metaconsoleId <= 0) { + $agentData['metaconsoleId'] = null; + } else { + $agentData['metaconsoleId'] = $metaconsoleId; + } + + // The agent Id should be a valid int or a null value. + $agentData['agentId'] = static::extractAgentId($data); + + // The agent name should be a valid string or a null value. + $agentData['agentName'] = static::notEmptyStringOr( + static::issetInArray($data, ['agentName', 'agent_name']), + null + ); + + // The agent alias should be a valid string or a null value. + $agentData['agentAlias'] = static::notEmptyStringOr( + static::issetInArray($data, ['agentAlias', 'agent_alias']), + null + ); + + // The agent description should be a valid string or a null value. + $agentData['agentDescription'] = static::notEmptyStringOr( + static::issetInArray($data, ['agentDescription', 'agent_description']), + null + ); + + // The agent address should be a valid string or a null value. + $agentData['agentAddress'] = static::notEmptyStringOr( + static::issetInArray($data, ['agentAddress', 'agent_address']), + null + ); + + return $agentData; + } + + + /** + * Extract the values of a linked module. + * + * @param array $data Unknown input data structure. + * + * @return array Data structure of the linked module info. + * + * @example [ + * 'metaconsoleId' => 1, + * 'agentId' => 2, + * 'agentName' => 'Foo', + * 'moduleId' => 1, + * 'moduleName' => 'cpu', + * ] + * @example [ + * 'agentId' => 4, + * 'agentName' => 'Bar', + * 'moduleId' => null, + * 'moduleName' => null, + * ] + * @example [ + * 'agentId' => null, + * 'agentName' => null, + * 'moduleId' => null, + * 'moduleName' => null, + * ] + */ + protected static function extractLinkedModule(array $data): array + { + // Initialize the data with the agent data and then expand it. + $moduleData = static::extractLinkedAgent($data); + + // The module Id should be a valid int or a null value. + $moduleData['moduleId'] = static::extractModuleId($data); + + // The module name should be a valid string or a null value. + $moduleData['moduleName'] = static::notEmptyStringOr( + static::issetInArray($data, ['moduleName', 'module_name']), + null + ); + + // The module description should be a valid string or a null value. + $moduleData['moduleDescription'] = static::notEmptyStringOr( + static::issetInArray($data, ['moduleDescription', 'module_description']), + null + ); + + return $moduleData; + } + + + /** + * Extract the values of a linked visual console. + * + * @param array $data Unknown input data structure. + * + * @return array Data structure of the linked visual console info. + * + * @example [ + * 'metaconsoleId' => 2, + * 'linkedLayoutId' => 12, + * 'linkedLayoutAgentId' => 48, + * 'linkedLayoutStatusType' => 'default', + * ] + * @example [ + * 'linkedLayoutId' => 11, + * 'linkedLayoutAgentId' => null, + * 'linkedLayoutStatusType' => 'weight', + * 'linkedLayoutStatusTypeWeight' => 80, + * ] + * @example [ + * 'metaconsoleId' => 2, + * 'linkedLayoutId' => 10, + * 'linkedLayoutAgentId' => 48, + * 'linkedLayoutStatusType' => 'service', + * 'linkedLayoutStatusTypeWarningThreshold' => 50, + * 'linkedLayoutStatusTypeCriticalThreshold' => 80, + * ] + */ + private static function extractLinkedVisualConsole(array $data): array + { + $vcData = []; + + // We should add the metaconsole Id if we can. If not, + // it doesn't have to be into the structure. + $metaconsoleId = static::extractMetaconsoleId($data); + if ($metaconsoleId !== null) { + $vcData['metaconsoleId'] = $metaconsoleId; + } + + // The linked vc Id should be a valid int or a null value. + $vcData['linkedLayoutId'] = static::parseIntOr( + static::issetInArray($data, ['linkedLayoutId', 'id_layout_linked']), + null + ); + + // The linked vc agent Id should be a valid int or a null value. + $vcData['linkedLayoutAgentId'] = static::parseIntOr( + static::issetInArray( + $data, + [ + 'linkedLayoutAgentId', + 'linked_layout_node_id', + ] + ), + null + ); + + // The linked vc status type should be a enum value. + $linkedLayoutStatusType = static::notEmptyStringOr( + static::issetInArray( + $data, + [ + 'linkedLayoutStatusType', + 'linked_layout_status_type', + ] + ), + null + ); + + // Extract data for the calculation of the linked visual console status. + switch ($linkedLayoutStatusType) { + case 'default': + default: + $vcData['linkedLayoutStatusType'] = 'default'; + break; + + case 'weight': + $vcData['linkedLayoutStatusType'] = 'weight'; + $vcData['linkedLayoutStatusTypeWeight'] = static::parseIntOr( + static::issetInArray( + $data, + [ + 'linkedLayoutStatusTypeWeight', + 'id_layout_linked_weight', + ] + ), + 0 + ); + break; + + case 'service': + $vcData['linkedLayoutStatusType'] = 'service'; + $vcData['linkedLayoutStatusTypeWarningThreshold'] = static::parseIntOr( + static::issetInArray( + $data, + [ + 'linkedLayoutStatusTypeWarningThreshold', + 'linked_layout_status_as_service_warning', + ] + ), + 0 + ); + $vcData['linkedLayoutStatusTypeCriticalThreshold'] = static::parseIntOr( + static::issetInArray( + $data, + [ + 'linkedLayoutStatusTypeCriticalThreshold', + 'linked_layout_status_as_service_critical', + ] + ), + 0 + ); + break; + } + + return $vcData; + } + + + /** + * Extract a encoded HTML representation of the item. + * + * @param array $data Unknown input data structure. + * + * @return string The HTML representation in base64 encoding. + */ + private static function extractEncodedHtml(array $data): string + { + if (isset($data['encodedHtml']) === true) { + return $data['encodedHtml']; + } else if (isset($data['html']) === true) { + return base64_encode($data['html']); + } + + return ''; + } + + + /** + * Fetch a vc item data structure from the database using a filter. + * + * @param array $filter Filter of the Visual Console Item. + * + * @return array The Visual Console Item 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): array + { + // Load side libraries. + global $config; + include_once $config['homedir'].'/include/functions_io.php'; + + // 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'); + } + + // Clean up to two levels of HTML entities. + $row = \io_safe_output(\io_safe_output($row)); + + /* + * Retrieve extra data. + */ + + // The linked module includes the agent data. + if (static::$useLinkedModule === true) { + $row = array_merge($row, static::fetchModuleDataFromDB($row)); + } else if (static::$useLinkedAgent === true) { + $row = array_merge($row, static::fetchAgentDataFromDB($row)); + } + + // Build the item link if needed. + if (static::extractIsLinkEnabled($row) === true) { + $row['link'] = static::buildLink($row); + } + + return $row; + } + + + /** + * Fetch a cache item data structure from the database using a filter. + * + * @param array $filter Filter of the Visual Console Item. + * + * @return array The Visual Console Item data structure stored into the DB. + * @throws \Exception When the data cannot be retrieved from the DB. + * + * @override CachedModel::fetchCachedData. + */ + protected static function fetchCachedData(array $filter) + { + global $config; + + $filter = [ + 'vc_id' => (int) $filter['id_layout'], + 'vc_item_id' => (int) $filter['id'], + '(UNIX_TIMESTAMP(`created_at`) + `expiration`) > UNIX_TIMESTAMP()' + ]; + + if (static::$indexCacheByUser === true) { + $filter['user_id'] = $config['id_user']; + } + + $data = \db_get_value_filter( + 'data', + 'tvisual_console_elements_cache', + $filter + ); + + if ($data === false) { + return null; + } + + return json_decode(base64_decode($data), true); + } + + + /** + * Stores the data structure obtained. + * + * @param array $filter Filter to save the modeled element. + * @param array $data Modeled element to save. + * + * @return boolean The modeled element data structure stored into the DB. + * @throws \Exception When the data cannot be retrieved from the DB. + * + * @override CachedModel::saveCachedData. + */ + protected static function saveCachedData(array $filter, array $data): bool + { + return \db_process_sql_insert( + 'tvisual_console_elements_cache', + [ + 'vc_id' => $filter['vc_id'], + 'vc_item_id' => $filter['vc_item_id'], + 'user_id' => $filter['user_id'], + 'data' => base64_encode(json_encode($data)), + 'expiration' => $filter['expiration'], + ] + ) > 0; + } + + + /** + * Deletes previous data that are not useful. + * + * @param array $filter Filter to retrieve the modeled element. + * + * @return array The modeled element data structure stored into the DB. + * @throws \Exception When the data cannot be retrieved from the DB. + * + * @override CachedModel::clearCachedData. + */ + protected static function clearCachedData(array $filter): int + { + return \db_process_sql_delete( + 'tvisual_console_elements_cache', + $filter + ); + } + + + /** + * Fetch a data structure of an agent from the database using the + * vs item's data. + * + * @param array $itemData Visual Console Item's data structure. + * + * @return array The agent data structure stored into the DB. + * + * @throws \InvalidArgumentException When the input agent Id is invalid. + * @throws \Exception When the data cannot be retrieved from the DB. + */ + protected static function fetchAgentDataFromDB(array $itemData): array + { + $agentData = []; + + // We should add the metaconsole Id if we can. + $metaconsoleId = static::extractMetaconsoleId($itemData); + + // Can't fetch an agent with an invalid Id. + $agentId = static::extractAgentId($itemData); + if ($agentId === null) { + throw new \InvalidArgumentException('invalid agent Id'); + } + + // Staticgraph don't need to have an agent. + if ($agentId === 0) { + return $agentData; + } + + if (\is_metaconsole() && $metaconsoleId === null) { + throw new \InvalidArgumentException('missing metaconsole node Id'); + } + + $agent = false; + + if (\is_metaconsole()) { + $sql = sprintf( + 'SELECT nombre, alias, direccion, comentarios + FROM tmetaconsole_agent + WHERE id_tagente = %s and id_tmetaconsole_setup = %s', + $agentId, + $metaconsoleId + ); + } else { + $sql = sprintf( + 'SELECT nombre, alias, direccion, comentarios + FROM tagente + WHERE id_agente = %s', + $agentId + ); + } + + $agent = \db_get_row_sql($sql); + + if ($agent === false) { + throw new \Exception('error fetching the data from the DB'); + } + + // The agent name should be a valid string or a null value. + $agentData['agentName'] = $agent['nombre']; + $agentData['agentAlias'] = $agent['alias']; + $agentData['agentDescription'] = $agent['comentarios']; + $agentData['agentAddress'] = $agent['direccion']; + + return $agentData; + } + + + /** + * Fetch a data structure of an module from the database using the + * vs item's data. + * + * @param array $itemData Visual Console Item's data structure. + * + * @return array The module data structure stored into the DB. + * @throws \InvalidArgumentException When the input module Id is invalid. + * @throws \Exception When the data cannot be retrieved from the DB. + */ + protected static function fetchModuleDataFromDB(array $itemData): array + { + // Load side libraries. + if (\is_metaconsole()) { + \enterprise_include_once('include/functions_metaconsole.php'); + } + + // Initialize with the agent data. + $moduleData = static::fetchAgentDataFromDB($itemData); + + // Can't fetch an module with a invalid Id. + $moduleId = static::extractModuleId($itemData); + if ($moduleId === null) { + throw new \InvalidArgumentException('invalid module Id'); + } + + // Staticgraph don't need to have a module. + if ($moduleId === 0) { + return $moduleData; + } + + // We should add the metaconsole Id if we can. + $metaconsoleId = static::extractMetaconsoleId($itemData); + + if (\is_metaconsole() && $metaconsoleId === null) { + throw new \InvalidArgumentException('missing metaconsole node Id'); + } + + $moduleName = false; + + // Connect to node. + if (\is_metaconsole() + && \metaconsole_connect(null, $metaconsoleId) !== NOERR + ) { + throw new \InvalidArgumentException( + 'error connecting to the node' + ); + } + + $sql = sprintf( + 'SELECT nombre, descripcion + FROM tagente_modulo + WHERE id_agente_modulo = %s', + $moduleId + ); + + $moduleName = \db_get_row_sql($sql); + + // Restore connection. + if (\is_metaconsole()) { + \metaconsole_restore_db(); + } + + if ($moduleName === false) { + throw new \Exception('error fetching the data from the DB'); + } + + $moduleData['moduleName'] = $moduleName['nombre']; + $moduleData['moduleDescription'] = $moduleName['descripcion']; + + return $moduleData; + } + + + /** + * Generate a link to something related with the item. + * + * @param array $data Visual Console Item's data structure. + * + * @return mixed The link or a null value. + * @throws \Exception Not really. It's controlled. + */ + protected static function buildLink(array $data) + { + global $config; + + // Load side libraries. + include_once $config['homedir'].'/include/functions_ui.php'; + if (\is_metaconsole()) { + \enterprise_include_once('include/functions_metaconsole.php'); + \enterprise_include_once('meta/include/functions_ui_meta.php'); + } + + $linkedVisualConsole = static::extractLinkedVisualConsole($data); + $linkedModule = static::extractLinkedModule($data); + $linkedAgent = static::extractLinkedAgent($data); + + $baseUrl = \ui_get_full_url('index.php'); + + // TODO: There's a feature to get the link from the label. + if (static::$useLinkedVisualConsole === true + && $linkedVisualConsole['linkedLayoutId'] !== null + && $linkedVisualConsole['linkedLayoutId'] > 0 + ) { + // Linked Visual Console. + $vcId = $linkedVisualConsole['linkedLayoutId']; + // The layout can be from another node. + $linkedLayoutAgentId = $linkedVisualConsole['linkedLayoutAgentId']; + + if (empty($linkedLayoutAgentId) === true && \is_metaconsole()) { + /* + * A Visual Console from this console. + * We are in a metaconsole. + */ + + return $baseUrl.'?'.http_build_query( + [ + 'sec' => 'screen', + 'sec2' => 'screens/screens', + 'action' => 'visualmap', + 'id_visualmap' => $vcId, + 'pure' => (int) $config['pure'], + ] + ); + } else if (empty($linkedLayoutAgentId) === true + && !\is_metaconsole() + ) { + /* + * A Visual Console from this console. + * We are in a regular console. + */ + + return $baseUrl.'?'.http_build_query( + [ + 'sec' => 'network', + 'sec2' => 'operation/visual_console/view', + 'id' => $vcId, + 'pure' => (int) $config['pure'], + ] + ); + } else if (\is_metaconsole() && \can_user_access_node()) { + /* + * A Visual Console from a meta node. + * We are in a metaconsole. + */ + + try { + $node = \metaconsole_get_connection_by_id( + $linkedLayoutAgentId + ); + return \ui_meta_get_node_url( + $node, + 'network', + // TODO: Link to a public view. + 'operation/visual_console/view', + [], + // No autologin from the public view. + !$config['public_view'] + ); + } catch (\Throwable $ignored) { + return null; + } + } + } else { + if (static::$useLinkedModule === true + && $linkedModule['moduleId'] !== null + && $linkedModule['moduleId'] > 0 + ) { + // Module Id. + $moduleId = $linkedModule['moduleId']; + // The module can be from another node. + $metaconsoleId = $linkedModule['metaconsoleId']; + + if (empty($metaconsoleId) === true) { + /* + * A module from this console. + */ + + // Check if the module is from a service. + $serviceId = (int) \db_get_value_filter( + 'custom_integer_1', + 'tagente_modulo', + [ + 'id_agente_modulo' => $moduleId, + 'prediction_module' => 1, + ] + ); + + if (empty($serviceId) === false) { + // A service. + $queryParams = [ + 'sec' => 'services', + 'sec2' => 'enterprise/operation/services/services', + 'id_service' => $serviceId, + ]; + } else { + // A regular module. + $queryParams = [ + 'sec' => 'view', + 'sec2' => 'operation/agentes/status_monitor', + 'id_module' => $moduleId, + ]; + } + + return $baseUrl.'?'.http_build_query($queryParams); + } else if (\is_metaconsole() && \can_user_access_node()) { + /* + * A module from a meta node. + * We are in a metaconsole. + */ + + try { + $node = \metaconsole_get_connection_by_id( + $metaconsoleId + ); + + // Connect to node. + if (\metaconsole_connect($node) !== NOERR) { + // Will be catched below. + throw new \Exception( + 'error connecting to the node' + ); + } + + // Check if the module is a service. + $serviceId = (int) \db_get_value_filter( + 'custom_integer_1', + 'tagente_modulo', + [ + 'id_agente_modulo' => $moduleId, + 'prediction_module' => 1, + ] + ); + + // Restore connection. + \metaconsole_restore_db(); + + if (empty($serviceId) === false) { + // A service. + return \ui_meta_get_node_url( + $node, + 'services', + 'enterprise/operation/services/services', + ['id_service' => $serviceId], + // No autologin from the public view. + !$config['public_view'] + ); + } else { + // A regular module. + return \ui_meta_get_node_url( + $node, + 'view', + 'operation/agentes/status_monitor', + ['id_module' => $moduleId], + // No autologin from the public view. + !$config['public_view'] + ); + } + } catch (\Throwable $ignored) { + return null; + } + } + } else if ((static::$useLinkedAgent === true + || static::$useLinkedModule === true) + && $linkedAgent['agentId'] !== null + && $linkedAgent['agentId'] > 0 + ) { + // Linked agent. + // Agent Id. + $agentId = $linkedAgent['agentId']; + // The agent can be from another node. + $metaconsoleId = $linkedAgent['metaconsoleId']; + + if (empty($metaconsoleId) === true) { + /* + * An agent from this console. + * We are in a regular console. + */ + + return $baseUrl.'?'.http_build_query( + [ + 'sec' => 'estado', + 'sec2' => 'operation/agentes/ver_agente', + 'id_agente' => $agentId, + ] + ); + } else if (\is_metaconsole() && \can_user_access_node()) { + /* + * An agent from a meta node. + * We are in a metaconsole. + */ + + try { + $node = \metaconsole_get_connection_by_id( + $metaconsoleId + ); + return \ui_meta_get_node_url( + $node, + 'estado', + 'operation/agentes/ver_agente', + ['id_agente' => $moduleId], + // No autologin from the public view. + !$config['public_view'] + ); + } catch (\Throwable $ignored) { + return null; + } + } + } + } + + return null; + } + + +} diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/BarsGraph.php b/pandora_console/include/rest-api/models/VisualConsole/Items/BarsGraph.php new file mode 100644 index 0000000000..4482b4d53d --- /dev/null +++ b/pandora_console/include/rest-api/models/VisualConsole/Items/BarsGraph.php @@ -0,0 +1,346 @@ +extractGridColor($data); + $return['backgroundColor'] = $this->extractBackgroundColor($data); + $return['typeGraph'] = $this->extractTypeGraph($data); + return $return; + } + + + /** + * Extract a grid color value. + * + * @param array $data Unknown input data structure. + * + * @return mixed String representing the grid color (not empty) or null. + */ + private function extractGridColor(array $data): string + { + return static::notEmptyStringOr( + static::issetInArray($data, ['gridColor', 'border_color']), + '#000000' + ); + } + + + /** + * Extract a background color value. + * + * @param array $data Unknown input data structure. + * + * @return string One of 'white', 'black' or 'transparent'. + * 'white' by default. + */ + private function extractBackgroundColor(array $data): string + { + $backgroundColor = static::notEmptyStringOr( + static::issetInArray($data, ['backgroundColor', 'image']), + null + ); + + switch ($backgroundColor) { + case 'black': + case 'transparent': + return $backgroundColor; + + default: + return 'white'; + } + } + + + /** + * Extract a type graph value. + * + * @param array $data Unknown input data structure. + * + * @return string One of 'vertical' or 'horizontal'. 'vertical' by default. + */ + private function extractTypeGraph(array $data): string + { + $typeGraph = static::notEmptyStringOr( + static::issetInArray($data, ['typeGraph', 'type_graph']), + null + ); + + switch ($typeGraph) { + case 'horizontal': + return 'horizontal'; + + default: + return 'vertical'; + } + } + + + /** + * Fetch a vc item data structure from the database using a filter. + * + * @param array $filter Filter of the Visual Console Item. + * + * @return array The Visual Console Item data structure stored into the DB. + * @throws \InvalidArgumentException When an agent Id cannot be found. + * + * @override Item::fetchDataFromDB. + */ + protected static function fetchDataFromDB(array $filter): array + { + // Due to this DB call, this function cannot be unit tested without + // a proper mock. + $data = parent::fetchDataFromDB($filter); + + /* + * Retrieve extra data. + */ + + // Load config. + global $config; + + // Load side libraries. + include_once $config['homedir'].'/include/functions_ui.php'; + include_once $config['homedir'].'/include/functions_visual_map.php'; + include_once $config['homedir'].'/include/graphs/fgraph.php'; + + if (is_metaconsole()) { + \enterprise_include_once('include/functions_metaconsole.php'); + } + + // Extract needed properties. + $gridColor = static::extractGridColor($data); + $backGroundColor = static::extractBackgroundColor($data); + $typeGraph = static::extractTypeGraph($data); + + // Get the linked agent and module Ids. + $linkedModule = static::extractLinkedModule($data); + $agentId = $linkedModule['agentId']; + $moduleId = $linkedModule['moduleId']; + $metaconsoleId = $linkedModule['metaconsoleId']; + + if ($agentId === null) { + throw new \InvalidArgumentException('missing agent Id'); + } + + if ($moduleId === null) { + throw new \InvalidArgumentException('missing module Id'); + } + + // Add colors that will use the graphics. + $color = []; + + $color[0] = [ + 'border' => '#000000', + 'color' => $config['graph_color1'], + 'alpha' => CHART_DEFAULT_ALPHA, + ]; + $color[1] = [ + 'border' => '#000000', + 'color' => $config['graph_color2'], + 'alpha' => CHART_DEFAULT_ALPHA, + ]; + $color[2] = [ + 'border' => '#000000', + 'color' => $config['graph_color3'], + 'alpha' => CHART_DEFAULT_ALPHA, + ]; + $color[3] = [ + 'border' => '#000000', + 'color' => $config['graph_color4'], + 'alpha' => CHART_DEFAULT_ALPHA, + ]; + $color[4] = [ + 'border' => '#000000', + 'color' => $config['graph_color5'], + 'alpha' => CHART_DEFAULT_ALPHA, + ]; + $color[5] = [ + 'border' => '#000000', + 'color' => $config['graph_color6'], + 'alpha' => CHART_DEFAULT_ALPHA, + ]; + $color[6] = [ + 'border' => '#000000', + 'color' => $config['graph_color7'], + 'alpha' => CHART_DEFAULT_ALPHA, + ]; + $color[7] = [ + 'border' => '#000000', + 'color' => $config['graph_color8'], + 'alpha' => CHART_DEFAULT_ALPHA, + ]; + $color[8] = [ + 'border' => '#000000', + 'color' => $config['graph_color9'], + 'alpha' => CHART_DEFAULT_ALPHA, + ]; + $color[9] = [ + 'border' => '#000000', + 'color' => $config['graph_color10'], + 'alpha' => CHART_DEFAULT_ALPHA, + ]; + $color[11] = [ + 'border' => '#000000', + 'color' => COL_GRAPH9, + 'alpha' => CHART_DEFAULT_ALPHA, + ]; + $color[12] = [ + 'border' => '#000000', + 'color' => COL_GRAPH10, + 'alpha' => CHART_DEFAULT_ALPHA, + ]; + $color[13] = [ + 'border' => '#000000', + 'color' => COL_GRAPH11, + 'alpha' => CHART_DEFAULT_ALPHA, + ]; + $color[14] = [ + 'border' => '#000000', + 'color' => COL_GRAPH12, + 'alpha' => CHART_DEFAULT_ALPHA, + ]; + $color[15] = [ + 'border' => '#000000', + 'color' => COL_GRAPH13, + 'alpha' => CHART_DEFAULT_ALPHA, + ]; + + // Maybe connect to node. + $nodeConnected = false; + if (\is_metaconsole() === true && $metaconsoleId !== null) { + $nodeConnected = \metaconsole_connect( + null, + $metaconsoleId + ) === NOERR; + + if ($nodeConnected === false) { + throw new \InvalidArgumentException( + 'error connecting to the node' + ); + } + } + + $moduleData = \get_bars_module_data($moduleId); + + $waterMark = [ + 'file' => $config['homedir'].'/images/logo_vertical_water.png', + 'url' => \ui_get_full_url( + 'images/logo_vertical_water.png', + false, + false, + false + ), + ]; + + if ((int) $data['width'] === 0 || (int) $data['height'] === 0) { + $width = 400; + $height = 400; + } else { + $width = (int) $data['width']; + $height = (int) $data['height']; + } + + if ($typeGraph === 'horizontal') { + $graph = \hbar_graph( + $moduleData, + $width, + $height, + $color, + [], + [], + \ui_get_full_url( + 'images/image_problem_area.png', + false, + false, + false + ), + '', + '', + $waterMark, + $config['fontpath'], + 6, + '', + 0, + $config['homeurl'], + $backGroundColor, + $gridColor + ); + } else { + $graph = \vbar_graph( + $moduleData, + $width, + $height, + $color, + [], + [], + \ui_get_full_url( + 'images/image_problem_area.png', + false, + false, + false + ), + '', + '', + $waterMark, + $config['fontpath'], + 6, + '', + 0, + $config['homeurl'], + $backGroundColor, + true, + false, + $gridColor + ); + } + + // Restore connection. + if ($nodeConnected === true) { + \metaconsole_restore_db(); + } + + $data['html'] = $graph; + + return $data; + } + + +} diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/Box.php b/pandora_console/include/rest-api/models/VisualConsole/Items/Box.php new file mode 100644 index 0000000000..144518ebb1 --- /dev/null +++ b/pandora_console/include/rest-api/models/VisualConsole/Items/Box.php @@ -0,0 +1,85 @@ +extractBorderWidth($data); + $boxData['borderColor'] = $this->extractBorderColor($data); + $boxData['fillColor'] = $this->extractFillColor($data); + return $boxData; + } + + + /** + * Extract a border width value. + * + * @param array $data Unknown input data structure. + * + * @return integer Valid border width. 0 by default. + */ + private function extractBorderWidth(array $data): int + { + return static::parseIntOr( + static::issetInArray($data, ['borderWidth', 'border_width']), + 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 function extractBorderColor(array $data) + { + return static::notEmptyStringOr( + static::issetInArray($data, ['borderColor', 'border_color']), + null + ); + } + + + /** + * Extract a fill color value. + * + * @param array $data Unknown input data structure. + * + * @return mixed String representing the fill color (not empty) or null. + */ + private function extractFillColor(array $data) + { + return static::notEmptyStringOr( + static::issetInArray($data, ['fillColor', 'fill_color']), + null + ); + } + + +} diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/Clock.php b/pandora_console/include/rest-api/models/VisualConsole/Items/Clock.php new file mode 100644 index 0000000000..ba72e0c30c --- /dev/null +++ b/pandora_console/include/rest-api/models/VisualConsole/Items/Clock.php @@ -0,0 +1,154 @@ +getOffset( + $dateTimeUtc + ); + } catch (\Throwable $e) { + throw new \InvalidArgumentException($e->getMessage()); + } + + // $clockData['showClockTimezone'] = static::parseBool( + // static::issetInArray($data, ['showClockTimezone']) + // ); + // TODO: Remove the true by default when added into the editor. + $clockData['showClockTimezone'] = true; + $clockData['color'] = static::extractColor($data); + return $clockData; + } + + + /** + * Extract a clock type value. + * + * @param array $data Unknown input data structure. + * + * @return string One of 'digital' or 'analogic'. 'analogic' by default. + */ + private static function extractClockType(array $data): string + { + $clockType = static::notEmptyStringOr( + static::issetInArray($data, ['clockType', 'clock_animation']), + null + ); + + switch ($clockType) { + case 'digital': + case 'digital_1': + return 'digital'; + + default: + return 'analogic'; + } + } + + + /** + * Extract a clock format value. + * + * @param array $data Unknown input data structure. + * + * @return string One of 'time' or 'datetime'. 'datetime' by default. + */ + private static function extractClockFormat(array $data): string + { + $clockFormat = static::notEmptyStringOr( + static::issetInArray($data, ['clockFormat', 'time_format']), + null + ); + + switch ($clockFormat) { + case 'time': + return 'time'; + + default: + return 'datetime'; + } + } + + + /** + * Extract a clock timezone value. + * + * @param array $data Unknown input data structure. + * + * @return string + * @throws \InvalidArgumentException When a valid clock timezone cannot be + * extracted. + */ + private static function extractClockTimezone(array $data): string + { + $clockTimezone = static::notEmptyStringOr( + static::issetInArray($data, ['clockTimezone', 'timezone']), + null + ); + + if ($clockTimezone === null) { + throw new \InvalidArgumentException( + 'the clockTimezone property is required and should be string' + ); + } + + return $clockTimezone; + } + + + /** + * Extract the color value. + * + * @param array $data Unknown input data structure. + * + * @return mixed returns a color or null. + */ + private static function extractColor(array $data) + { + return static::notEmptyStringOr( + static::issetInArray($data, ['color', 'fill_color']), + null + ); + } + + +} diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/ColorCloud.php b/pandora_console/include/rest-api/models/VisualConsole/Items/ColorCloud.php new file mode 100644 index 0000000000..807d8fb3e9 --- /dev/null +++ b/pandora_console/include/rest-api/models/VisualConsole/Items/ColorCloud.php @@ -0,0 +1,281 @@ +decode. + */ + protected function decode(array $data): array + { + $decodedData = parent::decode($data); + $decodedData['type'] = COLOR_CLOUD; + $decodedData['label'] = null; + $decodedData['defaultColor'] = static::extractDefaultColor($data); + $decodedData['colorRanges'] = static::extractColorRanges($data); + $decodedData['color'] = static::notEmptyStringOr( + static::issetInArray($data, ['color']), + null + ); + + return $decodedData; + } + + + /** + * Extract the default color value. + * + * @param array $data Unknown input data structure. + * + * @return string Default color. + * @throws \InvalidArgumentException If the default color cannot be + * extracted. + */ + private static function extractDefaultColor(array $data): string + { + if (isset($data['defaultColor'])) { + $defaultColor = static::notEmptyStringOr( + $data['defaultColor'], + null + ); + + if ($defaultColor === null) { + throw new \InvalidArgumentException( + 'the default color property is required and should be a not empty string' + ); + } + + return $defaultColor; + } else { + $dynamicData = static::extractDynamicData($data); + return $dynamicData['defaultColor']; + } + } + + + /** + * Extract a list of color ranges. + * + * @param array $data Unknown input data structure. + * + * @return array Color ranges list. + * @throws \InvalidArgumentException If any of the color ranges is invalid. + */ + private static function extractColorRanges(array $data): array + { + if (isset($data['colorRanges']) && \is_array($data['colorRanges'])) { + // Validate the color ranges. + foreach ($data['colorRanges'] as $colorRange) { + if (\is_numeric($colorRange['fromValue']) === false + || \is_numeric($colorRange['toValue']) === false + || static::notEmptyStringOr($colorRange['color'], null) === null + ) { + throw new \InvalidArgumentException('invalid color range'); + } + } + + return $data['colorRanges']; + } else if (isset($data['label']) === true) { + $dynamicData = static::extractDynamicData($data); + return $dynamicData['colorRanges']; + } else { + return []; + } + } + + + /** + * Extract a dynamic data structure from the 'label' field. + * + * @param array $data Unknown input data structure. + * + * @return array Dynamic data structure. + * @throws \InvalidArgumentException If the structure cannot be built. + * + * @example [ + * 'defaultColor' => '#FFF', + * 'colorRanges' => [ + * [ + * 'fromValue' => 50.0, + * 'toValue' => 150.5, + * 'color' => '#000', + * ], + * [ + * 'fromValue' => 200.0, + * 'toValue' => 300.5, + * 'color' => '#F0F0F0', + * ], + * ] + * ] + */ + private static function extractDynamicData(array $data): array + { + $dynamicDataEncoded = static::notEmptyStringOr($data['label'], null); + + if ($dynamicDataEncoded === null) { + throw new \InvalidArgumentException('dynamic data not found'); + } + + $result = []; + + try { + $dynamicData = \json_decode($dynamicDataEncoded, true); + + $result['defaultColor'] = $dynamicData['default_color']; + $result['colorRanges'] = []; + + if (\is_array($dynamicData['color_ranges']) === true) { + foreach ($dynamicData['color_ranges'] as $colorRange) { + if (\is_numeric($colorRange['from_value']) === true + && \is_numeric($colorRange['to_value']) === true + && static::notEmptyStringOr( + $colorRange['color'], + null + ) !== null + ) { + $result['colorRanges'][] = [ + 'color' => $colorRange['color'], + 'fromValue' => (float) $colorRange['from_value'], + 'toValue' => (float) $colorRange['to_value'], + ]; + } + } + } + } catch (\Throwable $e) { + throw new \InvalidArgumentException('invalid dynamic data'); + } + + return $result; + } + + + /** + * Fetch a vc item data structure from the database using a filter. + * + * @param array $filter Filter of the Visual Console Item. + * + * @return array The Visual Console Item data structure stored into the DB. + * @throws \InvalidArgumentException When an agent Id cannot be found. + * + * @override Item::fetchDataFromDB. + */ + protected static function fetchDataFromDB(array $filter): array + { + // Due to this DB call, this function cannot be unit tested without + // a proper mock. + $data = parent::fetchDataFromDB($filter); + + /* + * Retrieve extra data. + */ + + // Load side libraries. + global $config; + include_once $config['homedir'].'/include/functions_modules.php'; + if (is_metaconsole()) { + \enterprise_include_once('include/functions_metaconsole.php'); + } + + // Get the linked module Id. + $linkedModule = static::extractLinkedModule($data); + $moduleId = $linkedModule['moduleId']; + $metaconsoleId = $linkedModule['metaconsoleId']; + + if ($moduleId === null) { + throw new \InvalidArgumentException('missing module Id'); + } + + $dynamicData = static::extractDynamicData($data); + // Set the initial color. + $data['color'] = $dynamicData['defaultColor']; + + // Search for a matching color range. + if (empty($dynamicData['colorRanges']) === false) { + // Connect to node. + $nodeConnected = false; + if (\is_metaconsole() === true && $metaconsoleId !== null) { + $nodeConnected = \metaconsole_connect( + null, + $metaconsoleId + ) === NOERR; + + if ($nodeConnected === false) { + throw new \InvalidArgumentException( + 'error connecting to the node' + ); + } + } + + // Fetch module value. + $value = false; + if ($metaconsoleId === null + || ($metaconsoleId !== null && $nodeConnected) + ) { + $value = \modules_get_last_value($moduleId); + } + + // Restore connection. + if ($nodeConnected === true) { + \metaconsole_restore_db(); + } + + // Value found. + if ($value !== false) { + /* + * TODO: It would be ok to give support to string values in the + * future? + * + * It can be done by matching the range value with the value + * if it is a string. I think the function to retrieve the value + * only supports numeric values. + */ + + $value = (float) $value; + foreach ($dynamicData['colorRanges'] as $colorRange) { + if ($colorRange['fromValue'] <= $value + && $colorRange['toValue'] >= $value + ) { + // Range matched. Use the range color. + $data['color'] = $colorRange['color']; + break; + } + } + } + } + + return $data; + } + + +} diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/DonutGraph.php b/pandora_console/include/rest-api/models/VisualConsole/Items/DonutGraph.php new file mode 100644 index 0000000000..1adc948da2 --- /dev/null +++ b/pandora_console/include/rest-api/models/VisualConsole/Items/DonutGraph.php @@ -0,0 +1,193 @@ +'; + } + + return $data; + } + + +} diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/EventsHistory.php b/pandora_console/include/rest-api/models/VisualConsole/Items/EventsHistory.php new file mode 100644 index 0000000000..cb3313d35f --- /dev/null +++ b/pandora_console/include/rest-api/models/VisualConsole/Items/EventsHistory.php @@ -0,0 +1,159 @@ + 'eventos', + 'sec2' => 'operation/events/events', + 'id_agent' => $agentId, + 'module_search_hidden' => $moduleId, + 'event_view_hr' => (static::extractMaxTime($data) / 3600), + 'status' => -1, + ] + ); + } + + +} diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/Group.php b/pandora_console/include/rest-api/models/VisualConsole/Items/Group.php new file mode 100644 index 0000000000..e627003244 --- /dev/null +++ b/pandora_console/include/rest-api/models/VisualConsole/Items/Group.php @@ -0,0 +1,462 @@ + $groupId, + 'status' => AGENT_STATUS_CRITICAL, + ], + ['COUNT(*) AS total'], + 'AR', + false, + false, + true, + $isMetaconsole + ); + $numCritical = $agentsCritical[0]['total']; + $agentsWarning = \agents_get_agents( + [ + 'id_grupo' => $groupId, + 'status' => AGENT_STATUS_WARNING, + ], + ['COUNT(*) AS total'], + 'AR', + false, + false, + true, + $isMetaconsole + ); + $numWarning = $agentsWarning[0]['total']; + $agentsUnknown = \agents_get_agents( + [ + 'id_grupo' => $groupId, + 'status' => AGENT_STATUS_UNKNOWN, + ], + ['COUNT(*) AS total'], + 'AR', + false, + false, + true, + $isMetaconsole + ); + $numUnknown = $agentsUnknown[0]['total']; + $agentsOk = \agents_get_agents( + [ + 'id_grupo' => $groupId, + 'status' => AGENT_STATUS_OK, + ], + ['COUNT(*) AS total'], + 'AR', + false, + false, + true, + $isMetaconsole + ); + $numNormal = $agentsOk[0]['total']; + + $numTotal = ($numCritical + $numWarning + $numUnknown + $numNormal); + $agentStats = [ + 'critical' => ($numCritical / $numTotal * 100), + 'warning' => ($numWarning / $numTotal * 100), + 'normal' => ($numNormal / $numTotal * 100), + 'unknown' => ($numUnknown / $numTotal * 100), + ]; + + $groupName = \groups_get_name($groupId, true); + $data['html'] = static::printStatsTable( + $groupName, + $agentStats, + (int) $data['width'], + (int) $data['height'] + ); + } else { + if (\is_metaconsole()) { + $groupFilter = $groupId; + if ($groupId === 0) { + $groupFilter = implode( + ',', + array_keys(\users_get_groups()) + ); + } + + $sql = sprintf( + 'SELECT + SUM(fired_count) AS fired, + SUM(critical_count) AS critical, + SUM(warning_count) AS warning, + SUM(unknown_count) AS unknown + FROM tmetaconsole_agent + LEFT JOIN tmetaconsole_agent_secondary_group tasg + ON id_agente = tasg.id_agent + WHERE id_grupo IN (%s) + OR tasg.id_group IN (%s)', + $groupFilter, + $groupFilter + ); + + $countStatus = \db_get_row_sql($sql); + + if ($countStatus['fired'] > 0) { + $status = AGENT_STATUS_ALERT_FIRED; + } else if ($countStatus['critical'] > 0) { + $status = AGENT_STATUS_CRITICAL; + } else if ($countStatus['warning'] > 0) { + $status = AGENT_STATUS_WARNING; + } else if ($countStatus['unknown'] > 0) { + $status = AGENT_STATUS_UNKNOWN; + } else { + $status = AGENT_STATUS_NORMAL; + } + } else { + // Get the status img src. + $status = \groups_get_status($groupId); + } + + $imagePath = \visual_map_get_image_status_element($data, $status); + $data['statusImageSrc'] = \ui_get_full_url( + $imagePath, + false, + false, + false + ); + + // If the width or the height are equal to 0 we will extract them + // from the real image size. + $width = (int) $data['width']; + $height = (int) $data['height']; + if ($width === 0 || $height === 0) { + // TODO: This will be the default behaviour after we finish the + // builder. Don't delete this code. + // $sizeImage = getimagesize($config['homedir'].'/'.$imagePath); + // $data['width'] = $sizeImage[0]; + // $data['height'] = $sizeImage[1]; + $sizeImage = getimagesize($config['homedir'].'/'.$imagePath); + $imageHeight = $sizeImage[1]; + + if ($width === 0) { + $data['width'] = 70; + } + + if ($height === 0) { + $data['height'] = ($imageHeight > 70) ? 70 : $imageHeight; + } + } + + $data['html'] = ''; + } + + return $data; + } + + + /** + * HTML representation for the agent stats of a group. + * + * @param string $groupName Group name. + * @param array $agentStats Data structure with the agent statistics. + * @param integer $width Width. + * @param integer $height Height. + * + * @return string HTML representation. + */ + private static function printStatsTable( + string $groupName, + array $agentStats, + int $width=520, + int $height=80 + ): string { + $width = ($width > 0) ? $width : 520; + $height = ($height > 0) ? $height : 80; + + $tableStyle = \join( + [ + 'width:'.$width.'px;', + 'height:'.$height.'px;', + 'text-align:center;', + ] + ); + $headStyle = \join( + [ + 'text-align:center;', + 'background-color:#9d9ea0;', + 'color:black;', + 'font-weight:bold;', + ] + ); + $valueStyle = \join( + [ + 'margin-left: 2%;', + 'color: #FFF;', + 'font-size: 12px;', + 'display: inline;', + 'background-color: #FC4444;', + 'position: relative;', + 'height: 80%;', + 'width: 9.4%;', + 'height: 80%;', + 'border-radius: 2px;', + 'text-align: center;', + 'padding: 5px;', + ] + ); + $nameStyle = \join( + [ + 'background-color: white;', + 'color: black;', + 'font-size: 12px;', + 'display: inline;', + 'display: inline;', + 'position:relative;', + 'width: 9.4%;', + 'height: 80%;', + 'border-radius: 2px;', + 'text-align: center;', + 'padding: 5px;', + ] + ); + + $html = ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= '
    '.$groupName.'
    '; + + // Critical. + $html .= '
    '; + $html .= \number_format($agentStats['critical'], 2).'%'; + $html .= '
    '; + $html .= '
    '.__('Critical').'
    '; + // Warning. + $html .= '
    '; + $html .= \number_format($agentStats['warning'], 2).'%'; + $html .= '
    '; + $html .= '
    '.__('Warning').'
    '; + // Normal. + $html .= '
    '; + $html .= \number_format($agentStats['normal'], 2).'%'; + $html .= '
    '; + $html .= '
    '.__('Normal').'
    '; + // Unknown. + $html .= '
    '; + $html .= \number_format($agentStats['unknown'], 2).'%'; + $html .= '
    '; + $html .= '
    '.__('Unknown').'
    '; + + $html .= '
    '; + + return $html; + } + + + /** + * Generate a link to something related with the item. + * + * @param array $data Visual Console Item's data structure. + * + * @return mixed The link or a null value. + * + * @override Item::buildLink. + */ + protected static function buildLink(array $data) + { + // This will return the link to a linked VC if this item has one. + $link = parent::buildLink($data); + if ($link !== null) { + return $link; + } + + global $config; + + $groupId = static::extractGroupId($data); + $baseUrl = $config['homeurl'].'index.php'; + + if (\is_metaconsole()) { + return $baseUrl.'?'.http_build_query( + [ + 'sec' => 'monitoring', + 'sec2' => 'operation/tree', + 'group_id' => $groupId, + ] + ); + } + + return $baseUrl.'?'.http_build_query( + [ + 'sec' => 'estado', + 'sec2' => 'operation/agentes/estado_agente', + 'group_id' => $groupId, + ] + ); + } + + +} diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/Icon.php b/pandora_console/include/rest-api/models/VisualConsole/Items/Icon.php new file mode 100644 index 0000000000..29605ffb4f --- /dev/null +++ b/pandora_console/include/rest-api/models/VisualConsole/Items/Icon.php @@ -0,0 +1,144 @@ + 70) ? 70 : $imageHeight; + } + } + + return $data; + } + + +} diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/Label.php b/pandora_console/include/rest-api/models/VisualConsole/Items/Label.php new file mode 100644 index 0000000000..41c9c6c6d1 --- /dev/null +++ b/pandora_console/include/rest-api/models/VisualConsole/Items/Label.php @@ -0,0 +1,64 @@ +validateData. + */ + protected function validateData(array $data): void + { + parent::validateData($data); + if (static::notEmptyStringOr(static::issetInArray($data, ['label']), null) === null) { + throw new \InvalidArgumentException( + 'the label property is required and should be a not empty string' + ); + } + } + + + /** + * Returns a valid representation of the model. + * + * @param array $data Input data. + * + * @return array Data structure representing the model. + * + * @overrides Item->decode. + */ + protected function decode(array $data): array + { + $return = parent::decode($data); + $return['type'] = LABEL; + return $return; + } + + +} diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/Line.php b/pandora_console/include/rest-api/models/VisualConsole/Items/Line.php new file mode 100644 index 0000000000..fd6f64b4cb --- /dev/null +++ b/pandora_console/include/rest-api/models/VisualConsole/Items/Line.php @@ -0,0 +1,209 @@ +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' => LINE_ITEM, + '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), + ]; + } + + + /** + * 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 + ); + } + + + /** + * Obtain a vc item data structure from the database using a filter. + * + * @param array $filter Filter of the Visual Console Item. + * + * @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): 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'); + } + + return $row; + } + + +} diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/ModuleGraph.php b/pandora_console/include/rest-api/models/VisualConsole/Items/ModuleGraph.php new file mode 100644 index 0000000000..d89a01efff --- /dev/null +++ b/pandora_console/include/rest-api/models/VisualConsole/Items/ModuleGraph.php @@ -0,0 +1,274 @@ + $period, + 'width' => $data['width'], + 'height' => ($data['height'] - 30), + 'title' => '', + 'unit_name' => null, + 'show_alerts' => false, + 'only_image' => $imageOnly, + 'vconsole' => true, + 'backgroundColor' => $backgroundType, + ]; + + $paramsCombined = [ + 'id_graph' => $customGraphId, + 'stacked' => $customGraph['stacked'], + 'summatory' => $customGraph['summatory_series'], + 'average' => $customGraph['average_series'], + 'modules_series' => $customGraph['modules_series'], + ]; + + $data['html'] = \graphic_combined_module( + false, + $params, + $paramsCombined + ); + } else { + // Module graph. + if ($moduleId === null) { + throw new \InvalidArgumentException('missing module Id'); + } + + $params = [ + 'agent_module_id' => $moduleId, + 'period' => $period, + 'show_events' => false, + 'width' => $data['width'], + 'height' => ($data['height'] - 30), + 'title' => \modules_get_agentmodule_name($moduleId), + 'unit' => \modules_get_unit($moduleId), + 'only_image' => $imageOnly, + 'menu' => false, + 'backgroundColor' => $backgroundType, + 'type_graph' => $graphType, + 'vconsole' => true, + ]; + + $data['html'] = \grafico_modulo_sparse($params); + } + + // Restore connection. + if ($nodeConnected === true) { + \metaconsole_restore_db(); + } + + return $data; + } + + +} diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/Percentile.php b/pandora_console/include/rest-api/models/VisualConsole/Items/Percentile.php new file mode 100644 index 0000000000..d64c51bc4d --- /dev/null +++ b/pandora_console/include/rest-api/models/VisualConsole/Items/Percentile.php @@ -0,0 +1,245 @@ +validateData. + */ + protected function validateData(array $data): void + { + parent::validateData($data); + if (isset($data['value']) === false) { + throw new \InvalidArgumentException( + 'the value property is required and should be string' + ); + } + } + + + /** + * Returns a valid representation of the model. + * + * @param array $data Input data. + * + * @return array Data structure representing the model. + * + * @overrides Item->decode. + */ + protected function decode(array $data): array + { + $return = parent::decode($data); + $return['type'] = SIMPLE_VALUE; + $return['processValue'] = static::extractProcessValue($data); + $return['valueType'] = static::extractValueType($data); + $return['value'] = $data['value']; + + if ($return['processValue'] !== 'none') { + $return['period'] = static::extractPeriod($data); + } + + // Clear the size, as this element always have a dynamic size. + $return['width'] = 0; + $return['height'] = 0; + + return $return; + } + + + /** + * Extract a process value. + * + * @param array $data Unknown input data structure. + * + * @return string One of 'none', 'avg', 'max' or 'min'. 'none' by default. + */ + private static function extractProcessValue(array $data): string + { + if (isset($data['processValue'])) { + switch ($data['processValue']) { + case 'none': + case 'avg': + case 'max': + case 'min': + return $data['processValue']; + + default: + return 'none'; + } + } else { + switch ($data['type']) { + case SIMPLE_VALUE_MAX: + return 'max'; + + case SIMPLE_VALUE_MIN: + return 'min'; + + case SIMPLE_VALUE_AVG: + return 'avg'; + + default: + return 'none'; + } + } + } + + + /** + * Extract the value of period. + * + * @param array $data Unknown input data structure. + * + * @return integer The period in seconds. 0 is the minimum value. + */ + private static function extractPeriod(array $data): int + { + $period = static::parseIntOr( + static::issetInArray($data, ['period']), + 0 + ); + return ($period >= 0) ? $period : 0; + } + + + /** + * Extract a value type. + * + * @param array $data Unknown input data structure. + * + * @return string One of 'string' or 'image'. 'string' by default. + */ + private static function extractValueType(array $data): string + { + switch ($data['valueType']) { + case 'string': + case 'image': + return $data['valueType']; + + default: + return 'string'; + } + } + + + /** + * Fetch a vc item data structure from the database using a filter. + * + * @param array $filter Filter of the Visual Console Item. + * + * @return array The Visual Console Item data structure stored into the DB. + * @throws \InvalidArgumentException When a module Id cannot be found. + * + * @override Item::fetchDataFromDB. + */ + protected static function fetchDataFromDB(array $filter): array + { + // Due to this DB call, this function cannot be unit tested without + // a proper mock. + $data = parent::fetchDataFromDB($filter); + + /* + * Retrieve extra data. + */ + + // Load side libraries. + global $config; + include_once $config['homedir'].'/include/functions_visual_map.php'; + if (is_metaconsole()) { + \enterprise_include_once('include/functions_metaconsole.php'); + } + + // Get the linked module Id. + $linkedModule = static::extractLinkedModule($data); + $moduleId = static::parseIntOr($linkedModule['moduleId'], null); + $metaconsoleId = static::parseIntOr( + $linkedModule['metaconsoleId'], + null + ); + + if ($moduleId === null) { + throw new \InvalidArgumentException('missing module Id'); + } + + // Maybe connect to node. + $nodeConnected = false; + if (\is_metaconsole() === true && $metaconsoleId !== null) { + $nodeConnected = \metaconsole_connect( + null, + $metaconsoleId + ) === NOERR; + + if ($nodeConnected === false) { + throw new \InvalidArgumentException( + 'error connecting to the node' + ); + } + } + + // Get the formatted value. + $value = \visual_map_get_simple_value( + $data['type'], + $moduleId, + static::extractPeriod($data) + ); + + // Restore connection. + if ($nodeConnected === true) { + \metaconsole_restore_db(); + } + + // Some modules are image based. Extract the base64 image if needed. + $matches = []; + if (\preg_match('/src=\"(data:image.*)"/', $value, $matches) === 1) { + $data['valueType'] = 'image'; + $data['value'] = $matches[1]; + } else { + $data['valueType'] = 'string'; + $data['value'] = $value; + } + + return $data; + } + + +} diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/StaticGraph.php b/pandora_console/include/rest-api/models/VisualConsole/Items/StaticGraph.php new file mode 100644 index 0000000000..9af4287d26 --- /dev/null +++ b/pandora_console/include/rest-api/models/VisualConsole/Items/StaticGraph.php @@ -0,0 +1,256 @@ +decode. + */ + protected function decode(array $data): array + { + $return = parent::decode($data); + $return['type'] = STATIC_GRAPH; + $return['imageSrc'] = static::extractImageSrc($data); + $return['showLastValueTooltip'] = static::extractShowLastValueTooltip( + $data + ); + $return['statusImageSrc'] = static::notEmptyStringOr( + static::issetInArray($data, ['statusImageSrc']), + null + ); + $return['lastValue'] = static::notEmptyStringOr( + static::issetInArray($data, ['lastValue']), + null + ); + + return $return; + } + + + /** + * Extract a image src value. + * + * @param array $data Unknown input data structure. + * + * @return mixed String representing the image url (not empty) or null. + * + * @throws \InvalidArgumentException When a valid image src can't be found. + */ + private static function extractImageSrc(array $data): string + { + $imageSrc = static::notEmptyStringOr( + static::issetInArray($data, ['imageSrc', 'image']), + null + ); + + if ($imageSrc === null) { + throw new \InvalidArgumentException( + 'the image src property is required and should be a non empty string' + ); + } + + return $imageSrc; + } + + + /** + * Extract the value of showLastValueTooltip and + * return 'default', 'enabled' or 'disabled'. + * + * @param array $data Unknown input data structure. + * + * @return string + */ + private static function extractShowLastValueTooltip(array $data): string + { + $showLastValueTooltip = static::notEmptyStringOr( + static::issetInArray($data, ['showLastValueTooltip']), + null + ); + + if ($showLastValueTooltip === null) { + $showLastValueTooltip = static::parseIntOr( + static::issetInArray($data, ['show_last_value']), + null + ); + switch ($showLastValueTooltip) { + case 1: + return 'enabled'; + + case 2: + return 'disabled'; + + default: + return 'default'; + } + } else { + switch ($showLastValueTooltip) { + case 'enabled': + return 'enabled'; + + case 'disabled': + return 'disabled'; + + default: + return 'default'; + } + } + } + + + /** + * Fetch a vc item data structure from the database using a filter. + * + * @param array $filter Filter of the Visual Console Item. + * + * @return array The Visual Console Item data structure stored into the DB. + * @throws \InvalidArgumentException When an agent Id cannot be found. + * + * @override Item::fetchDataFromDB. + */ + protected static function fetchDataFromDB(array $filter): array + { + // Due to this DB call, this function cannot be unit tested without + // a proper mock. + $data = parent::fetchDataFromDB($filter); + + /* + * Retrieve extra data. + */ + + // Load side libraries. + global $config; + include_once $config['homedir'].'/include/functions_ui.php'; + include_once $config['homedir'].'/include/functions_io.php'; + include_once $config['homedir'].'/include/functions_visual_map.php'; + include_once $config['homedir'].'/include/functions_modules.php'; + if (is_metaconsole()) { + \enterprise_include_once('include/functions_metaconsole.php'); + } + + // Get the linked module Id. + $linkedModule = static::extractLinkedModule($data); + $moduleId = $linkedModule['moduleId']; + $metaconsoleId = $linkedModule['metaconsoleId']; + + if ($moduleId === null) { + throw new \InvalidArgumentException('missing module Id'); + } + + // Get the img src. + // There's no need to connect to the metaconsole before searching for + // the image status cause the function itself does that for us. + $imagePath = \visual_map_get_image_status_element($data); + $data['statusImageSrc'] = \ui_get_full_url( + $imagePath, + false, + false, + false + ); + + // If the width or the height are equal to 0 we will extract them + // from the real image size. + $width = (int) $data['width']; + $height = (int) $data['height']; + if ($width === 0 || $height === 0) { + // TODO: This will be the default behaviour after we finish the + // builder. Don't delete this code. + // $sizeImage = getimagesize($config['homedir'].'/'.$imagePath); + // $data['width'] = $sizeImage[0]; + // $data['height'] = $sizeImage[1]; + // Default value. Will be replaced by a dynamic image size + // calculation after the phase 3. + $sizeImage = getimagesize($config['homedir'].'/'.$imagePath); + $imageHeight = $sizeImage[1]; + + if ($width === 0) { + $data['width'] = 70; + } + + if ($height === 0) { + $data['height'] = ($imageHeight > 70) ? 70 : $imageHeight; + } + } + + // Get last value. + $showLastValueTooltip = static::extractShowLastValueTooltip($data); + if ($showLastValueTooltip !== 'disabled' && $moduleId > 0) { + // Maybe connect to node. + $nodeConnected = false; + if (\is_metaconsole() === true && $metaconsoleId !== null) { + $nodeConnected = \metaconsole_connect( + null, + $metaconsoleId + ) === NOERR; + + if ($nodeConnected === false) { + throw new \InvalidArgumentException( + 'error connecting to the node' + ); + } + } + + $imgTitle = ''; + + $unit = \trim(\io_safe_output(\modules_get_unit($moduleId))); + $value = \modules_get_last_value($moduleId); + + $isBooleanModule = \modules_is_boolean($moduleId); + if (!$isBooleanModule + || ($isBooleanModule && $showLastValueTooltip !== 'default') + ) { + if (\is_numeric($value)) { + $imgTitle .= __('Last value: ').\remove_right_zeros(\number_format((float) $value, (int) $config['graph_precision'])); + } else { + $imgTitle .= __('Last value: ').$value; + } + + if (empty($unit) === false && empty($imgTitle) === false) { + $imgTitle .= ' '.$unit; + } + + $data['lastValue'] = $imgTitle; + } + + // Restore connection. + if ($nodeConnected === true) { + \metaconsole_restore_db(); + } + } + + return $data; + } + + +} diff --git a/pandora_console/include/styles/agent_manager.css b/pandora_console/include/styles/agent_manager.css new file mode 100644 index 0000000000..fc648aefba --- /dev/null +++ b/pandora_console/include/styles/agent_manager.css @@ -0,0 +1,158 @@ +/* + * --------------------------------------------------------------------- + * - Create/Update Agent - agent_manager.php + * --------------------------------------------------------------------- + */ +.agent_options { + width: 100%; + margin-right: 0px; + display: flex; + flex-flow: row wrap; + flex-direction: row; + justify-content: space-between; + box-sizing: border-box; +} + +.agent_options_update { + width: 85%; + margin-right: 20px; +} + +.agent_options_column_left, +.agent_options_column_right { + width: 50%; + box-sizing: border-box; +} + +.agent_options_column_left { + padding-right: 50px; +} + +.agent_qr { + width: 15%; + text-align: center; + box-sizing: border-box; + padding: 20px 0px; + display: flex; + justify-content: center; + flex-direction: column; + min-width: 150px; +} + +a#qr_code_agent_view { + margin-top: 5px; +} + +.first_row .agent_options_column_right select, +.first_row .agent_options_column_right input, +.first_row .agent_options_column_left select#grupo { + width: 95%; + box-sizing: border-box; +} + +.first_row .agent_options_column_left .p-switch { + margin-right: 5px; + margin-left: 10px; +} + +.agent_options_column_left input#text-direccion, +.agent_options_column_left select#address_list, +.agent_options_column_left input#text-agente, +.agent_options_column_left input#text-alias { + width: 100%; + box-sizing: border-box; +} + +.agent_options_agent_name > * { + margin-left: 5px; +} + +.custom_fields_table { + border-spacing: 0px; +} + +.custom_fields_table tr.datos { + background-color: #f7f7f7; + display: none; +} + +.custom_fields_table tr.datos2 { + cursor: pointer; +} + +.custom_fields_table tr td { + border: 1px solid #e0e0e0; +} + +.custom_fields_table tr.datos2 td div.field_title { + padding: 10px; +} + +.custom_fields_table tr.datos2 td { + border-radius: 4px; + padding: 0px; +} + +.custom_fields_table tr.datos td { + padding: 15px 10px; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; +} + +.custom_fields_table .custom_field_row_opened td { + border-bottom-left-radius: 0px !important; + border-bottom-right-radius: 0px !important; +} + +.secondary_groups_select { + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 15px; +} + +.secondary_groups_select .secondary_groups_select_arrows input { + display: grid; + margin: 0 auto; +} + +.secondary_groups_select .secondary_groups_list_left { + text-align: right; + width: 50%; +} + +.secondary_groups_select .secondary_groups_list_right { + text-align: left; + width: 50%; +} + +.secondary_groups_select .secondary_groups_select_arrows { + padding: 0 50px; +} + +.secondary_groups_select_arrows a { + display: block; +} + +.agent_options_adv .agent_options_column_right .label_select select, +.agent_options_adv .agent_options_column_right .label_select input[type="text"], +.agent_options_adv #text-custom_id, +.agent_options_adv #cps { + width: 100%; + box-sizing: border-box; +} + +.agent_options_adv .label_select_simple.label_simple_one_item .p-switch { + margin-right: 5px; +} + +.agent_description { + min-height: 4.8em !important; +} +.agent_custom_id { + padding-bottom: 0.7em; + padding-top: 0.5em; + display: inline-block; + border-radius: 5px !important; + border: 1px solid #ccc; +} diff --git a/pandora_console/include/styles/agent_view.css b/pandora_console/include/styles/agent_view.css new file mode 100644 index 0000000000..fca8aaa4fc --- /dev/null +++ b/pandora_console/include/styles/agent_view.css @@ -0,0 +1,19 @@ +text.text-tooltip { + font-family: "lato-bolder", "Open Sans", sans-serif !important; +} + +div#bullets_modules span { + font-family: "lato-bolder", "Open Sans", sans-serif !important; +} + +table#agent_interface_info .noresizevc.graph { + width: 500px !important; +} + +div.agent_details_agent_alias { + flex: 1; +} + +div.agent_details_agent_alias * { + font-family: "lato-bolder", "Open Sans", sans-serif !important; +} diff --git a/pandora_console/include/styles/cluster_view.css b/pandora_console/include/styles/cluster_view.css index 74e30f1a8c..4d8f02ccb9 100644 --- a/pandora_console/include/styles/cluster_view.css +++ b/pandora_console/include/styles/cluster_view.css @@ -58,7 +58,7 @@ overflow-y: scroll; } -#cluster_map { +#simple_map { border: 1px solid lightgray; width: 900px; height: 500px; diff --git a/pandora_console/include/styles/discovery.css b/pandora_console/include/styles/discovery.css new file mode 100644 index 0000000000..0209a43a8e --- /dev/null +++ b/pandora_console/include/styles/discovery.css @@ -0,0 +1,259 @@ +/* + * Discovery css global + */ + +li.discovery { + display: inline-block; + float: left; + width: 250px; + height: 120px; + margin: 15px; + padding-bottom: 50px; +} + +li.discovery > a { + text-decoration: none; + color: #333; +} +li.discovery > a:hover { + color: #000; +} + +li.discovery img { + height: 90px; +} + +li.discovery > a label { + cursor: pointer; +} + +div.data_container > label { + font-family: "lato-bolder", "Open Sans", sans-serif !important; + font-weight: lighter; +} + +div.data_container { + width: 100%; + height: 100%; + text-align: center; + padding-top: 30px; + padding-bottom: 30px; +} + +div.data_container:hover { + box-shadow: 2px 2px 10px #ddd; +} + +/* + * TODO: This may be at hostdevices.css + */ +.texto { + height: auto; + text-align: center; +} +h1.wizard { + padding: 0; + margin: 0; +} +h1.wizard a { + margin-left: -20px; +} +h1.wizard a:hover { + color: #fff; +} +#text_wizard { + font-weight: bolder; + text-decoration: none; + font-size: 24px; +} +div.arrow_box { + display: inline-block; + position: relative; + color: #888; + padding: 1.3em; + margin-left: 20px; + margin-bottom: 10px; + padding-left: 3em; +} + +.arrow_box.selected { + background: #424242; + color: #ccc; +} + +.arrow_box:after { + left: 0%; + border-left-color: white; + border-width: 20px; + margin-top: -20px; +} + +div.arrow_box:before { + left: 100%; + border-left-color: #ccc; + border-width: 20px; + margin-top: -20px; +} +.arrow_box.selected:before { + border-left-color: #424242; +} + +.arrow_box.selected:hover { + color: #fff; +} +.arrow_box:hover { + color: #000; +} + +/* + * Breadcrum + */ + +#menu_tab_frame_view_bc { + display: flex; + justify-content: space-between; + border-bottom: 2px solid #82b92e; + max-height: 70px; + min-height: 55px; + width: 100%; + padding-right: 0px; + margin-left: 0px !important; + margin-bottom: 20px; + height: 55px; + box-sizing: border-box; + background-color: #fafafa; + border-top-right-radius: 7px; + border-top-left-radius: 7px; + box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.1); +} + +#menu_tab_frame_view_bc .breadcrumbs_container { + align-self: flex-start; +} + +.breadcrumbs_container { + padding-left: 10px; + padding-top: 4px; + text-indent: 0.25em; +} + +.breadcrumb_link { + color: #848484; + font-size: 10pt !important; + font-family: "lato-bolder", "Open Sans", sans-serif !important; + text-decoration: none !important; +} + +span.breadcrumb_link { + color: #d0d0d0; + font-size: 12pt !important; +} + +.breadcrumb_link.selected { + color: #95b750; +} + +.breadcrumb_link.selected:hover { + color: #95b750; +} +.breadcrumb_link:hover { + color: #95b750; +} + +/* + * Discovery forms structure + */ + +form.discovery * { + font-size: 10pt; +} + +.edit_discovery_info { + display: flex; + align-items: flex-start; + padding-top: 25px; +} + +.edit_discovery_input { + align-items: center; + margin-bottom: 25px; +} + +/* + * Discovery text inputs + */ + +.discovery_label_hint { + display: flex; +} + +label { + color: #343434 !important; + font-weight: bold; +} + +.discovery_full_width_input { + width: 100%; +} + +li > input[type="text"], +li > input[type="password"], +.discovery_text_input > input[type="password"], +.discovery_text_input > input[type="text"], +#interval_manual > input[type="text"] { + background-color: transparent !important; + border: none; + border-radius: 0 !important; + border-bottom: 1px solid #ccc; + font-family: "lato-bolder", "Open Sans", sans-serif !important; + font-weight: lighter; + padding: 0px 0px 2px 0px; + box-sizing: border-box; + margin-bottom: 4px; +} + +#interval_manual > input[type="text"] { + width: 50px; + margin-left: 10px; + margin-right: 10px; +} + +.discovery_list_input { + width: 100%; + border: 1px solid #cbcbcb; + overflow-y: auto; +} + +.discovery_list_input option { + text-align: left; +} + +.discovery_list_input option:checked { + background: #1aab8e -webkit-linear-gradient(bottom, #7db742 0%, #7db742 100%); + color: #fff; +} + +.discovery_textarea_input { + background-color: #fbfbfb !important; + padding-left: 10px; + width: 100%; + height: 100px; + max-height: 100px; + max-width: 100%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + resize: none; +} + +a.tip { + margin-left: 8px; +} + +.inline_switch > label { + float: right; +} + +.discovery_interval_select_width { + width: 90%; +} diff --git a/pandora_console/include/styles/events.css b/pandora_console/include/styles/events.css new file mode 100644 index 0000000000..20b1f59d15 --- /dev/null +++ b/pandora_console/include/styles/events.css @@ -0,0 +1,20 @@ +div.criticity { + width: 150px; + height: 2em; + color: #fff; + text-align: center; + border-radius: 5px; + font-size: 0.8em; + padding: 3px; + margin: 0; + display: table-cell; + vertical-align: middle; +} + +div.mini-criticity { + width: 5px; + height: 4em; + padding: 0; + margin: 0; + display: inline-block; +} diff --git a/pandora_console/include/styles/firts_task.css b/pandora_console/include/styles/firts_task.css index 32be0eb832..1b26b2bfbe 100755 --- a/pandora_console/include/styles/firts_task.css +++ b/pandora_console/include/styles/firts_task.css @@ -72,6 +72,7 @@ div.new_task_cluster > div { } #description_task { font-size: 12px; + line-height: 1.8em; } #fuerte { diff --git a/pandora_console/include/styles/hostdevices.css b/pandora_console/include/styles/hostdevices.css new file mode 100644 index 0000000000..461327705e --- /dev/null +++ b/pandora_console/include/styles/hostdevices.css @@ -0,0 +1,3 @@ +/* + * TODO: This may be at hostdevices.css + */ diff --git a/pandora_console/include/styles/js/cluetip.css b/pandora_console/include/styles/js/cluetip.css index dea766762b..233dbf3cbb 100644 --- a/pandora_console/include/styles/js/cluetip.css +++ b/pandora_console/include/styles/js/cluetip.css @@ -13,7 +13,7 @@ width: 43px; height: 11px; position: absolute; - background-image: url(../../images/wait.gif); + background-image: url(../../../images/wait.gif); } .cluetip-arrows { display: none; diff --git a/pandora_console/include/styles/js/jquery-ui_custom.css b/pandora_console/include/styles/js/jquery-ui_custom.css index ca2cdb51e7..f5bd560d69 100644 --- a/pandora_console/include/styles/js/jquery-ui_custom.css +++ b/pandora_console/include/styles/js/jquery-ui_custom.css @@ -70,13 +70,13 @@ float: right; } .ui-dialog .ui-dialog-buttonpane button { - margin: 0.5em 1em 0.5em 0 !important; - cursor: pointer !important; - background: white !important; - background-color: white !important; - border: 1px solid #82b92e !important; - height: 30px !important; - width: 90px !important; + margin: 0.5em 1em 0.5em 0; + cursor: pointer; + background: white; + background-color: white; + border: 1px solid #82b92e; + height: 30px; + width: 90px; } .ui-widget-header .ui-icon { background-image: url(../images/ui-icons_444444_256x240.png) !important; diff --git a/pandora_console/include/styles/js/jquery.contextMenu.css b/pandora_console/include/styles/js/jquery.contextMenu.css index 64d86cf7bc..7343aa5de1 100644 --- a/pandora_console/include/styles/js/jquery.contextMenu.css +++ b/pandora_console/include/styles/js/jquery.contextMenu.css @@ -107,61 +107,61 @@ background-position: 4px 2px; } .context-menu-item.icon-edit { - background-image: url(../../images/page_white_edit.png); + background-image: url(../../../images/page_white_edit.png); } .context-menu-item.icon-cut { - background-image: url(../../images/cut.png); + background-image: url(../../../images/cut.png); } .context-menu-item.icon-copy { - background-image: url(../../images/page_white_copy.png); + background-image: url(../../../images/page_white_copy.png); } .context-menu-item.icon-paste { - background-image: url(../../images/page_white_paste.png); + background-image: url(../../../images/page_white_paste.png); } .context-menu-item.icon-delete { - background-image: url(../../images/delete.png); + background-image: url(../../../images/delete.png); } .context-menu-item.icon-add { - background-image: url(../../images/page_white_add.png); + background-image: url(../../../images/page_white_add.png); } .context-menu-item.icon-quit { - background-image: url(../../images/door.png); + background-image: url(../../../images/door.png); } .context-menu-item.icon-refresh { - background-image: url(../../images/refresh.png); + background-image: url(../../../images/refresh.png); } .context-menu-item.icon-center { - background-image: url(../../images/set_center.png); + background-image: url(../../../images/set_center.png); } .context-menu-item.icon-details { - background-image: url(../../images/show_details.png); + background-image: url(../../../images/show_details.png); } .context-menu-item.icon-children { - background-image: url(../../images/children.png); + background-image: url(../../../images/children.png); } .context-menu-item.icon-cancel_set_parent { - background-image: url(../../images/link_delete.png); + background-image: url(../../../images/link_delete.png); } .context-menu-item.icon-set_parent { - background-image: url(../../images/father.png); + background-image: url(../../../images/father.png); } .context-menu-item.icon-add_node { - background-image: url(../../images/add.png); + background-image: url(../../../images/add.png); } .context-menu-item.icon-refresh_holding_area { - background-image: url(../../images/refresh_holding_area.png); + background-image: url(../../../images/refresh_holding_area.png); } .context-menu-item.icon-restart_map { - background-image: url(../../images/reset.png); + background-image: url(../../../images/reset.png); } .context-menu-item.icon-interface_link_children { - background-image: url(../../images/icono_link_hijo.png); + background-image: url(../../../images/icono_link_hijo.png); } .context-menu-item.icon-interface_link_parent { - background-image: url(../../images/icono_link_padre.png); + background-image: url(../../../images/icono_link_padre.png); } .context-menu-item.icon-interface_link_cancel { - background-image: url(../../images/link_abortar.png); + background-image: url(../../../images/link_abortar.png); } /* vertically align inside labels */ diff --git a/pandora_console/include/styles/login.css b/pandora_console/include/styles/login.css index f7066ba92c..bffcda19d5 100644 --- a/pandora_console/include/styles/login.css +++ b/pandora_console/include/styles/login.css @@ -29,41 +29,11 @@ div#error_buttons a { width: 100%; z-index: -9999; position: absolute; - background-image: url("../../images/backgrounds/background_pandora_console_keys.jpg"); + background: linear-gradient(74deg, #02020255 36%, transparent 36%), + url("../../images/backgrounds/background_pandora_console_keys.jpg"); background-repeat: repeat; } -/*@media screen and (max-width: 1024px) { /* Specific to this particular image */ -/* #login_body { - left: 50%; - margin-left: -512px; /* 50% */ -/* } -} -@media screen and (max-width: 1100px) { /* Specific to this particular image */ -/* #login_body { - background-image: url("../../images/backgrounds/background_pandora_console_keys.jpg"); - background-repeat: repeat; - } -} -@media screen and (max-width: 1400px) { /* Specific to this particular image */ -/* #login_body { - background-image: url("../../images/backgrounds/background_pandora_console_keys.jpg"); - background-repeat: repeat; - } -} -@media screen and (max-width: 2000px) { /* Specific to this particular image */ -/* #login_body { - background-image: url("../../images/backgrounds/background_pandora_console_keys.jpg"); - background-repeat: repeat; - } -} -@media screen and (min-width: 2000px) { /* Specific to this particular image */ -/* #login_body { - background-image: url("../../images/backgrounds/background_pandora_console_keys.jpg"); - background-repeat: repeat; - } -}*/ - p.log_in { color: #fff !important; padding: 0px 10px; @@ -77,7 +47,6 @@ h1#log_f { } div#error_login { - text-align: center; margin-top: 5px; margin-left: 5px; width: 75%; @@ -104,8 +73,11 @@ div#login_f { width: 100%; position: absolute; bottom: 10px; - color: #fff; + color: #878787; text-align: center; + font-family: "Open Sans", sans-serif; + font-weight: 700; + font-size: 8.5pt; } /* @@ -118,23 +90,17 @@ div#login_f { div#header_login { width: 100%; height: 65px; - background-color: rgba(255, 255, 255, 0.06); -} - -div#icon_custom_pandora { - float: left; - margin-top: 5px; - margin-left: 4%; } div#list_icon_docs_support { - float: right; - margin-top: 8px; - margin-right: 4%; + float: left; + margin-top: 25px; + margin-left: 5%; } div#list_icon_docs_support ul { margin-top: 5px; + line-height: 36px; } div#list_icon_docs_support ul li { @@ -145,6 +111,11 @@ div#list_icon_docs_support ul li { font-size: 10pt; } +div#list_icon_docs_support ul li a { + color: #979797; + font-size: 10pt; +} + li#li_margin_left { margin-left: 30px; } @@ -162,14 +133,6 @@ div.login_page { float: left; } -div.login_page form { - border-right: 1px solid #868686; - padding-top: 30px; - padding-bottom: 50px; - min-width: 400px; - max-height: 600px; -} - div.login_logo_icon { margin-bottom: 40px; text-align: center; @@ -177,7 +140,7 @@ div.login_logo_icon { div.login_logo_icon img { margin: 0 auto; - width: 150px; + max-width: 70%; } div.login_double_auth_code, @@ -186,27 +149,36 @@ div.login_pass { margin: 0 auto; width: 70%; height: 40px; - background-color: rgba(255, 255, 255, 0.2) !important; margin-bottom: 25px; min-width: 260px; + background-color: #fff; + opacity: 0.77; + box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1); + border-radius: 3px; } -div.login_nick img, -div.login_pass img { - vertical-align: middle; - margin: 3px; +div.login_nick input { + background-image: url("../../images/usuario_login.png"); +} + +div.login_pass input { + background-image: url("../../images/candado_login.png"); } div.login_nick input, div.login_pass input { - background-color: rgba(255, 255, 255, 0) !important; border: 0px !important; - color: white !important; - border-radius: 0px; - width: 89%; + color: #343434; + border-radius: 3px; + width: 100%; height: 40px; - font-size: 9pt; - padding: 0px !important; + font-size: 10pt; + padding: 0px 0px 0px 35px !important; + background-repeat: no-repeat; + background-size: 27px; + background-position: left center; + font-family: "Open Sans", sans-serif; + box-sizing: border-box; } div.login_nick input:focus, @@ -224,46 +196,76 @@ div.login_pass input:-webkit-autofill:focus, div.login_pass input:-webkit-autofill:active { transition: background-color 10000s ease-in-out 0s; -webkit-box-shadow: 0 0 0px 0px transparent inset !important; - -webkit-text-fill-color: white !important; + -webkit-text-fill-color: #343434 !important; border: 0px; width: 89%; } div.login_nick input::-webkit-input-placeholder, div.login_pass input::-webkit-input-placeholder { - color: white; + color: #343434; } -div.login_pass img, -div.login_nick img { - width: 30px; -} - -div.login_pass div, -div.login_nick div { - float: left; - width: 11%; -} - -div.login_button { +div.login_button, +div.login_button_saml { margin: 0 auto; - width: 70%; + width: 40%; height: 40px; - background-color: rgb(25, 25, 25); - border: 1px solid white; min-width: 260px; + margin-bottom: 20px; } div.login_button input { width: 100%; - background-color: rgb(25, 25, 25) !important; + background-color: #82b92e !important; text-align: center; - border: 0px; - border-radius: 0px; height: 40px; padding: 0px; - font-size: 9pt; - color: white; + font-size: 11pt; + color: #fff !important; + border: 1px solid #82b92e; + border-radius: 3px; +} + +div.login_button_saml input { + border: 1px solid #fff; + background-color: #fff !important; + color: #000 !important; + background-image: url("../../images/saml_login.png"); + background-repeat: no-repeat; + background-position: right 5% center; +} + +div.login_button input:hover { + background-color: #fff !important; + color: #000 !important; + border: 1px solid #fff !important; +} + +div.login_button_saml input:hover { + background-image: url("../../images/saml_login_hover.png"); + background-color: transparent !important; + color: #fff !important; + border: 1px solid #fff !important; +} + +#remove_button input { + background-image: url("../../images/user_login.png") !important; + background-repeat: no-repeat; + background-position: right 5% center; +} + +#remove_button input:hover { + background-image: url("../../images/user_login_hover.png") !important; +} + +.login_back input { + background-image: url("../../images/back_login.png") !important; + background-position: left 5% center !important; +} + +.login_back input:hover { + background-image: url("../../images/back_login_hover.png") !important; } div.login_data { @@ -307,6 +309,21 @@ div.img_banner_login img { min-height: 50%; } +.reset_password { + width: 70%; + height: 40px; + margin-right: auto; + margin-left: auto; + margin-top: 20px; + text-align: center; +} + +.reset_password a { + color: #ddd !important; + font-family: "Open Sans", sans-serif; + font-size: 8.5pt; +} + @media all and (max-width: 1200px) { span.span1 { font-size: 30pt; diff --git a/pandora_console/include/styles/menu.css b/pandora_console/include/styles/menu.css index a30978b3a8..7846a3f9a6 100644 --- a/pandora_console/include/styles/menu.css +++ b/pandora_console/include/styles/menu.css @@ -16,11 +16,24 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -.menu { - border-width: 0px 0px 0px 0px; - border-style: none; - border-color: #777; +.operation li, +.godmode li { + display: flex !important; + justify-content: flex-start; + align-items: center; } + +.operation > li.menu_icon.no_hidden_menu, +.godmode > li.menu_icon.no_hidden_menu { + justify-content: flex-end; +} + +.operation .menu_icon ul.submenu > li, +.godmode .menu_icon ul.submenu > li { + background-color: #282828; + padding-left: 1.5em; +} + .menu ul { list-style-type: none; padding: 0; @@ -28,14 +41,13 @@ } .menu li.selected, .menu li.not_selected { - border: 0px none black; - border-bottom: 0px none #d4d4d4; margin: 0; } .menu li a { color: #ffffff; text-decoration: none; + width: 100%; } li:hover ul { @@ -43,14 +55,11 @@ li:hover ul { } .submenu_text { - padding: 10.5px; margin-left: 0px; width: 100%; - color: #fff; -} - -.menu li.subselected a { - background-color: grey !important; + color: #b9b9b9; + font-family: "Open Sans", sans-serif; + font-size: 9.4pt; } .menu a:hover { @@ -61,26 +70,24 @@ li:hover ul { margin: 0px 0px 0px 0px; position: absolute; z-index: 999; - left: 44px; - min-height: 35px; - height: 35px; - width: 180px; + width: 240px; } .submenu2 { position: absolute; z-index: 999; - left: 180px; + left: 240px; + width: 240px; } .sub_subMenu { - min-height: 35px !important; - height: 35px; - width: 180px; font-weight: normal !important; + background-color: #202020; + padding-left: 1.5em; } + .sub_subMenu.selected { - font-weight: bold !important; + font-weight: 600 !important; } .submenu2 li a { @@ -95,18 +102,10 @@ li:hover ul { border-left: 1px; } -.menu li.has_submenu > a > div { - background: url(../../images/arrow.png) no-repeat 80% 50%; +.menu li.has_submenu { + background: url(../../images/arrow.png) no-repeat 95% 50%; z-index: 1; /* Positions it on top of the rest */ } -.menu li.has_submenu > .SubNoLink { - background: url(../../images/arrow.png) no-repeat 80% 50%; - z-index: 1; /* Positions it on top of the rest */ -} - -.is_submenu2 { - background-color: #e4e4e4 !important; -} .menu li.submenu_not_selected a, .menu li.submenu2_not_selected a { @@ -117,6 +116,18 @@ li:hover ul { margin-bottom: 0px !important; box-shadow: inset 4px 0 #80ba27 !important; } +.selected.submenu_selected { + background-color: #202020 !important; +} + +li.submenu_selected.selected { + background-color: #202020 !important; + font-weight: 600; +} + +li.sub_subMenu.selected { + background-color: #161616 !important; +} .menu .menu_icon, .menu li.links { @@ -132,21 +143,18 @@ li:hover ul { /* Icons specified here */ #icon_oper-networkconsole { - background: url(../../images/op_network.menu.png) no-repeat 50% 50%; + background: url(../../images/op_network.menu_gray.png) no-repeat; } #icon_oper-agents { - border-top-right-radius: 5px; - border-right-style: solid; - border-right-width: 0px; - background: url(../../images/op_monitoring.menu.png) no-repeat 50% 50%; + background: url(../../images/op_monitoring.menu_gray.png) no-repeat; } #icon_oper-events { - background: url(../../images/op_events.menu.png) no-repeat 50% 50%; + background: url(../../images/op_events.menu_gray.png) no-repeat; } /* users */ #icon_oper-users { - background: url(../../images/op_workspace.menu.png) no-repeat 50% 50%; + background: url(../../images/op_workspace.menu_gray.png) no-repeat; } /* trap console */ #icon_oper-snmpc, @@ -154,7 +162,7 @@ li:hover ul { background: url(../../images/op_snmp.menu.png) no-repeat 50% 50%; } #icon_oper-reporting { - background: url(../../images/op_reporting.menu.png) no-repeat 50% 50%; + background: url(../../images/op_reporting.menu_gray.png) no-repeat; } #icon_oper-gismaps { background: url(../../images/op_gis.menu.png) no-repeat 50% 50%; @@ -163,52 +171,51 @@ li:hover ul { background: url(../../images/op_netflow.menu.png) no-repeat 50% 50%; } #icon_oper-extensions { - background: url(../../images/extensions.menu.png) no-repeat 50% 50%; + background: url(../../images/extensions.menu_gray.png) no-repeat; } /* Godmode images */ +#icon_god-discovery { + background: url(../../images/gm_discovery.menu.png) no-repeat; +} #icon_god-resources { - background: url(../../images/gm_resources.menu.png) no-repeat 50% 50%; + background: url(../../images/gm_resources.menu_gray.png) no-repeat; } #icon_god-configuration { - background: url(../../images/gm_configuration.menu.png) no-repeat 50% 50%; + background: url(../../images/gm_configuration.menu_gray.png) no-repeat; } #icon_god-alerts { - background: url(../../images/gm_alerts.menu.png) no-repeat 50% 50%; + background: url(../../images/gm_alerts.menu_gray.png) no-repeat; } #icon_god-users { - background: url(../../images/gm_users.menu.png) no-repeat 50% 50%; + background: url(../../images/gm_users.menu_gray.png) no-repeat; } #icon_god-reporting { background: url(../../images/reporting_edit.menu.png) no-repeat 50% 50%; } #icon_god-servers { - background: url(../../images/gm_servers.menu.png) no-repeat 50% 50%; + background: url(../../images/gm_servers.menu_gray.png) no-repeat; } #icon_god-setup { - background: url(../../images/gm_setup.menu.png) no-repeat 50% 50%; + background: url(../../images/gm_setup.menu_gray.png) no-repeat; } #icon_god-events { - background: url(../../images/gm_events.menu.png) no-repeat 50% 50%; + background: url(../../images/gm_events.menu_gray.png) no-repeat; } #icon_god-extensions { - background: url(../../images/builder.menu.png) no-repeat 50% 50%; + background: url(../../images/builder.menu_gray.png) no-repeat; } #icon_god-links { - border-top: 4px solid #777 !important; - border-color: #777; - background: url(../../images/links.menu.png) no-repeat 50% 50%; + background: url(../../images/links.menu_gray.png) no-repeat; } #icon_god-um_messages { - border-color: #777; - background: url(../../images/um_messages.menu.png) no-repeat 50% 50%; + background: url(../../images/um_messages.menu_gray.png) no-repeat; } #menu_container { z-index: 3; position: absolute; left: -80px; - background-color: #aaa; } .notification_ball { @@ -253,140 +260,222 @@ ul li { } /* End */ -ul li a:hover { - color: #e2144a; -} /* Hover Styles */ -/*li ul li a { padding: 2px 5px; } Sub Menu Styles */ - /* * --------------------------------------------------------------------- * - MAIN LEFT MENU and SUBMENU - * --------------------------------------------------------------------- */ -.menu li.selected { - font-weight: bold; -} - -.menu_icon { - transition-property: background-color; - transition-duration: 0.5s; - transition-timing-function: ease-out; - -webkit-transition-property: background-color; - -webkit-transition-duration: 0.5s; - -webkit-transition-timing-function: ease-out; - -moz-transition-property: background-color; - -moz-transition-duration: 0.5s; - -moz-transition-timing-function: ease-out; - -o-transition-property: background-color; - -o-transition-duration: 0.5s; - -o-transition-timing-function: ease-out; -} .menu_icon:hover { - transition-property: background-color; - transition-duration: 0.5s; - transition-timing-function: ease-out; - -webkit-transition-property: background-color; - -webkit-transition-duration: 0.5s; - -webkit-transition-timing-function: ease-out; - -moz-transition-property: background-color; - -moz-transition-duration: 0.5s; - -moz-transition-timing-function: ease-out; - -o-transition-property: background-color; - -o-transition-duration: 0.5s; - -o-transition-timing-function: ease-out; - background-color: #585858 !important; + background-color: #282828 !important; } .submenu_not_selected:hover { - transition-property: background-color; - transition-duration: 0.5s; - transition-timing-function: ease-out; - -webkit-transition-property: background-color; - -webkit-transition-duration: 0.5s; - -webkit-transition-timing-function: ease-out; - -moz-transition-property: background-color; - -moz-transition-duration: 0.5s; - -moz-transition-timing-function: ease-out; - -o-transition-property: background-color; - -o-transition-duration: 0.5s; - -o-transition-timing-function: ease-out; - background-color: #585858 !important; + background-color: #202020 !important; } .submenu_selected:hover { - background-color: #585858 !important; -} -.sub_subMenu { - transition-property: background-color; - transition-duration: 0.5s; - transition-timing-function: ease-out; - -webkit-transition-property: background-color; - -webkit-transition-duration: 0.5s; - -webkit-transition-timing-function: ease-out; - -moz-transition-property: background-color; - -moz-transition-duration: 0.5s; - -moz-transition-timing-function: ease-out; - -o-transition-property: background-color; - -o-transition-duration: 0.5s; + background-color: #202020 !important; } .sub_subMenu:hover { - transition-property: background-color; - transition-duration: 0.5s; - transition-timing-function: ease-out; - -webkit-transition-property: background-color; - -webkit-transition-duration: 0.5s; - -webkit-transition-timing-function: ease-out; - -moz-transition-property: background-color; - -moz-transition-duration: 0.5s; - -moz-transition-timing-function: ease-out; - -o-transition-property: background-color; - -o-transition-duration: 0.5s; - background-color: #585858 !important; + background-color: #161616 !important; } .menu li.selected { box-shadow: inset 4px 0 #80ba27; } -/* creo que no se usan -.is_submenu2 li { - background-color: #ff0000; -} -.is_submenu2 { - background-color: #222222 !important; -} -*/ .operation { - background-color: #333 !important; - border-top-right-radius: 5px; - border-right-style: solid; - border-right-width: 0px; + background-color: #3d3d3d !important; + padding-top: 20px !important; } -.operation .selected { - background-color: #585858 !important; +.operation .selected, +.godmode .selected { + background-color: #282828 !important; +} + +.operation .selected #title_menu, +.godmode .selected #title_menu { + color: #fff !important; + font-weight: 600; } .menu li, -.menu .li.not_selected { - border-radius: 0px 0px 0px 0px; - display: block; +.menu li a, +.menu li div { min-height: 35px; - border-bottom: 0px none #424242; - vertical-align: middle; + display: flex; + align-items: center; } -.godmode, -.menu_icon ul li { - background-color: #222; -} -.operation .menu_icon ul li { - background-color: #333; +.menu li div { + background-clip: text; /* Very important to fix a bug in Firefox */ } .godmode { - border-top: 4px solid #777 !important; padding-bottom: 4px !important; - border-bottom-right-radius: 5px; - border-right-style: solid; - border-right-width: 0px; + background-color: #343434; +} + +/* Menu icons active */ +.selected#icon_oper-networkconsole { + background: url(../../images/op_network.menu_white.png) no-repeat; +} +.selected#icon_oper-agents { + background: url(../../images/op_monitoring.menu_white.png) no-repeat; +} +.selected#icon_oper-events { + background: url(../../images/op_events.menu_white.png) no-repeat; +} +.selected#icon_oper-users { + background: url(../../images/op_workspace.menu_white.png) no-repeat; +} +.selected#icon_oper-reporting { + background: url(../../images/op_reporting.menu_white.png) no-repeat; +} +.selected#icon_oper-extensions { + background: url(../../images/extensions.menu_white.png) no-repeat; +} +.selected#icon_god-discovery { + background: url(../../images/gm_discovery.menu_white.png) no-repeat; +} +.selected#icon_god-resources { + background: url(../../images/gm_resources.menu_white.png) no-repeat; +} +.selected#icon_god-configuration { + background: url(../../images/gm_configuration.menu_white.png) no-repeat; +} +.selected#icon_god-alerts { + background: url(../../images/gm_alerts.menu_white.png) no-repeat; +} +.selected#icon_god-users { + background: url(../../images/gm_users.menu_white.png) no-repeat; +} +.selected#icon_god-servers { + background: url(../../images/gm_servers.menu_white.png) no-repeat; +} +.selected#icon_god-setup { + background: url(../../images/gm_setup.menu_white.png) no-repeat; +} +.selected#icon_god-events { + background: url(../../images/gm_events.menu_white.png) no-repeat; +} +.selected#icon_god-extensions { + background: url(../../images/builder.menu_white.png) no-repeat; +} +.selected#icon_god-links { + background: url(../../images/links.menu_white.png) no-repeat; +} +.selected#icon_god-um_messages { + background: url(../../images/um_messages.menu_white.png) no-repeat; +} + +#menu_full { + width: 60px; /* This is overwritten by the classic menu (215px) */ + position: fixed; + z-index: 1; + top: 0; + left: 0; + background-color: #343434; + border-bottom: solid 3px #343434; + min-height: 943px; +} + +.button_collapse { + height: 38px; + background-color: #505050; + width: 60px; /* This is overwritten by the classic menu (215px) */ + text-align: center; + color: #fff; + cursor: pointer; + background-repeat: no-repeat; + background-position: center; + margin-top: 15px; +} + +.logo_green { + height: 60px; + display: flex; + justify-content: center; + align-items: center; +} + +.operation div, +.operation a, +.godmode div, +.godmode a { + font-family: "Open Sans", sans-serif; +} + +.menu_full_classic, +.button_classic { + width: 215px !important; +} + +.menu_full_collapsed, +.button_collapsed { + width: 60px !important; +} + +.button_classic { + width: 215px !important; + background-image: url(../../images/button_collapse_menu.png); + background-repeat: no-repeat; + background-position: center; +} + +.button_collapsed { + background-image: url(../../images/button_classic_menu.png); + background-repeat: no-repeat; + background-position: center; +} + +/* Menu height: 601px, 720px, 735px */ +@media screen and (max-height: 720px) { + .menu li, + .menu li a, + .menu li div { + min-height: 28px !important; + } +} + +@media screen and (max-height: 735px) { + .operation { + padding-top: 10px !important; + } + .button_collapse { + margin-top: 10px; + } +} + +/* + * --------------------------------------------------------------------- + * - STYLES TO CHANGE CLASSIC MENU AND COLLAPSED MENU - + * --------------------------------------------------------------------- + */ +.page_classic { + padding-left: 215px !important; +} + +.page_collapsed { + padding-left: 60px !important; +} + +.header_table_classic { + padding-left: 235px !important; /* 215 + 35 */ +} + +.header_table_collapsed { + padding-left: 80px !important; /* 60 + 35 */ +} + +.title_menu_classic { + display: flex !important; +} + +.title_menu_collapsed { + display: none !important; +} + +.menu_icon_collapsed { + background-position: 50% 50% !important; } diff --git a/pandora_console/include/styles/message_edit.css b/pandora_console/include/styles/message_edit.css new file mode 100644 index 0000000000..f4b2294580 --- /dev/null +++ b/pandora_console/include/styles/message_edit.css @@ -0,0 +1,49 @@ +/* Chat containers */ +.container { + border: 2px solid #dedede; + background-color: #f1f1f1; + border-radius: 5px; + padding: 10px; + margin: 10px 0; +} + +/* Darker chat container */ +.darker { + border-color: #ccc; + background-color: #ddd; +} + +/* Clear floats */ +.container::after { + content: ""; + clear: both; + display: table; +} + +/* Style images */ +.container img { + float: left; + max-width: 60px; + width: 100%; + margin-right: 20px; + border-radius: 50%; +} + +/* Style the right image */ +.container img.right { + float: right; + margin-left: 20px; + margin-right: 0; +} + +/* Style time text */ +.time-right { + float: right; + color: #aaa; +} + +/* Style time text */ +.time-left { + float: left; + color: #999; +} diff --git a/pandora_console/include/styles/networkmap.css b/pandora_console/include/styles/networkmap.css new file mode 100644 index 0000000000..f933fa07c3 --- /dev/null +++ b/pandora_console/include/styles/networkmap.css @@ -0,0 +1,35 @@ +.node { + stroke: #fff; + stroke-width: 1px; +} + +.node_over { + stroke: #999; +} + +.node_selected { + stroke: #343434; + stroke-width: 5; +} + +.node_children { + stroke: #00f; +} + +.link { + stroke-opacity: 0.6; +} + +.link_over { + stroke: #000; + stroke-opacity: 0.6; +} + +.holding_area { + stroke: #0f0; + stroke-dasharray: 12, 3; +} + +.holding_area_link { + stroke-dasharray: 12, 3; +} diff --git a/pandora_console/include/styles/pandora.css b/pandora_console/include/styles/pandora.css index 70a9c4920e..b4fa370521 100644 --- a/pandora_console/include/styles/pandora.css +++ b/pandora_console/include/styles/pandora.css @@ -1,34 +1,102 @@ -/* -Author: The Pandora FMS team -Name: Default theme -Description: The default Pandora FMS theme layout - -// Pandora FMS - http://pandorafms.com -// ========================================================== -// Copyright (c) 2004-2019 Artica Soluciones Tecnológicas S.L - -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; version 2 - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -/* Tree view styles */ -/*@import url(tree.css); -@import url(fixed-bottom-box.css);*/ +/** + * + * Name: Default theme + * + * Extension to manage a list of gateways and the node address where they should + * point to. + * + * @category Extensions + * @package Pandora FMS + * @subpackage Community + * @version 1.0.0 + * @license See below + * + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ + */ /* * --------------------------------------------------------------------- * - GENERAL STYLES - * --------------------------------------------------------------------- */ +/* latin-ext */ +@font-face { + font-family: "Open Sans"; + font-style: normal; + font-weight: 400; + src: local("Open Sans Regular"), local("OpenSans-Regular"), + url(../fonts/mem8YaGs126MiZpBA-UFW50bbck.woff2) format("woff2"); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, + U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: "Open Sans"; + font-style: normal; + font-weight: 400; + src: local("Open Sans Regular"), local("OpenSans-Regular"), + url(../fonts/mem8YaGs126MiZpBA-UFVZ0b.woff2) format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, + U+FEFF, U+FFFD; +} +/* latin-ext */ +@font-face { + font-family: "Open Sans"; + font-style: normal; + font-weight: 600; + src: local("Open Sans SemiBold"), local("OpenSans-SemiBold"), + url(../fonts/mem5YaGs126MiZpBA-UNirkOXOhpOqc.woff2) format("woff2"); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, + U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: "Open Sans"; + font-style: normal; + font-weight: 600; + src: local("Open Sans SemiBold"), local("OpenSans-SemiBold"), + url(../fonts/mem5YaGs126MiZpBA-UNirkOUuhp.woff2) format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, + U+FEFF, U+FFFD; +} +/* latin-ext */ +@font-face { + font-family: "Open Sans"; + font-style: normal; + font-weight: 700; + src: local("Open Sans Bold"), local("OpenSans-Bold"), + url(../fonts/mem5YaGs126MiZpBA-UN7rgOXOhpOqc.woff2) format("woff2"); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, + U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: "Open Sans"; + font-style: normal; + font-weight: 700; + src: local("Open Sans Bold"), local("OpenSans-Bold"), + url(../fonts/mem5YaGs126MiZpBA-UN7rgOUuhp.woff2) format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, + U+FEFF, U+FFFD; +} @font-face { font-family: "Nunito"; font-style: normal; @@ -129,11 +197,14 @@ a:hover { color: #373737; text-decoration: underline; } +:focus { + outline-color: #82b92e; +} a:focus, input:focus, button:focus { - outline-width: 0; outline: 0; + outline-width: 0; } th > label { padding-top: 7px; @@ -195,6 +266,36 @@ th { letter-spacing: 0.3pt; } +/* Remove background when autocomplete */ +input:-webkit-autofill, +input:-webkit-autofill:hover, +input:-webkit-autofill:focus textarea:-webkit-autofill, +textarea:-webkit-autofill:hover textarea:-webkit-autofill:focus, +select:-webkit-autofill, +select:-webkit-autofill:hover, +select:-webkit-autofill:focus { + -webkit-box-shadow: 0 0 0px 1000px #ffffff inset !important; +} + +/* All select type multiple */ +select[multiple] option:checked { + background: #82b92e linear-gradient(0deg, #82b92e 0%, #82b92e 100%); + color: #fff !important; +} + +select option:checked { + background-color: #82b92e; + color: #fff !important; +} + +select > option:hover { + background-color: #cbcbcb; +} + +select:-internal-list-box { + border: none; +} + /* --- Font ttf --- */ @font-face { font-family: "DejaVuSerif-BoldFont"; @@ -202,7 +303,7 @@ th { } .DejaVuSerif-Bold { - font-family: DejaVuSerif-BoldFont; + font-family: DejaVuSerif-BoldFont, sans-serif; } @font-face { @@ -211,7 +312,7 @@ th { } .DejaVuSerif-BoldItalic { - font-family: DejaVuSerif-BoldItalicFont; + font-family: DejaVuSerif-BoldItalicFont, sans-serif; } @font-face { @@ -220,7 +321,7 @@ th { } .DejaVuSerif-Italic { - font-family: DejaVuSerif-ItalicFont; + font-family: DejaVuSerif-ItalicFont, sans-serif; } @font-face { @@ -229,7 +330,7 @@ th { } .DejaVuSerif { - font-family: DejaVuSerifFont; + font-family: DejaVuSerifFont, sans-serif; } @font-face { @@ -238,7 +339,7 @@ th { } .DejaVuSerifCondensed-Bold { - font-family: DejaVuSerifCondensed-BoldFont; + font-family: DejaVuSerifCondensed-BoldFont, sans-serif; } @font-face { @@ -247,7 +348,7 @@ th { } .DejaVuSerifCondensed-BoldItalic { - font-family: DejaVuSerifCondensed-BoldItalicFont; + font-family: DejaVuSerifCondensed-BoldItalicFont, sans-serif; } @font-face { @@ -256,7 +357,7 @@ th { } .DejaVuSerifCondensed-Italic { - font-family: DejaVuSerifCondensed-ItalicFont; + font-family: DejaVuSerifCondensed-ItalicFont, sans-serif; } @font-face { @@ -265,7 +366,7 @@ th { } .DejaVuSerifCondensed { - font-family: DejaVuSerifCondensedFont; + font-family: DejaVuSerifCondensedFont, sans-serif; } @font-face { @@ -274,7 +375,7 @@ th { } .FreeSans { - font-family: FreeSansFont; + font-family: FreeSansFont, sans-serif; } @font-face { @@ -283,7 +384,7 @@ th { } .FreeSansBold { - font-family: FreeSansBoldFont; + font-family: FreeSansBoldFont, sans-serif; } @font-face { @@ -292,7 +393,7 @@ th { } .smallfont { - font-family: smallfontFont; + font-family: smallfontFont, sans-serif; } @font-face { @@ -320,19 +421,69 @@ th { src: url("../../fonts/leaguegothic.woff") format("woff"); } .unicode { - font-family: unicodeFont; + font-family: unicodeFont, sans-serif; } /* * --------------------------------------------------------------------- - * - GLOBAL STYLES - + * - GLOBAL STYLES - * --------------------------------------------------------------------- */ +.w10p { + max-width: 10%; +} + +.w20p { + max-width: 20%; +} + +.w30p { + max-width: 30%; +} + +.w40p { + max-width: 40%; +} + +.w50p { + max-width: 50%; +} + +.w100p { + max-width: 100%; +} + +.no-padding { + padding: 0; +} +.no-padding-imp { + padding: 0 !important; +} +.no-margin { + margin: 0; +} +.box-shadow { + box-shadow: 0px 0px 15px -4px #dadada; +} +.align-top td { + vertical-align: top; +} +.no-td-borders td { + border: none !important; +} +.no-td-padding td { + padding: 0 !important; +} + div#page { - background: #fff; + background: #fbfbfb; background-image: none; clear: both; width: auto; + padding-top: 5px !important; + padding-left: 60px; /* This is overwritten by the classic menu (215px)*/ + padding-right: 35px; + margin-left: 20px; } body.pure { @@ -350,12 +501,10 @@ div#container { div#main { width: auto; - margin: 0px 0% 0px 0%; - float: left; + margin: 0 auto; position: relative; min-height: 850px; - margin-left: 60px; - max-width: 93%; + max-width: 100%; min-width: 93%; } @@ -371,14 +520,6 @@ textarea.conf_error { background-position: top right; } -input.button { - font-family: Arial, Sans-serif; - border: 4px solid #ccc; - background: #fff; - padding: 2px 3px; - margin: 10px 15px; -} - a.white_bold { color: #eee; text-decoration: none; @@ -426,14 +567,18 @@ input.sub { font-weight: normal; -moz-border-radius: 2px; -webkit-border-radius: 2px; + height: auto !important; border-radius: 2px; - font-size: 8pt; - background-color: #333 !important; - background-repeat: no-repeat !important; - background-position: 92% 3px !important; - color: white !important; - padding: 3px 3px 5px 12px; - border-color: #333; + font-size: 1.2em; + background-color: #fff; + background-repeat: no-repeat; + background-position: 92% 10px; + color: #000; + padding-bottom: 10px; + padding-top: 10px; + padding-left: 15px; + border-color: #888; + font-family: "lato", "Open Sans", sans-serif !important; } input.sub[disabled] { @@ -582,17 +727,21 @@ a.footer span { } div#foot { - font-size: 6pt !important; - border-top: solid 2px #222; - padding-top: 8px; - padding-bottom: 5px; + padding-top: 10px; + padding-bottom: 10px; text-align: center; - background: #333333; - height: 30px; + background: #343434; clear: both; width: auto; } +div#foot a, +div#foot span { + font-family: "Open Sans", sans-serif; + font-size: 8pt; + color: #9ca4a6; +} + /* * --------------------------------------------------------------------- * - HEADER AND LEFT MENU STYLES - @@ -619,13 +768,12 @@ div#head { width: 100%; height: 60px; padding-top: 0px; - margin-bottom: 20px; - border-bottom-style: solid; - border-bottom-width: 3px; - border-color: #82b92e; + margin: 0 auto; + border-bottom: 1px solid #9ca4a6; min-width: 882px; - background-color: #333; - color: white; + background-color: #fff; + color: #000; + z-index: 2; } .fixed_header { @@ -911,6 +1059,13 @@ input.group_item_min[disabled] { background: #fefefe url(../../images/group_green.disabled.png) no-repeat center !important; } +input.color_cloud_min { + background: #fefefe url(../../images/color_cloud_item.png) no-repeat center !important; +} +input.color_cloud_min[disabled] { + background: #fefefe url(../../images/color_cloud_item.disabled.png) no-repeat + center !important; +} div#cont { position: fixed; @@ -923,22 +1078,6 @@ div#cont { background-color: #80BA27 !important; }*/ -/*tr.datos, tr.datost, tr.datosb , tr.datos_id, -tr.datosf9 { - #background-color: #eaeaea; -} - -tr.datos2, tr.datos2t, -tr.datos2b, tr.datos2_id , tr.datos2f9 { - #background-color: #f2f2f2; -} - -tr.datos:hover, tr.datost:hover, tr.datosb:hover, tr.datos_id:hover, -tr.datosf9:hover, tr.datos2:hover, tr.datos2t:hover, -tr.datos2b:hover, tr.datos2_id:hover, tr.datos2f9:hover { - #background-color: #efefef; -}*/ - /* * --------------------------------------------------------------------- * - REPORTS - @@ -955,17 +1094,26 @@ tr.datos2b:hover, tr.datos2_id:hover, tr.datos2f9:hover { } td.datos3, -td.datos3 * { - background-color: #666; - color: white !important; +td.datos4 { + background-color: #fff; + color: #000 !important; + border-bottom: 2px solid #82b92e !important; + border-left: none !important; + border-right: none !important; + height: 30px; + font-size: 8.6pt; + font-weight: normal; } -td.datos4, -td.datos4 * { +td.datos4 { /*Add !important because in php the function html_print_table write style in cell and this is style head.*/ text-align: center !important; - background-color: #666; - color: white !important; +} + +td.datos3 *, +td.datos4 * { + font-size: 8.6pt; + font-weight: normal; } /*td.datos_id { @@ -978,11 +1126,6 @@ tr.disabled_row_user * { } /* global syles */ -.bg { - /* op menu */ - background: #82b92e; -} - .bg { /* op menu */ background: #82b92e; @@ -1183,20 +1326,62 @@ div.title_line { * --------------------------------------------------------------------- */ #menu_tab_frame, -#menu_tab_frame_view { - display: block !important; - border-bottom: 1px solid #80ba27; - max-height: 31px; - min-height: 31px; +#menu_tab_frame_view, +#menu_tab_frame_view_bc { + display: flex; + align-items: flex-end; + justify-content: space-between; + border-bottom: 2px solid #82b92e; + min-height: 50px; width: 100%; padding-right: 0px; margin-left: 0px !important; margin-bottom: 20px; - height: 31px; + height: 50px; + box-sizing: border-box; + background-color: #fafafa; + border-top-right-radius: 7px; + border-top-left-radius: 7px; + box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.1); } +/* Breadcrum */ +#menu_tab_frame_view_bc { + min-height: 55px; + align-items: unset; +} + +#menu_tab_frame_view_bc .breadcrumbs_container { + align-self: flex-start; +} + +.menu_tab_left_bc { + flex-direction: column; + display: flex; + justify-content: space-between; + margin-right: 20px; + overflow: hidden; +} + +.breadcrumbs_container { + padding-left: 10px; + padding-top: 4px; + text-indent: 0.25em; + color: #848484; + font-size: 10pt !important; + font-family: "lato-bolder", "Open Sans", sans-serif !important; +} + +.breadcrumb_active { + color: #82b92e; + font-size: 10pt !important; + font-family: "lato-bolder", "Open Sans", sans-serif !important; +} +/* End - Breadcrum */ + #menu_tab { - margin: 0px 0px 0px 0px !important; + margin-right: 10px; + min-width: 510px; } #menu_tab .mn, @@ -1228,22 +1413,14 @@ div.title_line { text-decoration: none; padding: 0px; margin: 0px; + padding-top: 6px; } #menu_tab li.nomn:hover a, #menu_tab li:hover ul a:hover { color: #fff; } -#menu_tab li.nomn { - min-width: 30px; - height: 28px; -} -#menu_tab li.nomn_high { - min-width: 30px; - height: 28px; -} - -/* --- Submenu --- */ +/* --- Tabs Submenu --- */ ul.subsubmenu { border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; @@ -1251,12 +1428,10 @@ ul.subsubmenu { -moz-border-bottom-left-radius: 5px; -webkit-border-bottom-right-radius: 5px; -webkit-border-bottom-left-radius: 5px; - - background: #ececec !important; } ul.subsubmenu li { - background-color: #ececec; + background-color: #fff; font-weight: bold; text-decoration: none; font-size: 14px; @@ -1300,52 +1475,33 @@ div#agent_wizard_subtabs { */ /* TAB TITLE */ #menu_tab_left { - margin-left: 0px !important; + max-width: 60%; + margin-right: 20px; } #menu_tab_left .mn, #menu_tab_left ul, #menu_tab_left .mn ul { - background-color: #000; - color: #fff; - font-weight: bold; + color: #343434; padding: 0px 0px 0px 0px; list-style: none; margin: 0px 0px 0px 0px; } -#menu_tab_left .mn li { - float: left; - position: relative; - height: 26px; - max-height: 26px; -} + #menu_tab_left .mn li a { display: block; text-decoration: none; } #menu_tab_left li.view a { - color: #fff; - font-weight: bold; - font-weight: 100; - line-height: 18px; + color: #343434; display: none; } #menu_tab_left li.view { - background: #82b92e; - max-width: 60%; - min-width: 30%; - padding: 5px 5px 0px; - text-align: center; - -moz-border-top-right-radius: 3px; - -webkit-border-top-right-radius: 3px; - border-top-right-radius: 3px; - - -moz-border-top-left-radius: 3px; - -webkit-border-top-left-radius: 3px; - border-top-left-radius: 3px; margin-left: 0px !important; - overflow-y: hidden; + padding-left: 10px; + padding-bottom: 4px; + white-space: nowrap; } #menu_tab_left li.view img.bottom { @@ -1355,13 +1511,10 @@ div#agent_wizard_subtabs { #menu_tab_left li a, #menu_tab_left li span { - text-transform: uppercase; - color: #fff; - font-size: 100%; - line-height: 20px; - letter-spacing: 0px; - font-family: verdana, sans-serif; - font-weight: bold; + color: #343434; + font-family: "lato-bolder", "Open Sans", sans-serif !important; + font-size: 18pt; + line-height: 18pt; } /* @@ -1490,14 +1643,12 @@ table.databox { } .databox > thead > tr > th, -.databox > tbody > tr > th { +.databox > tbody > tr > th, +.databox > thead > tr > th a { padding: 9px 7px; font-weight: normal; color: #fff; } -.databox > td { - #border-bottom: 1px solid #e2e2e2; -} .databox > th * { color: #fff; @@ -1668,12 +1819,14 @@ div#main_pure { /* big_data is used in tactical and logon_ok */ .big_data { text-decoration: none; - font: bold 2em Arial, Sans-serif; + font-family: "lato", "Open Sans", sans-serif; + font-size: 2em; } .med_data { text-decoration: none; - font: bold 1.5em Arial, Sans-serif; + font-family: "lato", "Open Sans", sans-serif; + font-size: 1.5em; } .notify { @@ -1957,24 +2110,124 @@ div#pandora_logo_header { float: left; } -#header_table img { +/* + * --------------------------------------------------------------------- + * - HEADER - + * --------------------------------------------------------------------- + */ +#header_table { + margin: 0px; + padding: 0px; margin-top: 0px; + padding-left: 95px; /* This is overwritten by the classic menu */ + padding-right: 35px; +} + +#header_table_inner { + height: 60px; + min-width: 790px; + /*width: 100%;*/ + display: flex; + align-items: center; + justify-content: space-between; +} + +.header_title { + font-weight: 600; + font-size: 10.5pt; + font-family: "lato-bolder", "Open Sans", sans-serif !important; +} + +.header_subtitle { + font-size: 10pt; + font-family: "lato-bolder", "Open Sans", sans-serif !important; +} + +#header_table_inner a, +#header_table_inner span { + font-family: "Open Sans", sans-serif; +} + +#header_table_inner a:hover { + text-decoration: none; +} + +.header_left { + display: flex; + flex-direction: column; +} + +.header_center { + display: flex; + justify-content: center; + align-items: center; +} + +.header_right { + display: flex; + justify-content: flex-end; + align-items: center; +} + +.header_right > div { + padding-left: 15px; +} +.header_left img, +.header_center img, +.header_right img { + vertical-align: middle; +} + +#header_chat { + padding-left: 0; + padding-right: 15px; +} + +#header_autorefresh { + padding-left: 0; +} + +#header_table_inner #header_user span { + color: #777; + align-self: center; +} + +#header_table_inner #header_user a { + display: flex; + justify-content: center; +} + +#header_user img { + padding-right: 5px; +} + +div#header_autorefresh_counter { + padding-left: 0; } .autorefresh_disabled { cursor: not-allowed !important; } -a.autorefresh { - padding-right: 8px; -} - +a.autorefresh_txt, #refrcounter { - color: white; + color: #1c1c1c; + font-size: 8.5pt; } -#combo_refr select { - margin-right: 8px; +@media screen and (max-width: 1200px) { + #header_searchbar input.search_input { + width: 135px; + } + .header_right > div { + padding-left: 10px; + } +} + +@media screen and (max-width: 1300px) { + .header_right > div { + padding-left: 10px; + } } .disabled_module { @@ -1986,22 +2239,6 @@ div.warn { padding: 2px 1px 6px 25px; } -.submenu_not_selected { - transition-property: background-color; - transition-duration: 0.5s; - transition-timing-function: ease-out; - -webkit-transition-property: background-color; - -webkit-transition-duration: 0.5s; - -webkit-transition-timing-function: ease-out; - -moz-transition-property: background-color; - -moz-transition-duration: 0.5s; - -moz-transition-timing-function: ease-out; - -o-transition-property: background-color; - -o-transition-duration: 0.5s; - -o-transition-timing-function: ease-out; - font-weight: normal !important; -} - /* Submenus havent borders */ .submenu_not_selected, .submenu_selected, @@ -2010,9 +2247,6 @@ div.warn { min-height: 35px !important; } -ol.steps { - margin-bottom: 70px; -} div#steps_clean { display: none; } @@ -2041,10 +2275,6 @@ div#logo_text3 { margin-left: 4px; padding-top: 0px; }*/ -.pagination { - margin-top: 15px; - margin-bottom: 5px; -} .pagination * { margin-left: 0px !important; margin-right: 0px !important; @@ -2053,82 +2283,58 @@ div#logo_text3 { /* TABLAS */ /* Cells divs to set individual styles with the table objects */ -div.cellBold { - width: 100%; - height: 100%; +td.cellBold { font-weight: bold; } -div.cellRight { - width: 100%; - height: 100%; +td.cellRight { text-align: right; } -div.cellCenter { - width: 100%; - height: 100%; +td.cellCenter { text-align: center; } -div.cellWhite { - width: 100%; - height: 100%; +td.cellWhite { background: #fff; color: #111; } -div.cellNormal { - width: 100%; - height: 100%; +td.cellNormal { background: #6eb432; color: #fff; } -div.cellCritical { - width: 100%; - height: 100%; +td.cellCritical { background: #f85858; color: #fff; } -div.cellWarning { - width: 100%; - height: 100%; +td.cellWarning { background: #ffea59; color: #111; } -div.cellUnknown { - width: 100%; - height: 100%; +td.cellUnknown { background: #aaaaaa; color: #ffffff; } -div.cellNotInit { - width: 100%; - height: 100%; +td.cellNotInit { background: #3ba0ff; color: #ffffff; } -div.cellAlert { - width: 100%; - height: 100%; +td.cellAlert { background: #ff8800; color: #111; } -div.cellBorder1 { - width: 100%; - height: 100%; +td.cellBorder1 { border: 1px solid #666; } -div.cellBig { - width: 100%; - height: 100%; +td.cellBig { font-size: 18px; } @@ -2167,6 +2373,7 @@ div.cellBig { tr.group_view_data, .group_view_data { color: #3f3f3f; + font-family: "lato", "Open Sans", sans-serif; } tr.group_view_crit, @@ -2295,6 +2502,8 @@ select { -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; + font-family: "lato-bolder", "Open Sans", sans-serif; + font-size: 10pt; } /* plugins */ @@ -2733,6 +2942,12 @@ a.tip { a.tip > img { margin-left: 2px; margin-right: 2px; + margin-top: -3px; +} + +.head_tip { + display: inline; + margin-left: 10px; } /* @@ -2741,16 +2956,26 @@ a.tip > img { * --------------------------------------------------------------------- */ input.search_input { - background: white url("../../images/input_zoom.png") no-repeat right; + background-image: url("../../images/input_zoom_gray.png"); + background-position: center right 10px; + background-repeat: no-repeat; + background-size: 17px; + background-color: #f2f6f7 !important; padding: 0px; - padding-left: 5px; margin: 0; - width: 80%; - height: 19px; - margin-bottom: 5px; + width: 250px; + height: 30px; margin-left: 2px; - padding-right: 25px; - color: #999; + padding-left: 15px; + padding-right: 40px; + color: #777; + font-family: "Open Sans", sans-serif; + font-size: 8.5pt; + border-top-left-radius: 50px; + border-bottom-left-radius: 50px; + border-top-right-radius: 50px; + border-bottom-right-radius: 50px; + border-color: transparent; } /*.vertical_fields td input, .vertical_fields td select { @@ -2822,6 +3047,7 @@ div.nodata_container { position: absolute; top: 0; right: 20px; + background: #f9faf9; } #rmf_data { @@ -3079,7 +3305,8 @@ table#policy_modules td * { color: #fff; margin: 2px; padding: 10px 30px; - font-size: 15px; + font-size: 16px; + font-family: "lato-bolder", "Open Sans", sans-serif; font-weight: bold; border-radius: 2px; } @@ -3132,12 +3359,14 @@ div.div_groups_status { } #title_menu { - color: #fff; + color: #b9b9b9; float: right; - width: 70%; + width: 72%; letter-spacing: 0pt; - font-size: 8pt; + font-size: 10pt; white-space: pre-wrap; + padding-top: 0 !important; + font-family: "Open Sans", sans-serif; } .no_hidden_menu { @@ -3146,27 +3375,36 @@ div.div_groups_status { #menu_tab li.nomn, #menu_tab li.nomn_high { - background-color: #ececec; - padding-right: 3px; - padding-left: 3px; + padding-right: 8px; + padding-left: 8px; font-weight: bold; text-decoration: none; font-size: 14px; - border-color: #e2e2e2; - border-style: solid; - border-width: 1px; - margin-top: -10px; + margin-top: 0; + min-width: 30px; + min-height: 50px; + max-height: 53px; +} + +#menu_tab_frame_view_bc #menu_tab li.nomn, +#menu_tab_frame_view_bc #menu_tab li.nomn_high { + min-height: 53px; +} + +#menu_tab li:hover { + box-shadow: inset 0px 4px #82b92e; } #menu_tab li.nomn_high, #menu_tab li.nomn_high span { color: #fff; + box-shadow: inset 0px 4px #82b92e; background-color: #fff; } #menu_tab li.nomn img, #menu_tab li img { - margin-top: 3px; + margin-top: 10px; margin-left: 3px; } @@ -3184,8 +3422,7 @@ div.div_groups_status { } .databox.filters, -.databox.data, -.databox.profile_list { +.databox.data { margin-bottom: 20px; } @@ -3193,14 +3430,6 @@ div.div_groups_status { padding: 10px; padding-left: 20px; } -.databox.profile_list > tbody > tr > td { - padding: 4px 1px; - padding-left: 5px; - border-bottom: 1px solid #e2e2e2; -} -.databox.profile_list > tbody > tr > a.tip > img { - margin: 0px; -} .databox.filters > tbody > tr > td > img, .databox.filters > tbody > tr > td > div > a > img, @@ -3490,6 +3719,80 @@ div.simple_value > a > span.text p { cursor: pointer; } +.table_modal_alternate { + border-spacing: 0px; + text-align: left; +} + +/* Modal window - Show More */ +table.table_modal_alternate tr:nth-child(odd) td { + background-color: #ffffff; +} + +table.table_modal_alternate tr:nth-child(even) td { + background-color: #f9f9f9; + border-top: 1px solid #e0e0e0; + border-bottom: 1px solid #e0e0e0; +} + +table.table_modal_alternate tr td { + height: 33px; + max-height: 33px; + min-height: 33px; +} + +table.table_modal_alternate tr td:first-child { + width: 35%; + font-weight: bold; + padding-left: 20px; +} + +ul.events_tabs { + background: #ffffff !important; + border: 0px; + display: flex; + justify-content: space-between; + padding: 0px !important; +} + +ul.events_tabs:before, +ul.events_tabs:after { + content: none !important; +} + +ul.events_tabs > li { + margin: 0 !important; + width: 100%; + text-align: center; + float: none !important; + outline-width: 0; +} + +ul.events_tabs > li.ui-state-default { + background: #fff !important; + border: none !important; + border-bottom: 2px solid #cacaca !important; +} + +ul.events_tabs > li a { + text-align: center; + float: none !important; + padding: 8px !important; + display: block; +} + +ul.events_tabs > li span { + position: relative; + top: -6px; + left: 5px; + margin-right: 10px; +} + +ul.events_tabs > li.ui-tabs-active { + border-bottom: 2px solid #82b92e !important; + border-top: 2px solid #82b92e !important; +} + /* * --------------------------------------------------------------------- * - modal window and edit user - @@ -3520,7 +3823,7 @@ div.simple_value > a > span.text p { .modalheadertext { color: white; position: relative; - font-family: Nunito; + font-family: "Nunito", sans-serif; font-size: 13pt; top: 8px; } @@ -3533,7 +3836,7 @@ div.simple_value > a > span.text p { background-color: #82b92e; color: white; position: relative; - font-family: Nunito; + font-family: "Nunito", sans-serif; font-size: 11pt; } .modalclosex { @@ -3600,7 +3903,7 @@ div.simple_value > a > span.text p { -o-transition-property: background-color, color; -o-transition-duration: 1s; color: #82b92e; - font-family: Nunito; + font-family: "Nunito", sans-serif; font-size: 10pt; position: relative; top: 6px; @@ -3659,7 +3962,7 @@ div.simple_value > a > span.text p { -o-transition-property: background-color, color; -o-transition-duration: 1s; color: #fa5858; - font-family: Nunito; + font-family: "Nunito", sans-serif; font-size: 10pt; position: relative; top: 6px; @@ -3717,7 +4020,7 @@ div.simple_value > a > span.text p { -o-transition-property: background-color, color; -o-transition-duration: 1s; color: #82b92e; - font-family: Nunito; + font-family: "Nunito", sans-serif; font-size: 10pt; position: relative; top: 6px; @@ -3782,7 +4085,19 @@ div.simple_value > a > span.text p { font-size: 18pt; } +span.log_zone_line { + font-size: 12px; +} + +span.log_zone_line_error { + color: #fc4444; +} + /* global */ +.bolder { + font-weight: bolder; +} + .readonly { background-color: #dedede !important; } @@ -3818,7 +4133,7 @@ div.simple_value > a > span.text p { background-color: #eee; } .checkselected { - background-color: #eee; + background-color: #eee !important; } .tag-wrapper { padding: 0 10px 0 0; @@ -4153,9 +4468,6 @@ form ul.form_flex li ul li { } /* snmp */ -#snmp_data { - background: #f9faf9; -} #snmp_data .databox { border: 0px; } @@ -4185,6 +4497,18 @@ form ul.form_flex li ul li { text-align: center; } +.div-v-centered { + display: flex; + align-items: center; +} + +.div-v-centered > form > input[type="image"] { + margin: 0; + padding: 0; + width: 14px; + padding-left: 5px; +} + .pandora_upper { text-transform: uppercase; } @@ -4255,6 +4579,13 @@ tr:first-child > td > a.up_arrow { margin-right: 5px; } +.button-as-link { + text-decoration: underline; + background: none !important; + border: none; + padding: 0 !important; +} + /* * --------------------------------------------------------------------- * - MESSAGE LIST POPUP - @@ -4268,293 +4599,172 @@ div#dialog_messages table th:last-child { text-align: right; } -/* --- JQUERY-UI --- */ -.ui-button-text-only .ui-button-text { - font-family: "nunito", sans-serif; - font-size: 9pt; - color: #82b92e; -} -.ui-datepicker .ui-datepicker-title *, -.ui-datepicker th * { - color: white; -} -.ui-datepicker .ui-datepicker-title select, -.ui-datepicker .ui-datepicker-title option { - color: #111 !important; -} -.ui-dialog .ui-dialog-titlebar { - display: inherit; - text-align: center; - padding: 0.4em 1em; - height: 30px; - position: relative; - background-color: #82b92e !important; -} -.ui-dialog .ui-dialog-title { - font-family: "Nunito", sans-serif; - margin: 0.1em 0 !important; - white-space: nowrap !important; - width: 100% !important; - overflow: hidden !important; - text-overflow: ellipsis !important; - font-size: 11pt; - position: relative; - top: 5px; - float: none !important; -} -.ui-dialog .ui-dialog-titlebar-close { - position: absolute !important; - right: 1em !important; - width: 21px !important; - margin: 0px 0 0 0 !important; - padding: 1px !important; - height: 20px !important; - bottom: 30% !important; - top: 20% !important; -} -.ui-dialog .ui-dialog-content { - position: relative !important; - border: 0; - padding: 0.5em 1em !important; - background: none !important; - overflow: auto !important; - margin-bottom: 1em; -} -.ui-dialog .ui-dialog-buttonpane { - text-align: left; - border-width: 1px 0 0 0; - background-image: none; - margin-top: 0.5em; - padding: 0.3em 1em 0.5em 0.4em; -} -.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { - float: right; -} -.ui-dialog .ui-dialog-buttonpane button { - margin: 0.5em 1em 0.5em 0 !important; - cursor: pointer !important; - background: white !important; - background-color: white !important; - border: 1px solid #82b92e !important; - min-height: 35px !important; - width: 90px !important; -} -.ui-widget-content { - background: #ffffff url(include/styles/images/ui-bg_flat_75_ffffff_40x100.png) - 50% 50% repeat-x; -} -.ui-state-default, -.ui-widget-content .ui-state-default, -.ui-widget-header .ui-state-default { - margin-top: 3px; - border: 1px solid #d3d3d3 !important; - border-bottom: 0 !important; - background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% - repeat-x !important; - font-weight: normal !important; - color: #555555 !important; -} -.ui-corner-all, -.ui-corner-top, -.ui-corner-left, -.ui-corner-tl { - border-top-left-radius: 0 !important; -} -.ui-corner-all, -.ui-corner-top, -.ui-corner-right, -.ui-corner-tr { - border-top-right-radius: 0 !important; -} -.ui-corner-all, -.ui-corner-bottom, -.ui-corner-left, -.ui-corner-bl { - border-bottom-left-radius: 0 !important; -} -.ui-corner-all, -.ui-corner-bottom, -.ui-corner-right, -.ui-corner-br { - border-bottom-right-radius: 0 !important; -} -#ui-datepicker-div { - border-color: #b1b1b1; - background: #ffffff; -} -.ui-widget-header { - background: #b1b1b1 !important; - color: #ffffff !important; -} -.ui-datepicker-calendar th { - background-color: #3f3f3f; -} -.ui-dialog .ui-widget-header { - background-color: #82b92e; -} -.ui_tpicker_hour, -.ui_tpicker_minute, -.ui_tpicker_second, -.ui-slider-handle { - border: 1px solid #aaaaaa !important; -} -.ui-timepicker-div dd { - margin: 0px 15px 0px 15px; -} -.ui-timepicker-div .ui-datepicker-title { - color: white; -} -.ui-datepicker-buttonpane button { - border-color: #b1b1b1 !important; -} -.ui-datepicker-buttonpane .ui-datepicker-current { - margin-left: 0.2em !important; -} -.ui-dialog .ui-widget-content { - border: 0px !important; -} -.ui-dialog { - box-shadow: 5px 5px 19px #4e4e4e; - border: 0px !important; - padding: 0 !important; -} -.ui-dialog-titlebar { - border: 0px !important; -} -.ui-dialog-titlebar .ui-icon-closethick, -.ui-dialog-titlebar .ui-state-default, -.ui-dialog-titlebar .ui-state-hover, -.ui-dialog-titlebar button { - background: transparent; - border: 0px; -} +/* + * --------------------------------------------------------------------- + * - Notifications + * --------------------------------------------------------------------- + */ -.ui-dialog-title { - color: #ffffff; - font-size: 9pt; -} -.ui-widget input, -.ui-widget select, -.ui-widget textarea, -.ui-widget button { - font-family: Verdana, Arial, sans-serif !important; -} - -a.ui-button:active, -.ui-button:active, -.ui-button.ui-state-active:hover, -.ui-state-focus .ui-widget-content, -.ui-state-focus .ui-widget-header, -.ui-state-focus .ui-button:hover, -.ui-button:focus { - background: transparent !important; - border: none !important; -} - -.ui-state-hover, -.ui-widget-content .ui-state-hover, -.ui-widget-header .ui-state-hover { - border: 1px solid #999999 !important; - border-bottom: 0 !important; - background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% - repeat-x !important; -} - -.ui-state-active, -.ui-widget-content .ui-state-active, -.ui-widget-header .ui-state-active { - border: 1px solid #aaaaaa !important; - border-bottom: 0 !important; - background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% - repeat-x !important; - font-weight: normal !important; - color: #212121 !important; -} -.ui-state-active a, -.ui-state-active a:link, -.ui-state-active a:visited { - color: #212121 !important; -} - -ul.ui-front { - z-index: 1000000 !important; - padding-right: 0px !important; -} - -ul.ui-front li { - padding: 3px !important; -} - -ul.ui-front li:hover { - background-color: #e1e3e1 !important; -} - -ul.ui-front li a.ui-menu-item-wrapper { - background: transparent !important; - border: none !important; -} - -ul.ui-front li a.ui-menu-item-wrapper span { - padding-left: 5px !important; -} - -ul.ui-front li a.ui-menu-item-wrapper:hover { - text-decoration: none !important; -} -/* --- END - JQUERY-UI --- */ - -.toogle_switch { - position: relative; - display: inline-block; - width: 47px; - height: 24px; -} - -.toogle_switch input { - opacity: 0; - width: 0; - height: 0; -} - -.slider { - position: absolute; - cursor: pointer; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: #ccc; - -webkit-transition: 0.7s; - transition: 0.7s; - border-radius: 34px; -} - -.slider:before { - position: absolute; - content: ""; - height: 16px; - width: 16px; - left: 4px; - bottom: 4px; - background-color: white; - -webkit-transition: 0.7s; - transition: 0.7s; +.notification-ball { border-radius: 50%; + width: 24px; + height: 24px; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + color: #fff; + font-weight: bold; } -input:checked + .slider { +.notification-ball.notification-ball-new-messages:hover { + box-shadow: 0 0 3px #888; +} + +.notification-ball-no-messages { background-color: #82b92e; + cursor: pointer; +} +.notification-ball-new-messages { + background-color: #fc4444; } -input:focus + .slider { - box-shadow: 0 0 1px #82b92e; +#notification-wrapper { + background: white; + border: #a5a5a5 solid 1px; + z-index: 900000; + position: absolute; + width: 550px; + margin-top: -5px; + border-radius: 5px; +} +#notification-wrapper::before { + content: ""; + display: block; + position: absolute; + width: 0px; + height: 0; + border-color: transparent; + border-width: 12px; + border-style: solid; + bottom: 100%; + left: calc(58% - 7px); + margin-left: -12px; + border-bottom-color: white; +} +#notification-wrapper-inner { + max-height: 400px; + overflow: auto; +} +#notification-wrapper-shadow { + height: 100%; + width: 100%; + background: #111; + position: fixed; + z-index: 9009; + top: 0; + opacity: 0.3; +} +.notification-item { + background: whitesmoke; + height: 100px; + margin: 7px; + border: #e4e4e4 solid 1px; + display: flex; + flex-flow: row nowrap; + align-items: center; + padding: 5px; +} +.notification-item:hover { + border: #ccc solid 1px; + text-decoration: none; +} +.notification-item > * { + padding-left: 15px; + pointer-events: none; +} +.notification-item > img { + width: 75px; } -input:checked + .slider:before { - -webkit-transform: translateX(26px); - -ms-transform: translateX(26px); - transform: translateX(26px); - background-color: rgb(197, 235, 192); +.notification-info { + width: 87%; + display: flex; + flex-flow: column nowrap; + overflow: hidden; + max-height: 83px; + line-height: 1.4em; +} +.notification-item img { + max-width: 100%; + max-height: 100%; +} +.notification-title { + margin: 0; +} +.notification-subtitle { + margin: 0; + color: #373737; +} + +.global-config-notification-title { + display: flex; + flex-direction: row; + align-items: center; +} + +.global-config-notification-title h2 { + margin-left: 10px; +} + +.global-config-notification-checkboxes :first-child { + font-weight: bold; +} + +.global-config-notification-selectors { + display: flex; + flex-direction: row; + margin-bottom: 10px; +} + +.global-config-notification-selectors h4 { + margin: 0; +} + +.global-config-notification-single-selector, +.global_config_notifications_dialog_add select { + display: flex; + width: 100%; + padding: 0 10px; +} + +.global-config-notification-single-selector :first-child, +.global-config-notification-single-selector :first-child select { + width: 99%; +} + +.global-config-notification-single-selector :last-child, +.global_config_notifications_dialog_add_wrapper { + flex-direction: column; + display: flex; + justify-content: flex-end; +} + +.global_config_notifications_dialog_add { + display: flex; + flex-direction: row; + margin: 8px; +} + +.global_config_notifications_two_ways_form_arrows { + display: flex; + flex-flow: column; + justify-content: center; + margin: 0 5px; +} + +.global_config_notifications_two_ways_form_arrows img { + margin: 15px 0; } /* jQuery dialog */ @@ -4562,3 +4772,1327 @@ input:checked + .slider:before { display: none; } /* jQuery dialog */ + +/* --- SWITCH --- */ +.p-switch { + position: relative; + display: inline-block; + width: 30px; + height: 17px; +} + +.p-switch input { + opacity: 0; + width: 0; + height: 0; +} + +.p-slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + -webkit-transition: 0.4s; + transition: 0.4s; + border-radius: 34px; +} + +.p-slider:before { + position: absolute; + content: ""; + height: 13px; + width: 13px; + left: 2px; + bottom: 2px; + background-color: white; + -webkit-transition: 0.4s; + transition: 0.4s; + border-radius: 50%; +} + +input:checked + .p-slider { + background-color: #82b92e; +} + +input:focus + .p-slider { + box-shadow: 0 0 1px #82b92e; +} + +input:checked + .p-slider:before { + -webkit-transform: translateX(13px); + -ms-transform: translateX(13px); + transform: translateX(13px); +} + +/* --- END SWITCH --- */ + +/* --- TOAST --- */ +#notifications-toasts-wrapper { + position: fixed; + right: 20px; + top: 70px; + width: 270px; + height: 100%; + z-index: 6; + pointer-events: none; +} + +.snackbar { + max-width: 270px; + background-color: #333; + color: #fff; + text-align: center; + /* border-radius: 2px; */ + padding: 16px; + margin: 10px; + border-radius: 4px; + visibility: hidden; + pointer-events: all; +} + +.snackbar.show { + visibility: visible; + -webkit-animation: fadein 0.5s, fadeout 0.5s 7.5s; + animation: fadein 0.5s, fadeout 0.5s 7.5s; +} + +.snackbar p, +.snackbar h3 { + text-align: left; + margin: 0; + pointer-events: none; +} +.snackbar h3 { + color: white; + margin-bottom: 10px; +} + +@-webkit-keyframes fadein { + from { + bottom: 0; + opacity: 0; + } + to { + bottom: 30px; + opacity: 1; + } +} + +@keyframes fadein { + from { + bottom: 0; + opacity: 0; + } + to { + bottom: 30px; + opacity: 1; + } +} + +@-webkit-keyframes fadeout { + from { + bottom: 30px; + opacity: 1; + } + to { + bottom: 0; + opacity: 0; + } +} + +@keyframes fadeout { + from { + bottom: 30px; + opacity: 1; + } + to { + bottom: 0; + opacity: 0; + } +} + +/* --- END TOAST --- */ + +/* Button for Go to top */ +#top_btn { + display: none; + position: fixed; + bottom: 100px; + right: 4px; + border: none; + outline: none; + background: url("../../images/to_top_menu.png") no-repeat center; + background-color: #82b92e; + width: 27px; + height: 27px; + cursor: pointer; + border-radius: 5px; +} + +#top_btn:hover { + background: url("../../images/to_top_menu_hover.png") no-repeat center; + background-color: #fff; + border: 2px solid #82b92e; +} + +/* New white rounded boxes */ +.white_box { + background-color: #fff; + border: 1px solid #e1e1e1; + border-radius: 5px; + padding: 20px 50px; +} + +/* + * --------------------------------------------------------------------- + * - User edit + * --------------------------------------------------------------------- + */ + +#user_form * { + color: #4d4d4d; +} + +#user_form { + width: 100%; +} + +#user_form a.tip img { + margin-left: 8px; +} + +#edit_user_profiles { + margin-top: 40px; + margin-bottom: 30px; +} + +#edit_user_profiles table { + margin-bottom: 0 !important; +} + +.user_edit_first_row { + display: flex; +} + +.user_edit_second_row { + display: flex; + flex-flow: row wrap; + flex-direction: row; + justify-content: space-between; +} + +.user_edit_first_row, +.user_edit_second_row, +.user_edit_third_row { + margin-bottom: 20px; +} + +.edit_user_info { + width: 58%; + margin-right: 20px; + display: flex; + align-items: center; +} + +.edit_user_info_left { + width: 25%; + margin-right: 50px; + text-align: center; +} + +.edit_user_info_right { + width: 75%; +} + +.edit_user_info_right input { + background-color: transparent !important; + border: none; + border-radius: 0 !important; + border-bottom: 1px solid #343434; + padding: 10px 0px 2px 35px; + box-sizing: border-box; + background-repeat: no-repeat; + background-position: left bottom 2px; + width: 100%; + margin-bottom: 4px; +} + +.edit_user_info_right input:focus { + font-weight: bold; +} + +.edit_user_info_right #fullname { + background-image: url("../../images/user_name.png"); +} + +.edit_user_info_right #email { + background-image: url("../../images/user_email.png"); +} + +.edit_user_info_right #phone { + background-image: url("../../images/user_phone.png"); +} + +.edit_user_info_right #password_new, +.edit_user_info_right #password_conf { + background-image: url("../../images/user_password.png"); +} + +.edit_user_autorefresh { + width: 42%; +} + +.edit_user_options { + width: 50%; + padding-right: 50px; +} + +.edit_user_options #text-block_size { + background-color: transparent !important; + border: none; + border-radius: 0 !important; + border-bottom: 1px solid #343434; + padding: 0px 0px 0px 10px; +} + +.edit_user_options input#text-block_size:disabled { + border-bottom-color: #848484; + color: #848484; +} + +.edit_user_timezone { + width: 40%; +} + +.edit_user_timezone #zonepicker { + width: 100%; +} + +.edit_user_comments #textarea_comments { + background-color: #fbfbfb !important; + padding-left: 10px; +} + +.edit_user_labels { + color: #343434 !important; + font-weight: bold; + padding-right: 10px; + margin: 0px 0px 5px 0px; +} + +.label_select, +.label_select_simple { + margin-bottom: 15px; +} + +.label_select_simple .edit_user_labels { + margin-bottom: 0; + display: inline; +} + +.edit_user_options .label_select_simple { + display: flex; + align-items: center; +} + +.edit_user_options .label_select_simple .p-switch { + margin-right: 5px; + margin-left: 10px; +} + +.user_edit_first_row .edit_user_autorefresh > div:last-child, +.user_edit_first_row .edit_user_info_left > div:last-child, +.user_edit_first_row .edit_user_info_right > div:last-child, +.user_edit_second_row .edit_user_options > div:last-child { + margin-bottom: 0px !important; +} + +.user_avatar { + width: 100%; + margin-bottom: 20px; +} + +.autorefresh_select { + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 15px; +} + +.autorefresh_select_text { + margin: 0px 0px 5px 0px; +} + +#right_autorefreshlist { + margin-bottom: 10px; +} + +#autorefresh_list_out, +#autorefresh_list { + text-align: left; +} + +.autorefresh_select .autorefresh_select_list_out, +.autorefresh_select .autorefresh_select_list { + width: 45%; +} + +.autorefresh_select .autorefresh_select_arrows { + width: 10%; + text-align: center; +} + +.autorefresh_select_arrows a { + display: block; +} + +.edit_user_autorefresh select, +.user_edit_second_row select { + width: 100%; +} + +.edit_user_button { + margin-top: 20px; + width: 100%; + text-align: right; +} + +#user-notifications-wrapper { + width: 100%; + box-sizing: border-box; + color: #4d4d4d; +} + +/* This is to use divs like tables */ +.table_div { + display: table; +} +.table_thead, +.table_tbody { + display: table-row; +} +.table_th { + font-weight: bold; +} +.table_th, +.table_td { + display: table-cell; + vertical-align: middle; + padding: 10px; +} +/* Tables with 3 columns */ +.table_three_columns .table_th, +.table_three_columns .table_td { + width: 33%; +} + +/* + * --------------------------------------------------------------------- + * - TABLES TO SHOW INFORMATION + * --------------------------------------------------------------------- + */ + +table.info_table { + background-color: #fff; + margin-bottom: 10px; + border-spacing: 0; + border-collapse: collapse; + overflow: hidden; + border-radius: 5px; +} + +table.info_table > tbody > tr:nth-child(even) { + background-color: #f5f5f5; +} + +table.info_table tr:first-child > th { + background-color: #fff; + color: #000; + text-align: left; + vertical-align: middle; +} + +table.info_table th { + font-size: 7.5pt; + letter-spacing: 0.3pt; + color: #000; + background-color: #fff; +} + +table.info_table tr th { + border-bottom: 1px solid #e2e2e2; +} + +/* Radius top */ +table.info_table > thead > tr:first-child > th:first-child { + border-top-left-radius: 4px; +} +table.info_table > thead > tr:first-child > th:last-child { + border-top-right-radius: 4px; +} + +/* Radius bottom */ +table.info_table > tbody > tr:last-child > td:first-child { + border-top-left-radius: 4px; +} +table.info_table > tbody > tr:last-child > td:last-child { + border-top-right-radius: 4px; +} + +table.info_table > thead > tr > th, +table.info_table > tbody > tr > th, +table.info_table > thead > tr > th a { + padding-left: 9px; + padding-right: 9px; + padding-top: 9px; + padding-bottom: 9px; + font-weight: normal; + color: #000; + font-size: 8.6pt; +} + +table.info_table > tbody > tr { + border-bottom: 1px solid #e2e2e2; +} + +table.info_table > tbody > tr > td { + -moz-border-radius: 0px; + -webkit-border-radius: 0px; + border-radius: 0px; + border: none; + padding-left: 9px; + padding-right: 9px; + padding-top: 7px; + padding-bottom: 7px; +} + +table.info_table > tbody > tr > td > img, +table.info_table > thead > tr > th > img, +table.info_table > tbody > tr > td > div > a > img, +table.info_table > tbody > tr > td > span > img, +table.info_table > tbody > tr > td > span > a > img, +table.info_table > tbody > tr > td > a > img, +table.info_table > tbody > tr > td > form > a > img { + vertical-align: middle; +} + +table.info_table > tbody > tr:hover { + background-color: #eee !important; +} + +.info_table.profile_list > thead > tr > th > a.tip { + padding: 0px; +} + +/* This class is for the icons of actions and operations in the tables. */ +.action_buttons a[href] img, +.action_buttons input[type="image"], +.action_button_img { + border-radius: 4px; + border: 1px solid #dcdcdc !important; + padding: 1px; + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1); + max-width: 21px; + background-color: transparent !important; /*BORRAR*/ +} + +/* This class is for only one icon to be a button type. */ +.action_button_img { + cursor: pointer; +} + +.action_buttons a, +.action_buttons input[type="image"] { + margin-right: 5px; +} + +.action_buttons a:last-child, +.action_buttons input[type="image"]:last-child { + margin-right: 0px; +} + +.action_buttons a:hover { + background-color: #fff; + display: inline-block; + border-radius: 4px; +} + +.action_buttons input[type="image"]:hover { + background-color: #fff !important; +} + +/* Tables to upload files */ +#table_filemanager tr:first-child th span { + font-weight: bold; +} + +.file_table_buttons { + text-align: right; + margin-bottom: 10px; +} + +.file_table_buttons a img { + border: 1px solid #e2e2e2; + padding: 5px; + border-radius: 4px; + margin-right: 10px; + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1); +} + +#file_table_modal { + display: flex; + justify-content: space-between; + margin-bottom: 40px; +} + +#file_table_modal .create_folder, +#file_table_modal .create_text_file, +#file_table_modal .upload_file { + width: 33%; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + margin-right: 2px; + background-color: #e6e6e6; +} + +.file_table_buttons a:last-child img, +#file_table_modal .upload_file { + margin-right: 0px !important; +} + +#file_table_modal li a { + display: block; + padding: 5px; +} + +#file_table_modal li img, +#file_table_modal li span { + vertical-align: middle; +} + +#file_table_modal li img { + margin-right: 10px; +} + +#create_folder, +#create_text_file, +#upload_file { + margin-bottom: 30px; +} + +#create_folder input#text-dirname, +#create_text_file input#text-name_file { + width: 100%; + margin-right: 5px; + box-sizing: border-box; + margin-bottom: 10px; +} + +#upload_file input#file-file { + width: 70%; +} + +#create_folder input#submit-crt, +#create_text_file input#submit-create, +#upload_file input#submit-go { + float: right; +} + +#upload_file input#submit-go { + margin-top: 10px; +} + +.file_table_modal_active { + background-color: #fff !important; + border: 1px solid #e6e6e6; + border-bottom: none; +} + +/* Inventory table */ +.inventory_table_buttons { + text-align: right; + margin-bottom: 10px; +} + +.inventory_table_buttons a { + font-weight: bolder; + display: inline-block; + border: 1px solid #e2e2e2; + padding: 8px; + border-radius: 4px; + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1); +} + +.inventory_table_buttons a img, +.inventory_table_buttons a span { + vertical-align: middle; +} + +.inventory_table_buttons a img { + padding-left: 10px; +} + +.inventory_tables thead th span:first-child { + float: left; + font-weight: bold; +} + +.inventory_tables thead th span { + font-size: 8.6pt; +} + +.inventory_tables tbody > tr:first-child { + font-weight: bold; +} + +/* Tag view */ +table.info_table.agent_info_table { + margin-bottom: 20px; +} +table.agent_info_table tr { + background-color: #fff !important; +} + +table.agent_info_table > tbody > tr > td { + border-bottom: none; +} + +table.agent_info_table > tbody > tr:last-child > td { + border-bottom: 1px solid #e2e2e2; +} + +table.agent_info_table thead > tr:first-child th { + background-color: #f5f5f5; +} + +table.agent_info_table thead > tr:first-child th span, +table.agent_info_table thead > tr:first-child th { + font-weight: bold; + font-size: 8.6pt; +} + +table.info_table.agent_info_table td { + padding-left: 20px; + padding-right: 20px; +} + +table.info_table.agent_info_table table#agent_table { + padding-top: 15px; +} + +table.info_table.agent_info_table table#module_table { + padding-top: 10px; + padding-bottom: 15px; +} + +table.info_table.agent_info_table table.info_table { + margin-bottom: 0; +} + +.agent_info_table_opened { + background-color: #82b92e !important; + color: #fff !important; + border-color: #82b92e !important; +} + +.agent_info_table_closed { + background-color: #fff !important; + color: #000 !important; + border-radius: 4px; +} + +/* Tag view */ +table.info_table.policy_table tr { + background-color: #fff !important; +} + +table.info_table.policy_sub_table thead > tr:first-child th { + background-color: #f5f5f5; +} + +table.info_table.policy_sub_table { + padding: 20px 15px; + margin-bottom: 0; +} + +/* Arrows to sort the tables. */ +.sort_arrow { + display: inline-grid; + vertical-align: middle; +} +.sort_arrow a { + padding: 0 0 0 5px !important; +} +.sort_arrow img { + width: 0.8em; +} + +/* + * --------------------------------------------------------------------- + * - PAGINATION + * --------------------------------------------------------------------- + */ +.pagination { + display: flex; + justify-content: space-between; + align-items: flex-end; + margin-bottom: 10px; + margin-top: 15px; +} + +.pagination .page_number { + border: 1px solid #cacaca; + border-right: 0px; + text-align: center; +} + +.pagination .page_number a { + padding: 5px; + min-width: 12px; + display: block; +} + +.pagination .page_number:hover, +.pagination .pagination-arrows:hover { + background-color: #e2e2e2; +} + +.pagination .total_number > *:first-child { + border-top-left-radius: 2px; + border-bottom-left-radius: 2px; +} + +.pagination .total_number > *:last-child { + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-right: 1px solid #cacaca !important; +} + +.pagination .page_number_active { + font-weight: bold; + background-color: #82b92e; + color: #fff; + border-color: #82b92e; +} + +.pagination .page_number_active a { + color: #fff; +} + +.pagination .total_number { + display: flex; + justify-content: flex-end; +} + +.pagination a { + margin: 0 !important; +} + +.pagination .pagination-arrows { + border: 1px solid #cacaca; + border-right: 0px; +} + +.pagination-bottom { + margin-bottom: 15px; + margin-top: 0px; + align-items: flex-start; +} + +/* + * --------------------------------------------------------------------- + * - Layout for the new forms + * --------------------------------------------------------------------- + */ +.first_row { + margin-bottom: 20px; + display: flex; +} + +.label_simple_one_item { + display: flex; + align-items: flex-end; +} + +.label_simple_items { + display: flex; + align-items: center; + flex-wrap: wrap; +} + +.label_simple_items > * { + margin-right: 5px; +} + +.input_label { + color: #343434 !important; + font-weight: bold; + padding-right: 10px; + margin: 0px 0px 5px 0px; +} + +.input_label_simple { + margin-bottom: 0; + margin-top: 0; + display: inline; +} + +.label_select_parent { + display: flex; + justify-content: space-between; + align-items: center; +} + +.label_select_child_left { + width: 80%; + min-width: 100px; +} + +.label_select_child_right { + width: 20%; + min-width: 140px; + align-items: center; + display: flex; +} + +.label_select_child_icons { + text-align: right; + width: 5%; + min-width: 30px; +} + +/* Inputs type text shown as a black line */ +.agent_options input[type="text"] { + background-color: transparent !important; + border: none; + border-radius: 0 !important; + border-bottom: 1px solid #ccc; + font-family: "lato-bolder", "Open Sans", sans-serif !important; + font-size: 10pt; + padding: 2px 5px; + box-sizing: border-box; + background-repeat: no-repeat; + background-position: left bottom 2px; + margin-bottom: 4px; +} + +/* + * --------------------------------------------------------------------- + * - CLASSES FOR THE NEW TOGGLES - + * --------------------------------------------------------------------- + */ +.ui_toggle { + margin-bottom: 20px; +} + +.ui_toggle > a:first-child { + background-color: #fff; + border: 1px solid #e1e1e1; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + margin-bottom: -1px; + padding: 5px; + display: block; +} + +.white_box_opened { + border-top-left-radius: 0px; + border-top-right-radius: 0px; +} + +/* + * --------------------------------------------------------------------- + * - SWITCH RADIO BUTTONS - + * --------------------------------------------------------------------- + */ +.switch_radio_button { + display: flex; + overflow: hidden; +} + +.switch_radio_button input { + position: absolute !important; + clip: rect(0, 0, 0, 0); + height: 1px; + width: 1px; + border: 0; + overflow: hidden; +} + +.switch_radio_button label { + background-color: #fff; + color: rgba(0, 0, 0, 0.6); + line-height: 1; + text-align: center; + padding: 7px 14px; + margin-right: -1px; + border: 1px solid #cbcbcb; + border-radius: 4px; + transition: all 0.1s ease-in-out; +} + +.switch_radio_button label:hover { + cursor: pointer; +} + +.switch_radio_button input:checked + label { + background-color: #82b92e; + box-shadow: none; + color: #fff; +} + +.switch_radio_button label:last-child { + margin-right: 0px; +} + +/* + * --------------------------------------------------------------------- + * - MODULE GRAPHS + * --------------------------------------------------------------------- + */ +.module_graph_menu_dropdown { + padding-top: 20px; + padding-bottom: 20px; + position: absolute; + top: 10px; + width: 100%; + z-index: 1001; +} + +.module_graph_menu_content, +.module_graph_menu_header { + width: 95%; + border: 1px solid #e2e2e2; + margin: 0 auto; + box-sizing: border-box; + background-color: #fff; +} + +.module_graph_menu_header { + border-top-left-radius: 4px; + border-top-right-radius: 4px; + padding: 6px 10px; + cursor: pointer; + display: flex; + justify-content: space-between; + align-items: center; +} + +.module_graph_menu_header span > img { + vertical-align: middle; + padding-left: 5px; +} + +.module_graph_menu_content { + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + padding: 15px; + border-top: none; +} + +/* + * --------------------------------------------------------------------- + * - AGENT VIEW + * --------------------------------------------------------------------- + */ + +.bullet_modules { + width: 15px; + height: 15px; + border-radius: 50%; + margin-right: 5px; + margin-top: -2px; +} + +div#bullets_modules { + display: flex; + margin-left: 2em; +} + +div#bullets_modules div { + display: flex; + align-items: center; + margin: 0 5px; +} + +.orange_background { + background: #ffa631; +} +.red_background { + background: #fc4444; +} +.yellow_background { + background: #fad403; +} +.grey_background { + background: #b2b2b2; +} +.blue_background { + background: #3ba0ff; +} +.green_background { + background: #80ba27; +} + +/* First row in agent view */ +#agent_details_first_row { + display: flex; + margin-bottom: 20px; + width: 100%; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; +} + +.agent_details_col { + display: table-cell; + background-color: #fff; + border: 1px solid #e2e2e2; + border-radius: 5px; + flex: 0 1 auto; +} + +.agent_details_col_left { + width: 40%; + min-width: 300px; +} +.agent_details_col_right { + width: 59%; + min-width: 480px; +} + +.agent_access_rate_events { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; +} + +.white_table_graph#table_access_rate { + flex: 1 1 auto; + min-width: 450px; + margin-right: 1%; +} + +.white_table_graph#table_events { + flex: 1 1 auto; + min-width: 450px; +} + +@media screen and (max-width: 1150px) { + .agent_details_col { + flex: 1 1 auto; + } + .white_table_graph#table_access_rate { + margin-right: 0; + } +} + +.buttons_agent_view { + display: flex; + justify-content: flex-end; +} + +.buttons_agent_view a img { + border: 1px solid #dcdcdc; + border-radius: 4px; + padding: 1px; + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1); + max-width: 21px; + margin-left: 5px; +} + +/* Agent details in agent view */ +div#status_pie path { + stroke-width: 8px !important; +} +div#status_pie { + margin-bottom: 2em; +} + +.agent_details_header { + display: flex; + justify-content: flex-end; + align-items: center; + border-bottom: 1px solid #e2e2e2; + padding: 6px 20px; +} + +.agent_details_content { + display: flex; + align-items: center; + padding: 20px; + padding-bottom: 0; +} + +.agent_details_agent_name { + display: flex; + align-items: center; +} + +.agent_details_remote_cfg { + align-self: flex-start; +} + +.agent_details_graph { + text-align: center; + margin: 0 auto; +} + +.agent_details_info { + max-width: 45%; + overflow: hidden; + min-width: 220px; +} +.agent_details_info span { + text-overflow: ellipsis; +} + +.agent_details_info p { + display: flex; + align-items: center; +} + +.agent_details_info img { + padding-right: 5px; +} + +.agent_details_bullets #bullets_modules { + display: flex; + justify-content: flex-start; +} + +.agent_details_bullets #bullets_modules > div { + display: flex; + align-items: center; + padding-bottom: 20px; +} + +#agent_contact_main tr td img { + max-width: 100%; +} + +/* White tables to show graphs */ +.white_table_graph { + margin-bottom: 20px; +} + +.white_table_graph_header { + padding: 10px 20px; + background-color: #fff; + color: #000; + border: 1px solid #e2e2e2; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + font-weight: bold; +} + +.white_table_graph_header div#bullets_modules { + float: right; +} +.white_table_graph_header img, +.white_table_graph_header span { + vertical-align: middle; +} + +.white_table_graph_header span { + padding-left: 10px; +} + +.white-box-content { + width: 100%; + height: 100%; + background-color: #fff; + display: flex; + align-items: center; + flex-wrap: wrap; +} + +.white_table_graph_content { + border: 1px solid #e2e2e2; + border-top: none; + background-color: #fff; + padding: 20px; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + align-items: center; + flex-wrap: wrap; +} + +.white_table_graph_content.no-padding-imp .info_box { + margin: 0 !important; +} + +.white_table_graph_content.min-height-100 { + min-height: 100px; +} + +.white_table_graph_content.min-height-50 { + min-height: 50px; +} + +.white_table_graph_content.min-height-200 { + min-height: 200px; +} + +.white_table_graph_content div.pagination { + width: 100%; + padding: 0 1em; +} +.white_table_graph_content div.action-buttons { + padding: 10px; +} + +/* White tables */ +.white_table, +.white_table tr:first-child > th { + background-color: #fff; + color: #000; +} + +.white_table { + border: 1px solid #e2e2e2; + border-radius: 4px; + margin-bottom: 20px; + padding-bottom: 10px; +} + +.white_table thead tr:first-child > th { + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #e2e2e2; +} + +.white_table tbody tr:first-child > td { + padding-top: 25px; +} + +.white_table tr td:first-child, +.white_table tr th:first-child { + padding-left: 50px; +} + +.white_table tr td:last-child, +.white_table tr th:last-child { + padding-right: 50px; +} + +.white_table th, +.white_table td { + padding: 10px 20px; +} + +.white_table_droppable > thead > tr > th > img { + vertical-align: middle; +} + +.white_table_droppable tr th:first-child { + padding-left: 20px; +} + +.white_table_no_border { + border: none !important; +} diff --git a/pandora_console/include/styles/pandoraPDF.css b/pandora_console/include/styles/pandoraPDF.css new file mode 100644 index 0000000000..37d527c30b --- /dev/null +++ b/pandora_console/include/styles/pandoraPDF.css @@ -0,0 +1,78 @@ +/** + * Extension to manage a list of gateways and the node address where they should + * point to. + * + * @category Extensions + * @package Pandora FMS + * @subpackage Community + * @version 1.0.0 + * @license See below + * + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ + */ +table.header_table { + width: 100%; +} + +table.header_table thead tr th, +table.header_table tbody tr td { + padding: 10px; +} + +thead.header_tr tr { + background: #e6e6e6; +} + +thead.header_tr tr th { + font-weight: normal; + text-align: right; +} + +thead.header_tr tr th.th_first { + font-weight: bold; + text-align: left; +} + +thead.header_tr tr th.th_description { + background-color: #f5f5f5; + color: #1c1c1c; + text-align: justify; +} + +table.table_beauty { + border-collapse: collapse; + width: 100%; +} + +table.table_beauty tbody tr td { + padding: 5px; + border: 0.1pt solid #acacac; +} + +table.databox { + margin-bottom: 20px; +} + +th.title_table_pdf { + background-color: #acacac; + padding: 15px; +} + +table.table_agent_module tr td { + padding: 5px; +} diff --git a/pandora_console/include/styles/progress.css b/pandora_console/include/styles/progress.css new file mode 100644 index 0000000000..84c3224f27 --- /dev/null +++ b/pandora_console/include/styles/progress.css @@ -0,0 +1,20 @@ +span.progress_text { + position: absolute; + font-family: "lato-bolder", "Open Sans", sans-serif; + font-size: 2em; + margin-left: -0.5em; +} + +div.progress_main { + display: inline-block; + text-align: center; + height: 2.5em; + border: 1px solid #80ba27; +} + +div.progress { + width: 0%; + background: #80ba27; + height: 100%; + float: left; +} diff --git a/pandora_console/include/styles/register.css b/pandora_console/include/styles/register.css new file mode 100644 index 0000000000..d2589a3f01 --- /dev/null +++ b/pandora_console/include/styles/register.css @@ -0,0 +1,57 @@ +input[type="submit"].submit-cancel, +button.submit-cancel { + color: #fb4444 !important; + border: 1px solid #fb4444 !important; + background: #fff !important; + padding: 5px; + font-size: 1.3em; + margin: 0.5em 1em 0.5em 0 !important; + cursor: pointer !important; + text-align: center !important; + height: 30px !important; + width: 90px !important; +} + +input[type="submit"].submit-cancel:hover, +button.submit-cancel:hover { + color: #fff !important; + background: #fb4444 !important; +} + +input[type="submit"].submit-next, +button.submit-next, +input[type="button"].submit-next { + color: #82b92e !important; + border: 1px solid #82b92e !important; + background: #fff !important; + padding: 5px; + font-size: 1.3em; + margin: 0.5em 1em 0.5em 0 !important; + cursor: pointer !important; + text-align: center !important; + height: 30px !important; +} + +input[type="submit"].submit-next:hover, +button.submit-next:hover, +input[type="button"].submit-next:hover { + color: #fff !important; + background: #82b92e !important; +} + +div.submit_buttons_container { + position: absolute; + margin: 10px auto 0px; + bottom: 0px; + width: 90%; + position: relative; + clear: both; + height: 4em; +} + +.license_text { + width: 95%; + overflow-y: auto; + text-align: justify; + margin: 1em auto; +} diff --git a/pandora_console/include/styles/task_list.css b/pandora_console/include/styles/task_list.css new file mode 100644 index 0000000000..d3ffb5d546 --- /dev/null +++ b/pandora_console/include/styles/task_list.css @@ -0,0 +1,42 @@ +/** + * + * Name: Default theme + * + * Extension to manage a list of gateways and the node address where they should + * point to. + * + * @category css + * @package Pandora FMS + * @subpackage Community + * @version 1.0.0 + * @license See below + * + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ + */ + +ul.progress_task_discovery { + width: 80%; + margin: 0 auto; + display: flex; + flex-direction: column; +} + +ul.progress_task_discovery li span { + font-size: 9pt; + margin-left: 20px; +} diff --git a/pandora_console/include/styles/wizard.css b/pandora_console/include/styles/wizard.css new file mode 100644 index 0000000000..029addf5cb --- /dev/null +++ b/pandora_console/include/styles/wizard.css @@ -0,0 +1,28 @@ +/* + * Discovery > Wizard css global style + */ + +ul.wizard { +} + +ul.wizard li { + padding-bottom: 10px; + padding-top: 10px; +} + +ul.wizard li > label:not(.p-switch) { + width: 250px; + vertical-align: top; + display: inline-block; +} + +ul.wizard li > textarea { + width: 600px; + height: 15em; + display: inline-block; + font-family: monospace; +} + +.hidden { + display: none; +} diff --git a/pandora_console/include/visual-console-client/alarm-clock.ttf b/pandora_console/include/visual-console-client/alarm-clock.ttf new file mode 100644 index 0000000000..9e9b593459 Binary files /dev/null and b/pandora_console/include/visual-console-client/alarm-clock.ttf differ diff --git a/pandora_console/include/visual-console-client/vc.main.css b/pandora_console/include/visual-console-client/vc.main.css new file mode 100644 index 0000000000..20f5a1da7c --- /dev/null +++ b/pandora_console/include/visual-console-client/vc.main.css @@ -0,0 +1,95 @@ +#visual-console-container { + margin: 0px auto; + position: relative; + background-repeat: no-repeat; + background-size: 100% 100%; + background-position: center; +} + +.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; +} + +@font-face { + font-family: Alarm Clock; + src: url(alarm-clock.ttf); +} + +/* 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; +} + +.visual-console-item .digital-clock > span { + font-family: "Alarm Clock", "Courier New", Courier, monospace; + font-size: 50px; + + /* To improve legibility */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-rendering: optimizeLegibility; + text-shadow: rgba(0, 0, 0, 0.01) 0 0 1px; +} + +.visual-console-item .digital-clock > span.date { + font-size: 25px; +} + +.visual-console-item .digital-clock > span.timezone { + font-size: 25px; +} + +/* Analog clock */ + +.visual-console-item .analogic-clock { + text-align: center; +} + +.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; +} + + +/*# sourceMappingURL=vc.main.css.map*/ \ No newline at end of file diff --git a/pandora_console/include/visual-console-client/vc.main.css.map b/pandora_console/include/visual-console-client/vc.main.css.map new file mode 100644 index 0000000000..2b723c93b4 --- /dev/null +++ b/pandora_console/include/visual-console-client/vc.main.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///main.css","webpack:///styles.css"],"names":[],"mappings":"AAAA;EACE,gBAAgB;EAChB,kBAAkB;EAClB,4BAA4B;EAC5B,0BAA0B;EAC1B,2BAA2B;AAC7B;;AAEA;EACE,kBAAkB;EAClB,oBAAa;EAAb,oBAAa;EAAb,aAAa;EACb,2BAAuB;EAAvB,8BAAuB;MAAvB,2BAAuB;UAAvB,uBAAuB;EACvB,qBAAqB;EACrB,yBAAmB;MAAnB,sBAAmB;UAAnB,mBAAmB;EACnB,yBAAiB;KAAjB,sBAAiB;MAAjB,qBAAiB;UAAjB,iBAAiB;AACnB;;ACfA;EACE,wBAAwB;EACxB,0BAA2B;AAC7B;;AAEA,kBAAkB;;AAElB;EACE,oBAAa;EAAb,oBAAa;EAAb,aAAa;EACb,4BAAsB;EAAtB,6BAAsB;MAAtB,0BAAsB;UAAtB,sBAAsB;EACtB,wBAAuB;MAAvB,qBAAuB;UAAvB,uBAAuB;EACvB,qBAAqB;EACrB,0BAAqB;MAArB,qBAAqB;EACrB,yBAAmB;MAAnB,sBAAmB;UAAnB,mBAAmB;AACrB;;AAEA;EACE,6DAA6D;EAC7D,eAAe;;EAEf,0BAA0B;EAC1B,mCAAmC;EACnC,kCAAkC;EAClC,kCAAkC;EAClC,wCAAwC;AAC1C;;AAEA;EACE,eAAe;AACjB;;AAEA;EACE,eAAe;AACjB;;AAEA,iBAAiB;;AAEjB;EACE,kBAAkB;AACpB;;AAEA;EACE,qDAA6C;UAA7C,6CAA6C;AAC/C;;AAEA;EACE,sDAA8C;UAA9C,8CAA8C;AAChD;;AAEA;EACE,oDAA4C;UAA5C,4CAA4C;AAC9C","file":"vc.main.css","sourcesContent":["#visual-console-container {\n margin: 0px auto;\n position: relative;\n background-repeat: no-repeat;\n background-size: 100% 100%;\n background-position: center;\n}\n\n.visual-console-item {\n position: absolute;\n display: flex;\n flex-direction: initial;\n justify-items: center;\n align-items: center;\n user-select: text;\n}\n","@font-face {\n font-family: Alarm Clock;\n src: url(./alarm-clock.ttf);\n}\n\n/* Digital clock */\n\n.visual-console-item .digital-clock {\n display: flex;\n flex-direction: column;\n justify-content: center;\n justify-items: center;\n align-content: center;\n align-items: center;\n}\n\n.visual-console-item .digital-clock > span {\n font-family: \"Alarm Clock\", \"Courier New\", Courier, monospace;\n font-size: 50px;\n\n /* To improve legibility */\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-rendering: optimizeLegibility;\n text-shadow: rgba(0, 0, 0, 0.01) 0 0 1px;\n}\n\n.visual-console-item .digital-clock > span.date {\n font-size: 25px;\n}\n\n.visual-console-item .digital-clock > span.timezone {\n font-size: 25px;\n}\n\n/* Analog clock */\n\n.visual-console-item .analogic-clock {\n text-align: center;\n}\n\n.visual-console-item .analogic-clock .hour-hand {\n animation: rotate-hour 43200s infinite linear;\n}\n\n.visual-console-item .analogic-clock .minute-hand {\n animation: rotate-minute 3600s infinite linear;\n}\n\n.visual-console-item .analogic-clock .second-hand {\n animation: rotate-second 60s infinite linear;\n}\n"],"sourceRoot":""} \ No newline at end of file diff --git a/pandora_console/include/visual-console-client/vc.main.min.js b/pandora_console/include/visual-console-client/vc.main.min.js new file mode 100644 index 0000000000..9f2f23a09a --- /dev/null +++ b/pandora_console/include/visual-console-client/vc.main.min.js @@ -0,0 +1,2 @@ +!function(t){var e={};function n(i){if(e[i])return e[i].exports;var r=e[i]={i:i,l:!1,exports:{}};return t[i].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)n.d(i,r,function(e){return t[e]}.bind(null,r));return i},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=9)}([function(t,e,n){"use strict";n.d(e,"i",function(){return r}),n.d(e,"h",function(){return s}),n.d(e,"n",function(){return o}),n.d(e,"f",function(){return a}),n.d(e,"g",function(){return c}),n.d(e,"j",function(){return u}),n.d(e,"m",function(){return h}),n.d(e,"e",function(){return p}),n.d(e,"d",function(){return _}),n.d(e,"k",function(){return f}),n.d(e,"a",function(){return d}),n.d(e,"b",function(){return y}),n.d(e,"c",function(){return m}),n.d(e,"l",function(){return b});var i=function(){return(i=Object.assign||function(t){for(var e,n=1,i=arguments.length;n0&&!isNaN(parseInt(t))?parseInt(t):e}function s(t,e){return"number"==typeof t?t:"string"==typeof t&&t.length>0&&!isNaN(parseFloat(t))?parseFloat(t):e}function o(t){return null==t||0===t.length}function a(t,e){return"string"==typeof t&&t.length>0?t:e}function c(t){return"boolean"==typeof t?t:"number"==typeof t?t>0:"string"==typeof t&&("1"===t||"true"===t)}function l(t,e,n){void 0===n&&(n=" "),"number"==typeof t&&(t=""+t),"number"==typeof n&&(n=""+n);var i=e-t.length;if(0===i)return t;if(i<0)return t.substr(Math.abs(i));if(i===n.length)return""+n+t;if(i0){var n=document.createElement("table"),i=document.createElement("tr"),r=document.createElement("tr"),s=document.createElement("tr"),o=document.createElement("td");switch(o.innerHTML=e,i.append(o),n.append(r,i,s),n.style.textAlign="center",this.props.labelPosition){case"up":case"down":this.props.width>0&&(n.style.width=this.props.width+"px",n.style.height=null);break;case"left":case"right":this.props.height>0&&(n.style.width=null,n.style.height=this.props.height+"px")}t.append(n)}return t},t.prototype.getLabelWithMacrosReplaced=function(){var t=this.props;return Object(i.l)([{macro:"_date_",value:Object(i.b)(new Date)},{macro:"_time_",value:Object(i.c)(new Date)},{macro:"_agent_",value:null!=t.agentAlias?t.agentAlias:""},{macro:"_agentdescription_",value:null!=t.agentDescription?t.agentDescription:""},{macro:"_address_",value:null!=t.agentAddress?t.agentAddress:""},{macro:"_module_",value:null!=t.moduleName?t.moduleName:""},{macro:"_moduledescription_",value:null!=t.moduleDescription?t.moduleDescription:""}],this.props.label||"")},t.prototype.updateDomElement=function(t){t.innerHTML=this.createDomElement().innerHTML},Object.defineProperty(t.prototype,"props",{get:function(){return s({},this.itemProps)},set:function(t){var e=this.props;this.itemProps=t,this.shouldBeUpdated(e,t)&&this.render(e)},enumerable:!0,configurable:!0}),t.prototype.shouldBeUpdated=function(t,e){return t!==e},t.prototype.render=function(t){void 0===t&&(t=null),this.updateDomElement(this.childElementRef),t&&!this.positionChanged(t,this.props)||this.moveElement(this.props.x,this.props.y),t&&!this.sizeChanged(t,this.props)||this.resizeElement(this.props.width,this.props.height);var e=this.labelElementRef.innerHTML,n=this.createLabelDomElement().innerHTML;if(e!==n&&(this.labelElementRef.innerHTML=n),t&&t.labelPosition===this.props.labelPosition||this.changeLabelPosition(this.props.labelPosition),t&&(t.isLinkEnabled!==this.props.isLinkEnabled||this.props.isLinkEnabled&&t.link!==this.props.link)){var i=this.createContainerDomElement();i.innerHTML=this.elementRef.innerHTML;for(var r=this.elementRef.attributes,s=0;s0?e.item(0):null;if(n)switch(this.props.labelPosition){case"up":case"down":this.props.width>0&&(n.style.width=this.props.width+"px",n.style.height=null);break;case"left":case"right":this.props.height>0&&(n.style.width=null,n.style.height=this.props.height+"px")}},t.prototype.moveElement=function(t,e){this.elementRef.style.left=t+"px",this.elementRef.style.top=e+"px"},t.prototype.move=function(t,e){this.moveElement(t,e),this.itemProps=s({},this.props,{x:t,y:e})},t.prototype.sizeChanged=function(t,e){return t.width!==e.width||t.height!==e.height},t.prototype.resizeElement=function(t,e){this.childElementRef.style.width=t>0?t+"px":null,this.childElementRef.style.height=e>0?e+"px":null},t.prototype.resize=function(t,e){this.resizeElement(t,e),this.itemProps=s({},this.props,{width:t,height:e})},t.prototype.onClick=function(t){var e=this.clickEventManager.on(t);return this.disposables.push(e),e},t.prototype.onRemove=function(t){var e=this.removeEventManager.on(t);return this.disposables.push(e),e},t}();e.a=c},function(t,e,n){"use strict";var i=function(){return function(){var t=this;this.listeners=[],this.listenersOncer=[],this.on=function(e){return t.listeners.push(e),{dispose:function(){return t.off(e)}}},this.once=function(e){t.listenersOncer.push(e)},this.off=function(e){var n=t.listeners.indexOf(e);n>-1&&t.listeners.splice(n,1)},this.emit=function(e){t.listeners.forEach(function(t){return t(e)}),t.listenersOncer.forEach(function(t){return t(e)}),t.listenersOncer=[]},this.pipe=function(e){return t.on(function(t){return e.emit(t)})}}}();e.a=i},function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.d(__webpack_exports__,"b",function(){return eventsHistoryPropsDecoder});var _lib__WEBPACK_IMPORTED_MODULE_0__=__webpack_require__(0),_Item__WEBPACK_IMPORTED_MODULE_1__=__webpack_require__(1),__extends=(extendStatics=function(t,e){return(extendStatics=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(t,e)},function(t,e){function n(){this.constructor=t}extendStatics(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}),extendStatics,__assign=function(){return(__assign=Object.assign||function(t){for(var e,n=1,i=arguments.length;n0){var m=document.createElementNS(t,"text");m.setAttribute("text-anchor","middle"),m.setAttribute("font-size","8"),m.setAttribute("transform","translate(30 50) rotate(90)"),m.setAttribute("fill",i),m.textContent=y,f.append(m)}var b=document.createElementNS(t,"g");b.setAttribute("class","marks");var v=document.createElementNS(t,"g");v.setAttribute("class","mark"),v.setAttribute("transform","translate(50 50)");var g=document.createElementNS(t,"line");g.setAttribute("x1","36"),g.setAttribute("y1","0"),g.setAttribute("x2","46"),g.setAttribute("y2","0"),g.setAttribute("stroke",i),g.setAttribute("stroke-width","5");var x=document.createElementNS(t,"line");x.setAttribute("x1","36"),x.setAttribute("y1","0"),x.setAttribute("x2","46"),x.setAttribute("y2","0"),x.setAttribute("stroke",e),x.setAttribute("stroke-width","1"),v.append(g,x),b.append(v);for(var E=1;E<60;E++){var O=document.createElementNS(t,"line");O.setAttribute("y1","0"),O.setAttribute("y2","0"),O.setAttribute("stroke",i),O.setAttribute("transform","translate(50 50) rotate("+6*E+")"),E%5==0?(O.setAttribute("x1","38"),O.setAttribute("x2","46"),O.setAttribute("stroke-width",E%15==0?"2":"1")):(O.setAttribute("x1","42"),O.setAttribute("x2","46"),O.setAttribute("stroke-width","0.5")),b.append(O)}var w=document.createElementNS(t,"g");w.setAttribute("class","hour-hand"),w.setAttribute("transform","translate(50 50)");var T=document.createElementNS(t,"line");T.setAttribute("class","hour-hand-a"),T.setAttribute("x1","0"),T.setAttribute("y1","0"),T.setAttribute("x2","30"),T.setAttribute("y2","0"),T.setAttribute("stroke",o),T.setAttribute("stroke-width","4"),T.setAttribute("stroke-linecap","round");var A=document.createElementNS(t,"line");A.setAttribute("class","hour-hand-b"),A.setAttribute("x1","0"),A.setAttribute("y1","0"),A.setAttribute("x2","29.9"),A.setAttribute("y2","0"),A.setAttribute("stroke",s),A.setAttribute("stroke-width","3.1"),A.setAttribute("stroke-linecap","round"),w.append(T,A);var k=document.createElementNS(t,"g");k.setAttribute("class","minute-hand"),k.setAttribute("transform","translate(50 50)");var P=document.createElementNS(t,"line");P.setAttribute("class","minute-hand-a"),P.setAttribute("x1","0"),P.setAttribute("y1","0"),P.setAttribute("x2","40"),P.setAttribute("y2","0"),P.setAttribute("stroke",o),P.setAttribute("stroke-width","2"),P.setAttribute("stroke-linecap","round");var M=document.createElementNS(t,"line");M.setAttribute("class","minute-hand-b"),M.setAttribute("x1","0"),M.setAttribute("y1","0"),M.setAttribute("x2","39.9"),M.setAttribute("y2","0"),M.setAttribute("stroke",s),M.setAttribute("stroke-width","1.5"),M.setAttribute("stroke-linecap","round");var j=document.createElementNS(t,"circle");j.setAttribute("r","3"),j.setAttribute("fill",s),k.append(P,M,j);var S=document.createElementNS(t,"g");S.setAttribute("class","second-hand"),S.setAttribute("transform","translate(50 50)");var I=document.createElementNS(t,"line");I.setAttribute("x1","0"),I.setAttribute("y1","0"),I.setAttribute("x2","46"),I.setAttribute("y2","0"),I.setAttribute("stroke",a),I.setAttribute("stroke-width","1"),I.setAttribute("stroke-linecap","round");var N=document.createElementNS(t,"circle");N.setAttribute("r","2"),N.setAttribute("fill",a),S.append(I,N);var D=document.createElementNS(t,"circle");D.setAttribute("cx","50"),D.setAttribute("cy","50"),D.setAttribute("r","0.3"),D.setAttribute("fill",s);var L=this.getOriginDate(),R=L.getSeconds(),C=L.getMinutes(),B=6*R,z=6*C+R/60*6,W=30*L.getHours()+C/60*30;if(w.setAttribute("transform","translate(50 50) rotate("+W+")"),k.setAttribute("transform","translate(50 50) rotate("+z+")"),S.setAttribute("transform","translate(50 50) rotate("+B+")"),_.append(f,b,w,k,S,D),_.setAttribute("transform","rotate(-90)"),p.innerHTML="\n \n ",p.append(_),"datetime"===this.props.clockFormat){var H=document.createElement("span");H.className="date",H.textContent=Object(r.b)(L,"default"),H.style.fontSize=h+"px",this.props.color&&(H.style.color=this.props.color),p.append(H)}return p},e.prototype.createDigitalClock=function(){var t=document.createElement("div");t.className="digital-clock";var e=this.getElementSize().width,n=6/this.props.clockTimezone.length,i=20*e/100,s=10*e/100,o=Math.min(20*n*e/100,e/100*10),a=this.getOriginDate();if("datetime"===this.props.clockFormat){var c=document.createElement("span");c.className="date",c.textContent=Object(r.b)(a,"default"),c.style.fontSize=s+"px",this.props.color&&(c.style.color=this.props.color),t.append(c)}var l=document.createElement("span");l.className="time",l.textContent=Object(r.c)(a),l.style.fontSize=i+"px",this.props.color&&(l.style.color=this.props.color),t.append(l);var u=this.getHumanTimezone();if(u.length>0){var h=document.createElement("span");h.className="timezone",h.textContent=u,h.style.fontSize=o+"px",this.props.color&&(h.style.color=this.props.color),t.append(h)}return t},e.prototype.getOriginDate=function(t){void 0===t&&(t=null);var e=t||new Date,n=1e3*this.props.clockTimezoneOffset,i=60*e.getTimezoneOffset()*1e3,r=e.getTime()+n+i;return new Date(r)},e.prototype.getHumanTimezone=function(t){void 0===t&&(t=this.props.clockTimezone);var e=t.split("/")[1];return(void 0===e?"":e).replace("_"," ")},e.prototype.getElementSize=function(t,e){switch(void 0===t&&(t=this.props.width),void 0===e&&(e=this.props.height),this.props.clockType){case"analogic":var n=100;return t>0&&e>0?n=Math.min(t,e):t>0?n=t:e>0&&(n=e),{width:n,height:n};case"digital":return t>0&&e>0?e=t/20?e=t/2:e>0?t=2*e:(t=100,e=50),{width:t,height:e};default:throw new Error("invalid clock type.")}},e.TICK_INTERVAL=1e3,e}(s.a),j=function(){var t=function(e,n){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(e,n)};return function(e,n){function i(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(i.prototype=n.prototype,new i)}}(),S=function(){return(S=Object.assign||function(t){for(var e,n=1,i=arguments.length;n0){t.style.borderStyle="solid";var e=Math.min(this.props.width,this.props.height)/2,n=Math.min(this.props.borderWidth,e);t.style.borderWidth=n+"px",this.props.borderColor&&(t.style.borderColor=this.props.borderColor)}return t},e}(s.a),D=function(){var t=function(e,n){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(e,n)};return function(e,n){function i(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(i.prototype=n.prototype,new i)}}(),L=function(){return(L=Object.assign||function(t){for(var e,n=1,i=arguments.length;n0&&(n=Object(r.l)([{macro:/\(?_VALUE_\)?/i,value:n}],i)),t.innerHTML=n}return t},e.prototype.createLabelDomElement=function(){var t=document.createElement("div");return t.className="visual-console-item-label",t},e}(s.a),X=n(3),Z=Math.PI,Q=2*Z,J=Q-1e-6;function $(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function tt(){return new $}$.prototype=tt.prototype={constructor:$,moveTo:function(t,e){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+e)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,e){this._+="L"+(this._x1=+t)+","+(this._y1=+e)},quadraticCurveTo:function(t,e,n,i){this._+="Q"+ +t+","+ +e+","+(this._x1=+n)+","+(this._y1=+i)},bezierCurveTo:function(t,e,n,i,r,s){this._+="C"+ +t+","+ +e+","+ +n+","+ +i+","+(this._x1=+r)+","+(this._y1=+s)},arcTo:function(t,e,n,i,r){t=+t,e=+e,n=+n,i=+i,r=+r;var s=this._x1,o=this._y1,a=n-t,c=i-e,l=s-t,u=o-e,h=l*l+u*u;if(r<0)throw new Error("negative radius: "+r);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=e);else if(h>1e-6)if(Math.abs(u*a-c*l)>1e-6&&r){var p=n-s,_=i-o,f=a*a+c*c,d=p*p+_*_,y=Math.sqrt(f),m=Math.sqrt(h),b=r*Math.tan((Z-Math.acos((f+h-d)/(2*y*m)))/2),v=b/m,g=b/y;Math.abs(v-1)>1e-6&&(this._+="L"+(t+v*l)+","+(e+v*u)),this._+="A"+r+","+r+",0,0,"+ +(u*p>l*_)+","+(this._x1=t+g*a)+","+(this._y1=e+g*c)}else this._+="L"+(this._x1=t)+","+(this._y1=e);else;},arc:function(t,e,n,i,r,s){t=+t,e=+e;var o=(n=+n)*Math.cos(i),a=n*Math.sin(i),c=t+o,l=e+a,u=1^s,h=s?i-r:r-i;if(n<0)throw new Error("negative radius: "+n);null===this._x1?this._+="M"+c+","+l:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-l)>1e-6)&&(this._+="L"+c+","+l),n&&(h<0&&(h=h%Q+Q),h>J?this._+="A"+n+","+n+",0,1,"+u+","+(t-o)+","+(e-a)+"A"+n+","+n+",0,1,"+u+","+(this._x1=c)+","+(this._y1=l):h>1e-6&&(this._+="A"+n+","+n+",0,"+ +(h>=Z)+","+u+","+(this._x1=t+n*Math.cos(r))+","+(this._y1=e+n*Math.sin(r))))},rect:function(t,e,n,i){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+e)+"h"+ +n+"v"+ +i+"h"+-n+"Z"},toString:function(){return this._}};var et=tt,nt=function(t){return function(){return t}},it=Math.abs,rt=Math.atan2,st=Math.cos,ot=Math.max,at=Math.min,ct=Math.sin,lt=Math.sqrt,ut=1e-12,ht=Math.PI,pt=ht/2,_t=2*ht;function ft(t){return t>=1?pt:t<=-1?-pt:Math.asin(t)}function dt(t){return t.innerRadius}function yt(t){return t.outerRadius}function mt(t){return t.startAngle}function bt(t){return t.endAngle}function vt(t){return t&&t.padAngle}function gt(t,e,n,i,r,s,o){var a=t-n,c=e-i,l=(o?s:-s)/lt(a*a+c*c),u=l*c,h=-l*a,p=t+u,_=e+h,f=n+u,d=i+h,y=(p+f)/2,m=(_+d)/2,b=f-p,v=d-_,g=b*b+v*v,x=r-s,E=p*d-f*_,O=(v<0?-1:1)*lt(ot(0,x*x*g-E*E)),w=(E*v-b*O)/g,T=(-E*b-v*O)/g,A=(E*v+b*O)/g,k=(-E*b+v*O)/g,P=w-y,M=T-m,j=A-y,S=k-m;return P*P+M*M>j*j+S*S&&(w=A,T=k),{cx:w,cy:T,x01:-u,y01:-h,x11:w*(r/x-1),y11:T*(r/x-1)}}var xt=function(){var t=dt,e=yt,n=nt(0),i=null,r=mt,s=bt,o=vt,a=null;function c(){var c,l,u,h=+t.apply(this,arguments),p=+e.apply(this,arguments),_=r.apply(this,arguments)-pt,f=s.apply(this,arguments)-pt,d=it(f-_),y=f>_;if(a||(a=c=et()),put)if(d>_t-ut)a.moveTo(p*st(_),p*ct(_)),a.arc(0,0,p,_,f,!y),h>ut&&(a.moveTo(h*st(f),h*ct(f)),a.arc(0,0,h,f,_,y));else{var m,b,v=_,g=f,x=_,E=f,O=d,w=d,T=o.apply(this,arguments)/2,A=T>ut&&(i?+i.apply(this,arguments):lt(h*h+p*p)),k=at(it(p-h)/2,+n.apply(this,arguments)),P=k,M=k;if(A>ut){var j=ft(A/h*ct(T)),S=ft(A/p*ct(T));(O-=2*j)>ut?(x+=j*=y?1:-1,E-=j):(O=0,x=E=(_+f)/2),(w-=2*S)>ut?(v+=S*=y?1:-1,g-=S):(w=0,v=g=(_+f)/2)}var I=p*st(v),N=p*ct(v),D=h*st(E),L=h*ct(E);if(k>ut){var R,C=p*st(g),B=p*ct(g),z=h*st(x),W=h*ct(x);if(d1?0:u<-1?ht:Math.acos(u))/2),V=lt(R[0]*R[0]+R[1]*R[1]);P=at(k,(h-V)/(q-1)),M=at(k,(p-V)/(q+1))}}w>ut?M>ut?(m=gt(z,W,I,N,p,M,y),b=gt(C,B,D,L,p,M,y),a.moveTo(m.cx+m.x01,m.cy+m.y01),Mut&&O>ut?P>ut?(m=gt(D,L,C,B,h,-P,y),b=gt(I,N,z,W,h,-P,y),a.lineTo(m.cx+m.x01,m.cy+m.y01),P0)for(var i,r=t[0],s=e[0],o=t[n]-r,a=e[n]-s,c=-1;++c<=n;)i=c/n,this._basis.point(this._beta*t[c]+(1-this._beta)*(r+i*o),this._beta*e[c]+(1-this._beta)*(s+i*a));this._x=this._y=null,this._basis.lineEnd()},point:function(t,e){this._x.push(+t),this._y.push(+e)}};(function t(e){function n(t){return 1===e?new Mt(t):new It(t,e)}return n.beta=function(e){return t(+e)},n})(.85);function Nt(t,e,n){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-e),t._y2+t._k*(t._y1-n),t._x2,t._y2)}function Dt(t,e){this._context=t,this._k=(1-e)/6}Dt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:Nt(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2,this._x1=t,this._y1=e;break;case 2:this._point=3;default:Nt(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};(function t(e){function n(t){return new Dt(t,e)}return n.tension=function(e){return t(+e)},n})(0);function Lt(t,e){this._context=t,this._k=(1-e)/6}Lt.prototype={areaStart:kt,areaEnd:kt,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:Nt(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};(function t(e){function n(t){return new Lt(t,e)}return n.tension=function(e){return t(+e)},n})(0);function Rt(t,e){this._context=t,this._k=(1-e)/6}Rt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Nt(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};(function t(e){function n(t){return new Rt(t,e)}return n.tension=function(e){return t(+e)},n})(0);function Ct(t,e,n){var i=t._x1,r=t._y1,s=t._x2,o=t._y2;if(t._l01_a>ut){var a=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);i=(i*a-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,r=(r*a-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>ut){var l=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,u=3*t._l23_a*(t._l23_a+t._l12_a);s=(s*l+t._x1*t._l23_2a-e*t._l12_2a)/u,o=(o*l+t._y1*t._l23_2a-n*t._l12_2a)/u}t._context.bezierCurveTo(i,r,s,o,t._x2,t._y2)}function Bt(t,e){this._context=t,this._alpha=e}Bt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,i=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+i*i,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3;default:Ct(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};(function t(e){function n(t){return e?new Bt(t,e):new Dt(t,0)}return n.alpha=function(e){return t(+e)},n})(.5);function zt(t,e){this._context=t,this._alpha=e}zt.prototype={areaStart:kt,areaEnd:kt,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,i=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+i*i,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:Ct(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};(function t(e){function n(t){return e?new zt(t,e):new Lt(t,0)}return n.alpha=function(e){return t(+e)},n})(.5);function Wt(t,e){this._context=t,this._alpha=e}Wt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,i=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+i*i,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Ct(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};(function t(e){function n(t){return e?new Wt(t,e):new Rt(t,0)}return n.alpha=function(e){return t(+e)},n})(.5);function Ht(t){this._context=t}Ht.prototype={areaStart:kt,areaEnd:kt,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,e){t=+t,e=+e,this._point?this._context.lineTo(t,e):(this._point=1,this._context.moveTo(t,e))}};function Ut(t){return t<0?-1:1}function Kt(t,e,n){var i=t._x1-t._x0,r=e-t._x1,s=(t._y1-t._y0)/(i||r<0&&-0),o=(n-t._y1)/(r||i<0&&-0),a=(s*r+o*i)/(i+r);return(Ut(s)+Ut(o))*Math.min(Math.abs(s),Math.abs(o),.5*Math.abs(a))||0}function Gt(t,e){var n=t._x1-t._x0;return n?(3*(t._y1-t._y0)/n-e)/2:e}function qt(t,e,n){var i=t._x0,r=t._y0,s=t._x1,o=t._y1,a=(s-i)/3;t._context.bezierCurveTo(i+a,r+a*e,s-a,o-a*n,s,o)}function Vt(t){this._context=t}function Ft(t){this._context=new Yt(t)}function Yt(t){this._context=t}function Xt(t){this._context=t}function Zt(t){var e,n,i=t.length-1,r=new Array(i),s=new Array(i),o=new Array(i);for(r[0]=0,s[0]=2,o[0]=t[0]+2*t[1],e=1;e=0;--e)r[e]=(o[e]-r[e+1])/s[e];for(s[i-1]=(t[i]+r[i-1])/2,e=0;e=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,e),this._context.lineTo(t,e);else{var n=this._x*(1-this._t)+t*this._t;this._context.lineTo(n,this._y),this._context.lineTo(n,e)}}this._x=t,this._y=e}};var Jt=function(){var t=function(e,n){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(e,n)};return function(e,n){function i(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(i.prototype=n.prototype,new i)}}(),$t=function(){return($t=Object.assign||function(t){for(var e,n=1,i=arguments.length;n0){var p=document.createElementNS(ie,"tspan");p.setAttribute("x","0"),p.setAttribute("dy","1em"),p.textContent=""+t,p.style.fontSize="8pt";var _=document.createElementNS(ie,"tspan");_.setAttribute("x","0"),_.setAttribute("dy","1em"),_.textContent=""+this.props.unit,_.style.fontSize="8pt",h.append(p,_),h.setAttribute("transform","translate(50 33)")}else h.textContent=""+t,h.style.fontSize="8pt",h.setAttribute("transform","translate(50 50)");else h.textContent=n+"%",h.setAttribute("transform","translate(50 50)");r.append(h)}return i.append(r),i},e.prototype.getProgress=function(){var t=this.props.minValue||0,e=this.props.maxValue||100,n=null==this.props.value?0:this.props.value;return n<=t?0:n>=e?100:Math.trunc((n-t)/(e-t)*100)},e}(s.a),se=n(2),oe=n(4),ae=n(5),ce=n(6),le=function(){var t=function(e,n){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(e,n)};return function(e,n){function i(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(i.prototype=n.prototype,new i)}}(),ue=function(){return(ue=Object.assign||function(t){for(var e,n=1,i=arguments.length;ne.id?1:-1})).forEach(function(t){try{var e=fe(t);i.elementsById[e.props.id]=e,i.elementIds.push(e.props.id),e.onClick(i.handleElementClick),e.onRemove(i.handleElementRemove),i.containerRef.append(e.elementRef)}catch(t){console.log("Error creating a new element:",t.message)}}),this.buildRelations()}return Object.defineProperty(t.prototype,"elements",{get:function(){var t=this;return this.elementIds.map(function(e){return t.elementsById[e]}).filter(function(t){return null!=t})},enumerable:!0,configurable:!0}),t.prototype.updateElements=function(t){var e=this,n=t.map(function(t){return t.id||null}).filter(function(t){return null!=t});this.elementIds.filter(function(t){return n.indexOf(t)<0}).forEach(function(t){null!=e.elementsById[t]&&(e.elementsById[t].remove(),delete e.elementsById[t])}),this.elementIds=n,t.forEach(function(t){if(t.id)if(null==e.elementsById[t.id])try{var n=fe(t);e.elementsById[n.props.id]=n,n.onClick(e.handleElementClick),n.onRemove(e.handleElementRemove),e.containerRef.append(n.elementRef)}catch(t){console.log("Error creating a new element:",t.message)}else try{e.elementsById[t.id].props=function(t){var e=Object(r.i)(t.type,null);if(null==e)throw new TypeError("missing item type.");switch(e){case 0:return l(t);case 1:return Object(ce.b)(t);case 2:case 6:case 7:case 8:return F(t);case 3:case 9:case 15:case 16:return ne(t);case 4:return H(t);case 5:return _(t);case 10:return he(t);case 11:return E(t);case 12:return I(t);case 13:return R(t);case 14:return Object(X.b)(t);case 17:return Object(oe.b)(t);case 18:return Object(ae.a)(t);case 19:return P(t);case 20:return m(t);default:throw new TypeError("decoder not found")}}(t)}catch(t){console.log("Error updating an element:",t.message)}}),this.buildRelations()},Object.defineProperty(t.prototype,"props",{get:function(){return _e({},this._props)},set:function(t){var e=this.props;this._props=t,this.render(e)},enumerable:!0,configurable:!0}),t.prototype.render=function(t){void 0===t&&(t=null),t?(t.backgroundURL!==this.props.backgroundURL&&(this.containerRef.style.backgroundImage=null!==this.props.backgroundURL?"url("+this.props.backgroundURL+")":null),t.backgroundColor!==this.props.backgroundColor&&(this.containerRef.style.backgroundColor=this.props.backgroundColor),this.sizeChanged(t,this.props)&&this.resizeElement(this.props.width,this.props.height)):(this.containerRef.style.backgroundImage=null!==this.props.backgroundURL?"url("+this.props.backgroundURL+")":null,this.containerRef.style.backgroundColor=this.props.backgroundColor,this.resizeElement(this.props.width,this.props.height))},t.prototype.sizeChanged=function(t,e){return t.width!==e.width||t.height!==e.height},t.prototype.resizeElement=function(t,e){this.containerRef.style.width=t+"px",this.containerRef.style.height=e+"px"},t.prototype.resize=function(t,e){this.props=_e({},this.props,{width:t,height:e})},t.prototype.remove=function(){this.disposables.forEach(function(t){return t.dispose()}),this.elements.forEach(function(t){return t.remove()}),this.elementsById={},this.elementIds=[],this.clearRelations(),this.containerRef.innerHTML=""},t.prototype.buildRelations=function(){var t=this;this.clearRelations(),this.elements.forEach(function(e){if(null!==e.props.parentId){var n=t.elementsById[e.props.parentId],i=t.elementsById[e.props.id];n&&i&&t.addRelationLine(n,i)}})},t.prototype.clearRelations=function(t){if(null!=t)for(var e in this.relations){var n=e.split("|"),i=Number.parseInt(n[0]),r=Number.parseInt(n[1]);t!==i&&t!==r||(this.relations[e].remove(),delete this.relations[e])}else for(var e in this.relations)this.relations[e].remove(),delete this.relations[e]},t.prototype.getRelationLine=function(t,e){var n=t+"|"+e;return this.relations[n]||null},t.prototype.addRelationLine=function(t,e){var n=t.props.id+"|"+e.props.id;null!=this.relations[n]&&this.relations[n].remove();var i=t.props.x+t.elementRef.clientWidth/2,r=t.props.y+(t.elementRef.clientHeight-t.labelElementRef.clientHeight)/2,s=e.props.x+e.elementRef.clientWidth/2,o=e.props.y+(e.elementRef.clientHeight-e.labelElementRef.clientHeight)/2,a=new B(R({id:0,type:13,startX:i,startY:r,endX:s,endY:o,width:0,height:0,lineWidth:this.props.relationLineWidth,color:"#CCCCCC"}));return this.relations[n]=a,a.elementRef.style.zIndex="0",this.containerRef.append(a.elementRef),a},t.prototype.onClick=function(t){var e=this.clickEventManager.on(t);return this.disposables.push(e),e},t}(),ye=function(){function t(t){this.cancellable={cancel:function(){}},this._status="waiting",this.statusChangeEventManager=new se.a,this.disposables=[],this.taskInitiator=t}return Object.defineProperty(t.prototype,"status",{get:function(){return this._status},set:function(t){this._status=t,this.statusChangeEventManager.emit(t)},enumerable:!0,configurable:!0}),t.prototype.init=function(){var t=this;this.cancellable=this.taskInitiator(function(){t.status="finished"}),this.status="started"},t.prototype.cancel=function(){this.cancellable.cancel(),this.status="cancelled"},t.prototype.onStatusChange=function(t){var e=this.statusChangeEventManager.on(t);return this.disposables.push(e),e},t}();var me=function(){function t(){this.tasks={}}return t.prototype.add=function(t,e,n){void 0===n&&(n=0),this.tasks[t]&&"started"===this.tasks[t].status&&this.tasks[t].cancel();var i=n>0?function(t,e){return new ye(function(){var n=null;return t.onStatusChange(function(i){"finished"===i&&(n=window.setTimeout(function(){t.init()},e))}),t.init(),{cancel:function(){n&&clearTimeout(n),t.cancel()}}})}(new ye(e),n):new ye(e);return this.tasks[t]=i,this.tasks[t]},t.prototype.init=function(t){!this.tasks[t]||"waiting"!==this.tasks[t].status&&"cancelled"!==this.tasks[t].status&&"finished"!==this.tasks[t].status||this.tasks[t].init()},t.prototype.cancel=function(t){this.tasks[t]&&"started"===this.tasks[t].status&&this.tasks[t].cancel()},t}();window.VisualConsole=de,window.AsyncTaskManager=me}]); +//# sourceMappingURL=vc.main.min.js.map \ No newline at end of file diff --git a/pandora_console/include/visual-console-client/vc.main.min.js.map b/pandora_console/include/visual-console-client/vc.main.min.js.map new file mode 100644 index 0000000000..518b003c07 --- /dev/null +++ b/pandora_console/include/visual-console-client/vc.main.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./src/lib/index.ts","webpack:///./src/Item.ts","webpack:///./src/TypedEvent.ts","webpack:///./src/items/EventsHistory.ts","webpack:///./src/items/DonutGraph.ts","webpack:///./src/items/BarsGraph.ts","webpack:///./src/items/ModuleGraph.ts","webpack:///./src/items/StaticGraph.ts","webpack:///./src/items/Icon.ts","webpack:///./src/items/ColorCloud.ts","webpack:///./src/items/Group.ts","webpack:///./src/items/Clock/index.ts","webpack:///./src/items/Box.ts","webpack:///./src/items/Line.ts","webpack:///./src/items/Label.ts","webpack:///./src/items/SimpleValue.ts","webpack:///./node_modules/d3-path/src/path.js","webpack:///./node_modules/d3-shape/src/constant.js","webpack:///./node_modules/d3-shape/src/math.js","webpack:///./node_modules/d3-shape/src/arc.js","webpack:///./node_modules/d3-shape/src/curve/linear.js","webpack:///./node_modules/d3-shape/src/curve/radial.js","webpack:///./node_modules/d3-shape/src/array.js","webpack:///./node_modules/d3-shape/src/symbol/diamond.js","webpack:///./node_modules/d3-shape/src/symbol/circle.js","webpack:///./node_modules/d3-shape/src/symbol/star.js","webpack:///./node_modules/d3-shape/src/noop.js","webpack:///./node_modules/d3-shape/src/symbol/triangle.js","webpack:///./node_modules/d3-shape/src/symbol/wye.js","webpack:///./node_modules/d3-shape/src/curve/basis.js","webpack:///./node_modules/d3-shape/src/curve/basisClosed.js","webpack:///./node_modules/d3-shape/src/curve/basisOpen.js","webpack:///./node_modules/d3-shape/src/curve/bundle.js","webpack:///./node_modules/d3-shape/src/curve/cardinal.js","webpack:///./node_modules/d3-shape/src/curve/cardinalClosed.js","webpack:///./node_modules/d3-shape/src/curve/cardinalOpen.js","webpack:///./node_modules/d3-shape/src/curve/catmullRom.js","webpack:///./node_modules/d3-shape/src/curve/catmullRomClosed.js","webpack:///./node_modules/d3-shape/src/curve/catmullRomOpen.js","webpack:///./node_modules/d3-shape/src/curve/linearClosed.js","webpack:///./node_modules/d3-shape/src/curve/monotone.js","webpack:///./node_modules/d3-shape/src/curve/natural.js","webpack:///./node_modules/d3-shape/src/curve/step.js","webpack:///./node_modules/d3-shape/src/order/descending.js","webpack:///./src/items/Percentile.ts","webpack:///./src/items/Service.ts","webpack:///./src/VisualConsole.ts","webpack:///./src/lib/AsyncTaskManager.ts","webpack:///./src/index.ts"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","parseIntOr","defaultValue","length","isNaN","parseInt","parseFloatOr","parseFloat","stringIsEmpty","notEmptyStringOr","parseBoolean","leftPad","pad","diffLength","substr","Math","abs","substring","repeatTimes","floor","restLength","newPad","positionPropsDecoder","data","x","y","sizePropsDecoder","width","height","TypeError","modulePropsDecoder","__assign","moduleName","moduleDescription","agentProps","agentId","agent","agentName","agentAlias","agentDescription","agentAddress","metaconsoleId","agentPropsDecoder","linkedVCPropsDecoder","id","linkedLayoutId","linkedLayoutAgentId","linkedLayoutStatusProps","linkedLayoutStatusType","weight","linkedLayoutStatusTypeWeight","warningThreshold","linkedLayoutStatusTypeWarningThreshold","criticalThreshold","linkedLayoutStatusTypeCriticalThreshold","linkedLayoutBaseProps","prefixedCssRules","ruleName","ruleValue","rule","decodeBase64","input","decodeURIComponent","escape","window","atob","humanDate","date","locale","Intl","DateTimeFormat","day","month","year","format","getDate","getMonth","getFullYear","humanTime","getHours","getMinutes","getSeconds","replaceMacros","macros","text","reduce","acc","_a","macro","replace","parseLabelPosition","labelPosition","itemBasePropsDecoder","type","label","_lib__WEBPACK_IMPORTED_MODULE_0__","isLinkEnabled","link","isOnTop","parentId","aclGroupId","VisualConsoleItem","props","this","clickEventManager","_TypedEvent__WEBPACK_IMPORTED_MODULE_1__","removeEventManager","disposables","itemProps","elementRef","createContainerDomElement","labelElementRef","createLabelDomElement","childElementRef","createDomElement","append","resizeElement","changeLabelPosition","box","_this","document","createElement","href","className","style","zIndex","left","top","onclick","e","emit","nativeEvent","element","getLabelWithMacrosReplaced","table","row","emptyRow1","emptyRow2","cell","innerHTML","textAlign","Date","updateDomElement","newProps","prevProps","shouldBeUpdated","render","positionChanged","moveElement","sizeChanged","oldLabelHtml","newLabelHtml","container","attrs","attributes","nodeName","setAttributeNode","parentNode","replaceChild","remove","forEach","disposable","dispose","ignored","prevPosition","newPosition","position","flexDirection","tables","getElementsByTagName","item","move","prevSize","newSize","resize","onClick","listener","on","push","onRemove","__webpack_exports__","TypedEvent","listeners","listenersOncer","off","once","callbackIndex","indexOf","splice","event","pipe","te","eventsHistoryPropsDecoder","html","encodedHtml","_Item__WEBPACK_IMPORTED_MODULE_1__","maxTime","EventsHistory","_super","__extends","scripts","src","setTimeout","eval","trim","aux","donutGraphPropsDecoder","DonutGraph","barsGraphPropsDecoder","BarsGraph","moduleGraphPropsDecoder","ModuleGraph","legendP","margin","overviewGraphs","getElementsByClassName","parseShowLastValueTooltip","showLastValueTooltip","staticGraphPropsDecoder","imageSrc","Item","statusImageSrc","lib","lastValue","StaticGraph","imgSrc","background","backgroundSize","backgroundPosition","setAttribute","iconPropsDecoder","Icon_assign","Icon","Icon_extends","colorCloudPropsDecoder","color","ColorCloud_assign","ColorCloud_svgNS","ColorCloud","ColorCloud_extends","createSvgElement","gradientId","svg","createElementNS","defs","radialGradient","stop0","stop100","circle","groupPropsDecoder","groupId","showStatistics","extractHtml","Group_assign","Group","Group_extends","parseClockType","clockType","parseClockFormat","clockFormat","clockPropsDecoder","clockTimezone","Clock_assign","clockTimezoneOffset","showClockTimezone","items_Clock","Clock","intervalRef","startTick","createClock","TICK_INTERVAL","Clock_extends","stopTick","clearInterval","handler","interval","setInterval","getElementSize","newWidth","newHeight","createAnalogicClock","createDigitalClock","Error","svgNS","colors","dateFontSize","baseTimeFontSize","div","clockFace","clockFaceBackground","city","getHumanTimezone","timezoneComplication","textContent","marksGroup","mainMarkGroup","mark1a","mark1b","mark","hourHand","hourHandA","hourHandB","minuteHand","minuteHandA","minuteHandB","minuteHandPin","secondHand","secondHandBar","secondHandPin","pin","getOriginDate","seconds","minutes","secAngle","minuteAngle","hourAngle","join","dateElem","fontSize","tzFontSizeMultiplier","timeFontSize","tzFontSize","min","timeElem","tzElem","initialDate","targetTZOffset","localTZOffset","getTimezoneOffset","utimestamp","getTime","timezone","_b","split","diameter","boxPropsDecoder","Box_assign","borderWidth","borderColor","fillColor","Box","Box_extends","boxSizing","backgroundColor","borderStyle","maxBorderWidth","linePropsDecoder","Line_assign","startPosition","startX","startY","endPosition","endX","endY","lineWidth","Line","extractBoxSizeAndPosition","Line_extends","toString","line","labelPropsDecoder","Label_assign","Label","Label_extends","parseValueType","valueType","parseProcessValue","processValue","simpleValuePropsDecoder","SimpleValue_assign","period","SimpleValue","SimpleValue_extends","img","pi","PI","tau","tauEpsilon","Path","_x0","_y0","_x1","_y1","_","path","constructor","moveTo","closePath","lineTo","quadraticCurveTo","x1","y1","bezierCurveTo","x2","y2","arcTo","x0","y0","x21","y21","x01","y01","l01_2","x20","y20","l21_2","l20_2","l21","sqrt","l01","tan","acos","t01","t21","arc","a0","a1","ccw","dx","cos","dy","sin","cw","da","rect","w","h","src_path","constant","atan2","max","math_epsilon","math_pi","halfPi","math_tau","asin","arcInnerRadius","innerRadius","arcOuterRadius","outerRadius","arcStartAngle","startAngle","arcEndAngle","endAngle","arcPadAngle","padAngle","cornerTangents","r1","rc","lo","ox","oy","x11","y11","x10","y10","x00","y00","d2","D","cx0","cy0","cx1","cy1","dx0","dy0","dx1","dy1","cx","cy","src_arc","cornerRadius","padRadius","context","buffer","r0","apply","arguments","t0","t1","a01","a11","a00","a10","da0","da1","ap","rp","rc0","rc1","p0","p1","oc","x3","y3","x32","y32","intersect","ax","ay","bx","by","kc","lc","centroid","a","Linear","_context","areaStart","_line","areaEnd","NaN","lineStart","_point","lineEnd","point","linear","curveRadial","Radial","curve","_curve","radial","Array","slice","kr","noop","that","Basis","BasisClosed","_x2","_x3","_x4","_y2","_y3","_y4","BasisOpen","Bundle","beta","_basis","_beta","_x","_y","j","custom","bundle","cardinal_point","_k","Cardinal","tension","cardinal","CardinalClosed","_x5","_y5","CardinalOpen","catmullRom_point","_l01_a","_l01_2a","_l12_a","_l12_2a","_l23_a","b","_l23_2a","CatmullRom","alpha","_alpha","x23","y23","pow","catmullRom","CatmullRomClosed","CatmullRomOpen","LinearClosed","sign","slope3","h0","h1","s0","s1","slope2","monotone_point","MonotoneX","MonotoneY","ReflectContext","Natural","controlPoints","_t0","px","py","i0","i1","Step","_t","extractPercentileType","extractValueType","percentilePropsDecoder","Percentile_assign","percentileType","minValue","maxValue","labelColor","unit","Percentile_svgNS","Percentile","Percentile_extends","formatValue","progress","getProgress","NumberFormat","backgroundRect","progressRect","backgroundCircle","progressCircle","arcProps","trunc","servicePropsDecoder","encodedTitle","serviceId","Service_assign","Service","Service_extends","itemInstanceFrom","items_StaticGraph","items_SimpleValue","items_Percentile","items_Label","items_Icon","items_Service","items_Group","items_Box","items_Line","items_ColorCloud","VisualConsole","items","elementsById","elementIds","relations","handleElementClick","handleElementRemove","filter","clearRelations","containerRef","_props","backgroundURL","isFavorite","relationLineWidth","VisualConsole_assign","visualConsolePropsDecoder","sort","itemInstance","error","console","log","message","buildRelations","map","updateElements","itemIds","decodeProps","backgroundImage","elements","parent_1","child","addRelationLine","itemId","ids","Number","childId","getRelationLine","identifier","parent","clientWidth","clientHeight","AsyncTaskManager_AsyncTask","AsyncTask","taskInitiator","cancellable","cancel","_status","statusChangeEventManager","status","init","onStatusChange","AsyncTaskManager","tasks","add","asyncTask","task","ref","clearTimeout","asyncPeriodic","src_VisualConsole","lib_AsyncTaskManager"],"mappings":"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","file":"vc.main.min.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 9);\n","import {\n UnknownObject,\n Position,\n Size,\n WithAgentProps,\n WithModuleProps,\n LinkedVisualConsoleProps,\n LinkedVisualConsolePropsStatus\n} from \"../types\";\n\n/**\n * Return a number or a default value from a raw value.\n * @param value Raw value from which we will try to extract a valid number.\n * @param defaultValue Default value to use if we cannot extract a valid number.\n * @return A valid number or the default value.\n */\nexport function parseIntOr(value: unknown, defaultValue: T): number | T {\n if (typeof value === \"number\") return value;\n if (typeof value === \"string\" && value.length > 0 && !isNaN(parseInt(value)))\n return parseInt(value);\n else return defaultValue;\n}\n\n/**\n * Return a number or a default value from a raw value.\n * @param value Raw value from which we will try to extract a valid number.\n * @param defaultValue Default value to use if we cannot extract a valid number.\n * @return A valid number or the default value.\n */\nexport function parseFloatOr(value: unknown, defaultValue: T): number | T {\n if (typeof value === \"number\") return value;\n if (\n typeof value === \"string\" &&\n value.length > 0 &&\n !isNaN(parseFloat(value))\n )\n return parseFloat(value);\n else return defaultValue;\n}\n\n/**\n * Check if a string exists and it's not empty.\n * @param value Value to check.\n * @return The check result.\n */\nexport function stringIsEmpty(value?: string | null): boolean {\n return value == null || value.length === 0;\n}\n\n/**\n * Return a not empty string or a default value from a raw value.\n * @param value Raw value from which we will try to extract a non empty string.\n * @param defaultValue Default value to use if we cannot extract a non empty string.\n * @return A non empty string or the default value.\n */\nexport function notEmptyStringOr(\n value: unknown,\n defaultValue: T\n): string | T {\n return typeof value === \"string\" && value.length > 0 ? value : defaultValue;\n}\n\n/**\n * Return a boolean from a raw value.\n * @param value Raw value from which we will try to extract the boolean.\n * @return A valid boolean value. false by default.\n */\nexport function parseBoolean(value: unknown): boolean {\n if (typeof value === \"boolean\") return value;\n else if (typeof value === \"number\") return value > 0;\n else if (typeof value === \"string\") return value === \"1\" || value === \"true\";\n else return false;\n}\n\n/**\n * Pad the current string with another string (multiple times, if needed)\n * until the resulting string reaches the given length.\n * The padding is applied from the start (left) of the current string.\n * @param value Text that needs to be padded.\n * @param length Length of the returned text.\n * @param pad Text to add.\n * @return Padded text.\n */\nexport function leftPad(\n value: string | number,\n length: number,\n pad: string | number = \" \"\n): string {\n if (typeof value === \"number\") value = `${value}`;\n if (typeof pad === \"number\") pad = `${pad}`;\n\n const diffLength = length - value.length;\n if (diffLength === 0) return value;\n if (diffLength < 0) return value.substr(Math.abs(diffLength));\n\n if (diffLength === pad.length) return `${pad}${value}`;\n if (diffLength < pad.length) return `${pad.substring(0, diffLength)}${value}`;\n\n const repeatTimes = Math.floor(diffLength / pad.length);\n const restLength = diffLength - pad.length * repeatTimes;\n\n let newPad = \"\";\n for (let i = 0; i < repeatTimes; i++) newPad += pad;\n\n if (restLength === 0) return `${newPad}${value}`;\n return `${newPad}${pad.substring(0, restLength)}${value}`;\n}\n\n/* Decoders */\n\n/**\n * Build a valid typed object from a raw object.\n * @param data Raw object.\n * @return An object representing the position.\n */\nexport function positionPropsDecoder(data: UnknownObject): Position {\n return {\n x: parseIntOr(data.x, 0),\n y: parseIntOr(data.y, 0)\n };\n}\n\n/**\n * Build a valid typed object from a raw object.\n * @param data Raw object.\n * @return An object representing the size.\n * @throws Will throw a TypeError if the width and height are not valid numbers.\n */\nexport function sizePropsDecoder(data: UnknownObject): Size | never {\n if (\n data.width == null ||\n isNaN(parseInt(data.width)) ||\n data.height == null ||\n isNaN(parseInt(data.height))\n ) {\n throw new TypeError(\"invalid size.\");\n }\n\n return {\n width: parseInt(data.width),\n height: parseInt(data.height)\n };\n}\n\n/**\n * Build a valid typed object from a raw object.\n * @param data Raw object.\n * @return An object representing the agent properties.\n */\nexport function agentPropsDecoder(data: UnknownObject): WithAgentProps {\n const agentProps: WithAgentProps = {\n agentId: parseIntOr(data.agent, null),\n agentName: notEmptyStringOr(data.agentName, null),\n agentAlias: notEmptyStringOr(data.agentAlias, null),\n agentDescription: notEmptyStringOr(data.agentDescription, null),\n agentAddress: notEmptyStringOr(data.agentAddress, null)\n };\n\n return data.metaconsoleId != null\n ? {\n metaconsoleId: data.metaconsoleId,\n ...agentProps // Object spread: http://es6-features.org/#SpreadOperator\n }\n : agentProps;\n}\n\n/**\n * Build a valid typed object from a raw object.\n * @param data Raw object.\n * @return An object representing the module and agent properties.\n */\nexport function modulePropsDecoder(data: UnknownObject): WithModuleProps {\n return {\n moduleId: parseIntOr(data.moduleId, null),\n moduleName: notEmptyStringOr(data.moduleName, null),\n moduleDescription: notEmptyStringOr(data.moduleDescription, null),\n ...agentPropsDecoder(data) // Object spread: http://es6-features.org/#SpreadOperator\n };\n}\n\n/**\n * Build a valid typed object from a raw object.\n * @param data Raw object.\n * @return An object representing the linked visual console properties.\n * @throws Will throw a TypeError if the status calculation properties are invalid.\n */\nexport function linkedVCPropsDecoder(\n data: UnknownObject\n): LinkedVisualConsoleProps | never {\n // Object destructuring: http://es6-features.org/#ObjectMatchingShorthandNotation\n const {\n metaconsoleId,\n linkedLayoutId: id,\n linkedLayoutAgentId: agentId\n } = data;\n\n let linkedLayoutStatusProps: LinkedVisualConsolePropsStatus = {\n linkedLayoutStatusType: \"default\"\n };\n switch (data.linkedLayoutStatusType) {\n case \"weight\": {\n const weight = parseIntOr(data.linkedLayoutStatusTypeWeight, null);\n if (weight == null)\n throw new TypeError(\"invalid status calculation properties.\");\n\n if (data.linkedLayoutStatusTypeWeight)\n linkedLayoutStatusProps = {\n linkedLayoutStatusType: \"weight\",\n linkedLayoutStatusTypeWeight: weight\n };\n break;\n }\n case \"service\": {\n const warningThreshold = parseIntOr(\n data.linkedLayoutStatusTypeWarningThreshold,\n null\n );\n const criticalThreshold = parseIntOr(\n data.linkedLayoutStatusTypeCriticalThreshold,\n null\n );\n if (warningThreshold == null || criticalThreshold == null) {\n throw new TypeError(\"invalid status calculation properties.\");\n }\n\n linkedLayoutStatusProps = {\n linkedLayoutStatusType: \"service\",\n linkedLayoutStatusTypeWarningThreshold: warningThreshold,\n linkedLayoutStatusTypeCriticalThreshold: criticalThreshold\n };\n break;\n }\n }\n\n const linkedLayoutBaseProps = {\n linkedLayoutId: parseIntOr(id, null),\n linkedLayoutAgentId: parseIntOr(agentId, null),\n ...linkedLayoutStatusProps // Object spread: http://es6-features.org/#SpreadOperator\n };\n\n return metaconsoleId != null\n ? {\n metaconsoleId,\n ...linkedLayoutBaseProps // Object spread: http://es6-features.org/#SpreadOperator\n }\n : linkedLayoutBaseProps;\n}\n\n/**\n * To get a CSS rule with the most used prefixes.\n * @param ruleName Name of the CSS rule.\n * @param ruleValue Value of the CSS rule.\n * @return An array of rules with the prefixes applied.\n */\nexport function prefixedCssRules(\n ruleName: string,\n ruleValue: string\n): string[] {\n const rule = `${ruleName}: ${ruleValue};`;\n return [\n `-webkit-${rule}`,\n `-moz-${rule}`,\n `-ms-${rule}`,\n `-o-${rule}`,\n `${rule}`\n ];\n}\n\n/**\n * Decode a base64 string.\n * @param input Data encoded using base64.\n * @return Decoded data.\n */\nexport function decodeBase64(input: string): string {\n return decodeURIComponent(escape(window.atob(input)));\n}\n\n/**\n * Generate a date representation with the format 'd/m/Y'.\n * @param initialDate Date to be used instead of a generated one.\n * @param locale Locale to use if localization is required and available.\n * @example 24/02/2020.\n * @return Date representation.\n */\nexport function humanDate(date: Date, locale: string | null = null): string {\n if (locale && Intl && Intl.DateTimeFormat) {\n // Format using the user locale.\n const options: Intl.DateTimeFormatOptions = {\n day: \"2-digit\",\n month: \"2-digit\",\n year: \"numeric\"\n };\n return Intl.DateTimeFormat(locale, options).format(date);\n } else {\n // Use getDate, getDay returns the week day.\n const day = leftPad(date.getDate(), 2, 0);\n // The getMonth function returns the month starting by 0.\n const month = leftPad(date.getMonth() + 1, 2, 0);\n const year = leftPad(date.getFullYear(), 4, 0);\n\n // Format: 'd/m/Y'.\n return `${day}/${month}/${year}`;\n }\n}\n\n/**\n * Generate a time representation with the format 'hh:mm:ss'.\n * @param initialDate Date to be used instead of a generated one.\n * @example 01:34:09.\n * @return Time representation.\n */\nexport function humanTime(date: Date): string {\n const hours = leftPad(date.getHours(), 2, 0);\n const minutes = leftPad(date.getMinutes(), 2, 0);\n const seconds = leftPad(date.getSeconds(), 2, 0);\n\n return `${hours}:${minutes}:${seconds}`;\n}\n\ninterface Macro {\n macro: string | RegExp;\n value: string;\n}\n/**\n * Replace the macros of a text.\n * @param macros List of macros and their replacements.\n * @param text Text in which we need to replace the macros.\n */\nexport function replaceMacros(macros: Macro[], text: string): string {\n return macros.reduce(\n (acc, { macro, value }) => acc.replace(macro, value),\n text\n );\n}\n","import { Position, Size, UnknownObject, WithModuleProps } from \"./types\";\nimport {\n sizePropsDecoder,\n positionPropsDecoder,\n parseIntOr,\n parseBoolean,\n notEmptyStringOr,\n replaceMacros,\n humanDate,\n humanTime\n} from \"./lib\";\nimport TypedEvent, { Listener, Disposable } from \"./TypedEvent\";\n\n// Enum: https://www.typescriptlang.org/docs/handbook/enums.html.\nexport const enum ItemType {\n STATIC_GRAPH = 0,\n MODULE_GRAPH = 1,\n SIMPLE_VALUE = 2,\n PERCENTILE_BAR = 3,\n LABEL = 4,\n ICON = 5,\n SIMPLE_VALUE_MAX = 6,\n SIMPLE_VALUE_MIN = 7,\n SIMPLE_VALUE_AVG = 8,\n PERCENTILE_BUBBLE = 9,\n SERVICE = 10,\n GROUP_ITEM = 11,\n BOX_ITEM = 12,\n LINE_ITEM = 13,\n AUTO_SLA_GRAPH = 14,\n CIRCULAR_PROGRESS_BAR = 15,\n CIRCULAR_INTERIOR_PROGRESS_BAR = 16,\n DONUT_GRAPH = 17,\n BARS_GRAPH = 18,\n CLOCK = 19,\n COLOR_CLOUD = 20\n}\n\n// Base item properties. This interface should be extended by the item implementations.\nexport interface ItemProps extends Position, Size {\n readonly id: number;\n readonly type: ItemType;\n label: string | null;\n labelPosition: \"up\" | \"right\" | \"down\" | \"left\";\n isLinkEnabled: boolean;\n link: string | null;\n isOnTop: boolean;\n parentId: number | null;\n aclGroupId: number | null;\n}\n\n// FIXME: Fix type compatibility.\nexport interface ItemClickEvent {\n // data: Props;\n data: UnknownObject;\n nativeEvent: Event;\n}\n\n// FIXME: Fix type compatibility.\nexport interface ItemRemoveEvent {\n // data: Props;\n data: UnknownObject;\n}\n\n/**\n * Extract a valid enum value from a raw label positi9on value.\n * @param labelPosition Raw value.\n */\nconst parseLabelPosition = (\n labelPosition: unknown\n): ItemProps[\"labelPosition\"] => {\n switch (labelPosition) {\n case \"up\":\n case \"right\":\n case \"down\":\n case \"left\":\n return labelPosition;\n default:\n return \"down\";\n }\n};\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the item props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function itemBasePropsDecoder(data: UnknownObject): ItemProps | never {\n if (data.id == null || isNaN(parseInt(data.id))) {\n throw new TypeError(\"invalid id.\");\n }\n if (data.type == null || isNaN(parseInt(data.type))) {\n throw new TypeError(\"invalid type.\");\n }\n\n return {\n id: parseInt(data.id),\n type: parseInt(data.type),\n label: notEmptyStringOr(data.label, null),\n labelPosition: parseLabelPosition(data.labelPosition),\n isLinkEnabled: parseBoolean(data.isLinkEnabled),\n link: notEmptyStringOr(data.link, null),\n isOnTop: parseBoolean(data.isOnTop),\n parentId: parseIntOr(data.parentId, null),\n aclGroupId: parseIntOr(data.aclGroupId, null),\n ...sizePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n ...positionPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\n/**\n * Base class of the visual console items. Should be extended to use its capabilities.\n */\nabstract class VisualConsoleItem {\n // Properties of the item.\n private itemProps: Props;\n // Reference to the DOM element which will contain the item.\n public elementRef: HTMLElement;\n public readonly labelElementRef: HTMLElement;\n // Reference to the DOM element which will contain the view of the item which extends this class.\n protected readonly childElementRef: HTMLElement;\n // Event manager for click events.\n private readonly clickEventManager = new TypedEvent>();\n // Event manager for remove events.\n private readonly removeEventManager = new TypedEvent<\n ItemRemoveEvent\n >();\n // List of references to clean the event listeners.\n private readonly disposables: Disposable[] = [];\n\n /**\n * To create a new element which will be inside the item box.\n * @return Item.\n */\n protected abstract createDomElement(): HTMLElement;\n\n public constructor(props: Props) {\n this.itemProps = props;\n\n /*\n * Get a HTMLElement which represents the container box\n * of the Visual Console item. This element will manage\n * all the common things like click events, show a border\n * when hovered, etc.\n */\n this.elementRef = this.createContainerDomElement();\n this.labelElementRef = this.createLabelDomElement();\n\n /*\n * Get a HTMLElement which represents the custom view\n * of the Visual Console item. This element will be\n * different depending on the item implementation.\n */\n this.childElementRef = this.createDomElement();\n\n // Insert the elements into the container.\n this.elementRef.append(this.childElementRef, this.labelElementRef);\n\n // Resize element.\n this.resizeElement(props.width, props.height);\n // Set label position.\n this.changeLabelPosition(props.labelPosition);\n }\n\n /**\n * To create a new box for the visual console item.\n * @return Item box.\n */\n private createContainerDomElement(): HTMLElement {\n let box;\n if (this.props.isLinkEnabled) {\n box = document.createElement(\"a\");\n box as HTMLAnchorElement;\n if (this.props.link) box.href = this.props.link;\n } else {\n box = document.createElement(\"div\");\n box as HTMLDivElement;\n }\n\n box.className = \"visual-console-item\";\n box.style.zIndex = this.props.isOnTop ? \"2\" : \"1\";\n box.style.left = `${this.props.x}px`;\n box.style.top = `${this.props.y}px`;\n box.onclick = e =>\n this.clickEventManager.emit({ data: this.props, nativeEvent: e });\n\n return box;\n }\n\n /**\n * To create a new label for the visual console item.\n * @return Item label.\n */\n protected createLabelDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"visual-console-item-label\";\n // Add the label if it exists.\n const label = this.getLabelWithMacrosReplaced();\n if (label.length > 0) {\n // Ugly table we need to use to replicate the legacy style.\n const table = document.createElement(\"table\");\n const row = document.createElement(\"tr\");\n const emptyRow1 = document.createElement(\"tr\");\n const emptyRow2 = document.createElement(\"tr\");\n const cell = document.createElement(\"td\");\n\n cell.innerHTML = label;\n row.append(cell);\n table.append(emptyRow1, row, emptyRow2);\n table.style.textAlign = \"center\";\n\n // Change the table size depending on its position.\n switch (this.props.labelPosition) {\n case \"up\":\n case \"down\":\n if (this.props.width > 0) {\n table.style.width = `${this.props.width}px`;\n table.style.height = null;\n }\n break;\n case \"left\":\n case \"right\":\n if (this.props.height > 0) {\n table.style.width = null;\n table.style.height = `${this.props.height}px`;\n }\n break;\n }\n\n // element.innerHTML = this.props.label;\n element.append(table);\n }\n\n return element;\n }\n\n /**\n * Return the label stored into the props with some macros replaced.\n */\n protected getLabelWithMacrosReplaced(): string {\n // We assert that the props may have some needed properties.\n const props = this.props as Partial;\n\n return replaceMacros(\n [\n {\n macro: \"_date_\",\n value: humanDate(new Date())\n },\n {\n macro: \"_time_\",\n value: humanTime(new Date())\n },\n {\n macro: \"_agent_\",\n value: props.agentAlias != null ? props.agentAlias : \"\"\n },\n {\n macro: \"_agentdescription_\",\n value: props.agentDescription != null ? props.agentDescription : \"\"\n },\n {\n macro: \"_address_\",\n value: props.agentAddress != null ? props.agentAddress : \"\"\n },\n {\n macro: \"_module_\",\n value: props.moduleName != null ? props.moduleName : \"\"\n },\n {\n macro: \"_moduledescription_\",\n value: props.moduleDescription != null ? props.moduleDescription : \"\"\n }\n ],\n this.props.label || \"\"\n );\n }\n\n /**\n * To update the content element.\n * @return Item.\n */\n protected updateDomElement(element: HTMLElement): void {\n element.innerHTML = this.createDomElement().innerHTML;\n }\n\n /**\n * Public accessor of the `props` property.\n * @return Properties.\n */\n public get props(): Props {\n return { ...this.itemProps }; // Return a copy.\n }\n\n /**\n * Public setter of the `props` property.\n * If the new props are different enough than the\n * stored props, a render would be fired.\n * @param newProps\n */\n public set props(newProps: Props) {\n const prevProps = this.props;\n // Update the internal props.\n this.itemProps = newProps;\n\n // From this point, things which rely on this.props can access to the changes.\n\n // Check if we should re-render.\n if (this.shouldBeUpdated(prevProps, newProps)) this.render(prevProps);\n }\n\n /**\n * To compare the previous and the new props and returns a boolean value\n * in case the difference is meaningfull enough to perform DOM changes.\n *\n * Here, the only comparision is done by reference.\n *\n * Override this function to perform a different comparision depending on the item needs.\n *\n * @param prevProps\n * @param newProps\n * @return Whether the difference is meaningful enough to perform DOM changes or not.\n */\n protected shouldBeUpdated(prevProps: Props, newProps: Props): boolean {\n return prevProps !== newProps;\n }\n\n /**\n * To recreate or update the HTMLElement which represents the item into the DOM.\n * @param prevProps If exists it will be used to only perform DOM updates instead of a full replace.\n */\n public render(prevProps: Props | null = null): void {\n this.updateDomElement(this.childElementRef);\n\n // Move box.\n if (!prevProps || this.positionChanged(prevProps, this.props)) {\n this.moveElement(this.props.x, this.props.y);\n }\n // Resize box.\n if (!prevProps || this.sizeChanged(prevProps, this.props)) {\n this.resizeElement(this.props.width, this.props.height);\n }\n // Change label.\n const oldLabelHtml = this.labelElementRef.innerHTML;\n const newLabelHtml = this.createLabelDomElement().innerHTML;\n if (oldLabelHtml !== newLabelHtml) {\n this.labelElementRef.innerHTML = newLabelHtml;\n }\n // Change label position.\n if (!prevProps || prevProps.labelPosition !== this.props.labelPosition) {\n this.changeLabelPosition(this.props.labelPosition);\n }\n // Change link.\n if (\n prevProps &&\n (prevProps.isLinkEnabled !== this.props.isLinkEnabled ||\n (this.props.isLinkEnabled && prevProps.link !== this.props.link))\n ) {\n const container = this.createContainerDomElement();\n // Add the children of the old element.\n container.innerHTML = this.elementRef.innerHTML;\n // Copy the attributes.\n const attrs = this.elementRef.attributes;\n for (let i = 0; i < attrs.length; i++) {\n if (attrs[i].nodeName !== \"id\") {\n container.setAttributeNode(attrs[i]);\n }\n }\n // Replace the reference.\n if (this.elementRef.parentNode !== null) {\n this.elementRef.parentNode.replaceChild(container, this.elementRef);\n }\n\n // Changed the reference to the main element. It's ugly, but needed.\n this.elementRef = container;\n }\n }\n\n /**\n * To remove the event listeners and the elements from the DOM.\n */\n public remove(): void {\n // Call the remove event.\n this.removeEventManager.emit({ data: this.props });\n // Event listeners.\n this.disposables.forEach(disposable => {\n try {\n disposable.dispose();\n } catch (ignored) {} // eslint-disable-line no-empty\n });\n // VisualConsoleItem DOM element.\n this.elementRef.remove();\n }\n\n /**\n * Compare the previous and the new position and return\n * a boolean value in case the position changed.\n * @param prevPosition\n * @param newPosition\n * @return Whether the position changed or not.\n */\n protected positionChanged(\n prevPosition: Position,\n newPosition: Position\n ): boolean {\n return prevPosition.x !== newPosition.x || prevPosition.y !== newPosition.y;\n }\n\n /**\n * Move the label around the item content.\n * @param position Label position.\n */\n protected changeLabelPosition(position: Props[\"labelPosition\"]): void {\n switch (position) {\n case \"up\":\n this.elementRef.style.flexDirection = \"column-reverse\";\n break;\n case \"left\":\n this.elementRef.style.flexDirection = \"row-reverse\";\n break;\n case \"right\":\n this.elementRef.style.flexDirection = \"row\";\n break;\n case \"down\":\n default:\n this.elementRef.style.flexDirection = \"column\";\n break;\n }\n\n // Ugly table to show the label as its legacy counterpart.\n const tables = this.labelElementRef.getElementsByTagName(\"table\");\n const table = tables.length > 0 ? tables.item(0) : null;\n // Change the table size depending on its position.\n if (table) {\n switch (this.props.labelPosition) {\n case \"up\":\n case \"down\":\n if (this.props.width > 0) {\n table.style.width = `${this.props.width}px`;\n table.style.height = null;\n }\n break;\n case \"left\":\n case \"right\":\n if (this.props.height > 0) {\n table.style.width = null;\n table.style.height = `${this.props.height}px`;\n }\n break;\n }\n }\n }\n\n /**\n * Move the DOM container.\n * @param x Horizontal axis position.\n * @param y Vertical axis position.\n */\n protected moveElement(x: number, y: number): void {\n this.elementRef.style.left = `${x}px`;\n this.elementRef.style.top = `${y}px`;\n }\n\n /**\n * Update the position into the properties and move the DOM container.\n * @param x Horizontal axis position.\n * @param y Vertical axis position.\n */\n public move(x: number, y: number): void {\n this.moveElement(x, y);\n this.itemProps = {\n ...this.props, // Object spread: http://es6-features.org/#SpreadOperator\n x,\n y\n };\n }\n\n /**\n * Compare the previous and the new size and return\n * a boolean value in case the size changed.\n * @param prevSize\n * @param newSize\n * @return Whether the size changed or not.\n */\n protected sizeChanged(prevSize: Size, newSize: Size): boolean {\n return (\n prevSize.width !== newSize.width || prevSize.height !== newSize.height\n );\n }\n\n /**\n * Resize the DOM content container.\n * @param width\n * @param height\n */\n protected resizeElement(width: number, height: number): void {\n // The most valuable size is the content size.\n this.childElementRef.style.width = width > 0 ? `${width}px` : null;\n this.childElementRef.style.height = height > 0 ? `${height}px` : null;\n }\n\n /**\n * Update the size into the properties and resize the DOM container.\n * @param width\n * @param height\n */\n public resize(width: number, height: number): void {\n this.resizeElement(width, height);\n this.itemProps = {\n ...this.props, // Object spread: http://es6-features.org/#SpreadOperator\n width,\n height\n };\n }\n\n /**\n * To add an event handler to the click of the linked visual console elements.\n * @param listener Function which is going to be executed when a linked console is clicked.\n */\n public onClick(listener: Listener>): Disposable {\n /*\n * The '.on' function returns a function which will clean the event\n * listener when executed. We store all the 'dispose' functions to\n * call them when the item should be cleared.\n */\n const disposable = this.clickEventManager.on(listener);\n this.disposables.push(disposable);\n\n return disposable;\n }\n\n /**\n * To add an event handler to the removal of the item.\n * @param listener Function which is going to be executed when a item is removed.\n */\n public onRemove(listener: Listener>): Disposable {\n /*\n * The '.on' function returns a function which will clean the event\n * listener when executed. We store all the 'dispose' functions to\n * call them when the item should be cleared.\n */\n const disposable = this.removeEventManager.on(listener);\n this.disposables.push(disposable);\n\n return disposable;\n }\n}\n\nexport default VisualConsoleItem;\n","export interface Listener {\n (event: T): void;\n}\n\nexport interface Disposable {\n dispose: () => void;\n}\n\n/** passes through events as they happen. You will not get events from before you start listening */\nexport default class TypedEvent {\n private listeners: Listener[] = [];\n private listenersOncer: Listener[] = [];\n\n public on = (listener: Listener): Disposable => {\n this.listeners.push(listener);\n return {\n dispose: () => this.off(listener)\n };\n };\n\n public once = (listener: Listener): void => {\n this.listenersOncer.push(listener);\n };\n\n public off = (listener: Listener): void => {\n const callbackIndex = this.listeners.indexOf(listener);\n if (callbackIndex > -1) this.listeners.splice(callbackIndex, 1);\n };\n\n public emit = (event: T): void => {\n /** Update any general listeners */\n this.listeners.forEach(listener => listener(event));\n\n /** Clear the `once` queue */\n this.listenersOncer.forEach(listener => listener(event));\n this.listenersOncer = [];\n };\n\n public pipe = (te: TypedEvent): Disposable => this.on(e => te.emit(e));\n}\n","import { UnknownObject, WithModuleProps } from \"../types\";\nimport {\n modulePropsDecoder,\n parseIntOr,\n decodeBase64,\n stringIsEmpty\n} from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type EventsHistoryProps = {\n type: ItemType.AUTO_SLA_GRAPH;\n maxTime: number | null;\n html: string;\n} & ItemProps &\n WithModuleProps;\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the events history props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function eventsHistoryPropsDecoder(\n data: UnknownObject\n): EventsHistoryProps | never {\n if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {\n throw new TypeError(\"missing html content.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.AUTO_SLA_GRAPH,\n maxTime: parseIntOr(data.maxTime, null),\n html: !stringIsEmpty(data.html)\n ? data.html\n : decodeBase64(data.encodedHtml),\n ...modulePropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class EventsHistory extends Item {\n protected createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"events-history\";\n element.innerHTML = this.props.html;\n\n // Hack to execute the JS after the HTML is added to the DOM.\n const scripts = element.getElementsByTagName(\"script\");\n for (let i = 0; i < scripts.length; i++) {\n if (scripts[i].src.length === 0) {\n setTimeout(() => {\n try {\n eval(scripts[i].innerHTML.trim());\n } catch (ignored) {} // eslint-disable-line no-empty\n }, 0);\n }\n }\n\n return element;\n }\n\n protected updateDomElement(element: HTMLElement): void {\n element.innerHTML = this.props.html;\n\n // Hack to execute the JS after the HTML is added to the DOM.\n const aux = document.createElement(\"div\");\n aux.innerHTML = this.props.html;\n const scripts = aux.getElementsByTagName(\"script\");\n for (let i = 0; i < scripts.length; i++) {\n if (scripts[i].src.length === 0) {\n eval(scripts[i].innerHTML.trim());\n }\n }\n }\n}\n","import {\n LinkedVisualConsoleProps,\n UnknownObject,\n WithModuleProps\n} from \"../types\";\nimport {\n linkedVCPropsDecoder,\n modulePropsDecoder,\n decodeBase64,\n stringIsEmpty\n} from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type DonutGraphProps = {\n type: ItemType.DONUT_GRAPH;\n html: string;\n} & ItemProps &\n WithModuleProps &\n LinkedVisualConsoleProps;\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the donut graph props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function donutGraphPropsDecoder(\n data: UnknownObject\n): DonutGraphProps | never {\n if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {\n throw new TypeError(\"missing html content.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.DONUT_GRAPH,\n html: !stringIsEmpty(data.html)\n ? data.html\n : decodeBase64(data.encodedHtml),\n ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class DonutGraph extends Item {\n protected createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"donut-graph\";\n element.innerHTML = this.props.html;\n\n // Hack to execute the JS after the HTML is added to the DOM.\n const scripts = element.getElementsByTagName(\"script\");\n for (let i = 0; i < scripts.length; i++) {\n setTimeout(() => {\n if (scripts[i].src.length === 0) eval(scripts[i].innerHTML.trim());\n }, 0);\n }\n\n return element;\n }\n\n protected updateDomElement(element: HTMLElement): void {\n element.innerHTML = this.props.html;\n\n // Hack to execute the JS after the HTML is added to the DOM.\n const aux = document.createElement(\"div\");\n aux.innerHTML = this.props.html;\n const scripts = aux.getElementsByTagName(\"script\");\n for (let i = 0; i < scripts.length; i++) {\n if (scripts[i].src.length === 0) {\n eval(scripts[i].innerHTML.trim());\n }\n }\n }\n}\n","import { UnknownObject, WithModuleProps } from \"../types\";\nimport { modulePropsDecoder, decodeBase64, stringIsEmpty } from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type BarsGraphProps = {\n type: ItemType.BARS_GRAPH;\n html: string;\n} & ItemProps &\n WithModuleProps;\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the bars graph props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function barsGraphPropsDecoder(\n data: UnknownObject\n): BarsGraphProps | never {\n if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {\n throw new TypeError(\"missing html content.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.BARS_GRAPH,\n html: !stringIsEmpty(data.html)\n ? data.html\n : decodeBase64(data.encodedHtml),\n ...modulePropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class BarsGraph extends Item {\n protected createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"bars-graph\";\n element.innerHTML = this.props.html;\n\n // Hack to execute the JS after the HTML is added to the DOM.\n const scripts = element.getElementsByTagName(\"script\");\n for (let i = 0; i < scripts.length; i++) {\n setTimeout(() => {\n if (scripts[i].src.length === 0) eval(scripts[i].innerHTML.trim());\n }, 0);\n }\n\n return element;\n }\n\n protected updateDomElement(element: HTMLElement): void {\n element.innerHTML = this.props.html;\n\n // Hack to execute the JS after the HTML is added to the DOM.\n const aux = document.createElement(\"div\");\n aux.innerHTML = this.props.html;\n const scripts = aux.getElementsByTagName(\"script\");\n for (let i = 0; i < scripts.length; i++) {\n if (scripts[i].src.length === 0) {\n eval(scripts[i].innerHTML.trim());\n }\n }\n }\n}\n","import {\n LinkedVisualConsoleProps,\n UnknownObject,\n WithModuleProps\n} from \"../types\";\nimport {\n linkedVCPropsDecoder,\n modulePropsDecoder,\n decodeBase64,\n stringIsEmpty\n} from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type ModuleGraphProps = {\n type: ItemType.MODULE_GRAPH;\n html: string;\n} & ItemProps &\n WithModuleProps &\n LinkedVisualConsoleProps;\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the module graph props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function moduleGraphPropsDecoder(\n data: UnknownObject\n): ModuleGraphProps | never {\n if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {\n throw new TypeError(\"missing html content.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.MODULE_GRAPH,\n html: !stringIsEmpty(data.html)\n ? data.html\n : decodeBase64(data.encodedHtml),\n ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class ModuleGraph extends Item {\n /**\n * @override Item.resizeElement.\n * Resize the DOM content container.\n * We need to override the resize function cause this item's height\n * is larger than the configured and the graph is over the label.\n * @param width\n * @param height\n */\n protected resizeElement(width: number): void {\n super.resizeElement(width, 0);\n }\n\n protected createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"module-graph\";\n element.innerHTML = this.props.html;\n\n // Remove the overview graph.\n const legendP = element.getElementsByTagName(\"p\");\n for (let i = 0; i < legendP.length; i++) {\n legendP[i].style.margin = \"0px\";\n }\n\n // Remove the overview graph.\n const overviewGraphs = element.getElementsByClassName(\"overview_graph\");\n for (let i = 0; i < overviewGraphs.length; i++) {\n overviewGraphs[i].remove();\n }\n\n // Hack to execute the JS after the HTML is added to the DOM.\n const scripts = element.getElementsByTagName(\"script\");\n for (let i = 0; i < scripts.length; i++) {\n if (scripts[i].src.length === 0) {\n setTimeout(() => {\n try {\n eval(scripts[i].innerHTML.trim());\n } catch (ignored) {} // eslint-disable-line no-empty\n }, 0);\n }\n }\n\n return element;\n }\n\n protected updateDomElement(element: HTMLElement): void {\n element.innerHTML = this.props.html;\n\n // Remove the overview graph.\n const legendP = element.getElementsByTagName(\"p\");\n for (let i = 0; i < legendP.length; i++) {\n legendP[i].style.margin = \"0px\";\n }\n\n // Remove the overview graph.\n const overviewGraphs = element.getElementsByClassName(\"overview_graph\");\n for (let i = 0; i < overviewGraphs.length; i++) {\n overviewGraphs[i].remove();\n }\n\n // Hack to execute the JS after the HTML is added to the DOM.\n const aux = document.createElement(\"div\");\n aux.innerHTML = this.props.html;\n const scripts = aux.getElementsByTagName(\"script\");\n for (let i = 0; i < scripts.length; i++) {\n if (scripts[i].src.length === 0) {\n eval(scripts[i].innerHTML.trim());\n }\n }\n }\n}\n","import {\n WithModuleProps,\n LinkedVisualConsoleProps,\n UnknownObject\n} from \"../types\";\n\nimport {\n modulePropsDecoder,\n linkedVCPropsDecoder,\n notEmptyStringOr\n} from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type StaticGraphProps = {\n type: ItemType.STATIC_GRAPH;\n imageSrc: string; // URL?\n showLastValueTooltip: \"default\" | \"enabled\" | \"disabled\";\n statusImageSrc: string | null; // URL?\n lastValue: string | null;\n} & ItemProps &\n (WithModuleProps | LinkedVisualConsoleProps);\n\n/**\n * Extract a valid enum value from a raw unknown value.\n * @param showLastValueTooltip Raw value.\n */\nconst parseShowLastValueTooltip = (\n showLastValueTooltip: unknown\n): StaticGraphProps[\"showLastValueTooltip\"] => {\n switch (showLastValueTooltip) {\n case \"default\":\n case \"enabled\":\n case \"disabled\":\n return showLastValueTooltip;\n default:\n return \"default\";\n }\n};\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the static graph props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function staticGraphPropsDecoder(\n data: UnknownObject\n): StaticGraphProps | never {\n if (typeof data.imageSrc !== \"string\" || data.imageSrc.length === 0) {\n throw new TypeError(\"invalid image src.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.STATIC_GRAPH,\n imageSrc: data.imageSrc,\n showLastValueTooltip: parseShowLastValueTooltip(data.showLastValueTooltip),\n statusImageSrc: notEmptyStringOr(data.statusImageSrc, null),\n lastValue: notEmptyStringOr(data.lastValue, null),\n ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class StaticGraph extends Item {\n protected createDomElement(): HTMLElement {\n const imgSrc = this.props.statusImageSrc || this.props.imageSrc;\n const element = document.createElement(\"div\");\n element.className = \"static-graph\";\n element.style.background = `url(${imgSrc}) no-repeat`;\n element.style.backgroundSize = \"contain\";\n element.style.backgroundPosition = \"center\";\n\n // Show last value in a tooltip.\n if (\n this.props.lastValue !== null &&\n this.props.showLastValueTooltip !== \"disabled\"\n ) {\n element.className = \"static-graph image forced_title\";\n element.setAttribute(\"data-use_title_for_force_title\", \"1\");\n element.setAttribute(\"data-title\", this.props.lastValue);\n }\n\n return element;\n }\n}\n","import { LinkedVisualConsoleProps, UnknownObject } from \"../types\";\nimport { linkedVCPropsDecoder } from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type IconProps = {\n type: ItemType.ICON;\n imageSrc: string; // URL?\n} & ItemProps &\n LinkedVisualConsoleProps;\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the icon props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function iconPropsDecoder(data: UnknownObject): IconProps | never {\n if (typeof data.imageSrc !== \"string\" || data.imageSrc.length === 0) {\n throw new TypeError(\"invalid image src.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.ICON,\n imageSrc: data.imageSrc,\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class Icon extends Item {\n protected createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"icon\";\n element.style.background = `url(${this.props.imageSrc}) no-repeat`;\n element.style.backgroundSize = \"contain\";\n element.style.backgroundPosition = \"center\";\n\n return element;\n }\n}\n","import {\n WithModuleProps,\n LinkedVisualConsoleProps,\n UnknownObject\n} from \"../types\";\nimport { modulePropsDecoder, linkedVCPropsDecoder } from \"../lib\";\nimport Item, { itemBasePropsDecoder, ItemType, ItemProps } from \"../Item\";\n\nexport type ColorCloudProps = {\n type: ItemType.COLOR_CLOUD;\n color: string;\n // TODO: Add the rest of the color cloud values?\n} & ItemProps &\n WithModuleProps &\n LinkedVisualConsoleProps;\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the static graph props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function colorCloudPropsDecoder(\n data: UnknownObject\n): ColorCloudProps | never {\n // TODO: Validate the color.\n if (typeof data.color !== \"string\" || data.color.length === 0) {\n throw new TypeError(\"invalid color.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.COLOR_CLOUD,\n color: data.color,\n ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nconst svgNS = \"http://www.w3.org/2000/svg\";\n\nexport default class ColorCloud extends Item {\n protected createDomElement(): HTMLElement {\n const container: HTMLDivElement = document.createElement(\"div\");\n container.className = \"color-cloud\";\n\n // Add the SVG.\n container.append(this.createSvgElement());\n\n return container;\n }\n\n public createSvgElement(): SVGSVGElement {\n const gradientId = `grad_${this.props.id}`;\n // SVG container.\n const svg = document.createElementNS(svgNS, \"svg\");\n // Auto resize SVG using the view box magic: https://css-tricks.com/scale-svg/\n svg.setAttribute(\"viewBox\", \"0 0 100 100\");\n\n // Defs.\n const defs = document.createElementNS(svgNS, \"defs\");\n // Radial gradient.\n const radialGradient = document.createElementNS(svgNS, \"radialGradient\");\n radialGradient.setAttribute(\"id\", gradientId);\n radialGradient.setAttribute(\"cx\", \"50%\");\n radialGradient.setAttribute(\"cy\", \"50%\");\n radialGradient.setAttribute(\"r\", \"50%\");\n radialGradient.setAttribute(\"fx\", \"50%\");\n radialGradient.setAttribute(\"fy\", \"50%\");\n // Stops.\n const stop0 = document.createElementNS(svgNS, \"stop\");\n stop0.setAttribute(\"offset\", \"0%\");\n stop0.setAttribute(\n \"style\",\n `stop-color:${this.props.color};stop-opacity:0.9`\n );\n const stop100 = document.createElementNS(svgNS, \"stop\");\n stop100.setAttribute(\"offset\", \"100%\");\n stop100.setAttribute(\n \"style\",\n `stop-color:${this.props.color};stop-opacity:0`\n );\n // Circle.\n const circle = document.createElementNS(svgNS, \"circle\");\n circle.setAttribute(\"fill\", `url(#${gradientId})`);\n circle.setAttribute(\"cx\", \"50%\");\n circle.setAttribute(\"cy\", \"50%\");\n circle.setAttribute(\"r\", \"50%\");\n\n // Append elements.\n radialGradient.append(stop0, stop100);\n defs.append(radialGradient);\n svg.append(defs, circle);\n\n return svg;\n }\n}\n","import { LinkedVisualConsoleProps, UnknownObject } from \"../types\";\nimport {\n linkedVCPropsDecoder,\n parseIntOr,\n notEmptyStringOr,\n stringIsEmpty,\n decodeBase64,\n parseBoolean\n} from \"../lib\";\nimport Item, { ItemProps, itemBasePropsDecoder, ItemType } from \"../Item\";\n\nexport type GroupProps = {\n type: ItemType.GROUP_ITEM;\n groupId: number;\n imageSrc: string | null; // URL?\n statusImageSrc: string | null;\n showStatistics: boolean;\n html?: string | null;\n} & ItemProps &\n LinkedVisualConsoleProps;\n\nfunction extractHtml(data: UnknownObject): string | null {\n if (!stringIsEmpty(data.html)) return data.html;\n if (!stringIsEmpty(data.encodedHtml)) return decodeBase64(data.encodedHtml);\n return null;\n}\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the group props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function groupPropsDecoder(data: UnknownObject): GroupProps | never {\n if (\n (typeof data.imageSrc !== \"string\" || data.imageSrc.length === 0) &&\n data.encodedHtml === null\n ) {\n throw new TypeError(\"invalid image src.\");\n }\n if (parseIntOr(data.groupId, null) === null) {\n throw new TypeError(\"invalid group Id.\");\n }\n\n const showStatistics = parseBoolean(data.showStatistics);\n const html = showStatistics ? extractHtml(data) : null;\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.GROUP_ITEM,\n groupId: parseInt(data.groupId),\n imageSrc: notEmptyStringOr(data.imageSrc, null),\n statusImageSrc: notEmptyStringOr(data.statusImageSrc, null),\n showStatistics,\n html,\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class Group extends Item {\n protected createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"group\";\n\n if (!this.props.showStatistics && this.props.statusImageSrc !== null) {\n // Icon with status.\n element.style.background = `url(${this.props.statusImageSrc}) no-repeat`;\n element.style.backgroundSize = \"contain\";\n element.style.backgroundPosition = \"center\";\n } else if (this.props.showStatistics && this.props.html != null) {\n // Stats table.\n element.innerHTML = this.props.html;\n }\n\n return element;\n }\n}\n","import \"./styles.css\";\n\nimport { LinkedVisualConsoleProps, UnknownObject, Size } from \"../../types\";\nimport {\n linkedVCPropsDecoder,\n parseIntOr,\n parseBoolean,\n prefixedCssRules,\n notEmptyStringOr,\n humanDate,\n humanTime\n} from \"../../lib\";\nimport Item, { ItemProps, itemBasePropsDecoder, ItemType } from \"../../Item\";\n\nexport type ClockProps = {\n type: ItemType.CLOCK;\n clockType: \"analogic\" | \"digital\";\n clockFormat: \"datetime\" | \"time\";\n clockTimezone: string;\n clockTimezoneOffset: number; // Offset of the timezone to UTC in seconds.\n showClockTimezone: boolean;\n color?: string | null;\n} & ItemProps &\n LinkedVisualConsoleProps;\n\n/**\n * Extract a valid enum value from a raw unknown value.\n * @param clockType Raw value.\n */\nconst parseClockType = (clockType: unknown): ClockProps[\"clockType\"] => {\n switch (clockType) {\n case \"analogic\":\n case \"digital\":\n return clockType;\n default:\n return \"analogic\";\n }\n};\n\n/**\n * Extract a valid enum value from a raw unknown value.\n * @param clockFormat Raw value.\n */\nconst parseClockFormat = (clockFormat: unknown): ClockProps[\"clockFormat\"] => {\n switch (clockFormat) {\n case \"datetime\":\n case \"time\":\n return clockFormat;\n default:\n return \"datetime\";\n }\n};\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the clock props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function clockPropsDecoder(data: UnknownObject): ClockProps | never {\n if (\n typeof data.clockTimezone !== \"string\" ||\n data.clockTimezone.length === 0\n ) {\n throw new TypeError(\"invalid timezone.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.CLOCK,\n clockType: parseClockType(data.clockType),\n clockFormat: parseClockFormat(data.clockFormat),\n clockTimezone: data.clockTimezone,\n clockTimezoneOffset: parseIntOr(data.clockTimezoneOffset, 0),\n showClockTimezone: parseBoolean(data.showClockTimezone),\n color: notEmptyStringOr(data.color, null),\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class Clock extends Item {\n public static readonly TICK_INTERVAL = 1000; // In ms.\n private intervalRef: number | null = null;\n\n public constructor(props: ClockProps) {\n // Call the superclass constructor.\n super(props);\n\n /* The item is already loaded and inserted into the DOM.\n * The class properties are now initialized.\n * Now you can modify the item, add event handlers, timers, etc.\n */\n\n /* The use of the arrow function is important here. startTick will\n * use the function passed as an argument to call the global setInterval\n * function. The interval, timeout or event functions, among other, are\n * called into another execution loop and using a different context.\n * The arrow functions, unlike the classic functions, doesn't create\n * their own context (this), so their context at execution time will be\n * use the current context at the declaration time.\n * http://es6-features.org/#Lexicalthis\n */\n this.startTick(\n () => {\n // Replace the old element with the updated date.\n this.childElementRef.innerHTML = this.createClock().innerHTML;\n },\n /* The analogic clock doesn't need to tick,\n * but it will be refreshed every 20 seconds\n * to avoid a desync caused by page freezes.\n */\n this.props.clockType === \"analogic\" ? 20000 : Clock.TICK_INTERVAL\n );\n }\n\n /**\n * Wrap a window.clearInterval call.\n */\n private stopTick(): void {\n if (this.intervalRef !== null) {\n window.clearInterval(this.intervalRef);\n this.intervalRef = null;\n }\n }\n\n /**\n * Wrap a window.setInterval call.\n * @param handler Function to be called every time the interval\n * timer is reached.\n * @param interval Number in milliseconds for the interval timer.\n */\n private startTick(\n handler: TimerHandler,\n interval: number = Clock.TICK_INTERVAL\n ): void {\n this.stopTick();\n this.intervalRef = window.setInterval(handler, interval);\n }\n\n /**\n * Create a element which contains the DOM representation of the item.\n * @return DOM Element.\n * @override\n */\n protected createDomElement(): HTMLElement | never {\n return this.createClock();\n }\n\n /**\n * To remove the event listeners and the elements from the DOM.\n * @override\n */\n public remove(): void {\n // Clear the interval.\n this.stopTick();\n // Call to the parent clean function.\n super.remove();\n }\n\n /**\n * @override Item.resizeElement\n * Resize the DOM content container.\n * @param width\n * @param height\n */\n protected resizeElement(width: number, height: number): void {\n const { width: newWidth, height: newHeight } = this.getElementSize(\n width,\n height\n ); // Destructuring assigment: http://es6-features.org/#ObjectMatchingShorthandNotation\n super.resizeElement(newWidth, newHeight);\n // Re-render the item to force it calculate a new font size.\n if (this.props.clockType === \"digital\") {\n // Replace the old element with the updated date.\n this.childElementRef.innerHTML = this.createClock().innerHTML;\n }\n }\n\n /**\n * Create a element which contains a representation of a clock.\n * It choose between the clock types.\n * @return DOM Element.\n * @throws Error.\n */\n private createClock(): HTMLElement | never {\n switch (this.props.clockType) {\n case \"analogic\":\n return this.createAnalogicClock();\n case \"digital\":\n return this.createDigitalClock();\n default:\n throw new Error(\"invalid clock type.\");\n }\n }\n\n /**\n * Create a element which contains a representation of an analogic clock.\n * @return DOM Element.\n */\n private createAnalogicClock(): HTMLElement {\n const svgNS = \"http://www.w3.org/2000/svg\";\n const colors = {\n watchFace: \"#FFFFF0\",\n watchFaceBorder: \"#242124\",\n mark: \"#242124\",\n handDark: \"#242124\",\n handLight: \"#525252\",\n secondHand: \"#DC143C\"\n };\n\n const { width, height } = this.getElementSize(); // Destructuring assigment: http://es6-features.org/#ObjectMatchingShorthandNotation\n\n // Calculate font size to adapt the font to the item size.\n const baseTimeFontSize = 20; // Per 100px of width.\n const dateFontSizeMultiplier = 0.5;\n const dateFontSize =\n (baseTimeFontSize * dateFontSizeMultiplier * width) / 100;\n\n const div = document.createElement(\"div\");\n div.className = \"analogic-clock\";\n div.style.width = `${width}px`;\n div.style.height = `${height}px`;\n\n // SVG container.\n const svg = document.createElementNS(svgNS, \"svg\");\n // Auto resize SVG using the view box magic: https://css-tricks.com/scale-svg/\n svg.setAttribute(\"viewBox\", \"0 0 100 100\");\n\n // Clock face.\n const clockFace = document.createElementNS(svgNS, \"g\");\n clockFace.setAttribute(\"class\", \"clockface\");\n const clockFaceBackground = document.createElementNS(svgNS, \"circle\");\n clockFaceBackground.setAttribute(\"cx\", \"50\");\n clockFaceBackground.setAttribute(\"cy\", \"50\");\n clockFaceBackground.setAttribute(\"r\", \"48\");\n clockFaceBackground.setAttribute(\"fill\", colors.watchFace);\n clockFaceBackground.setAttribute(\"stroke\", colors.watchFaceBorder);\n clockFaceBackground.setAttribute(\"stroke-width\", \"2\");\n clockFaceBackground.setAttribute(\"stroke-linecap\", \"round\");\n // Insert the clockface background into the clockface group.\n clockFace.append(clockFaceBackground);\n\n // Timezone complication.\n const city = this.getHumanTimezone();\n if (city.length > 0) {\n const timezoneComplication = document.createElementNS(svgNS, \"text\");\n timezoneComplication.setAttribute(\"text-anchor\", \"middle\");\n timezoneComplication.setAttribute(\"font-size\", \"8\");\n timezoneComplication.setAttribute(\n \"transform\",\n \"translate(30 50) rotate(90)\" // Rotate to counter the clock rotation.\n );\n timezoneComplication.setAttribute(\"fill\", colors.mark);\n timezoneComplication.textContent = city;\n clockFace.append(timezoneComplication);\n }\n\n // Marks group.\n const marksGroup = document.createElementNS(svgNS, \"g\");\n marksGroup.setAttribute(\"class\", \"marks\");\n // Build the 12 hours mark.\n const mainMarkGroup = document.createElementNS(svgNS, \"g\");\n mainMarkGroup.setAttribute(\"class\", \"mark\");\n mainMarkGroup.setAttribute(\"transform\", \"translate(50 50)\");\n const mark1a = document.createElementNS(svgNS, \"line\");\n mark1a.setAttribute(\"x1\", \"36\");\n mark1a.setAttribute(\"y1\", \"0\");\n mark1a.setAttribute(\"x2\", \"46\");\n mark1a.setAttribute(\"y2\", \"0\");\n mark1a.setAttribute(\"stroke\", colors.mark);\n mark1a.setAttribute(\"stroke-width\", \"5\");\n const mark1b = document.createElementNS(svgNS, \"line\");\n mark1b.setAttribute(\"x1\", \"36\");\n mark1b.setAttribute(\"y1\", \"0\");\n mark1b.setAttribute(\"x2\", \"46\");\n mark1b.setAttribute(\"y2\", \"0\");\n mark1b.setAttribute(\"stroke\", colors.watchFace);\n mark1b.setAttribute(\"stroke-width\", \"1\");\n // Insert the 12 mark lines into their group.\n mainMarkGroup.append(mark1a, mark1b);\n // Insert the main mark into the marks group.\n marksGroup.append(mainMarkGroup);\n // Build the rest of the marks.\n for (let i = 1; i < 60; i++) {\n const mark = document.createElementNS(svgNS, \"line\");\n mark.setAttribute(\"y1\", \"0\");\n mark.setAttribute(\"y2\", \"0\");\n mark.setAttribute(\"stroke\", colors.mark);\n mark.setAttribute(\"transform\", `translate(50 50) rotate(${i * 6})`);\n\n if (i % 5 === 0) {\n mark.setAttribute(\"x1\", \"38\");\n mark.setAttribute(\"x2\", \"46\");\n mark.setAttribute(\"stroke-width\", i % 15 === 0 ? \"2\" : \"1\");\n } else {\n mark.setAttribute(\"x1\", \"42\");\n mark.setAttribute(\"x2\", \"46\");\n mark.setAttribute(\"stroke-width\", \"0.5\");\n }\n\n // Insert the mark into the marks group.\n marksGroup.append(mark);\n }\n\n /* Clock hands */\n\n // Hour hand.\n const hourHand = document.createElementNS(svgNS, \"g\");\n hourHand.setAttribute(\"class\", \"hour-hand\");\n hourHand.setAttribute(\"transform\", \"translate(50 50)\");\n // This will go back and will act like a border.\n const hourHandA = document.createElementNS(svgNS, \"line\");\n hourHandA.setAttribute(\"class\", \"hour-hand-a\");\n hourHandA.setAttribute(\"x1\", \"0\");\n hourHandA.setAttribute(\"y1\", \"0\");\n hourHandA.setAttribute(\"x2\", \"30\");\n hourHandA.setAttribute(\"y2\", \"0\");\n hourHandA.setAttribute(\"stroke\", colors.handLight);\n hourHandA.setAttribute(\"stroke-width\", \"4\");\n hourHandA.setAttribute(\"stroke-linecap\", \"round\");\n // This will go in front of the previous line.\n const hourHandB = document.createElementNS(svgNS, \"line\");\n hourHandB.setAttribute(\"class\", \"hour-hand-b\");\n hourHandB.setAttribute(\"x1\", \"0\");\n hourHandB.setAttribute(\"y1\", \"0\");\n hourHandB.setAttribute(\"x2\", \"29.9\");\n hourHandB.setAttribute(\"y2\", \"0\");\n hourHandB.setAttribute(\"stroke\", colors.handDark);\n hourHandB.setAttribute(\"stroke-width\", \"3.1\");\n hourHandB.setAttribute(\"stroke-linecap\", \"round\");\n // Append the elements to finish the hour hand.\n hourHand.append(hourHandA, hourHandB);\n\n // Minute hand.\n const minuteHand = document.createElementNS(svgNS, \"g\");\n minuteHand.setAttribute(\"class\", \"minute-hand\");\n minuteHand.setAttribute(\"transform\", \"translate(50 50)\");\n // This will go back and will act like a border.\n const minuteHandA = document.createElementNS(svgNS, \"line\");\n minuteHandA.setAttribute(\"class\", \"minute-hand-a\");\n minuteHandA.setAttribute(\"x1\", \"0\");\n minuteHandA.setAttribute(\"y1\", \"0\");\n minuteHandA.setAttribute(\"x2\", \"40\");\n minuteHandA.setAttribute(\"y2\", \"0\");\n minuteHandA.setAttribute(\"stroke\", colors.handLight);\n minuteHandA.setAttribute(\"stroke-width\", \"2\");\n minuteHandA.setAttribute(\"stroke-linecap\", \"round\");\n // This will go in front of the previous line.\n const minuteHandB = document.createElementNS(svgNS, \"line\");\n minuteHandB.setAttribute(\"class\", \"minute-hand-b\");\n minuteHandB.setAttribute(\"x1\", \"0\");\n minuteHandB.setAttribute(\"y1\", \"0\");\n minuteHandB.setAttribute(\"x2\", \"39.9\");\n minuteHandB.setAttribute(\"y2\", \"0\");\n minuteHandB.setAttribute(\"stroke\", colors.handDark);\n minuteHandB.setAttribute(\"stroke-width\", \"1.5\");\n minuteHandB.setAttribute(\"stroke-linecap\", \"round\");\n const minuteHandPin = document.createElementNS(svgNS, \"circle\");\n minuteHandPin.setAttribute(\"r\", \"3\");\n minuteHandPin.setAttribute(\"fill\", colors.handDark);\n // Append the elements to finish the minute hand.\n minuteHand.append(minuteHandA, minuteHandB, minuteHandPin);\n\n // Second hand.\n const secondHand = document.createElementNS(svgNS, \"g\");\n secondHand.setAttribute(\"class\", \"second-hand\");\n secondHand.setAttribute(\"transform\", \"translate(50 50)\");\n const secondHandBar = document.createElementNS(svgNS, \"line\");\n secondHandBar.setAttribute(\"x1\", \"0\");\n secondHandBar.setAttribute(\"y1\", \"0\");\n secondHandBar.setAttribute(\"x2\", \"46\");\n secondHandBar.setAttribute(\"y2\", \"0\");\n secondHandBar.setAttribute(\"stroke\", colors.secondHand);\n secondHandBar.setAttribute(\"stroke-width\", \"1\");\n secondHandBar.setAttribute(\"stroke-linecap\", \"round\");\n const secondHandPin = document.createElementNS(svgNS, \"circle\");\n secondHandPin.setAttribute(\"r\", \"2\");\n secondHandPin.setAttribute(\"fill\", colors.secondHand);\n // Append the elements to finish the second hand.\n secondHand.append(secondHandBar, secondHandPin);\n\n // Pin.\n const pin = document.createElementNS(svgNS, \"circle\");\n pin.setAttribute(\"cx\", \"50\");\n pin.setAttribute(\"cy\", \"50\");\n pin.setAttribute(\"r\", \"0.3\");\n pin.setAttribute(\"fill\", colors.handDark);\n\n // Get the hand angles.\n const date = this.getOriginDate();\n const seconds = date.getSeconds();\n const minutes = date.getMinutes();\n const hours = date.getHours();\n const secAngle = (360 / 60) * seconds;\n const minuteAngle = (360 / 60) * minutes + (360 / 60) * (seconds / 60);\n const hourAngle = (360 / 12) * hours + (360 / 12) * (minutes / 60);\n // Set the clock time by moving the hands.\n hourHand.setAttribute(\"transform\", `translate(50 50) rotate(${hourAngle})`);\n minuteHand.setAttribute(\n \"transform\",\n `translate(50 50) rotate(${minuteAngle})`\n );\n secondHand.setAttribute(\n \"transform\",\n `translate(50 50) rotate(${secAngle})`\n );\n\n // Build the clock\n svg.append(clockFace, marksGroup, hourHand, minuteHand, secondHand, pin);\n // Rotate the clock to its normal position.\n svg.setAttribute(\"transform\", \"rotate(-90)\");\n\n /* Add the animation declaration to the container.\n * Since the animation keyframes need to know the\n * start angle, this angle is dynamic (current time),\n * and we can't edit keyframes through javascript\n * safely and with backwards compatibility, we need\n * to inject it.\n */\n div.innerHTML = `\n \n `;\n // Add the clock to the container\n div.append(svg);\n\n // Date.\n if (this.props.clockFormat === \"datetime\") {\n const dateElem: HTMLSpanElement = document.createElement(\"span\");\n dateElem.className = \"date\";\n dateElem.textContent = humanDate(date, \"default\");\n dateElem.style.fontSize = `${dateFontSize}px`;\n if (this.props.color) dateElem.style.color = this.props.color;\n div.append(dateElem);\n }\n\n return div;\n }\n\n /**\n * Create a element which contains a representation of a digital clock.\n * @return DOM Element.\n */\n private createDigitalClock(): HTMLElement {\n const element: HTMLDivElement = document.createElement(\"div\");\n element.className = \"digital-clock\";\n\n const { width } = this.getElementSize(); // Destructuring assigment: http://es6-features.org/#ObjectMatchingShorthandNotation\n\n // Calculate font size to adapt the font to the item size.\n const baseTimeFontSize = 20; // Per 100px of width.\n const dateFontSizeMultiplier = 0.5;\n const tzFontSizeMultiplier = 6 / this.props.clockTimezone.length;\n const timeFontSize = (baseTimeFontSize * width) / 100;\n const dateFontSize =\n (baseTimeFontSize * dateFontSizeMultiplier * width) / 100;\n const tzFontSize = Math.min(\n (baseTimeFontSize * tzFontSizeMultiplier * width) / 100,\n (width / 100) * 10\n );\n\n // Date calculated using the original timezone.\n const date = this.getOriginDate();\n\n // Date.\n if (this.props.clockFormat === \"datetime\") {\n const dateElem: HTMLSpanElement = document.createElement(\"span\");\n dateElem.className = \"date\";\n dateElem.textContent = humanDate(date, \"default\");\n dateElem.style.fontSize = `${dateFontSize}px`;\n if (this.props.color) dateElem.style.color = this.props.color;\n element.append(dateElem);\n }\n\n // Time.\n const timeElem: HTMLSpanElement = document.createElement(\"span\");\n timeElem.className = \"time\";\n timeElem.textContent = humanTime(date);\n timeElem.style.fontSize = `${timeFontSize}px`;\n if (this.props.color) timeElem.style.color = this.props.color;\n element.append(timeElem);\n\n // City name.\n const city = this.getHumanTimezone();\n if (city.length > 0) {\n const tzElem: HTMLSpanElement = document.createElement(\"span\");\n tzElem.className = \"timezone\";\n tzElem.textContent = city;\n tzElem.style.fontSize = `${tzFontSize}px`;\n if (this.props.color) tzElem.style.color = this.props.color;\n element.append(tzElem);\n }\n\n return element;\n }\n\n /**\n * Generate the current date using the timezone offset stored into the properties.\n * @return The current date.\n */\n private getOriginDate(initialDate: Date | null = null): Date {\n const d = initialDate ? initialDate : new Date();\n const targetTZOffset = this.props.clockTimezoneOffset * 1000; // In ms.\n const localTZOffset = d.getTimezoneOffset() * 60 * 1000; // In ms.\n const utimestamp = d.getTime() + targetTZOffset + localTZOffset;\n\n return new Date(utimestamp);\n }\n\n /**\n * Extract a human readable city name from the timezone text.\n * @param timezone Timezone text.\n */\n public getHumanTimezone(timezone: string = this.props.clockTimezone): string {\n const [, city = \"\"] = timezone.split(\"/\");\n return city.replace(\"_\", \" \");\n }\n\n /**\n * Generate a element size using the current size and the default values.\n * @return The size.\n */\n private getElementSize(\n width: number = this.props.width,\n height: number = this.props.height\n ): Size {\n switch (this.props.clockType) {\n case \"analogic\": {\n let diameter = 100; // Default value.\n\n if (width > 0 && height > 0) {\n diameter = Math.min(width, height);\n } else if (width > 0) {\n diameter = width;\n } else if (height > 0) {\n diameter = height;\n }\n\n return {\n width: diameter,\n height: diameter\n };\n }\n case \"digital\": {\n if (width > 0 && height > 0) {\n // The proportion of the clock should be (width = height / 2) aproximately.\n height = width / 2 < height ? width / 2 : height;\n } else if (width > 0) {\n height = width / 2;\n } else if (height > 0) {\n // The proportion of the clock should be (height * 2 = width) aproximately.\n width = height * 2;\n } else {\n width = 100; // Default value.\n height = 50; // Default value.\n }\n\n return {\n width,\n height\n };\n }\n default:\n throw new Error(\"invalid clock type.\");\n }\n }\n}\n","import { UnknownObject } from \"../types\";\nimport { parseIntOr, notEmptyStringOr } from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\ninterface BoxProps extends ItemProps {\n // Overrided properties.\n readonly type: ItemType.BOX_ITEM;\n label: null;\n isLinkEnabled: false;\n parentId: null;\n aclGroupId: null;\n // Custom properties.\n borderWidth: number;\n borderColor: string | null;\n fillColor: string | null;\n}\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the item props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function boxPropsDecoder(data: UnknownObject): BoxProps | never {\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.BOX_ITEM,\n label: null,\n isLinkEnabled: false,\n parentId: null,\n aclGroupId: null,\n // Custom properties.\n borderWidth: parseIntOr(data.borderWidth, 0),\n borderColor: notEmptyStringOr(data.borderColor, null),\n fillColor: notEmptyStringOr(data.fillColor, null)\n };\n}\n\nexport default class Box extends Item {\n protected createDomElement(): HTMLElement {\n const box: HTMLDivElement = document.createElement(\"div\");\n box.className = \"box\";\n // To prevent this item to expand beyond its parent.\n box.style.boxSizing = \"border-box\";\n\n if (this.props.fillColor) {\n box.style.backgroundColor = this.props.fillColor;\n }\n\n // Border.\n if (this.props.borderWidth > 0) {\n box.style.borderStyle = \"solid\";\n // Control the max width to prevent this item to expand beyond its parent.\n const maxBorderWidth = Math.min(this.props.width, this.props.height) / 2;\n const borderWidth = Math.min(this.props.borderWidth, maxBorderWidth);\n box.style.borderWidth = `${borderWidth}px`;\n\n if (this.props.borderColor) {\n box.style.borderColor = this.props.borderColor;\n }\n }\n\n return box;\n }\n}\n","import { UnknownObject, Position, Size } from \"../types\";\nimport { parseIntOr, notEmptyStringOr } from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\ninterface LineProps extends ItemProps {\n // Overrided properties.\n readonly type: ItemType.LINE_ITEM;\n label: null;\n isLinkEnabled: false;\n parentId: null;\n aclGroupId: null;\n // Custom properties.\n startPosition: Position;\n endPosition: Position;\n lineWidth: number;\n color: string | null;\n}\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the item props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function linePropsDecoder(data: UnknownObject): LineProps | never {\n const props: LineProps = {\n ...itemBasePropsDecoder({ ...data, width: 1, height: 1 }), // Object spread. It will merge the properties of the two objects.\n type: ItemType.LINE_ITEM,\n label: null,\n isLinkEnabled: false,\n parentId: null,\n aclGroupId: null,\n // Initialize Position & Size.\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n // Custom properties.\n startPosition: {\n x: parseIntOr(data.startX, 0),\n y: parseIntOr(data.startY, 0)\n },\n endPosition: {\n x: parseIntOr(data.endX, 0),\n y: parseIntOr(data.endY, 0)\n },\n lineWidth: parseIntOr(data.lineWidth || data.borderWidth, 1),\n color: notEmptyStringOr(data.borderColor || data.color, null)\n };\n\n /*\n * We need to enhance the props with the extracted size and position\n * of the box cause there are missing at the props update. A better\n * solution would be overriding the props setter to do it there, but\n * the language doesn't allow it while targetting ES5.\n * TODO: We need to figure out a more consistent solution.\n */\n\n return {\n ...props,\n // Enhance the props extracting the box size and position.\n // eslint-disable-next-line @typescript-eslint/no-use-before-define\n ...Line.extractBoxSizeAndPosition(props)\n };\n}\n\nexport default class Line extends Item {\n /**\n * @override\n */\n public constructor(props: LineProps) {\n /*\n * We need to override the constructor cause we need to obtain\n * the\n * box size and position from the start and finish points\n * of the line.\n */\n super({\n ...props,\n ...Line.extractBoxSizeAndPosition(props)\n });\n }\n\n /**\n * @override\n * To create the item's DOM representation.\n * @return Item.\n */\n protected createDomElement(): HTMLElement {\n const element: HTMLDivElement = document.createElement(\"div\");\n element.className = \"line\";\n\n const svgNS = \"http://www.w3.org/2000/svg\";\n // SVG container.\n const svg = document.createElementNS(svgNS, \"svg\");\n // Set SVG size.\n svg.setAttribute(\n \"width\",\n (this.props.width + this.props.lineWidth).toString()\n );\n svg.setAttribute(\n \"height\",\n (this.props.height + this.props.lineWidth).toString()\n );\n const line = document.createElementNS(svgNS, \"line\");\n line.setAttribute(\n \"x1\",\n `${this.props.startPosition.x - this.props.x + this.props.lineWidth / 2}`\n );\n line.setAttribute(\n \"y1\",\n `${this.props.startPosition.y - this.props.y + this.props.lineWidth / 2}`\n );\n line.setAttribute(\n \"x2\",\n `${this.props.endPosition.x - this.props.x + this.props.lineWidth / 2}`\n );\n line.setAttribute(\n \"y2\",\n `${this.props.endPosition.y - this.props.y + this.props.lineWidth / 2}`\n );\n line.setAttribute(\"stroke\", this.props.color || \"black\");\n line.setAttribute(\"stroke-width\", this.props.lineWidth.toString());\n\n svg.append(line);\n element.append(svg);\n\n return element;\n }\n\n /**\n * Extract the size and position of the box from\n * the start and the finish of the line.\n * @param props Item properties.\n */\n public static extractBoxSizeAndPosition(props: LineProps): Size & Position {\n return {\n width: Math.abs(props.startPosition.x - props.endPosition.x),\n height: Math.abs(props.startPosition.y - props.endPosition.y),\n x: Math.min(props.startPosition.x, props.endPosition.x),\n y: Math.min(props.startPosition.y, props.endPosition.y)\n };\n }\n}\n","import { LinkedVisualConsoleProps, UnknownObject } from \"../types\";\nimport { linkedVCPropsDecoder } from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type LabelProps = {\n type: ItemType.LABEL;\n} & ItemProps &\n LinkedVisualConsoleProps;\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the label props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function labelPropsDecoder(data: UnknownObject): LabelProps | never {\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.LABEL,\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class Label extends Item {\n protected createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"label\";\n element.innerHTML = this.getLabelWithMacrosReplaced();\n\n return element;\n }\n\n /**\n * @override Item.createLabelDomElement\n * Create a new label for the visual console item.\n * @return Item label.\n */\n public createLabelDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"visual-console-item-label\";\n // Always return an empty label.\n return element;\n }\n}\n","import {\n LinkedVisualConsoleProps,\n UnknownObject,\n WithModuleProps\n} from \"../types\";\nimport {\n linkedVCPropsDecoder,\n parseIntOr,\n modulePropsDecoder,\n replaceMacros\n} from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type SimpleValueProps = {\n type: ItemType.SIMPLE_VALUE;\n valueType: \"string\" | \"image\";\n value: string;\n} & (\n | {\n processValue: \"none\";\n }\n | {\n processValue: \"avg\" | \"max\" | \"min\";\n period: number;\n }) &\n ItemProps &\n WithModuleProps &\n LinkedVisualConsoleProps;\n\n/**\n * Extract a valid enum value from a raw value type.\n * @param valueType Raw value.\n */\nconst parseValueType = (valueType: unknown): SimpleValueProps[\"valueType\"] => {\n switch (valueType) {\n case \"string\":\n case \"image\":\n return valueType;\n default:\n return \"string\";\n }\n};\n\n/**\n * Extract a valid enum value from a raw process value.\n * @param processValue Raw value.\n */\nconst parseProcessValue = (\n processValue: unknown\n): SimpleValueProps[\"processValue\"] => {\n switch (processValue) {\n case \"none\":\n case \"avg\":\n case \"max\":\n case \"min\":\n return processValue;\n default:\n return \"none\";\n }\n};\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the simple value props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function simpleValuePropsDecoder(\n data: UnknownObject\n): SimpleValueProps | never {\n if (typeof data.value !== \"string\" || data.value.length === 0) {\n throw new TypeError(\"invalid value\");\n }\n\n const processValue = parseProcessValue(data.processValue);\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.SIMPLE_VALUE,\n valueType: parseValueType(data.valueType),\n value: data.value,\n ...(processValue === \"none\"\n ? { processValue }\n : { processValue, period: parseIntOr(data.period, 0) }), // Object spread. It will merge the properties of the two objects.\n ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class SimpleValue extends Item {\n protected createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"simple-value\";\n\n if (this.props.valueType === \"image\") {\n const img = document.createElement(\"img\");\n img.src = this.props.value;\n element.append(img);\n } else {\n // Add the value to the label and show it.\n let text = this.props.value;\n let label = this.getLabelWithMacrosReplaced();\n if (label.length > 0) {\n text = replaceMacros([{ macro: /\\(?_VALUE_\\)?/i, value: text }], label);\n }\n\n element.innerHTML = text;\n }\n\n return element;\n }\n\n /**\n * @override Item.createLabelDomElement\n * Create a new label for the visual console item.\n * @return Item label.\n */\n protected createLabelDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"visual-console-item-label\";\n // Always return an empty label.\n return element;\n }\n}\n","var pi = Math.PI,\n tau = 2 * pi,\n epsilon = 1e-6,\n tauEpsilon = tau - epsilon;\n\nfunction Path() {\n this._x0 = this._y0 = // start of current subpath\n this._x1 = this._y1 = null; // end of current subpath\n this._ = \"\";\n}\n\nfunction path() {\n return new Path;\n}\n\nPath.prototype = path.prototype = {\n constructor: Path,\n moveTo: function(x, y) {\n this._ += \"M\" + (this._x0 = this._x1 = +x) + \",\" + (this._y0 = this._y1 = +y);\n },\n closePath: function() {\n if (this._x1 !== null) {\n this._x1 = this._x0, this._y1 = this._y0;\n this._ += \"Z\";\n }\n },\n lineTo: function(x, y) {\n this._ += \"L\" + (this._x1 = +x) + \",\" + (this._y1 = +y);\n },\n quadraticCurveTo: function(x1, y1, x, y) {\n this._ += \"Q\" + (+x1) + \",\" + (+y1) + \",\" + (this._x1 = +x) + \",\" + (this._y1 = +y);\n },\n bezierCurveTo: function(x1, y1, x2, y2, x, y) {\n this._ += \"C\" + (+x1) + \",\" + (+y1) + \",\" + (+x2) + \",\" + (+y2) + \",\" + (this._x1 = +x) + \",\" + (this._y1 = +y);\n },\n arcTo: function(x1, y1, x2, y2, r) {\n x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;\n var x0 = this._x1,\n y0 = this._y1,\n x21 = x2 - x1,\n y21 = y2 - y1,\n x01 = x0 - x1,\n y01 = y0 - y1,\n l01_2 = x01 * x01 + y01 * y01;\n\n // Is the radius negative? Error.\n if (r < 0) throw new Error(\"negative radius: \" + r);\n\n // Is this path empty? Move to (x1,y1).\n if (this._x1 === null) {\n this._ += \"M\" + (this._x1 = x1) + \",\" + (this._y1 = y1);\n }\n\n // Or, is (x1,y1) coincident with (x0,y0)? Do nothing.\n else if (!(l01_2 > epsilon));\n\n // Or, are (x0,y0), (x1,y1) and (x2,y2) collinear?\n // Equivalently, is (x1,y1) coincident with (x2,y2)?\n // Or, is the radius zero? Line to (x1,y1).\n else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon) || !r) {\n this._ += \"L\" + (this._x1 = x1) + \",\" + (this._y1 = y1);\n }\n\n // Otherwise, draw an arc!\n else {\n var x20 = x2 - x0,\n y20 = y2 - y0,\n l21_2 = x21 * x21 + y21 * y21,\n l20_2 = x20 * x20 + y20 * y20,\n l21 = Math.sqrt(l21_2),\n l01 = Math.sqrt(l01_2),\n l = r * Math.tan((pi - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2),\n t01 = l / l01,\n t21 = l / l21;\n\n // If the start tangent is not coincident with (x0,y0), line to.\n if (Math.abs(t01 - 1) > epsilon) {\n this._ += \"L\" + (x1 + t01 * x01) + \",\" + (y1 + t01 * y01);\n }\n\n this._ += \"A\" + r + \",\" + r + \",0,0,\" + (+(y01 * x20 > x01 * y20)) + \",\" + (this._x1 = x1 + t21 * x21) + \",\" + (this._y1 = y1 + t21 * y21);\n }\n },\n arc: function(x, y, r, a0, a1, ccw) {\n x = +x, y = +y, r = +r;\n var dx = r * Math.cos(a0),\n dy = r * Math.sin(a0),\n x0 = x + dx,\n y0 = y + dy,\n cw = 1 ^ ccw,\n da = ccw ? a0 - a1 : a1 - a0;\n\n // Is the radius negative? Error.\n if (r < 0) throw new Error(\"negative radius: \" + r);\n\n // Is this path empty? Move to (x0,y0).\n if (this._x1 === null) {\n this._ += \"M\" + x0 + \",\" + y0;\n }\n\n // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).\n else if (Math.abs(this._x1 - x0) > epsilon || Math.abs(this._y1 - y0) > epsilon) {\n this._ += \"L\" + x0 + \",\" + y0;\n }\n\n // Is this arc empty? We’re done.\n if (!r) return;\n\n // Does the angle go the wrong way? Flip the direction.\n if (da < 0) da = da % tau + tau;\n\n // Is this a complete circle? Draw two arcs to complete the circle.\n if (da > tauEpsilon) {\n this._ += \"A\" + r + \",\" + r + \",0,1,\" + cw + \",\" + (x - dx) + \",\" + (y - dy) + \"A\" + r + \",\" + r + \",0,1,\" + cw + \",\" + (this._x1 = x0) + \",\" + (this._y1 = y0);\n }\n\n // Is this arc non-empty? Draw an arc!\n else if (da > epsilon) {\n this._ += \"A\" + r + \",\" + r + \",0,\" + (+(da >= pi)) + \",\" + cw + \",\" + (this._x1 = x + r * Math.cos(a1)) + \",\" + (this._y1 = y + r * Math.sin(a1));\n }\n },\n rect: function(x, y, w, h) {\n this._ += \"M\" + (this._x0 = this._x1 = +x) + \",\" + (this._y0 = this._y1 = +y) + \"h\" + (+w) + \"v\" + (+h) + \"h\" + (-w) + \"Z\";\n },\n toString: function() {\n return this._;\n }\n};\n\nexport default path;\n","export default function(x) {\n return function constant() {\n return x;\n };\n}\n","export var abs = Math.abs;\nexport var atan2 = Math.atan2;\nexport var cos = Math.cos;\nexport var max = Math.max;\nexport var min = Math.min;\nexport var sin = Math.sin;\nexport var sqrt = Math.sqrt;\n\nexport var epsilon = 1e-12;\nexport var pi = Math.PI;\nexport var halfPi = pi / 2;\nexport var tau = 2 * pi;\n\nexport function acos(x) {\n return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);\n}\n\nexport function asin(x) {\n return x >= 1 ? halfPi : x <= -1 ? -halfPi : Math.asin(x);\n}\n","import {path} from \"d3-path\";\nimport constant from \"./constant\";\nimport {abs, acos, asin, atan2, cos, epsilon, halfPi, max, min, pi, sin, sqrt, tau} from \"./math\";\n\nfunction arcInnerRadius(d) {\n return d.innerRadius;\n}\n\nfunction arcOuterRadius(d) {\n return d.outerRadius;\n}\n\nfunction arcStartAngle(d) {\n return d.startAngle;\n}\n\nfunction arcEndAngle(d) {\n return d.endAngle;\n}\n\nfunction arcPadAngle(d) {\n return d && d.padAngle; // Note: optional!\n}\n\nfunction intersect(x0, y0, x1, y1, x2, y2, x3, y3) {\n var x10 = x1 - x0, y10 = y1 - y0,\n x32 = x3 - x2, y32 = y3 - y2,\n t = y32 * x10 - x32 * y10;\n if (t * t < epsilon) return;\n t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t;\n return [x0 + t * x10, y0 + t * y10];\n}\n\n// Compute perpendicular offset line of length rc.\n// http://mathworld.wolfram.com/Circle-LineIntersection.html\nfunction cornerTangents(x0, y0, x1, y1, r1, rc, cw) {\n var x01 = x0 - x1,\n y01 = y0 - y1,\n lo = (cw ? rc : -rc) / sqrt(x01 * x01 + y01 * y01),\n ox = lo * y01,\n oy = -lo * x01,\n x11 = x0 + ox,\n y11 = y0 + oy,\n x10 = x1 + ox,\n y10 = y1 + oy,\n x00 = (x11 + x10) / 2,\n y00 = (y11 + y10) / 2,\n dx = x10 - x11,\n dy = y10 - y11,\n d2 = dx * dx + dy * dy,\n r = r1 - rc,\n D = x11 * y10 - x10 * y11,\n d = (dy < 0 ? -1 : 1) * sqrt(max(0, r * r * d2 - D * D)),\n cx0 = (D * dy - dx * d) / d2,\n cy0 = (-D * dx - dy * d) / d2,\n cx1 = (D * dy + dx * d) / d2,\n cy1 = (-D * dx + dy * d) / d2,\n dx0 = cx0 - x00,\n dy0 = cy0 - y00,\n dx1 = cx1 - x00,\n dy1 = cy1 - y00;\n\n // Pick the closer of the two intersection points.\n // TODO Is there a faster way to determine which intersection to use?\n if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;\n\n return {\n cx: cx0,\n cy: cy0,\n x01: -ox,\n y01: -oy,\n x11: cx0 * (r1 / r - 1),\n y11: cy0 * (r1 / r - 1)\n };\n}\n\nexport default function() {\n var innerRadius = arcInnerRadius,\n outerRadius = arcOuterRadius,\n cornerRadius = constant(0),\n padRadius = null,\n startAngle = arcStartAngle,\n endAngle = arcEndAngle,\n padAngle = arcPadAngle,\n context = null;\n\n function arc() {\n var buffer,\n r,\n r0 = +innerRadius.apply(this, arguments),\n r1 = +outerRadius.apply(this, arguments),\n a0 = startAngle.apply(this, arguments) - halfPi,\n a1 = endAngle.apply(this, arguments) - halfPi,\n da = abs(a1 - a0),\n cw = a1 > a0;\n\n if (!context) context = buffer = path();\n\n // Ensure that the outer radius is always larger than the inner radius.\n if (r1 < r0) r = r1, r1 = r0, r0 = r;\n\n // Is it a point?\n if (!(r1 > epsilon)) context.moveTo(0, 0);\n\n // Or is it a circle or annulus?\n else if (da > tau - epsilon) {\n context.moveTo(r1 * cos(a0), r1 * sin(a0));\n context.arc(0, 0, r1, a0, a1, !cw);\n if (r0 > epsilon) {\n context.moveTo(r0 * cos(a1), r0 * sin(a1));\n context.arc(0, 0, r0, a1, a0, cw);\n }\n }\n\n // Or is it a circular or annular sector?\n else {\n var a01 = a0,\n a11 = a1,\n a00 = a0,\n a10 = a1,\n da0 = da,\n da1 = da,\n ap = padAngle.apply(this, arguments) / 2,\n rp = (ap > epsilon) && (padRadius ? +padRadius.apply(this, arguments) : sqrt(r0 * r0 + r1 * r1)),\n rc = min(abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),\n rc0 = rc,\n rc1 = rc,\n t0,\n t1;\n\n // Apply padding? Note that since r1 ≥ r0, da1 ≥ da0.\n if (rp > epsilon) {\n var p0 = asin(rp / r0 * sin(ap)),\n p1 = asin(rp / r1 * sin(ap));\n if ((da0 -= p0 * 2) > epsilon) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;\n else da0 = 0, a00 = a10 = (a0 + a1) / 2;\n if ((da1 -= p1 * 2) > epsilon) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;\n else da1 = 0, a01 = a11 = (a0 + a1) / 2;\n }\n\n var x01 = r1 * cos(a01),\n y01 = r1 * sin(a01),\n x10 = r0 * cos(a10),\n y10 = r0 * sin(a10);\n\n // Apply rounded corners?\n if (rc > epsilon) {\n var x11 = r1 * cos(a11),\n y11 = r1 * sin(a11),\n x00 = r0 * cos(a00),\n y00 = r0 * sin(a00),\n oc;\n\n // Restrict the corner radius according to the sector angle.\n if (da < pi && (oc = intersect(x01, y01, x00, y00, x11, y11, x10, y10))) {\n var ax = x01 - oc[0],\n ay = y01 - oc[1],\n bx = x11 - oc[0],\n by = y11 - oc[1],\n kc = 1 / sin(acos((ax * bx + ay * by) / (sqrt(ax * ax + ay * ay) * sqrt(bx * bx + by * by))) / 2),\n lc = sqrt(oc[0] * oc[0] + oc[1] * oc[1]);\n rc0 = min(rc, (r0 - lc) / (kc - 1));\n rc1 = min(rc, (r1 - lc) / (kc + 1));\n }\n }\n\n // Is the sector collapsed to a line?\n if (!(da1 > epsilon)) context.moveTo(x01, y01);\n\n // Does the sector’s outer ring have rounded corners?\n else if (rc1 > epsilon) {\n t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);\n t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);\n\n context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);\n\n // Have the corners merged?\n if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);\n\n // Otherwise, draw the two corners and the ring.\n else {\n context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);\n context.arc(0, 0, r1, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), !cw);\n context.arc(t1.cx, t1.cy, rc1, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);\n }\n }\n\n // Or is the outer ring just a circular arc?\n else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);\n\n // Is there no inner ring, and it’s a circular sector?\n // Or perhaps it’s an annular sector collapsed due to padding?\n if (!(r0 > epsilon) || !(da0 > epsilon)) context.lineTo(x10, y10);\n\n // Does the sector’s inner ring (or point) have rounded corners?\n else if (rc0 > epsilon) {\n t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);\n t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);\n\n context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);\n\n // Have the corners merged?\n if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);\n\n // Otherwise, draw the two corners and the ring.\n else {\n context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);\n context.arc(0, 0, r0, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), cw);\n context.arc(t1.cx, t1.cy, rc0, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);\n }\n }\n\n // Or is the inner ring just a circular arc?\n else context.arc(0, 0, r0, a10, a00, cw);\n }\n\n context.closePath();\n\n if (buffer) return context = null, buffer + \"\" || null;\n }\n\n arc.centroid = function() {\n var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,\n a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi / 2;\n return [cos(a) * r, sin(a) * r];\n };\n\n arc.innerRadius = function(_) {\n return arguments.length ? (innerRadius = typeof _ === \"function\" ? _ : constant(+_), arc) : innerRadius;\n };\n\n arc.outerRadius = function(_) {\n return arguments.length ? (outerRadius = typeof _ === \"function\" ? _ : constant(+_), arc) : outerRadius;\n };\n\n arc.cornerRadius = function(_) {\n return arguments.length ? (cornerRadius = typeof _ === \"function\" ? _ : constant(+_), arc) : cornerRadius;\n };\n\n arc.padRadius = function(_) {\n return arguments.length ? (padRadius = _ == null ? null : typeof _ === \"function\" ? _ : constant(+_), arc) : padRadius;\n };\n\n arc.startAngle = function(_) {\n return arguments.length ? (startAngle = typeof _ === \"function\" ? _ : constant(+_), arc) : startAngle;\n };\n\n arc.endAngle = function(_) {\n return arguments.length ? (endAngle = typeof _ === \"function\" ? _ : constant(+_), arc) : endAngle;\n };\n\n arc.padAngle = function(_) {\n return arguments.length ? (padAngle = typeof _ === \"function\" ? _ : constant(+_), arc) : padAngle;\n };\n\n arc.context = function(_) {\n return arguments.length ? ((context = _ == null ? null : _), arc) : context;\n };\n\n return arc;\n}\n","function Linear(context) {\n this._context = context;\n}\n\nLinear.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._point = 0;\n },\n lineEnd: function() {\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; // proceed\n default: this._context.lineTo(x, y); break;\n }\n }\n};\n\nexport default function(context) {\n return new Linear(context);\n}\n","import curveLinear from \"./linear\";\n\nexport var curveRadialLinear = curveRadial(curveLinear);\n\nfunction Radial(curve) {\n this._curve = curve;\n}\n\nRadial.prototype = {\n areaStart: function() {\n this._curve.areaStart();\n },\n areaEnd: function() {\n this._curve.areaEnd();\n },\n lineStart: function() {\n this._curve.lineStart();\n },\n lineEnd: function() {\n this._curve.lineEnd();\n },\n point: function(a, r) {\n this._curve.point(r * Math.sin(a), r * -Math.cos(a));\n }\n};\n\nexport default function curveRadial(curve) {\n\n function radial(context) {\n return new Radial(curve(context));\n }\n\n radial._curve = curve;\n\n return radial;\n}\n","export var slice = Array.prototype.slice;\n","var tan30 = Math.sqrt(1 / 3),\n tan30_2 = tan30 * 2;\n\nexport default {\n draw: function(context, size) {\n var y = Math.sqrt(size / tan30_2),\n x = y * tan30;\n context.moveTo(0, -y);\n context.lineTo(x, 0);\n context.lineTo(0, y);\n context.lineTo(-x, 0);\n context.closePath();\n }\n};\n","import {pi, tau} from \"../math\";\n\nexport default {\n draw: function(context, size) {\n var r = Math.sqrt(size / pi);\n context.moveTo(r, 0);\n context.arc(0, 0, r, 0, tau);\n }\n};\n","import {pi, tau} from \"../math\";\n\nvar ka = 0.89081309152928522810,\n kr = Math.sin(pi / 10) / Math.sin(7 * pi / 10),\n kx = Math.sin(tau / 10) * kr,\n ky = -Math.cos(tau / 10) * kr;\n\nexport default {\n draw: function(context, size) {\n var r = Math.sqrt(size * ka),\n x = kx * r,\n y = ky * r;\n context.moveTo(0, -r);\n context.lineTo(x, y);\n for (var i = 1; i < 5; ++i) {\n var a = tau * i / 5,\n c = Math.cos(a),\n s = Math.sin(a);\n context.lineTo(s * r, -c * r);\n context.lineTo(c * x - s * y, s * x + c * y);\n }\n context.closePath();\n }\n};\n","export default function() {}\n","var sqrt3 = Math.sqrt(3);\n\nexport default {\n draw: function(context, size) {\n var y = -Math.sqrt(size / (sqrt3 * 3));\n context.moveTo(0, y * 2);\n context.lineTo(-sqrt3 * y, -y);\n context.lineTo(sqrt3 * y, -y);\n context.closePath();\n }\n};\n","var c = -0.5,\n s = Math.sqrt(3) / 2,\n k = 1 / Math.sqrt(12),\n a = (k / 2 + 1) * 3;\n\nexport default {\n draw: function(context, size) {\n var r = Math.sqrt(size / a),\n x0 = r / 2,\n y0 = r * k,\n x1 = x0,\n y1 = r * k + r,\n x2 = -x1,\n y2 = y1;\n context.moveTo(x0, y0);\n context.lineTo(x1, y1);\n context.lineTo(x2, y2);\n context.lineTo(c * x0 - s * y0, s * x0 + c * y0);\n context.lineTo(c * x1 - s * y1, s * x1 + c * y1);\n context.lineTo(c * x2 - s * y2, s * x2 + c * y2);\n context.lineTo(c * x0 + s * y0, c * y0 - s * x0);\n context.lineTo(c * x1 + s * y1, c * y1 - s * x1);\n context.lineTo(c * x2 + s * y2, c * y2 - s * x2);\n context.closePath();\n }\n};\n","export function point(that, x, y) {\n that._context.bezierCurveTo(\n (2 * that._x0 + that._x1) / 3,\n (2 * that._y0 + that._y1) / 3,\n (that._x0 + 2 * that._x1) / 3,\n (that._y0 + 2 * that._y1) / 3,\n (that._x0 + 4 * that._x1 + x) / 6,\n (that._y0 + 4 * that._y1 + y) / 6\n );\n}\n\nexport function Basis(context) {\n this._context = context;\n}\n\nBasis.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 =\n this._y0 = this._y1 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 3: point(this, this._x1, this._y1); // proceed\n case 2: this._context.lineTo(this._x1, this._y1); break;\n }\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); // proceed\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = x;\n this._y0 = this._y1, this._y1 = y;\n }\n};\n\nexport default function(context) {\n return new Basis(context);\n}\n","import noop from \"../noop\";\nimport {point} from \"./basis\";\n\nfunction BasisClosed(context) {\n this._context = context;\n}\n\nBasisClosed.prototype = {\n areaStart: noop,\n areaEnd: noop,\n lineStart: function() {\n this._x0 = this._x1 = this._x2 = this._x3 = this._x4 =\n this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 1: {\n this._context.moveTo(this._x2, this._y2);\n this._context.closePath();\n break;\n }\n case 2: {\n this._context.moveTo((this._x2 + 2 * this._x3) / 3, (this._y2 + 2 * this._y3) / 3);\n this._context.lineTo((this._x3 + 2 * this._x2) / 3, (this._y3 + 2 * this._y2) / 3);\n this._context.closePath();\n break;\n }\n case 3: {\n this.point(this._x2, this._y2);\n this.point(this._x3, this._y3);\n this.point(this._x4, this._y4);\n break;\n }\n }\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._x2 = x, this._y2 = y; break;\n case 1: this._point = 2; this._x3 = x, this._y3 = y; break;\n case 2: this._point = 3; this._x4 = x, this._y4 = y; this._context.moveTo((this._x0 + 4 * this._x1 + x) / 6, (this._y0 + 4 * this._y1 + y) / 6); break;\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = x;\n this._y0 = this._y1, this._y1 = y;\n }\n};\n\nexport default function(context) {\n return new BasisClosed(context);\n}\n","import {point} from \"./basis\";\n\nfunction BasisOpen(context) {\n this._context = context;\n}\n\nBasisOpen.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 =\n this._y0 = this._y1 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; var x0 = (this._x0 + 4 * this._x1 + x) / 6, y0 = (this._y0 + 4 * this._y1 + y) / 6; this._line ? this._context.lineTo(x0, y0) : this._context.moveTo(x0, y0); break;\n case 3: this._point = 4; // proceed\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = x;\n this._y0 = this._y1, this._y1 = y;\n }\n};\n\nexport default function(context) {\n return new BasisOpen(context);\n}\n","import {Basis} from \"./basis\";\n\nfunction Bundle(context, beta) {\n this._basis = new Basis(context);\n this._beta = beta;\n}\n\nBundle.prototype = {\n lineStart: function() {\n this._x = [];\n this._y = [];\n this._basis.lineStart();\n },\n lineEnd: function() {\n var x = this._x,\n y = this._y,\n j = x.length - 1;\n\n if (j > 0) {\n var x0 = x[0],\n y0 = y[0],\n dx = x[j] - x0,\n dy = y[j] - y0,\n i = -1,\n t;\n\n while (++i <= j) {\n t = i / j;\n this._basis.point(\n this._beta * x[i] + (1 - this._beta) * (x0 + t * dx),\n this._beta * y[i] + (1 - this._beta) * (y0 + t * dy)\n );\n }\n }\n\n this._x = this._y = null;\n this._basis.lineEnd();\n },\n point: function(x, y) {\n this._x.push(+x);\n this._y.push(+y);\n }\n};\n\nexport default (function custom(beta) {\n\n function bundle(context) {\n return beta === 1 ? new Basis(context) : new Bundle(context, beta);\n }\n\n bundle.beta = function(beta) {\n return custom(+beta);\n };\n\n return bundle;\n})(0.85);\n","export function point(that, x, y) {\n that._context.bezierCurveTo(\n that._x1 + that._k * (that._x2 - that._x0),\n that._y1 + that._k * (that._y2 - that._y0),\n that._x2 + that._k * (that._x1 - x),\n that._y2 + that._k * (that._y1 - y),\n that._x2,\n that._y2\n );\n}\n\nexport function Cardinal(context, tension) {\n this._context = context;\n this._k = (1 - tension) / 6;\n}\n\nCardinal.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 = this._x2 =\n this._y0 = this._y1 = this._y2 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 2: this._context.lineTo(this._x2, this._y2); break;\n case 3: point(this, this._x1, this._y1); break;\n }\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; this._x1 = x, this._y1 = y; break;\n case 2: this._point = 3; // proceed\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(tension) {\n\n function cardinal(context) {\n return new Cardinal(context, tension);\n }\n\n cardinal.tension = function(tension) {\n return custom(+tension);\n };\n\n return cardinal;\n})(0);\n","import noop from \"../noop\";\nimport {point} from \"./cardinal\";\n\nexport function CardinalClosed(context, tension) {\n this._context = context;\n this._k = (1 - tension) / 6;\n}\n\nCardinalClosed.prototype = {\n areaStart: noop,\n areaEnd: noop,\n lineStart: function() {\n this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =\n this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 1: {\n this._context.moveTo(this._x3, this._y3);\n this._context.closePath();\n break;\n }\n case 2: {\n this._context.lineTo(this._x3, this._y3);\n this._context.closePath();\n break;\n }\n case 3: {\n this.point(this._x3, this._y3);\n this.point(this._x4, this._y4);\n this.point(this._x5, this._y5);\n break;\n }\n }\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._x3 = x, this._y3 = y; break;\n case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;\n case 2: this._point = 3; this._x5 = x, this._y5 = y; break;\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(tension) {\n\n function cardinal(context) {\n return new CardinalClosed(context, tension);\n }\n\n cardinal.tension = function(tension) {\n return custom(+tension);\n };\n\n return cardinal;\n})(0);\n","import {point} from \"./cardinal\";\n\nexport function CardinalOpen(context, tension) {\n this._context = context;\n this._k = (1 - tension) / 6;\n}\n\nCardinalOpen.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 = this._x2 =\n this._y0 = this._y1 = this._y2 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;\n case 3: this._point = 4; // proceed\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(tension) {\n\n function cardinal(context) {\n return new CardinalOpen(context, tension);\n }\n\n cardinal.tension = function(tension) {\n return custom(+tension);\n };\n\n return cardinal;\n})(0);\n","import {epsilon} from \"../math\";\nimport {Cardinal} from \"./cardinal\";\n\nexport function point(that, x, y) {\n var x1 = that._x1,\n y1 = that._y1,\n x2 = that._x2,\n y2 = that._y2;\n\n if (that._l01_a > epsilon) {\n var a = 2 * that._l01_2a + 3 * that._l01_a * that._l12_a + that._l12_2a,\n n = 3 * that._l01_a * (that._l01_a + that._l12_a);\n x1 = (x1 * a - that._x0 * that._l12_2a + that._x2 * that._l01_2a) / n;\n y1 = (y1 * a - that._y0 * that._l12_2a + that._y2 * that._l01_2a) / n;\n }\n\n if (that._l23_a > epsilon) {\n var b = 2 * that._l23_2a + 3 * that._l23_a * that._l12_a + that._l12_2a,\n m = 3 * that._l23_a * (that._l23_a + that._l12_a);\n x2 = (x2 * b + that._x1 * that._l23_2a - x * that._l12_2a) / m;\n y2 = (y2 * b + that._y1 * that._l23_2a - y * that._l12_2a) / m;\n }\n\n that._context.bezierCurveTo(x1, y1, x2, y2, that._x2, that._y2);\n}\n\nfunction CatmullRom(context, alpha) {\n this._context = context;\n this._alpha = alpha;\n}\n\nCatmullRom.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 = this._x2 =\n this._y0 = this._y1 = this._y2 = NaN;\n this._l01_a = this._l12_a = this._l23_a =\n this._l01_2a = this._l12_2a = this._l23_2a =\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 2: this._context.lineTo(this._x2, this._y2); break;\n case 3: this.point(this._x2, this._y2); break;\n }\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n\n if (this._point) {\n var x23 = this._x2 - x,\n y23 = this._y2 - y;\n this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));\n }\n\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; // proceed\n default: point(this, x, y); break;\n }\n\n this._l01_a = this._l12_a, this._l12_a = this._l23_a;\n this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(alpha) {\n\n function catmullRom(context) {\n return alpha ? new CatmullRom(context, alpha) : new Cardinal(context, 0);\n }\n\n catmullRom.alpha = function(alpha) {\n return custom(+alpha);\n };\n\n return catmullRom;\n})(0.5);\n","import {CardinalClosed} from \"./cardinalClosed\";\nimport noop from \"../noop\";\nimport {point} from \"./catmullRom\";\n\nfunction CatmullRomClosed(context, alpha) {\n this._context = context;\n this._alpha = alpha;\n}\n\nCatmullRomClosed.prototype = {\n areaStart: noop,\n areaEnd: noop,\n lineStart: function() {\n this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =\n this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;\n this._l01_a = this._l12_a = this._l23_a =\n this._l01_2a = this._l12_2a = this._l23_2a =\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 1: {\n this._context.moveTo(this._x3, this._y3);\n this._context.closePath();\n break;\n }\n case 2: {\n this._context.lineTo(this._x3, this._y3);\n this._context.closePath();\n break;\n }\n case 3: {\n this.point(this._x3, this._y3);\n this.point(this._x4, this._y4);\n this.point(this._x5, this._y5);\n break;\n }\n }\n },\n point: function(x, y) {\n x = +x, y = +y;\n\n if (this._point) {\n var x23 = this._x2 - x,\n y23 = this._y2 - y;\n this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));\n }\n\n switch (this._point) {\n case 0: this._point = 1; this._x3 = x, this._y3 = y; break;\n case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;\n case 2: this._point = 3; this._x5 = x, this._y5 = y; break;\n default: point(this, x, y); break;\n }\n\n this._l01_a = this._l12_a, this._l12_a = this._l23_a;\n this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(alpha) {\n\n function catmullRom(context) {\n return alpha ? new CatmullRomClosed(context, alpha) : new CardinalClosed(context, 0);\n }\n\n catmullRom.alpha = function(alpha) {\n return custom(+alpha);\n };\n\n return catmullRom;\n})(0.5);\n","import {CardinalOpen} from \"./cardinalOpen\";\nimport {point} from \"./catmullRom\";\n\nfunction CatmullRomOpen(context, alpha) {\n this._context = context;\n this._alpha = alpha;\n}\n\nCatmullRomOpen.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 = this._x2 =\n this._y0 = this._y1 = this._y2 = NaN;\n this._l01_a = this._l12_a = this._l23_a =\n this._l01_2a = this._l12_2a = this._l23_2a =\n this._point = 0;\n },\n lineEnd: function() {\n if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n\n if (this._point) {\n var x23 = this._x2 - x,\n y23 = this._y2 - y;\n this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));\n }\n\n switch (this._point) {\n case 0: this._point = 1; break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;\n case 3: this._point = 4; // proceed\n default: point(this, x, y); break;\n }\n\n this._l01_a = this._l12_a, this._l12_a = this._l23_a;\n this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(alpha) {\n\n function catmullRom(context) {\n return alpha ? new CatmullRomOpen(context, alpha) : new CardinalOpen(context, 0);\n }\n\n catmullRom.alpha = function(alpha) {\n return custom(+alpha);\n };\n\n return catmullRom;\n})(0.5);\n","import noop from \"../noop\";\n\nfunction LinearClosed(context) {\n this._context = context;\n}\n\nLinearClosed.prototype = {\n areaStart: noop,\n areaEnd: noop,\n lineStart: function() {\n this._point = 0;\n },\n lineEnd: function() {\n if (this._point) this._context.closePath();\n },\n point: function(x, y) {\n x = +x, y = +y;\n if (this._point) this._context.lineTo(x, y);\n else this._point = 1, this._context.moveTo(x, y);\n }\n};\n\nexport default function(context) {\n return new LinearClosed(context);\n}\n","function sign(x) {\n return x < 0 ? -1 : 1;\n}\n\n// Calculate the slopes of the tangents (Hermite-type interpolation) based on\n// the following paper: Steffen, M. 1990. A Simple Method for Monotonic\n// Interpolation in One Dimension. Astronomy and Astrophysics, Vol. 239, NO.\n// NOV(II), P. 443, 1990.\nfunction slope3(that, x2, y2) {\n var h0 = that._x1 - that._x0,\n h1 = x2 - that._x1,\n s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0),\n s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0),\n p = (s0 * h1 + s1 * h0) / (h0 + h1);\n return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;\n}\n\n// Calculate a one-sided slope.\nfunction slope2(that, t) {\n var h = that._x1 - that._x0;\n return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;\n}\n\n// According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations\n// \"you can express cubic Hermite interpolation in terms of cubic Bézier curves\n// with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1\".\nfunction point(that, t0, t1) {\n var x0 = that._x0,\n y0 = that._y0,\n x1 = that._x1,\n y1 = that._y1,\n dx = (x1 - x0) / 3;\n that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1);\n}\n\nfunction MonotoneX(context) {\n this._context = context;\n}\n\nMonotoneX.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 =\n this._y0 = this._y1 =\n this._t0 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 2: this._context.lineTo(this._x1, this._y1); break;\n case 3: point(this, this._t0, slope2(this, this._t0)); break;\n }\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n var t1 = NaN;\n\n x = +x, y = +y;\n if (x === this._x1 && y === this._y1) return; // Ignore coincident points.\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; point(this, slope2(this, t1 = slope3(this, x, y)), t1); break;\n default: point(this, this._t0, t1 = slope3(this, x, y)); break;\n }\n\n this._x0 = this._x1, this._x1 = x;\n this._y0 = this._y1, this._y1 = y;\n this._t0 = t1;\n }\n}\n\nfunction MonotoneY(context) {\n this._context = new ReflectContext(context);\n}\n\n(MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x, y) {\n MonotoneX.prototype.point.call(this, y, x);\n};\n\nfunction ReflectContext(context) {\n this._context = context;\n}\n\nReflectContext.prototype = {\n moveTo: function(x, y) { this._context.moveTo(y, x); },\n closePath: function() { this._context.closePath(); },\n lineTo: function(x, y) { this._context.lineTo(y, x); },\n bezierCurveTo: function(x1, y1, x2, y2, x, y) { this._context.bezierCurveTo(y1, x1, y2, x2, y, x); }\n};\n\nexport function monotoneX(context) {\n return new MonotoneX(context);\n}\n\nexport function monotoneY(context) {\n return new MonotoneY(context);\n}\n","function Natural(context) {\n this._context = context;\n}\n\nNatural.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x = [];\n this._y = [];\n },\n lineEnd: function() {\n var x = this._x,\n y = this._y,\n n = x.length;\n\n if (n) {\n this._line ? this._context.lineTo(x[0], y[0]) : this._context.moveTo(x[0], y[0]);\n if (n === 2) {\n this._context.lineTo(x[1], y[1]);\n } else {\n var px = controlPoints(x),\n py = controlPoints(y);\n for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) {\n this._context.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x[i1], y[i1]);\n }\n }\n }\n\n if (this._line || (this._line !== 0 && n === 1)) this._context.closePath();\n this._line = 1 - this._line;\n this._x = this._y = null;\n },\n point: function(x, y) {\n this._x.push(+x);\n this._y.push(+y);\n }\n};\n\n// See https://www.particleincell.com/2012/bezier-splines/ for derivation.\nfunction controlPoints(x) {\n var i,\n n = x.length - 1,\n m,\n a = new Array(n),\n b = new Array(n),\n r = new Array(n);\n a[0] = 0, b[0] = 2, r[0] = x[0] + 2 * x[1];\n for (i = 1; i < n - 1; ++i) a[i] = 1, b[i] = 4, r[i] = 4 * x[i] + 2 * x[i + 1];\n a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x[n - 1] + x[n];\n for (i = 1; i < n; ++i) m = a[i] / b[i - 1], b[i] -= m, r[i] -= m * r[i - 1];\n a[n - 1] = r[n - 1] / b[n - 1];\n for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i];\n b[n - 1] = (x[n] + a[n - 1]) / 2;\n for (i = 0; i < n - 1; ++i) b[i] = 2 * x[i + 1] - a[i + 1];\n return [a, b];\n}\n\nexport default function(context) {\n return new Natural(context);\n}\n","function Step(context, t) {\n this._context = context;\n this._t = t;\n}\n\nStep.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x = this._y = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y);\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; // proceed\n default: {\n if (this._t <= 0) {\n this._context.lineTo(this._x, y);\n this._context.lineTo(x, y);\n } else {\n var x1 = this._x * (1 - this._t) + x * this._t;\n this._context.lineTo(x1, this._y);\n this._context.lineTo(x1, y);\n }\n break;\n }\n }\n this._x = x, this._y = y;\n }\n};\n\nexport default function(context) {\n return new Step(context, 0.5);\n}\n\nexport function stepBefore(context) {\n return new Step(context, 0);\n}\n\nexport function stepAfter(context) {\n return new Step(context, 1);\n}\n","import ascending from \"./ascending\";\n\nexport default function(series) {\n return ascending(series).reverse();\n}\n","import { arc as arcFactory } from \"d3-shape\";\n\nimport {\n LinkedVisualConsoleProps,\n UnknownObject,\n WithModuleProps\n} from \"../types\";\nimport {\n linkedVCPropsDecoder,\n modulePropsDecoder,\n notEmptyStringOr,\n parseIntOr,\n parseFloatOr\n} from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type PercentileProps = {\n type: ItemType.PERCENTILE_BAR;\n percentileType:\n | \"progress-bar\"\n | \"bubble\"\n | \"circular-progress-bar\"\n | \"circular-progress-bar-alt\";\n valueType: \"percent\" | \"value\";\n minValue: number | null;\n maxValue: number | null;\n color: string | null;\n labelColor: string | null;\n value: number | null;\n unit: string | null;\n} & ItemProps &\n WithModuleProps &\n LinkedVisualConsoleProps;\n\n/**\n * Extract a valid enum value from a raw type value.\n * @param type Raw value.\n */\nfunction extractPercentileType(\n type: unknown\n): PercentileProps[\"percentileType\"] {\n switch (type) {\n case \"progress-bar\":\n case \"bubble\":\n case \"circular-progress-bar\":\n case \"circular-progress-bar-alt\":\n return type;\n default:\n case ItemType.PERCENTILE_BAR:\n return \"progress-bar\";\n case ItemType.PERCENTILE_BUBBLE:\n return \"bubble\";\n case ItemType.CIRCULAR_PROGRESS_BAR:\n return \"circular-progress-bar\";\n case ItemType.CIRCULAR_INTERIOR_PROGRESS_BAR:\n return \"circular-progress-bar-alt\";\n }\n}\n\n/**\n * Extract a valid enum value from a raw value type value.\n * @param type Raw value.\n */\nfunction extractValueType(valueType: unknown): PercentileProps[\"valueType\"] {\n switch (valueType) {\n case \"percent\":\n case \"value\":\n return valueType;\n default:\n return \"percent\";\n }\n}\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the percentile props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function percentilePropsDecoder(\n data: UnknownObject\n): PercentileProps | never {\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.PERCENTILE_BAR,\n percentileType: extractPercentileType(data.percentileType || data.type),\n valueType: extractValueType(data.valueType),\n minValue: parseIntOr(data.minValue, null),\n maxValue: parseIntOr(data.maxValue, null),\n color: notEmptyStringOr(data.color, null),\n labelColor: notEmptyStringOr(data.labelColor, null),\n value: parseFloatOr(data.value, null),\n unit: notEmptyStringOr(data.unit, null),\n ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nconst svgNS = \"http://www.w3.org/2000/svg\";\n\nexport default class Percentile extends Item {\n protected createDomElement(): HTMLElement {\n const colors = {\n background: \"#000000\",\n progress: this.props.color || \"#F0F0F0\",\n text: this.props.labelColor || \"#444444\"\n };\n // Progress.\n const progress = this.getProgress();\n // Main element.\n const element = document.createElement(\"div\");\n // SVG container.\n const svg = document.createElementNS(svgNS, \"svg\");\n\n var formatValue;\n if (this.props.value != null) {\n if (Intl) {\n formatValue = Intl.NumberFormat(\"en-EN\").format(this.props.value);\n } else {\n formatValue = this.props.value;\n }\n }\n\n switch (this.props.percentileType) {\n case \"progress-bar\":\n {\n const backgroundRect = document.createElementNS(svgNS, \"rect\");\n backgroundRect.setAttribute(\"fill\", colors.background);\n backgroundRect.setAttribute(\"fill-opacity\", \"0.5\");\n backgroundRect.setAttribute(\"width\", \"100\");\n backgroundRect.setAttribute(\"height\", \"20\");\n backgroundRect.setAttribute(\"rx\", \"5\");\n backgroundRect.setAttribute(\"ry\", \"5\");\n const progressRect = document.createElementNS(svgNS, \"rect\");\n progressRect.setAttribute(\"fill\", colors.progress);\n progressRect.setAttribute(\"fill-opacity\", \"1\");\n progressRect.setAttribute(\"width\", `${progress}`);\n progressRect.setAttribute(\"height\", \"20\");\n progressRect.setAttribute(\"rx\", \"5\");\n progressRect.setAttribute(\"ry\", \"5\");\n const text = document.createElementNS(svgNS, \"text\");\n text.setAttribute(\"text-anchor\", \"middle\");\n text.setAttribute(\"alignment-baseline\", \"middle\");\n text.setAttribute(\"font-size\", \"12\");\n text.setAttribute(\"font-family\", \"arial\");\n text.setAttribute(\"font-weight\", \"bold\");\n text.setAttribute(\"transform\", \"translate(50 11)\");\n text.setAttribute(\"fill\", colors.text);\n\n if (this.props.valueType === \"value\") {\n text.style.fontSize = \"6pt\";\n\n text.textContent = this.props.unit\n ? `${formatValue} ${this.props.unit}`\n : `${formatValue}`;\n } else {\n text.textContent = `${progress}%`;\n }\n\n // Auto resize SVG using the view box magic: https://css-tricks.com/scale-svg/\n svg.setAttribute(\"viewBox\", \"0 0 100 20\");\n svg.append(backgroundRect, progressRect, text);\n }\n break;\n case \"bubble\":\n case \"circular-progress-bar\":\n case \"circular-progress-bar-alt\":\n {\n // Auto resize SVG using the view box magic: https://css-tricks.com/scale-svg/\n svg.setAttribute(\"viewBox\", \"0 0 100 100\");\n\n if (this.props.percentileType === \"bubble\") {\n // Create and append the circles.\n const backgroundCircle = document.createElementNS(svgNS, \"circle\");\n backgroundCircle.setAttribute(\"transform\", \"translate(50 50)\");\n backgroundCircle.setAttribute(\"fill\", colors.background);\n backgroundCircle.setAttribute(\"fill-opacity\", \"0.5\");\n backgroundCircle.setAttribute(\"r\", \"50\");\n const progressCircle = document.createElementNS(svgNS, \"circle\");\n progressCircle.setAttribute(\"transform\", \"translate(50 50)\");\n progressCircle.setAttribute(\"fill\", colors.progress);\n progressCircle.setAttribute(\"fill-opacity\", \"1\");\n progressCircle.setAttribute(\"r\", `${progress / 2}`);\n\n svg.append(backgroundCircle, progressCircle);\n } else {\n // Create and append the circles.\n const arcProps = {\n innerRadius:\n this.props.percentileType === \"circular-progress-bar\" ? 30 : 0,\n outerRadius: 50,\n startAngle: 0,\n endAngle: Math.PI * 2\n };\n const arc = arcFactory();\n\n const backgroundCircle = document.createElementNS(svgNS, \"path\");\n backgroundCircle.setAttribute(\"transform\", \"translate(50 50)\");\n backgroundCircle.setAttribute(\"fill\", colors.background);\n backgroundCircle.setAttribute(\"fill-opacity\", \"0.5\");\n backgroundCircle.setAttribute(\"d\", `${arc(arcProps)}`);\n const progressCircle = document.createElementNS(svgNS, \"path\");\n progressCircle.setAttribute(\"transform\", \"translate(50 50)\");\n progressCircle.setAttribute(\"fill\", colors.progress);\n progressCircle.setAttribute(\"fill-opacity\", \"1\");\n progressCircle.setAttribute(\n \"d\",\n `${arc({\n ...arcProps,\n endAngle: arcProps.endAngle * (progress / 100)\n })}`\n );\n\n svg.append(backgroundCircle, progressCircle);\n }\n\n // Create and append the text.\n const text = document.createElementNS(svgNS, \"text\");\n text.setAttribute(\"text-anchor\", \"middle\");\n text.setAttribute(\"alignment-baseline\", \"middle\");\n text.setAttribute(\"font-size\", \"16\");\n text.setAttribute(\"font-family\", \"arial\");\n text.setAttribute(\"font-weight\", \"bold\");\n text.setAttribute(\"fill\", colors.text);\n\n if (this.props.valueType === \"value\" && this.props.value != null) {\n // Show value and unit in 1 (no unit) or 2 lines.\n if (this.props.unit && this.props.unit.length > 0) {\n const value = document.createElementNS(svgNS, \"tspan\");\n value.setAttribute(\"x\", \"0\");\n value.setAttribute(\"dy\", \"1em\");\n value.textContent = `${formatValue}`;\n value.style.fontSize = \"8pt\";\n const unit = document.createElementNS(svgNS, \"tspan\");\n unit.setAttribute(\"x\", \"0\");\n unit.setAttribute(\"dy\", \"1em\");\n unit.textContent = `${this.props.unit}`;\n unit.style.fontSize = \"8pt\";\n text.append(value, unit);\n text.setAttribute(\"transform\", \"translate(50 33)\");\n } else {\n text.textContent = `${formatValue}`;\n text.style.fontSize = \"8pt\";\n text.setAttribute(\"transform\", \"translate(50 50)\");\n }\n } else {\n // Percentage.\n text.textContent = `${progress}%`;\n text.setAttribute(\"transform\", \"translate(50 50)\");\n }\n\n svg.append(text);\n }\n break;\n }\n\n element.append(svg);\n\n return element;\n }\n\n private getProgress(): number {\n const minValue = this.props.minValue || 0;\n const maxValue = this.props.maxValue || 100;\n const value = this.props.value == null ? 0 : this.props.value;\n\n if (value <= minValue) return 0;\n else if (value >= maxValue) return 100;\n else return Math.trunc(((value - minValue) / (maxValue - minValue)) * 100);\n }\n}\n","import { UnknownObject } from \"../types\";\nimport {\n stringIsEmpty,\n notEmptyStringOr,\n decodeBase64,\n parseIntOr\n} from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type ServiceProps = {\n type: ItemType.SERVICE;\n serviceId: number;\n imageSrc: string | null;\n statusImageSrc: string | null;\n encodedTitle: string | null;\n} & ItemProps;\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the service props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function servicePropsDecoder(data: UnknownObject): ServiceProps | never {\n if (data.imageSrc !== null) {\n if (\n typeof data.statusImageSrc !== \"string\" ||\n data.imageSrc.statusImageSrc === 0\n ) {\n throw new TypeError(\"invalid status image src.\");\n }\n } else {\n if (stringIsEmpty(data.encodedTitle)) {\n throw new TypeError(\"missing encode tittle content.\");\n }\n }\n\n if (parseIntOr(data.serviceId, null) === null) {\n throw new TypeError(\"invalid service id.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.SERVICE,\n serviceId: data.serviceId,\n imageSrc: notEmptyStringOr(data.imageSrc, null),\n statusImageSrc: notEmptyStringOr(data.statusImageSrc, null),\n encodedTitle: notEmptyStringOr(data.encodedTitle, null)\n };\n}\n\nexport default class Service extends Item {\n public createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"service\";\n\n if (this.props.statusImageSrc !== null) {\n element.style.background = `url(${this.props.statusImageSrc}) no-repeat`;\n element.style.backgroundSize = \"contain\";\n element.style.backgroundPosition = \"center\";\n } else if (this.props.encodedTitle !== null) {\n element.innerHTML = decodeBase64(this.props.encodedTitle);\n }\n\n return element;\n }\n}\n","import { UnknownObject, Size } from \"./types\";\nimport {\n parseBoolean,\n sizePropsDecoder,\n parseIntOr,\n notEmptyStringOr\n} from \"./lib\";\nimport Item, {\n ItemType,\n ItemProps,\n ItemClickEvent,\n ItemRemoveEvent\n} from \"./Item\";\nimport StaticGraph, { staticGraphPropsDecoder } from \"./items/StaticGraph\";\nimport Icon, { iconPropsDecoder } from \"./items/Icon\";\nimport ColorCloud, { colorCloudPropsDecoder } from \"./items/ColorCloud\";\nimport Group, { groupPropsDecoder } from \"./items/Group\";\nimport Clock, { clockPropsDecoder } from \"./items/Clock\";\nimport Box, { boxPropsDecoder } from \"./items/Box\";\nimport Line, { linePropsDecoder } from \"./items/Line\";\nimport Label, { labelPropsDecoder } from \"./items/Label\";\nimport SimpleValue, { simpleValuePropsDecoder } from \"./items/SimpleValue\";\nimport EventsHistory, {\n eventsHistoryPropsDecoder\n} from \"./items/EventsHistory\";\nimport Percentile, { percentilePropsDecoder } from \"./items/Percentile\";\nimport TypedEvent, { Disposable, Listener } from \"./TypedEvent\";\nimport DonutGraph, { donutGraphPropsDecoder } from \"./items/DonutGraph\";\nimport BarsGraph, { barsGraphPropsDecoder } from \"./items/BarsGraph\";\nimport ModuleGraph, { moduleGraphPropsDecoder } from \"./items/ModuleGraph\";\nimport Service, { servicePropsDecoder } from \"./items/Service\";\n\n// TODO: Document.\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type\nfunction itemInstanceFrom(data: UnknownObject) {\n const type = parseIntOr(data.type, null);\n if (type == null) throw new TypeError(\"missing item type.\");\n\n switch (type as ItemType) {\n case ItemType.STATIC_GRAPH:\n return new StaticGraph(staticGraphPropsDecoder(data));\n case ItemType.MODULE_GRAPH:\n return new ModuleGraph(moduleGraphPropsDecoder(data));\n case ItemType.SIMPLE_VALUE:\n case ItemType.SIMPLE_VALUE_MAX:\n case ItemType.SIMPLE_VALUE_MIN:\n case ItemType.SIMPLE_VALUE_AVG:\n return new SimpleValue(simpleValuePropsDecoder(data));\n case ItemType.PERCENTILE_BAR:\n case ItemType.PERCENTILE_BUBBLE:\n case ItemType.CIRCULAR_PROGRESS_BAR:\n case ItemType.CIRCULAR_INTERIOR_PROGRESS_BAR:\n return new Percentile(percentilePropsDecoder(data));\n case ItemType.LABEL:\n return new Label(labelPropsDecoder(data));\n case ItemType.ICON:\n return new Icon(iconPropsDecoder(data));\n case ItemType.SERVICE:\n return new Service(servicePropsDecoder(data));\n case ItemType.GROUP_ITEM:\n return new Group(groupPropsDecoder(data));\n case ItemType.BOX_ITEM:\n return new Box(boxPropsDecoder(data));\n case ItemType.LINE_ITEM:\n return new Line(linePropsDecoder(data));\n case ItemType.AUTO_SLA_GRAPH:\n return new EventsHistory(eventsHistoryPropsDecoder(data));\n case ItemType.DONUT_GRAPH:\n return new DonutGraph(donutGraphPropsDecoder(data));\n case ItemType.BARS_GRAPH:\n return new BarsGraph(barsGraphPropsDecoder(data));\n case ItemType.CLOCK:\n return new Clock(clockPropsDecoder(data));\n case ItemType.COLOR_CLOUD:\n return new ColorCloud(colorCloudPropsDecoder(data));\n default:\n throw new TypeError(\"item not found\");\n }\n}\n\n// TODO: Document.\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type\nfunction decodeProps(data: UnknownObject) {\n const type = parseIntOr(data.type, null);\n if (type == null) throw new TypeError(\"missing item type.\");\n\n switch (type as ItemType) {\n case ItemType.STATIC_GRAPH:\n return staticGraphPropsDecoder(data);\n case ItemType.MODULE_GRAPH:\n return moduleGraphPropsDecoder(data);\n case ItemType.SIMPLE_VALUE:\n case ItemType.SIMPLE_VALUE_MAX:\n case ItemType.SIMPLE_VALUE_MIN:\n case ItemType.SIMPLE_VALUE_AVG:\n return simpleValuePropsDecoder(data);\n case ItemType.PERCENTILE_BAR:\n case ItemType.PERCENTILE_BUBBLE:\n case ItemType.CIRCULAR_PROGRESS_BAR:\n case ItemType.CIRCULAR_INTERIOR_PROGRESS_BAR:\n return percentilePropsDecoder(data);\n case ItemType.LABEL:\n return labelPropsDecoder(data);\n case ItemType.ICON:\n return iconPropsDecoder(data);\n case ItemType.SERVICE:\n return servicePropsDecoder(data);\n case ItemType.GROUP_ITEM:\n return groupPropsDecoder(data);\n case ItemType.BOX_ITEM:\n return boxPropsDecoder(data);\n case ItemType.LINE_ITEM:\n return linePropsDecoder(data);\n case ItemType.AUTO_SLA_GRAPH:\n return eventsHistoryPropsDecoder(data);\n case ItemType.DONUT_GRAPH:\n return donutGraphPropsDecoder(data);\n case ItemType.BARS_GRAPH:\n return barsGraphPropsDecoder(data);\n case ItemType.CLOCK:\n return clockPropsDecoder(data);\n case ItemType.COLOR_CLOUD:\n return colorCloudPropsDecoder(data);\n default:\n throw new TypeError(\"decoder not found\");\n }\n}\n\n// Base properties.\nexport interface VisualConsoleProps extends Size {\n readonly id: number;\n name: string;\n groupId: number;\n backgroundURL: string | null; // URL?\n backgroundColor: string | null;\n isFavorite: boolean;\n relationLineWidth: number;\n}\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the Visual Console props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function visualConsolePropsDecoder(\n data: UnknownObject\n): VisualConsoleProps | never {\n // Object destructuring: http://es6-features.org/#ObjectMatchingShorthandNotation\n const {\n id,\n name,\n groupId,\n backgroundURL,\n backgroundColor,\n isFavorite,\n relationLineWidth\n } = data;\n\n if (id == null || isNaN(parseInt(id))) {\n throw new TypeError(\"invalid Id.\");\n }\n if (typeof name !== \"string\" || name.length === 0) {\n throw new TypeError(\"invalid name.\");\n }\n if (groupId == null || isNaN(parseInt(groupId))) {\n throw new TypeError(\"invalid group Id.\");\n }\n\n return {\n id: parseInt(id),\n name,\n groupId: parseInt(groupId),\n backgroundURL: notEmptyStringOr(backgroundURL, null),\n backgroundColor: notEmptyStringOr(backgroundColor, null),\n isFavorite: parseBoolean(isFavorite),\n relationLineWidth: parseIntOr(relationLineWidth, 0),\n ...sizePropsDecoder(data)\n };\n}\n\nexport default class VisualConsole {\n // Reference to the DOM element which will contain the items.\n private readonly containerRef: HTMLElement;\n // Properties.\n private _props: VisualConsoleProps;\n // Visual Console Item instances by their Id.\n private elementsById: {\n [key: number]: Item;\n } = {};\n // Visual Console Item Ids.\n private elementIds: ItemProps[\"id\"][] = [];\n // Dictionary which store the created lines.\n private relations: {\n [key: string]: Line;\n } = {};\n // Event manager for click events.\n private readonly clickEventManager = new TypedEvent<\n ItemClickEvent\n >();\n // List of references to clean the event listeners.\n private readonly disposables: Disposable[] = [];\n\n /**\n * React to a click on an element.\n * @param e Event object.\n */\n private handleElementClick: (e: ItemClickEvent) => void = e => {\n this.clickEventManager.emit(e);\n // console.log(`Clicked element #${e.data.id}`, e);\n };\n\n /**\n * Clear some element references.\n * @param e Event object.\n */\n private handleElementRemove: (e: ItemRemoveEvent) => void = e => {\n // Remove the element from the list and its relations.\n this.elementIds = this.elementIds.filter(id => id !== e.data.id);\n delete this.elementsById[e.data.id];\n this.clearRelations(e.data.id);\n };\n\n public constructor(\n container: HTMLElement,\n props: UnknownObject,\n items: UnknownObject[]\n ) {\n this.containerRef = container;\n this._props = visualConsolePropsDecoder(props);\n\n // Force the first render.\n this.render();\n\n // Sort by isOnTop, id ASC\n items = items.sort(function(a, b) {\n if (\n a.isOnTop == null ||\n b.isOnTop == null ||\n a.id == null ||\n b.id == null\n ) {\n return 0;\n }\n\n if (a.isOnTop && !b.isOnTop) return 1;\n else if (!a.isOnTop && b.isOnTop) return -1;\n else if (a.id > b.id) return 1;\n else return -1;\n });\n\n // Initialize the items.\n items.forEach(item => {\n try {\n const itemInstance = itemInstanceFrom(item);\n // Add the item to the list.\n this.elementsById[itemInstance.props.id] = itemInstance;\n this.elementIds.push(itemInstance.props.id);\n // Item event handlers.\n itemInstance.onClick(this.handleElementClick);\n itemInstance.onRemove(this.handleElementRemove);\n // Add the item to the DOM.\n this.containerRef.append(itemInstance.elementRef);\n } catch (error) {\n console.log(\"Error creating a new element:\", error.message);\n }\n });\n\n // Create lines.\n this.buildRelations();\n }\n\n /**\n * Public accessor of the `elements` property.\n * @return Properties.\n */\n public get elements(): Item[] {\n // Ensure the type cause Typescript doesn't know the filter removes null items.\n return this.elementIds\n .map(id => this.elementsById[id])\n .filter(_ => _ != null) as Item[];\n }\n\n /**\n * Public setter of the `elements` property.\n * @param items.\n */\n public updateElements(items: UnknownObject[]): void {\n const itemIds = items.map(item => item.id || null).filter(id => id != null);\n itemIds as number[]; // Tell the type system to rely on us.\n // Get the elements we should delete.\n const deletedIds: number[] = this.elementIds.filter(\n id => itemIds.indexOf(id) < 0\n );\n // Delete the elements.\n deletedIds.forEach(id => {\n if (this.elementsById[id] != null) {\n this.elementsById[id].remove();\n delete this.elementsById[id];\n }\n });\n // Replace the element ids.\n this.elementIds = itemIds;\n\n // Initialize the items.\n items.forEach(item => {\n if (item.id) {\n if (this.elementsById[item.id] == null) {\n // New item.\n try {\n const itemInstance = itemInstanceFrom(item);\n // Add the item to the list.\n this.elementsById[itemInstance.props.id] = itemInstance;\n // Item event handlers.\n itemInstance.onClick(this.handleElementClick);\n itemInstance.onRemove(this.handleElementRemove);\n // Add the item to the DOM.\n this.containerRef.append(itemInstance.elementRef);\n } catch (error) {\n console.log(\"Error creating a new element:\", error.message);\n }\n } else {\n // Update item.\n try {\n this.elementsById[item.id].props = decodeProps(item);\n } catch (error) {\n console.log(\"Error updating an element:\", error.message);\n }\n }\n }\n });\n\n // Re-build relations.\n this.buildRelations();\n }\n\n /**\n * Public accessor of the `props` property.\n * @return Properties.\n */\n public get props(): VisualConsoleProps {\n return { ...this._props }; // Return a copy.\n }\n\n /**\n * Public setter of the `props` property.\n * If the new props are different enough than the\n * stored props, a render would be fired.\n * @param newProps\n */\n public set props(newProps: VisualConsoleProps) {\n const prevProps = this.props;\n // Update the internal props.\n this._props = newProps;\n\n // From this point, things which rely on this.props can access to the changes.\n\n // Re-render.\n this.render(prevProps);\n }\n\n /**\n * Recreate or update the HTMLElement which represents the Visual Console into the DOM.\n * @param prevProps If exists it will be used to only DOM updates instead of a full replace.\n */\n public render(prevProps: VisualConsoleProps | null = null): void {\n if (prevProps) {\n if (prevProps.backgroundURL !== this.props.backgroundURL) {\n this.containerRef.style.backgroundImage =\n this.props.backgroundURL !== null\n ? `url(${this.props.backgroundURL})`\n : null;\n }\n if (prevProps.backgroundColor !== this.props.backgroundColor) {\n this.containerRef.style.backgroundColor = this.props.backgroundColor;\n }\n if (this.sizeChanged(prevProps, this.props)) {\n this.resizeElement(this.props.width, this.props.height);\n }\n } else {\n this.containerRef.style.backgroundImage =\n this.props.backgroundURL !== null\n ? `url(${this.props.backgroundURL})`\n : null;\n\n this.containerRef.style.backgroundColor = this.props.backgroundColor;\n this.resizeElement(this.props.width, this.props.height);\n }\n }\n\n /**\n * Compare the previous and the new size and return\n * a boolean value in case the size changed.\n * @param prevSize\n * @param newSize\n * @return Whether the size changed or not.\n */\n public sizeChanged(prevSize: Size, newSize: Size): boolean {\n return (\n prevSize.width !== newSize.width || prevSize.height !== newSize.height\n );\n }\n\n /**\n * Resize the DOM container.\n * @param width\n * @param height\n */\n public resizeElement(width: number, height: number): void {\n this.containerRef.style.width = `${width}px`;\n this.containerRef.style.height = `${height}px`;\n }\n\n /**\n * Update the size into the properties and resize the DOM container.\n * @param width\n * @param height\n */\n public resize(width: number, height: number): void {\n this.props = {\n ...this.props, // Object spread: http://es6-features.org/#SpreadOperator\n width,\n height\n };\n }\n\n /**\n * To remove the event listeners and the elements from the DOM.\n */\n public remove(): void {\n this.disposables.forEach(d => d.dispose()); // Arrow function.\n this.elements.forEach(e => e.remove()); // Arrow function.\n this.elementsById = {};\n this.elementIds = [];\n // Clear relations.\n this.clearRelations();\n // Clean container.\n this.containerRef.innerHTML = \"\";\n }\n\n /**\n * Create line elements which connect the elements with their parents.\n */\n private buildRelations(): void {\n // Clear relations.\n this.clearRelations();\n // Add relations.\n this.elements.forEach(item => {\n if (item.props.parentId !== null) {\n const parent = this.elementsById[item.props.parentId];\n const child = this.elementsById[item.props.id];\n if (parent && child) this.addRelationLine(parent, child);\n }\n });\n }\n\n /**\n * @param itemId Optional identifier of a parent or child item.\n * Remove the line elements which connect the elements with their parents.\n */\n private clearRelations(itemId?: number): void {\n if (itemId != null) {\n for (let key in this.relations) {\n const ids = key.split(\"|\");\n const parentId = Number.parseInt(ids[0]);\n const childId = Number.parseInt(ids[1]);\n\n if (itemId === parentId || itemId === childId) {\n this.relations[key].remove();\n delete this.relations[key];\n }\n }\n } else {\n for (let key in this.relations) {\n this.relations[key].remove();\n delete this.relations[key];\n }\n }\n }\n\n /**\n * Retrieve the line element which represent the relation between items.\n * @param parentId Identifier of the parent item.\n * @param childId Itentifier of the child item.\n * @return The line element or nothing.\n */\n private getRelationLine(parentId: number, childId: number): Line | null {\n const identifier = `${parentId}|${childId}`;\n return this.relations[identifier] || null;\n }\n\n /**\n * Add a new line item to represent a relation between the items.\n * @param parent Parent item.\n * @param child Child item.\n * @return Whether the line was added or not.\n */\n private addRelationLine(\n parent: Item,\n child: Item\n ): Line {\n const identifier = `${parent.props.id}|${child.props.id}`;\n if (this.relations[identifier] != null) {\n this.relations[identifier].remove();\n }\n\n // Get the items center.\n const startX = parent.props.x + parent.elementRef.clientWidth / 2;\n const startY =\n parent.props.y +\n (parent.elementRef.clientHeight - parent.labelElementRef.clientHeight) /\n 2;\n const endX = child.props.x + child.elementRef.clientWidth / 2;\n const endY =\n child.props.y +\n (child.elementRef.clientHeight - child.labelElementRef.clientHeight) / 2;\n\n const line = new Line(\n linePropsDecoder({\n id: 0,\n type: ItemType.LINE_ITEM,\n startX,\n startY,\n endX,\n endY,\n width: 0,\n height: 0,\n lineWidth: this.props.relationLineWidth,\n color: \"#CCCCCC\"\n })\n );\n // Save a reference to the line item.\n this.relations[identifier] = line;\n\n // Add the line to the DOM.\n line.elementRef.style.zIndex = \"0\";\n this.containerRef.append(line.elementRef);\n\n return line;\n }\n\n /**\n * Add an event handler to the click of the linked visual console elements.\n * @param listener Function which is going to be executed when a linked console is clicked.\n */\n public onClick(listener: Listener>): Disposable {\n /*\n * The '.on' function returns a function which will clean the event\n * listener when executed. We store all the 'dispose' functions to\n * call them when the item should be cleared.\n */\n const disposable = this.clickEventManager.on(listener);\n this.disposables.push(disposable);\n\n return disposable;\n }\n}\n","import TypedEvent, { Disposable, Listener } from \"../TypedEvent\";\n\ninterface Cancellable {\n cancel(): void;\n}\n\ntype AsyncTaskStatus = \"waiting\" | \"started\" | \"cancelled\" | \"finished\";\ntype AsyncTaskInitiator = (done: () => void) => Cancellable;\n\n/**\n * Defines an async task which can be started and cancelled.\n * It's possible to observe the status changes of the task.\n */\nclass AsyncTask {\n private readonly taskInitiator: AsyncTaskInitiator;\n private cancellable: Cancellable = { cancel: () => {} };\n private _status: AsyncTaskStatus = \"waiting\";\n\n // Event manager for status change events.\n private readonly statusChangeEventManager = new TypedEvent();\n // List of references to clean the event listeners.\n private readonly disposables: Disposable[] = [];\n\n public constructor(taskInitiator: AsyncTaskInitiator) {\n this.taskInitiator = taskInitiator;\n }\n\n /**\n * Public setter of the `status` property.\n * @param status.\n */\n public set status(status: AsyncTaskStatus) {\n this._status = status;\n this.statusChangeEventManager.emit(status);\n }\n\n /**\n * Public accessor of the `status` property.\n * @return status.\n */\n public get status() {\n return this._status;\n }\n\n /**\n * Start the async task.\n */\n public init(): void {\n this.cancellable = this.taskInitiator(() => {\n this.status = \"finished\";\n });\n this.status = \"started\";\n }\n\n /**\n * Cancel the async task.\n */\n public cancel(): void {\n this.cancellable.cancel();\n this.status = \"cancelled\";\n }\n\n /**\n * Add an event handler to the status change.\n * @param listener Function which is going to be executed when the status changes.\n */\n public onStatusChange(listener: Listener): Disposable {\n /*\n * The '.on' function returns a function which will clean the event\n * listener when executed. We store all the 'dispose' functions to\n * call them when the item should be cleared.\n */\n const disposable = this.statusChangeEventManager.on(listener);\n this.disposables.push(disposable);\n\n return disposable;\n }\n}\n\n/**\n * Wrap an async task into another which will execute that task indefinitely\n * every time the tash finnish and the chosen period ends.\n * Will last until cancellation.\n *\n * @param task Async task to execute.\n * @param period Time in milliseconds to wait until the next async esecution.\n *\n * @return A new async task.\n */\nfunction asyncPeriodic(task: AsyncTask, period: number): AsyncTask {\n return new AsyncTask(() => {\n let ref: number | null = null;\n\n task.onStatusChange(status => {\n if (status === \"finished\") {\n ref = window.setTimeout(() => {\n task.init();\n }, period);\n }\n });\n\n task.init();\n\n return {\n cancel: () => {\n if (ref) clearTimeout(ref);\n task.cancel();\n }\n };\n });\n}\n\n/**\n * Manages a list of async tasks.\n */\nexport default class AsyncTaskManager {\n private tasks: { [identifier: string]: AsyncTask } = {};\n\n /**\n * Adds an async task to the manager.\n *\n * @param identifier Unique identifier.\n * @param taskInitiator Function to initialize the async task.\n * Should return a structure to cancel the task.\n * @param period Optional period to repeat the task indefinitely.\n */\n public add(\n identifier: string,\n taskInitiator: AsyncTaskInitiator,\n period: number = 0\n ): AsyncTask {\n if (this.tasks[identifier] && this.tasks[identifier].status === \"started\") {\n this.tasks[identifier].cancel();\n }\n\n const asyncTask =\n period > 0\n ? asyncPeriodic(new AsyncTask(taskInitiator), period)\n : new AsyncTask(taskInitiator);\n\n this.tasks[identifier] = asyncTask;\n\n return this.tasks[identifier];\n }\n\n /**\n * Starts an async task.\n *\n * @param identifier Unique identifier.\n */\n public init(identifier: string) {\n if (\n this.tasks[identifier] &&\n (this.tasks[identifier].status === \"waiting\" ||\n this.tasks[identifier].status === \"cancelled\" ||\n this.tasks[identifier].status === \"finished\")\n ) {\n this.tasks[identifier].init();\n }\n }\n\n /**\n * Cancel a running async task.\n *\n * @param identifier Unique identifier.\n */\n public cancel(identifier: string) {\n if (this.tasks[identifier] && this.tasks[identifier].status === \"started\") {\n this.tasks[identifier].cancel();\n }\n }\n}\n","/*\n * Useful resources.\n * http://es6-features.org/\n * http://exploringjs.com/es6\n * https://www.typescriptlang.org/\n */\n\nimport \"./main.css\"; // CSS import.\nimport VisualConsole from \"./VisualConsole\";\nimport AsyncTaskManager from \"./lib/AsyncTaskManager\";\n\n// Export the VisualConsole class to the global object.\n// eslint-disable-next-line\n(window as any).VisualConsole = VisualConsole;\n\n// Export the AsyncTaskManager class to the global object.\n// eslint-disable-next-line\n(window as any).AsyncTaskManager = AsyncTaskManager;\n"],"sourceRoot":""} \ No newline at end of file diff --git a/pandora_console/index.php b/pandora_console/index.php index ad4b93465a..06793c1a87 100755 --- a/pandora_console/index.php +++ b/pandora_console/index.php @@ -173,8 +173,8 @@ if (!empty($config['https']) && empty($_SERVER['HTTPS'])) { // Pure mode (without menu, header and footer). $config['pure'] = (bool) get_parameter('pure'); -// Auto Refresh page (can now be disabled anywhere in the script) -if (get_parameter('refr')) { +// Auto Refresh page (can now be disabled anywhere in the script). +if (get_parameter('refr') != null) { $config['refr'] = (int) get_parameter('refr'); } @@ -244,6 +244,10 @@ if (strlen($search) > 0) { // Login process if (! isset($config['id_user'])) { + // Clear error messages. + unset($_COOKIE['errormsg']); + setcookie('errormsg', null, -1); + if (isset($_GET['login'])) { include_once 'include/functions_db.php'; // Include it to use escape_string_sql function @@ -619,10 +623,9 @@ if (! isset($config['id_user'])) { header('Location: '.$config['homeurl'].'index.php'.$redirect_url); exit; - // Always exit after sending location headers - } - // Hash login process - else if (isset($_GET['loginhash'])) { + // Always exit after sending location headers. + } else if (isset($_GET['loginhash'])) { + // Hash login process $loginhash_data = get_parameter('loginhash_data', ''); $loginhash_user = str_rot13(get_parameter('loginhash_user', '')); @@ -638,9 +641,8 @@ if (! isset($config['id_user'])) { exit(''); } - } - // There is no user connected - else { + } else { + // There is no user connected. if ($config['enterprise_installed']) { enterprise_include_once('include/functions_reset_pass.php'); } @@ -722,64 +724,55 @@ if (! isset($config['id_user'])) { $show_error = false; if (!$first) { - if ($reset) { - if ($user_reset_pass == '') { + if ($user_reset_pass == '') { + $reset = false; + $error = __('Id user cannot be empty'); + $show_error = true; + } else { + $check_user = check_user_id($user_reset_pass); + + if (!$check_user) { $reset = false; - $error = __('Id user cannot be empty'); + register_pass_change_try($user_reset_pass, 0); + $error = __('Error in reset password request'); $show_error = true; } else { - $check_user = check_user_id($user_reset_pass); + $check_mail = check_user_have_mail($user_reset_pass); - if (!$check_user) { + if (!$check_mail) { $reset = false; register_pass_change_try($user_reset_pass, 0); - $error = __('Error in reset password request'); + $error = __('This user doesn\'t have a valid email address'); $show_error = true; } else { - $check_mail = check_user_have_mail($user_reset_pass); - - if (!$check_mail) { - $reset = false; - register_pass_change_try($user_reset_pass, 0); - $error = __('This user doesn\'t have a valid email address'); - $show_error = true; - } else { - $mail = $check_mail; - } + $mail = $check_mail; } } } - if (!$reset) { - if ($config['enterprise_installed']) { - include_once 'enterprise/include/reset_pass.php'; - } + $cod_hash = $user_reset_pass.'::::'.md5(rand(10, 1000000).rand(10, 1000000).rand(10, 1000000)); + + $subject = '['.io_safe_output(get_product_name()).'] '.__('Reset password'); + $body = __('This is an automatically sent message for user '); + $body .= ' "'.$user_reset_pass.'"'; + $body .= '

    '; + $body .= __('Please click the link below to reset your password'); + $body .= '

    '; + $body .= ''.__('Reset your password').''; + $body .= '

    '; + $body .= get_product_name(); + $body .= '

    '; + $body .= ''.__('Please do not reply to this email.').''; + + $result = send_email_to_user($mail, $body, $subject); + + if (!$result) { + $process_error_message = __('Error at sending the email'); } else { - $cod_hash = $user_reset_pass.'::::'.md5(rand(10, 1000000).rand(10, 1000000).rand(10, 1000000)); - - $subject = '['.get_product_name().'] '.__('Reset password'); - $body = __('This is an automatically sent message for user '); - $body .= ' "'.$user_reset_pass.'"'; - $body .= '

    '; - $body .= __('Please click the link below to reset your password'); - $body .= '

    '; - $body .= ''.__('Reset your password').''; - $body .= '

    '; - $body .= get_product_name(); - $body .= '

    '; - $body .= ''.__('Please do not reply to this email.').''; - - $result = send_email_to_user($mail, $body, $subject); - - $process_error_message = ''; - if (!$result) { - $process_error_message = __('Error at sending the email'); - } else { - send_token_to_db($user_reset_pass, $cod_hash); - } - - include_once 'general/login_page.php'; + send_token_to_db($user_reset_pass, $cod_hash); } + + include_once 'general/login_page.php'; } else { include_once 'enterprise/include/reset_pass.php'; } @@ -898,15 +891,6 @@ clear_pandora_error_for_header(); $config['logged'] = false; extensions_load_extensions($process_login); -// Check for update manager messages -if (license_free() && is_user_admin($config['id_user']) - && (($config['last_um_check'] < time()) - || (!isset($config['last_um_check']))) -) { - include_once 'include/functions_update_manager.php'; - update_manager_download_messages(); -} - if ($process_login) { // Call all extensions login function extensions_call_login_function(); @@ -982,31 +966,9 @@ if ($old_global_counter_chat != $now_global_counter_chat) { } } -// Pop-ups display order: -// 1) login_required (timezone and email) -// 2) identification (newsletter and register) -// 3) last_message (update manager message popup -// 4) login_help (online help, enterpirse version, forums, documentation) -if (is_user_admin($config['id_user']) - && (!isset($config['initial_wizard']) || $config['initial_wizard'] != 1) -) { - include_once 'general/login_required.php'; -} +require_once 'general/register.php'; if (get_parameter('login', 0) !== 0) { - // Display news dialog - include_once 'general/news_dialog.php'; - - // Display login help info dialog - // If it's configured to not skip this - $display_previous_popup = false; - if (license_free() && is_user_admin($config['id_user']) && $config['initial_wizard'] == 1) { - $display_previous_popup = include_once 'general/login_identification_wizard.php'; - if ($display_previous_popup === false) { - $display_previous_popup = include_once 'general/last_message.php'; - } - } - if ((!isset($config['skip_login_help_dialog']) || $config['skip_login_help_dialog'] == 0) && $display_previous_popup === false && $config['initial_wizard'] == 1 @@ -1023,20 +985,18 @@ if (get_parameter('login', 0) !== 0) { // Header if ($config['pure'] == 0) { - if ($config['classic_menu']) { - echo '

    '; - echo '
    '; + echo '