diff --git a/pandora_agents/unix/DEBIAN/control b/pandora_agents/unix/DEBIAN/control index d215a0b3dc..819a95905f 100644 --- a/pandora_agents/unix/DEBIAN/control +++ b/pandora_agents/unix/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-agent-unix -Version: 7.0NG.772-230728 +Version: 7.0NG.772-230808 Architecture: all Priority: optional Section: admin diff --git a/pandora_agents/unix/DEBIAN/make_deb_package.sh b/pandora_agents/unix/DEBIAN/make_deb_package.sh index 7502761fe4..6000c9a8c2 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.772-230728" +pandora_version="7.0NG.772-230808" echo "Test if you has the tools for to make the packages." whereis dpkg-deb | cut -d":" -f2 | grep dpkg-deb > /dev/null @@ -42,6 +42,7 @@ mkdir -p temp_package/usr/bin/ mkdir -p temp_package/usr/sbin/ mkdir -p temp_package/etc/pandora/plugins mkdir -p temp_package/etc/pandora/collections +mkdir -p temp_package/etc/pandora/ref mkdir -p temp_package/etc/pandora/trans mkdir -p temp_package/etc/pandora/commands mkdir -p temp_package/etc/init.d/ diff --git a/pandora_agents/unix/Darwin/dmg/scripts/postinstall b/pandora_agents/unix/Darwin/dmg/scripts/postinstall index 5b25222a37..ff930b840c 100644 --- a/pandora_agents/unix/Darwin/dmg/scripts/postinstall +++ b/pandora_agents/unix/Darwin/dmg/scripts/postinstall @@ -30,6 +30,7 @@ else mkdir -p /usr/local/share/man/man1/ mkdir -p /usr/local/share/pandora_agent/collections/ mkdir -p /usr/local/share/pandora_agent/commands/ + mkdir -p /usr/local/share/pandora_agent/ref/ mkdir -p /etc/pandora/ mkdir -p /var/spool/pandora/data_out/ mkdir -p /var/log/pandora/ @@ -39,6 +40,7 @@ else # Setting permissions to directories and files chmod -R 700 /usr/local/share/pandora_agent/collections chmod -R 700 /usr/local/share/pandora_agent/commands + chmod -R 700 /usr/local/share/pandora_agent/ref chmod -R 755 /etc/pandora/ chmod -R 700 /var/spool/pandora/data_out chmod -R 711 /var/log/pandora @@ -69,6 +71,7 @@ chown root:wheel /usr/local/bin/tentacle_client ln -s /usr/local/share/pandora_agent/plugins /etc/pandora/plugins ln -s /usr/local/share/pandora_agent/commands /etc/pandora/commands ln -s /usr/local/share/pandora_agent/collections /etc/pandora/collections +ln -s /usr/local/share/pandora_agent/ref /etc/pandora/ref # Copy manuals @@ -90,4 +93,4 @@ echo "/var/log/pandora/pandora_agent.log : 640 5 204 # Clean all install utilites rm -Rf inst_utilities -exit 0 \ No newline at end of file +exit 0 diff --git a/pandora_agents/unix/pandora_agent b/pandora_agents/unix/pandora_agent index eccd4eae0e..4dfced67f7 100755 --- a/pandora_agents/unix/pandora_agent +++ b/pandora_agents/unix/pandora_agent @@ -1003,7 +1003,7 @@ use strict; use warnings; use Scalar::Util qw(looks_like_number); -use POSIX qw(strftime floor); +use POSIX qw(ceil floor strftime); use Sys::Hostname; use File::Basename; use File::Copy; @@ -1031,7 +1031,7 @@ my $Sem = undef; my $ThreadSem = undef; use constant AGENT_VERSION => '7.0NG.772'; -use constant AGENT_BUILD => '230728'; +use constant AGENT_BUILD => '230808'; # Agent log default file size maximum and instances use constant DEFAULT_MAX_LOG_SIZE => 600000; @@ -1121,6 +1121,7 @@ my %DefaultConf = ( 'server_path_md5' => 'md5', #undocumented 'server_path_conf' => 'conf', #undocumented 'server_path_zip' => 'collections', #undocumented + 'server_path_ref' => 'ref', #undocumented 'logfile' =>'/var/log/pandora/pandora_agent.log', 'logsize' => DEFAULT_MAX_LOG_SIZE, 'logrotate' => DEFAULT_LOG_ROTATE, @@ -1569,6 +1570,34 @@ sub parse_conf_modules($) { $module->{'post_process'} = $1; } elsif ($line =~ /^\s*module_interval\s+(\d+)\s*$/) { $module->{'interval'} = $1; + } elsif ($line =~ /^\s*module_absoluteinterval\s+(.*)$/) { + my $absolute_interval = $1; + if ($absolute_interval eq 'once') { + $module->{'absoluteinterval'} = 0; + } elsif ($absolute_interval =~ /^(\d+)([smhd])?\s*$/) { + if (defined($2)) { + # Seconds. + if ($2 eq 's') { + $module->{'absoluteinterval'} = int($1); + } + # Minutes (convert to seconds). + elsif ($2 eq 'm') { + $module->{'absoluteinterval'} = int($1) * 60; + } + # Hours (convert to seconds). + elsif ($2 eq 'h') { + $module->{'absoluteinterval'} = int($1) * 3600; + } + # Days (convert to seconds). + elsif ($2 eq 'd') { + $module->{'absoluteinterval'} = int($1) * 86400; + } + } else { + $module->{'absoluteinterval'} = int($1) * $Conf{'interval'}; + } + } else { + log_message ('setup', "Invalid value for module_absoluteinterval: $absolute_interval"); + } } elsif ($line =~ /^\s*module_timeout\s+(\d+)\s*$/) { $module->{'timeout'} = $1; } elsif ($line =~ /^\s*module_save\s+(\w+)$/) { @@ -1636,6 +1665,27 @@ sub parse_conf_modules($) { next; } + # Configure modules with an absolute interval. + if (defined($module->{'absoluteinterval'})) { + + # Convert from seconds to actual agent intervals. + $module->{'interval'} = ceil($module->{'absoluteinterval'} / $Conf{'interval'}); + + # Make sure modules that run once are asynchronous. + if ($module->{'interval'} == 0) { + if ($module->{'type'} eq 'generic_data') { + $module->{'type'} = 'async_data'; + } elsif ($module->{'type'} eq 'generic_proc') { + $module->{'type'} = 'async_proc'; + } elsif ($module->{'type'} eq 'generic_data_string') { + $module->{'type'} = 'async_string'; + } + } + + # This file will be used for persistence. + $module->{'timestamp_file'} = $ConfDir . '/' . $Conf{'server_path_ref'} . '/' . md5($module->{'name'}) . '.ref'; + } + # Set the intensive interval if ($module->{'is_intensive'} == 1) { $module->{'intensive_interval'} = $module->{'interval'}; @@ -1643,9 +1693,9 @@ sub parse_conf_modules($) { $module->{'intensive_interval'} = $module->{'interval'} * ($Conf{'interval'} / $Conf{'intensive_interval'}); } - # Make the module run the first time - $module->{'counter'} = $module->{'intensive_interval'}; - + # Initialize the module's execution counter. + init_counter($module); + # Replace macros replace_macros ($module); @@ -2805,7 +2855,15 @@ sub exec_module { } } - if (++($module->{'counter'}) < $module->{'intensive_interval'}) { + # Modules that will run once. + if ($module->{'interval'} == 0) { + if ($module->{'counter'} == 0) { + $ThreadSem->up () if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1); + return; + } + } + # Modules that will run periodically. + elsif (++($module->{'counter'}) < $module->{'intensive_interval'}) { $ThreadSem->up () if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1); return; } @@ -2862,6 +2920,9 @@ sub exec_module { } } + # Save the module's timestamp to disk. + save_module_timestamp($module); + $ThreadSem->up () if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1); } @@ -3547,6 +3608,44 @@ sub check_module_cron { return 0; } +################################################################################ +# Initialize a module's internal execution counter. +################################################################################ +sub init_counter($) { + my ($module) = @_; + + # Open the timestamp file if available. + my $fh; + if (!defined($module->{'timestamp_file'}) || + !open($fh, '<', $module->{'timestamp_file'})) { + # If intensive_interval is 0, setting counter to any value != 0 will make the module run. + $module->{'counter'} = $module->{'intensive_interval'} == 0 ? 1 : $module->{'intensive_interval'}; + return; + } + + # Read the timestamp from disk. + my $timestamp = int(<$fh>); + close($fh); + + # Update the module's execution counter. + # If intensive_interval is 0, setting counter to 0 will prevent the module from running again. + $module->{'counter'} = $module->{'intensive_interval'} == 0 ? 0 : floor((time() - $timestamp) / $Conf{'interval'}); +} + +################################################################################ +# Save a module's execution timestamp to disk for persistence. +################################################################################ +sub save_module_timestamp($) { + my ($module) = @_; + + return if (!defined($module->{'timestamp_file'})); + + # Update the time reference. + open(my $fh, '>', $module->{'timestamp_file'}) or return; + print $fh time(); + close($fh); +} + ################################################################################ # Write module data in XML format. ################################################################################ diff --git a/pandora_agents/unix/pandora_agent.redhat.spec b/pandora_agents/unix/pandora_agent.redhat.spec index 11d9893c3e..d3cadf0da4 100644 --- a/pandora_agents/unix/pandora_agent.redhat.spec +++ b/pandora_agents/unix/pandora_agent.redhat.spec @@ -4,7 +4,7 @@ %global __os_install_post %{nil} %define name pandorafms_agent_linux %define version 7.0NG.772 -%define release 230728 +%define release 230808 Summary: Pandora FMS Linux agent, PERL version Name: %{name} @@ -100,6 +100,11 @@ if [ ! -e /etc/pandora/collections ]; then ln -s /usr/share/pandora_agent/collections /etc/pandora fi +if [ ! -e /etc/pandora/ref ]; then + mkdir -p /usr/share/pandora_agent/ref + ln -s /usr/share/pandora_agent/ref /etc/pandora +fi + if [ ! -e /etc/pandora/commands ]; then mkdir -p /usr/share/pandora_agent/commands ln -s /usr/share/pandora_agent/commands /etc/pandora @@ -143,7 +148,7 @@ fi # Remove symbolic links pushd /etc/pandora -for f in pandora_agent.conf plugins collections +for f in pandora_agent.conf plugins collections ref do [ -L $f ] && rm -f $f done diff --git a/pandora_agents/unix/pandora_agent.spec b/pandora_agents/unix/pandora_agent.spec index d66c93089d..17280c4486 100644 --- a/pandora_agents/unix/pandora_agent.spec +++ b/pandora_agents/unix/pandora_agent.spec @@ -4,7 +4,7 @@ %global __os_install_post %{nil} %define name pandorafms_agent_linux %define version 7.0NG.772 -%define release 230728 +%define release 230808 Summary: Pandora FMS Linux agent, PERL version Name: %{name} @@ -94,6 +94,10 @@ if [ ! -e /etc/pandora/collections ]; then mkdir /etc/pandora/collections fi +if [ ! -e /etc/pandora/ref ]; then + mkdir /etc/pandora/ref +fi + if [ ! -e /etc/pandora/commands ]; then mkdir /etc/pandora/commands fi diff --git a/pandora_agents/unix/pandora_agent_installer b/pandora_agents/unix/pandora_agent_installer index 0b3f05ea5f..7b3d0770b0 100755 --- a/pandora_agents/unix/pandora_agent_installer +++ b/pandora_agents/unix/pandora_agent_installer @@ -10,7 +10,7 @@ # ********************************************************************** PI_VERSION="7.0NG.772" -PI_BUILD="230728" +PI_BUILD="230808" OS_NAME=`uname -s` FORCE=0 @@ -408,6 +408,11 @@ install () { chmod -R 700 $PANDORA_BASE$PANDORA_HOME/commands ln -s $PANDORA_BASE_REAL$PANDORA_HOME/commands $PANDORA_BASE$PANDORA_CFG + echo "Creating the ref directory in to $PANDORA_BASE$PANDORA_HOME/ref..." + mkdir -p $PANDORA_BASE$PANDORA_HOME/ref + chmod -R 700 $PANDORA_BASE$PANDORA_HOME/ref + ln -s $PANDORA_BASE_REAL$PANDORA_HOME/ref $PANDORA_BASE$PANDORA_CFG + if [ $WITHOUT_TENTACLE_SERVER -eq 0 ] then echo "Copying tentacle server to $PANDORA_BASE$TENTACLE_SERVER" diff --git a/pandora_agents/win32/installer/pandora.mpi b/pandora_agents/win32/installer/pandora.mpi index e06ad9ef16..000586c8ff 100644 --- a/pandora_agents/win32/installer/pandora.mpi +++ b/pandora_agents/win32/installer/pandora.mpi @@ -186,7 +186,7 @@ UpgradeApplicationID {} Version -{230728} +{230808} ViewReadme {Yes} diff --git a/pandora_agents/win32/misc/pandora_file.h b/pandora_agents/win32/misc/pandora_file.h index 424addcfca..f7bd238541 100644 --- a/pandora_agents/win32/misc/pandora_file.h +++ b/pandora_agents/win32/misc/pandora_file.h @@ -31,6 +31,10 @@ using namespace std; * File operations. */ namespace Pandora_File { + + /* Size of a buffer that will be passed to Pandora_File::md5. */ + const int MD5_BUF_SIZE = 33; + /** * File super-class exception. */ diff --git a/pandora_agents/win32/modules/pandora_module.cc b/pandora_agents/win32/modules/pandora_module.cc index 6d479d3136..2df46ad9d5 100644 --- a/pandora_agents/win32/modules/pandora_module.cc +++ b/pandora_agents/win32/modules/pandora_module.cc @@ -19,11 +19,14 @@ */ #include "pandora_module.h" +#include "pandora_windows_service.h" +#include "../misc/pandora_file.h" #include "../pandora_strutils.h" #include "../pandora.h" #include #include +#include #define BUFSIZE 4096 @@ -472,18 +475,27 @@ Pandora_Module::setNoOutput () { */ void Pandora_Module::run () { - /* Check the interval */ - if (this->executions % this->intensive_interval != 0) { + + // Run once. + if (this->intensive_interval == 0) { + if (this->executions == 0) { + has_output = false; + throw Interval_Not_Fulfilled (); + } + } + // Run periodically. + else if (++this->executions < this->intensive_interval) { pandoraDebug ("%s: Interval is not fulfilled", this->module_name.c_str ()); - this->executions++; has_output = false; throw Interval_Not_Fulfilled (); } - /* Increment the executions after check. This is done to execute the - first time */ - this->executions++; + // Reset the execution counter. + this->executions = 0; has_output = true; + + // Update the execution timestamp. + this->updateTimestampFile(); } /** @@ -1663,6 +1675,63 @@ Pandora_Module::getTimestamp () { return this->timestamp; } +/** + * Sets the module timestamp file. + * + * @param file_name The name of the timestamp file. + */ +void +Pandora_Module::setTimestampFile (string file_name) { + this->timestamp_file = file_name; +} + +/** + * Gets the module timestamp file. + * + * @return The name of the timestamp file. + */ +string +Pandora_Module::getTimestampFile () { + return this->timestamp_file; +} + +/** + * Update the timestamp file with the current time. + * + */ +void +Pandora_Module::updateTimestampFile () { + try { + Pandora_File::writeFile(this->timestamp_file, std::to_string(std::time(NULL))); + } catch (...) { + /* Ignore errors. */ + } +} + +/** + * Initialize the module's internal execution counter. + * + */ +void +Pandora_Module::initExecutions () { + string timestamp; + + try { + if (this->timestamp_file != "" && Pandora_File::readFile(this->timestamp_file, timestamp) != FILE_NOT_FOUND) { + // If the interval is 0, setting executions to 0 will prevent the module from running. + this->executions = this->intensive_interval == 0 ? + 0 : + floor((1000.0 * (std::time(NULL) - strtoint(timestamp))) / Pandora_Windows_Service::getInstance()->getInterval()); + return; + } + } catch (...) { + // Ignore errors. + } + + // If the interval is 0, setting executions to any value != 0 will make the module run. + this->executions = this->intensive_interval == 0 ? 1 : this->intensive_interval; +} + /** * Sets the value of intensive_match. * diff --git a/pandora_agents/win32/modules/pandora_module.h b/pandora_agents/win32/modules/pandora_module.h index dfb59f8c8c..111fc79c79 100644 --- a/pandora_agents/win32/modules/pandora_module.h +++ b/pandora_agents/win32/modules/pandora_module.h @@ -171,6 +171,7 @@ namespace Pandora_Modules { Cron *cron; list *intensive_condition_list; time_t timestamp; + string timestamp_file; unsigned char intensive_match; int intensive_interval; string unit, custom_id, str_warning, str_critical; @@ -238,6 +239,7 @@ namespace Pandora_Modules { bool getAsync (); void setExecutions(long executions=0); long getExecutions(); + void initExecutions (); virtual string getXml (); @@ -303,6 +305,9 @@ namespace Pandora_Modules { int hasOutput (); void setTimestamp (time_t timestamp); time_t getTimestamp (); + void setTimestampFile (string file_name); + string getTimestampFile (); + void updateTimestampFile (); void setIntensiveMatch (unsigned char intensive_match); unsigned char getIntensiveMatch (); bool isIntensive (); diff --git a/pandora_agents/win32/modules/pandora_module_factory.cc b/pandora_agents/win32/modules/pandora_module_factory.cc index 94af3ab5ef..de149293ff 100644 --- a/pandora_agents/win32/modules/pandora_module_factory.cc +++ b/pandora_agents/win32/modules/pandora_module_factory.cc @@ -41,7 +41,10 @@ #include "pandora_module_snmpget.h" #include "../windows/pandora_wmi.h" #include "../pandora_strutils.h" +#include "../misc/pandora_file.h" +#include "../pandora.h" #include +#include using namespace Pandora; using namespace Pandora_Modules; @@ -50,6 +53,7 @@ using namespace Pandora_Strutils; #define TOKEN_NAME ("module_name ") #define TOKEN_TYPE ("module_type ") #define TOKEN_INTERVAL ("module_interval ") +#define TOKEN_ABSOLUTEINTERVAL ("module_absoluteinterval ") #define TOKEN_EXEC ("module_exec ") #define TOKEN_PROC ("module_proc ") #define TOKEN_SERVICE ("module_service ") @@ -156,7 +160,8 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { list::iterator iter; string module_name, module_type, module_exec; string module_min, module_max, module_description; - string module_interval, module_proc, module_service; + string module_interval, module_absoluteinterval; + string module_proc, module_service; string module_freedisk, module_cpuusage, module_inventory; string module_freedisk_percent, module_freememory_percent; string module_dsn, module_freememory; @@ -196,6 +201,7 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { module_max = ""; module_description = ""; module_interval = ""; + module_absoluteinterval = ""; module_exec = ""; module_proc = ""; module_service = ""; @@ -290,6 +296,9 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { if (module_interval == "") { module_interval = parseLine (line, TOKEN_INTERVAL); } + if (module_absoluteinterval == "") { + module_absoluteinterval = parseLine (line, TOKEN_ABSOLUTEINTERVAL); + } if (module_exec == "") { module_exec = parseLine (line, TOKEN_EXEC); } @@ -603,6 +612,13 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { } } + if (module_absoluteinterval != "") { + pos_macro = module_absoluteinterval.find(macro_name); + if (pos_macro != string::npos){ + module_absoluteinterval.replace(pos_macro, macro_name.size(), macro_value); + } + } + if (module_exec != "") { pos_macro = module_exec.find(macro_name); if (pos_macro != string::npos){ @@ -1323,6 +1339,61 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { } } + /* Set the module absolute interval */ + if (module_absoluteinterval != "") { + int interval; + + try { + service = Pandora_Windows_Service::getInstance(); + + // Run once. + if (module_absoluteinterval == "once") { + interval = 0; + } + // Seconds. + else if (module_absoluteinterval.back() == 's') { + interval = strtoint (module_absoluteinterval.substr(0, module_absoluteinterval.size() - 1)); + } + // Minutes. + else if (module_absoluteinterval.back() == 'm') { + interval = strtoint (module_absoluteinterval.substr(0, module_absoluteinterval.size() - 1)) * 60; + } + // Hours. + else if (module_absoluteinterval.back() == 'h') { + interval = strtoint (module_absoluteinterval.substr(0, module_absoluteinterval.size() - 1)) * 3600; + } + // Days. + else if (module_absoluteinterval.back() == 'd') { + interval = strtoint (module_absoluteinterval.substr(0, module_absoluteinterval.size() - 1)) * 86400; + } + // Number of agent intervals. + else { + interval = strtoint(module_absoluteinterval) * (service->getIntervalSec()); + } + + // Convert from seconds to agent executions. + interval = ceil(interval / double(service->getIntervalSec())); + + // Set the module interval. + module->setInterval (interval); + module->setIntensiveInterval (interval); + + // Compute the MD5 hash of the module's name. + char module_name_md5[Pandora_File::MD5_BUF_SIZE]; + Pandora_File::md5(module_name.c_str(), module_name.size(), module_name_md5); + + // Set the timestamp file. + module->setTimestampFile(Pandora::getPandoraInstallDir().append("/ref/").append(module_name_md5).append(".ref")); + } catch (Invalid_Conversion e) { + pandoraLog ("Invalid absolute interval value \"%s\" for module %s", + module_absoluteinterval.c_str (), + module_name.c_str ()); + } + catch (...) { + // Should not happen. Ignore errors. + } + } + /* Module intensive condition */ if (intensive_condition_list.size () > 0) { intensive_condition_iter = intensive_condition_list.begin (); @@ -1337,6 +1408,9 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { module->setIntensiveInterval (module->getInterval () * (service->getInterval () / service->getIntensiveInterval ())); } + /* Initialize the module's execution counter. */ + module->initExecutions (); + /* Module cron */ module->setCron (module_crontab); @@ -1374,6 +1448,18 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { numeric = false; } + // Make sure modules that run once are asynchronous. + if (module->getInterval() == 0) { + type = module->getTypeInt(); + if (type == TYPE_GENERIC_DATA) { + module->setType("async_data"); + } else if (type == TYPE_GENERIC_PROC) { + module->setType("async_proc"); + } else if (type == TYPE_GENERIC_DATA_STRING) { + module->setType("async_string"); + } + } + if (numeric) { if (module_max != "") { try { diff --git a/pandora_agents/win32/pandora.cc b/pandora_agents/win32/pandora.cc index b07be290e9..104e3b9109 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.772 Build 230728") +#define PANDORA_VERSION ("7.0NG.772 Build 230808") string pandora_path; string pandora_dir; diff --git a/pandora_agents/win32/pandora_windows_service.cc b/pandora_agents/win32/pandora_windows_service.cc index b91e382432..dc9b4d909f 100644 --- a/pandora_agents/win32/pandora_windows_service.cc +++ b/pandora_agents/win32/pandora_windows_service.cc @@ -2197,6 +2197,11 @@ Pandora_Windows_Service::getInterval () { return this->interval; } +long +Pandora_Windows_Service::getIntervalSec () { + return this->interval_sec; +} + long Pandora_Windows_Service::getIntensiveInterval () { return this->intensive_interval; diff --git a/pandora_agents/win32/pandora_windows_service.h b/pandora_agents/win32/pandora_windows_service.h index 99f523eeb9..bc11d6f76f 100644 --- a/pandora_agents/win32/pandora_windows_service.h +++ b/pandora_agents/win32/pandora_windows_service.h @@ -122,6 +122,7 @@ namespace Pandora { Pandora_Agent_Conf *getConf (); string getEHKey (string ehorus_conf); long getInterval (); + long getIntervalSec (); long getIntensiveInterval (); string generateAgentName (); bool writeToBuffer (string temporal); diff --git a/pandora_agents/win32/versioninfo.rc b/pandora_agents/win32/versioninfo.rc index 240fc2309e..3621848429 100644 --- a/pandora_agents/win32/versioninfo.rc +++ b/pandora_agents/win32/versioninfo.rc @@ -11,7 +11,7 @@ BEGIN VALUE "LegalCopyright", "Pandora FMS" VALUE "OriginalFilename", "PandoraAgent.exe" VALUE "ProductName", "Pandora FMS Windows Agent" - VALUE "ProductVersion", "(7.0NG.772(Build 230728))" + VALUE "ProductVersion", "(7.0NG.772(Build 230808))" VALUE "FileVersion", "1.0.0.0" END END diff --git a/pandora_console/DEBIAN/control b/pandora_console/DEBIAN/control index 7d89b38bc8..51ab839e13 100644 --- a/pandora_console/DEBIAN/control +++ b/pandora_console/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-console -Version: 7.0NG.772-230728 +Version: 7.0NG.772-230808 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 099ad85bb3..5818202887 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.772-230728" +pandora_version="7.0NG.772-230808" package_pear=0 package_pandora=1 diff --git a/pandora_console/extensions/api_checker.php b/pandora_console/extensions/api_checker.php index 98a988d487..fce3e1a00f 100755 --- a/pandora_console/extensions/api_checker.php +++ b/pandora_console/extensions/api_checker.php @@ -157,7 +157,6 @@ function extension_api_checker() } $url = io_safe_output(get_parameter('url', '')); - $ip = io_safe_output(get_parameter('ip', '127.0.0.1')); $pandora_url = io_safe_output(get_parameter('pandora_url', $config['homeurl_static'])); $apipass = io_safe_output(get_parameter('apipass', '')); @@ -175,6 +174,17 @@ function extension_api_checker() $api_execute = (bool) get_parameter('api_execute', false); + if ($url !== '') { + $validate_url = parse_url($url); + if ($validate_url['scheme'] === 'http' || $validate_url['scheme'] === 'https') { + ui_print_success_message(__('Request successfully processed')); + } else { + ui_print_error_message(__('Incorrect URL')); + $url = ''; + $api_execute = false; + } + } + $return_call_api = ''; if ($api_execute === true) { $return_call_api = api_execute( diff --git a/pandora_console/extensions/resource_exportation.php b/pandora_console/extensions/resource_exportation.php index 71ad6d36bc..476b7ef1bf 100755 --- a/pandora_console/extensions/resource_exportation.php +++ b/pandora_console/extensions/resource_exportation.php @@ -453,7 +453,7 @@ function resource_exportation_extension_main() true ) ); - $table->data[0][] = html_print_button(__('Export'), '', false, 'export_to_ptr("report");', ['mode' => 'link'], true); + $table->data[0][] = html_print_button(__('Export'), '', false, 'export_to_ptr("report");', '', true); $table->data[1][] = html_print_label_input_block( __('Visual console'), @@ -465,7 +465,7 @@ function resource_exportation_extension_main() true ) ); - $table->data[1][] = html_print_button(__('Export'), '', false, 'export_to_ptr("visual_console");', ['mode' => 'link'], true); + $table->data[1][] = html_print_button(__('Export'), '', false, 'export_to_ptr("visual_console");', '', true); if ($hook_enterprise === true) { add_rows_for_enterprise($table->data); diff --git a/pandora_console/extras/mr/65.sql b/pandora_console/extras/mr/65.sql index 67efb5b908..563d00e82c 100644 --- a/pandora_console/extras/mr/65.sql +++ b/pandora_console/extras/mr/65.sql @@ -70,6 +70,10 @@ ALTER TABLE `tlayout_template` ADD COLUMN `grid_color` VARCHAR(45) NOT NULL DEFAULT '#cccccc' AFTER `maintenance_mode`, ADD COLUMN `grid_size` VARCHAR(45) NOT NULL DEFAULT '10' AFTER `grid_color`; +ALTER TABLE `tagente_modulo` ADD COLUMN `quiet_by_downtime` TINYINT NOT NULL DEFAULT 0; +ALTER TABLE `tagente_modulo` ADD COLUMN `disabled_by_downtime` TINYINT NOT NULL DEFAULT 0; +ALTER TABLE `talert_template_modules` ADD COLUMN `disabled_by_downtime` TINYINT NOT NULL DEFAULT 0; +ALTER TABLE `tagente` ADD COLUMN `disabled_by_downtime` TINYINT NOT NULL DEFAULT 0; DELETE FROM tconfig WHERE token = 'refr'; @@ -83,4 +87,32 @@ INSERT INTO `tmodule_inventory` (`id_module_inventory`, `id_os`, `name`, `descri ALTER TABLE `treport_content` ADD COLUMN `period_range` INT NULL DEFAULT 0 AFTER `period`; +CREATE TABLE IF NOT EXISTS `tevent_comment` ( + `id` serial PRIMARY KEY, + `id_event` BIGINT UNSIGNED NOT NULL, + `utimestamp` BIGINT NOT NULL DEFAULT 0, + `comment` TEXT, + `id_user` VARCHAR(255) DEFAULT NULL, + `action` TEXT, + FOREIGN KEY (`id_event`) REFERENCES `tevento`(`id_evento`) + ON UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY (`id_user`) REFERENCES tusuario(`id_user`) + ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; + +INSERT INTO `tevent_comment` (`id_event`, `utimestamp`, `comment`, `id_user`, `action`) +SELECT * FROM ( + SELECT tevento.id_evento AS `id_event`, + JSON_UNQUOTE(JSON_EXTRACT(tevento.user_comment, CONCAT('$[',n.num,'].utimestamp'))) AS `utimestamp`, + JSON_UNQUOTE(JSON_EXTRACT(tevento.user_comment, CONCAT('$[',n.num,'].comment'))) AS `comment`, + JSON_UNQUOTE(JSON_EXTRACT(tevento.user_comment, CONCAT('$[',n.num,'].id_user'))) AS `id_user`, + JSON_UNQUOTE(JSON_EXTRACT(tevento.user_comment, CONCAT('$[',n.num,'].action'))) AS `action` + FROM tevento + INNER JOIN (SELECT 0 num UNION ALL SELECT 1 UNION ALL SELECT 2) n + ON n.num < JSON_LENGTH(tevento.user_comment) + WHERE tevento.user_comment != "" +) t order by utimestamp DESC; + +ALTER TABLE tevento DROP COLUMN user_comment; + COMMIT; diff --git a/pandora_console/general/header.php b/pandora_console/general/header.php index 36090b9446..b73e2d63e3 100644 --- a/pandora_console/general/header.php +++ b/pandora_console/general/header.php @@ -228,7 +228,9 @@ echo sprintf('
', $menuTypeClass); ); $autorefresh_list = json_decode( - $select[0]['autorefresh_white_list'] + (empty($select[0]['autorefresh_white_list']) === false) + ? $select[0]['autorefresh_white_list'] + : '' ); $header_autorefresh = ''; diff --git a/pandora_console/general/main_menu.php b/pandora_console/general/main_menu.php index 60bffeb27f..d64ea45838 100644 --- a/pandora_console/general/main_menu.php +++ b/pandora_console/general/main_menu.php @@ -185,6 +185,10 @@ echo '
'; $(`#sub${this.id}`).hide(); }) } else if ($('#menu_full').hasClass('menu_full_collapsed')) { + $(".arrow_menu_right").each(function() { + $(this).removeClass('arrow_menu_right'); + $(this).addClass('arrow_menu_down'); + }); localStorage.setItem("menuType", "classic"); $('ul.submenu').css('left', '280px'); var menuType_val = localStorage.getItem("menuType"); @@ -273,6 +277,14 @@ echo ''; $('.menu_icon').mouseenter(function() { var menuType_val = localStorage.getItem("menuType"); if (!click_display && menuType_val === 'collapsed') { + $(".arrow_menu_down").each(function() { + $(this).removeClass('arrow_menu_down'); + $(this).addClass('arrow_menu_right'); + }); + $(".arrow_menu_up").each(function() { + $(this).removeClass('arrow_menu_up'); + $(this).addClass('arrow_menu_right'); + }); table_hover = $(this); handsIn = 1; openTime = new Date().getTime(); @@ -305,6 +317,7 @@ echo ''; table_hover2 = $(this); handsIn2 = 1; openTime2 = new Date().getTime(); + $("#sub" + table_hover2[0].id).attr('style', 'display: none; position: fixed; left: 340px;'); $("#sub" + table_hover2[0].id).show(); if (typeof(table_noHover2) != 'undefined') { if ("ul#sub" + table_hover2[0].id != "ul#sub" + table_noHover2[0].id) { @@ -315,6 +328,7 @@ echo ''; }).mouseleave(function() { var menuType_val = localStorage.getItem("menuType"); if (!click_display && menuType_val === 'collapsed') { + $("#sub" + $(this)[0].id).attr('style', 'display: none;'); table_noHover2 = table_hover2; handsIn2 = 0; setTimeout(function() { @@ -474,4 +488,10 @@ echo ''; return height_logo + height_tabs + padding_menu + height_position; } }); + + + $('#icon_god-extensions').find('span').attr('style', 'white-space: nowrap;'); + \ No newline at end of file diff --git a/pandora_console/godmode/agentes/agent_manager.php b/pandora_console/godmode/agentes/agent_manager.php index c1a14a31f5..70c2b1cf60 100644 --- a/pandora_console/godmode/agentes/agent_manager.php +++ b/pandora_console/godmode/agentes/agent_manager.php @@ -300,7 +300,7 @@ if (enterprise_installed() === true) { // Parent agents. $paramsParentAgent = []; $paramsParentAgent['return'] = true; -$paramsParentAgent['show_helptip'] = false; +$paramsParentAgent['show_helptip'] = true; $paramsParentAgent['input_name'] = 'id_parent'; $paramsParentAgent['print_hidden_input_idagent'] = true; $paramsParentAgent['hidden_input_idagent_name'] = 'id_agent_parent'; @@ -646,7 +646,7 @@ if (enterprise_installed() === true) { // Parent agent. $tableAdvancedAgent->data['parent_agent'][] = html_print_label_input_block( - __('Parent'), + __('Agent parent'), ui_print_agent_autocomplete_input($paramsParentAgent) ); @@ -931,7 +931,7 @@ foreach ($fields as $field) { // Filling the data. $combo = []; $combo = $field['combo_values']; - $combo = explode(',', $combo); + $combo = explode(',', (empty($combo) === true) ? '' : $combo); $combo_values = []; foreach ($combo as $value) { $combo_values[$value] = $value; @@ -1205,15 +1205,30 @@ ui_require_jquery_file('bgiframe'); $("#cascade_protection_module").attr("disabled", 'disabled'); } - $("#checkbox-cascade_protection").change(function () { - var checked = $("#checkbox-cascade_protection").is(":checked"); - - if (checked) { + $("#text-id_parent").change(function(){ + const parent = $("#text-id_parent").val(); + if (parent != '') { + $("#checkbox-cascade_protection").prop('checked', true); $("#cascade_protection_module").removeAttr("disabled"); } else { $("#cascade_protection_module").val(0); $("#cascade_protection_module").attr("disabled", 'disabled'); + $("#text-id_parent").removeAttr("required"); + $("#cascade_protection_module").empty(); + $("#checkbox-cascade_protection").prop('checked', false); + } + }); + + $("#checkbox-cascade_protection").change(function () { + var checked = $("#checkbox-cascade_protection").is(":checked"); if (checked) { + $("#cascade_protection_module").removeAttr("disabled"); + $("#text-id_parent").attr("required", "required"); + } + else { + $("#cascade_protection_module").val(0); + $("#cascade_protection_module").attr("disabled", 'disabled'); + $("#text-id_parent").removeAttr("required"); } }); diff --git a/pandora_console/godmode/agentes/modificar_agente.php b/pandora_console/godmode/agentes/modificar_agente.php index 9021514178..a14bff4b92 100644 --- a/pandora_console/godmode/agentes/modificar_agente.php +++ b/pandora_console/godmode/agentes/modificar_agente.php @@ -996,6 +996,8 @@ if ($agents !== false) { $tableAgents->data[$key][6] = $actionButtonsColumn; } + $total_items = '
'.sprintf(__('Total items: %s'), $total_agents).'
'; + echo $total_items; html_print_table($tableAgents); $tablePagination = ui_pagination( diff --git a/pandora_console/godmode/agentes/module_manager_editor_common.php b/pandora_console/godmode/agentes/module_manager_editor_common.php index d63dff4035..8ac79fd767 100644 --- a/pandora_console/godmode/agentes/module_manager_editor_common.php +++ b/pandora_console/godmode/agentes/module_manager_editor_common.php @@ -1847,6 +1847,22 @@ $(document).ready (function () { setModuleType(type_name_selected); }); + $('#checkbox-warning_inverse_string').change( function () { + if ($(this).prop('checked') === true) { + $('input[name="warning_thresholds_checks"]').val('warning_inverse'); + } else { + $('input[name="warning_thresholds_checks"]').val('normal_warning'); + } + }); + + $('#checkbox-critical_inverse_string').change( function () { + if ($(this).prop('checked') === true) { + $('input[name="critical_thresholds_checks"]').val('critical_inverse'); + } else { + $('input[name="critical_thresholds_checks"]').val('normal_critical'); + } + }); + function setModuleType(type_name_selected) { if (type_name_selected.match(/_string$/) == null) { // Hide string fields. diff --git a/pandora_console/godmode/agentes/module_manager_editor_plugin.php b/pandora_console/godmode/agentes/module_manager_editor_plugin.php index 0744a5849e..970a2c4d9f 100644 --- a/pandora_console/godmode/agentes/module_manager_editor_plugin.php +++ b/pandora_console/godmode/agentes/module_manager_editor_plugin.php @@ -171,6 +171,8 @@ foreach ($password_fields as $k => $p) { } $(document).ready(function () { - changePluginSelect(); + if ($("#id_plugin").val() === 0) { + changePluginSelect(); + } }); diff --git a/pandora_console/godmode/alerts/alert_commands.php b/pandora_console/godmode/alerts/alert_commands.php index 771a842cc3..75a80d8d57 100644 --- a/pandora_console/godmode/alerts/alert_commands.php +++ b/pandora_console/godmode/alerts/alert_commands.php @@ -725,17 +725,17 @@ if ($copy_command) { $is_management_allowed = is_management_allowed(); if ($is_management_allowed === false) { if (is_metaconsole() === false) { - $url = ''.__('metaconsole').''; } else { - $url = __('any node'); + $url_redirect = __('any node'); } ui_print_warning_message( __( 'This node is configured with centralized mode. All alert commands information is read only. Go to %s to manage it.', - $url + $url_redirect ) ); } @@ -807,12 +807,12 @@ foreach ($commands as $command) { // (IMPORTANT, DO NOT CHANGE!) only users with permissions over "All" group have access to edition of commands belonging to "All" group. if ($is_management_allowed === true && !$command['internal'] && check_acl_restricted_all($config['id_user'], $command['id_group'], 'LM')) { if (is_user_admin($config['id_user']) === true) { - $data['action'] = ''; + $data['action'] = ''; $data['action'] .= ''.html_print_image('images/copy.svg', true, ['class' => 'main_menu_icon invert_filter']).''; + onClick="if (!confirm(\''.__('Are you sure?').'\')) return false;">'.html_print_image('images/copy.svg', true, ['class' => 'main_menu_icon invert_filter ', 'title' => 'Duplicate']).''; $data['action'] .= ''.html_print_image('images/delete.svg', true, ['class' => 'main_menu_icon invert_filter']).''; + onClick="if (!confirm(\''.__('Are you sure?').'\')) return false;">'.html_print_image('images/delete.svg', true, ['class' => 'main_menu_icon invert_filter', 'title' => 'Delete']).''; $data['action'] .= ''; } } diff --git a/pandora_console/godmode/alerts/alert_list.list.php b/pandora_console/godmode/alerts/alert_list.list.php index 3dd8a831f9..5dc0c78019 100644 --- a/pandora_console/godmode/alerts/alert_list.list.php +++ b/pandora_console/godmode/alerts/alert_list.list.php @@ -912,7 +912,10 @@ foreach ($simple_alerts as $alert) { 1, 'padding:0px; width: 22px; height: 22px;', true, - ['class' => 'invert_filter main_menu_icon'] + [ + 'class' => 'invert_filter main_menu_icon', + 'title' => __('Enable'), + ] ); $data[4] .= html_print_input_hidden('enable_alert', 1, true); } else { @@ -922,7 +925,10 @@ foreach ($simple_alerts as $alert) { 1, 'padding:0px; width: 22px; height: 22px;', true, - ['class' => 'main_menu_icon'] + [ + 'class' => 'invert filter main_menu_icon', + 'title' => __('Disable'), + ] ); $data[4] .= html_print_input_hidden('disable_alert', 1, true); } @@ -940,7 +946,10 @@ foreach ($simple_alerts as $alert) { 1, 'padding:0px; width: 22px; height: 22px;', true, - ['class' => 'invert_filter main_menu_icon'] + [ + 'class' => 'invert_filter main_menu_icon', + 'title' => __('Standby off'), + ] ); $data[4] .= html_print_input_hidden('standbyon_alert', 1, true); } else { @@ -950,7 +959,10 @@ foreach ($simple_alerts as $alert) { 1, 'padding:0px; width: 22px; height: 22px;', true, - ['class' => 'invert_filter main_menu_icon'] + [ + 'class' => 'invert_filter main_menu_icon', + 'title' => __('Standby on'), + ] ); $data[4] .= html_print_input_hidden('standbyoff_alert', 1, true); } @@ -1139,8 +1151,7 @@ if (! $id_agente) { return false; }); - $("input[name=disable]").attr ("title", "") - .hover (function () { + $("input[name=disable]").hover (function () { $(this).attr ("src", ") - .hover (function () { + $("input[name=enable]").hover (function () { $(this).attr ("src", ") - .hover (function () { + $("input[name=standby_on]").hover (function () { $(this).attr ("src", ") - .hover (function () { + $("input[name=standby_off]").hover (function () { $(this).attr ("src", $(document).ready (function () { + $('li#icon_oper-agents').addClass('selected'); + $('ul#subicon_oper-agents').show(); + $('#title_menu').children().last().removeClass('arrow_menu_down'); + $('#title_menu').children().last().addClass('arrow_menu_up'); + $('#title_menu').children().first().next().addClass('span_selected'); + $('li#Views').show(); + $('li#Views').children().first().children().last().removeClass('arrow_menu_down'); + $('li#Views').children().first().children().last().addClass('arrow_menu_up'); + $('li#Views').children().first().children().first().addClass('span_selected'); + $('li#Views').addClass('submenu_selected'); + $('li#Views').removeClass('submenu_not_selected'); + $('ul#subViews').show(); + var parent = $('div[title="Alert details"]').parent().parent(); + parent.addClass('selected'); + $('.sub_subMenu.selected').prepend(`
`); + + var calendarEl = document.getElementById('calendar_map'); if(calendarEl){ var eventsBBDD = $("#hidden-schedule").val(); diff --git a/pandora_console/godmode/massive/massive_delete_profiles.php b/pandora_console/godmode/massive/massive_delete_profiles.php index a94e496927..1efa15ffe0 100644 --- a/pandora_console/godmode/massive/massive_delete_profiles.php +++ b/pandora_console/godmode/massive/massive_delete_profiles.php @@ -67,8 +67,27 @@ if (is_ajax()) { if ($get_users) { $id_group = get_parameter('id_group'); $id_profile = get_parameter('id_profile'); + $get_all_groups = get_parameter('get_all_groups', '0'); + + if ($get_all_groups !== '0') { + $profile_data = db_get_all_rows_sql( + 'SELECT * + FROM tusuario_perfil + WHERE `id_perfil` = "'.$id_profile[0].'" + GROUP BY id_usuario' + ); + } else { + if (strlen($id_profile[0]) > 0 && strlen($id_group[0]) > 0) { + $profile_data = db_get_all_rows_filter( + 'tusuario_perfil', + [ + 'id_perfil' => $id_profile[0], + 'id_grupo' => $id_group[0], + ] + ); + } + } - $profile_data = db_get_all_rows_filter('tusuario_perfil', ['id_perfil' => $id_profile[0], 'id_grupo' => $id_group[0]]); if (!users_is_admin()) { foreach ($profile_data as $user => $values) { if (users_is_admin($values['id_usuario'])) { @@ -243,6 +262,21 @@ $data[2] .= html_print_select( ); array_push($table->data, $data); +$table->data[1][0] = ''; +$table->data[1][1] = html_print_label_input_block( + __('Show all groups'), + html_print_checkbox_switch( + 'get_all_groups', + 1, + $get_all_groups, + true, + false, + '', + false, + ' float-right' + ), + ['div_class' => 'center_align'] +); html_print_table($table); @@ -273,7 +307,8 @@ $(document).ready (function () { {"page" : "godmode/massive/massive_delete_profiles", "get_users" : 1, "id_group[]" : $("#groups_id").val(), - "id_profile[]" : $("#profiles_id").val() + "id_profile[]" : $("#profiles_id").val(), + "get_all_groups" : $('#checkbox-get_all_groups').is(':checked') ? 1 : 0 }, function (data, status) { options = ""; @@ -295,6 +330,10 @@ $(document).ready (function () { $("#profiles_id").change (function () { update_users(); }); + + $("#checkbox-get_all_groups").change (function () { + update_users(); + }); }); /* ]]> */ diff --git a/pandora_console/godmode/netflow/nf_edit_form.php b/pandora_console/godmode/netflow/nf_edit_form.php index 9083cd2881..e79ed2715a 100644 --- a/pandora_console/godmode/netflow/nf_edit_form.php +++ b/pandora_console/godmode/netflow/nf_edit_form.php @@ -261,8 +261,8 @@ $table->data['first_line'][] = html_print_label_input_block( 'assign_group', $assign_group, '', - '', - -1, + __('All'), + 0, true, false, false, diff --git a/pandora_console/godmode/reporting/reporting_builder.php b/pandora_console/godmode/reporting/reporting_builder.php index 697561a59f..5cc94049f7 100755 --- a/pandora_console/godmode/reporting/reporting_builder.php +++ b/pandora_console/godmode/reporting/reporting_builder.php @@ -3907,7 +3907,7 @@ if ($resultOperationDB !== null) { break; case 'SLA': - $err .= 'You must enter some character in SLA limit field'; + $err .= 'No changes found.'; default: $err .= ''; break; @@ -3916,7 +3916,7 @@ if ($resultOperationDB !== null) { ui_print_result_message( $resultOperationDB, __('Successfull action'), - __('Unsuccessful action

'.$err) + __($err) ); } diff --git a/pandora_console/godmode/reporting/visual_console_builder.elements.php b/pandora_console/godmode/reporting/visual_console_builder.elements.php index 05668797ec..300ea33f40 100755 --- a/pandora_console/godmode/reporting/visual_console_builder.elements.php +++ b/pandora_console/godmode/reporting/visual_console_builder.elements.php @@ -182,7 +182,7 @@ if ($layoutDatas === false) { $alternativeStyle = true; $parents = visual_map_get_items_parents($idVisualConsole); - +$x = 0; foreach ($layoutDatas as $layoutData) { $idLayoutData = $layoutData['id']; @@ -537,7 +537,8 @@ foreach ($layoutDatas as $layoutData) { $table->data[($i + 1)][5] = ''; $table->data[($i + 1)][5] .= html_print_checkbox('multiple_delete_items', $idLayoutData, false, true); - $table->data[($i + 1)][5] .= ''.html_print_image('images/delete.svg', true, ['class' => 'main_menu_icon invert_filter']).''; + $table->data[($i + 1)][5] .= ''.html_print_image('images/delete.svg', true, ['class' => 'main_menu_icon invert_filter']).''; + $table->data[($i + 1)][5] .= html_print_input_hidden('updated_'.$idLayoutData, '0', true); // Second row $table->data[($i + 2)]['icon'] = ''; @@ -778,6 +779,12 @@ foreach ($layoutDatas as $layoutData) { $alternativeStyle = !$alternativeStyle; $i = ($i + 3); + $x++; +} + +$x = (($x * 13) + 14); +if ($x > ini_get('max_input_vars')) { + ui_print_warning_message(__('You have to change the "max_input_vars" and set bigger value on php.ini for update, there is too much elements to update')); } $pure = get_parameter('pure', 0); @@ -888,6 +895,16 @@ ui_require_javascript_file('tinymce', 'vendor/tinymce/tinymce/'); return false; }); + $('select[id^="image_"], input[name^="width_"], input[name^="height"], input[name^="left_"], input[name^="top_"], select[id^="parent_"], input[id^="agent_"], select[id^="module_"]').change(function(){ + var id = $(this).attr('id').split('_')[1]; + $('#hidden-updated_'+id).val('1'); + }); + + $('select[id^="map_linked"]').change(function(){ + var id = $(this).attr('id').split('_')[2]; + $('#hidden-updated_'+id).val('1'); + }); + defineTinyMCE('#tinyMCE_editor'); $("#dialog_label_editor").hide () diff --git a/pandora_console/godmode/reporting/visual_console_builder.php b/pandora_console/godmode/reporting/visual_console_builder.php index 9988704695..c7da988cd0 100755 --- a/pandora_console/godmode/reporting/visual_console_builder.php +++ b/pandora_console/godmode/reporting/visual_console_builder.php @@ -418,7 +418,6 @@ switch ($activeTab) { case 'update': // Update background $background = get_parameter('background'); - $background_color = get_parameter('background_color'); $width = get_parameter('width'); $height = get_parameter('height'); @@ -433,10 +432,9 @@ switch ($activeTab) { db_process_sql_update( 'tlayout', [ - 'background' => $background, - 'background_color' => $background_color, - 'width' => $width, - 'height' => $height, + 'background' => $background, + 'width' => $width, + 'height' => $height, ], ['id' => $idVisualConsole] ); @@ -463,62 +461,65 @@ switch ($activeTab) { foreach ($idsElements as $idElement) { $id = $idElement['id']; - $values = []; - $values['label'] = get_parameter('label_'.$id, ''); - $values['image'] = get_parameter('image_'.$id, ''); - $values['width'] = get_parameter('width_'.$id, 0); - $values['height'] = get_parameter('height_'.$id, 0); - $values['pos_x'] = get_parameter('left_'.$id, 0); - $values['pos_y'] = get_parameter('top_'.$id, 0); - switch ($idElement['type']) { - case NETWORK_LINK: - case LINE_ITEM: - continue 2; + $update = get_parameter('updated_'.$id, 0); + if ($update === '1') { + $values = []; + $values['label'] = get_parameter('label_'.$id, ''); + $values['image'] = get_parameter('image_'.$id, ''); + $values['width'] = get_parameter('width_'.$id, 0); + $values['height'] = get_parameter('height_'.$id, 0); + $values['pos_x'] = get_parameter('left_'.$id, 0); + $values['pos_y'] = get_parameter('top_'.$id, 0); + switch ($idElement['type']) { + case NETWORK_LINK: + case LINE_ITEM: + continue 2; - break; + break; - case SIMPLE_VALUE_MAX: - case SIMPLE_VALUE_MIN: - case SIMPLE_VALUE_AVG: - $values['period'] = get_parameter('period_'.$id, 0); - break; + case SIMPLE_VALUE_MAX: + case SIMPLE_VALUE_MIN: + case SIMPLE_VALUE_AVG: + $values['period'] = get_parameter('period_'.$id, 0); + break; - case MODULE_GRAPH: - $values['period'] = get_parameter('period_'.$id, 0); - unset($values['image']); - break; + case MODULE_GRAPH: + $values['period'] = get_parameter('period_'.$id, 0); + unset($values['image']); + break; - case GROUP_ITEM: - $values['id_group'] = get_parameter('group_'.$id, 0); - break; + case GROUP_ITEM: + $values['id_group'] = get_parameter('group_'.$id, 0); + break; - case CIRCULAR_PROGRESS_BAR: - case CIRCULAR_INTERIOR_PROGRESS_BAR: - case PERCENTILE_BUBBLE: - case PERCENTILE_BAR: - unset($values['height']); - break; + case CIRCULAR_PROGRESS_BAR: + case CIRCULAR_INTERIOR_PROGRESS_BAR: + case PERCENTILE_BUBBLE: + case PERCENTILE_BAR: + unset($values['height']); + break; + } + + $agentName = get_parameter('agent_'.$id, ''); + if (defined('METACONSOLE')) { + $values['id_metaconsole'] = (int) get_parameter('id_server_id_'.$id, ''); + $values['id_agent'] = (int) get_parameter('id_agent_'.$id, 0); + } else { + $agent_id = (int) get_parameter('id_agent_'.$id, 0); + $values['id_agent'] = $agent_id; + } + + $values['id_agente_modulo'] = get_parameter('module_'.$id, 0); + $values['id_custom_graph'] = get_parameter('custom_graph_'.$id, 0); + $values['parent_item'] = get_parameter('parent_'.$id, 0); + $values['id_layout_linked'] = get_parameter('map_linked_'.$id, 0); + + if (enterprise_installed()) { + enterprise_visual_map_update_action_from_list_elements($type, $values, $id); + } + + db_process_sql_update('tlayout_data', $values, ['id' => $id]); } - - $agentName = get_parameter('agent_'.$id, ''); - if (defined('METACONSOLE')) { - $values['id_metaconsole'] = (int) get_parameter('id_server_id_'.$id, ''); - $values['id_agent'] = (int) get_parameter('id_agent_'.$id, 0); - } else { - $agent_id = (int) get_parameter('id_agent_'.$id, 0); - $values['id_agent'] = $agent_id; - } - - $values['id_agente_modulo'] = get_parameter('module_'.$id, 0); - $values['id_custom_graph'] = get_parameter('custom_graph_'.$id, 0); - $values['parent_item'] = get_parameter('parent_'.$id, 0); - $values['id_layout_linked'] = get_parameter('map_linked_'.$id, 0); - - if (enterprise_installed()) { - enterprise_visual_map_update_action_from_list_elements($type, $values, $id); - } - - db_process_sql_update('tlayout_data', $values, ['id' => $id]); } break; diff --git a/pandora_console/godmode/servers/modificar_server.php b/pandora_console/godmode/servers/modificar_server.php index 34ce122954..4b3f26606a 100644 --- a/pandora_console/godmode/servers/modificar_server.php +++ b/pandora_console/godmode/servers/modificar_server.php @@ -45,9 +45,120 @@ if (! check_acl($config['id_user'], 0, 'AW')) { if (isset($_GET['server']) === true) { $id_server = get_parameter_get('server'); + $title = __('Update').' '; + $sql = sprintf('SELECT name, ip_address, description, server_type, exec_proxy, port FROM tserver WHERE id_server = %d', $id_server); + $row = db_get_row_sql($sql); + + switch ($row['server_type']) { + case SERVER_TYPE_DATA: + $title .= __('Data server').' ID: '.$id_server; + break; + + case SERVER_TYPE_NETWORK: + $title .= __('Network server').' ID: '.$id_server; + break; + + case SERVER_TYPE_SNMP: + $title .= __('SNMP Trap server').' ID: '.$id_server; + break; + + case SERVER_TYPE_DISCOVERY: + $title .= __('Discovery server').' ID: '.$id_server; + break; + + case SERVER_TYPE_PLUGIN: + $title .= __('Plugin server').' ID: '.$id_server; + break; + + case SERVER_TYPE_PREDICTION: + $title .= __('Prediction server').' ID: '.$id_server; + break; + + case SERVER_TYPE_WMI: + $title .= __('WMI server').' ID: '.$id_server; + break; + + case SERVER_TYPE_EXPORT: + $title .= __('Export server').' ID: '.$id_server; + $id_modulo = 0; + break; + + case SERVER_TYPE_INVENTORY: + $title .= __('Inventory server').' ID: '.$id_server; + break; + + case SERVER_TYPE_WEB: + $title .= __('Web server').' ID: '.$id_server; + break; + + case SERVER_TYPE_EVENT: + $title .= __('Event server').' ID: '.$id_server; + break; + + case SERVER_TYPE_CORRELATION: + $title .= __('Correlation server').' ID: '.$id_server; + break; + + case SERVER_TYPE_ENTERPRISE_ICMP: + $title .= __('Enterprise ICMP server').' ID: '.$id_server; + break; + + case SERVER_TYPE_ENTERPRISE_SNMP: + $title .= __('Enterprise SNMP server').' ID: '.$id_server; + break; + + case SERVER_TYPE_ENTERPRISE_SATELLITE: + $title .= __('Enterprise Satellite server').' ID: '.$id_server; + break; + + case SERVER_TYPE_ENTERPRISE_TRANSACTIONAL: + $title .= __('Enterprise Transactional server').' ID: '.$id_server; + break; + + case SERVER_TYPE_MAINFRAME: + $title .= __('Mainframe server').' ID: '.$id_server; + break; + + case SERVER_TYPE_SYNC: + $title .= __('Sync server').' ID: '.$id_server; + break; + + case SERVER_TYPE_WUX: + $title .= __('Wux server').' ID: '.$id_server; + break; + + case SERVER_TYPE_SYSLOG: + $title .= __('Log server').' ID: '.$id_server; + break; + + case SERVER_TYPE_NCM: + $title .= __('NCM server').' ID: '.$id_server; + break; + + case SERVER_TYPE_AUTOPROVISION: + $title .= __('Autoprovision server').' ID: '.$id_server; + break; + + case SERVER_TYPE_MIGRATION: + $title .= __('Migration server').' ID: '.$id_server; + break; + + case SERVER_TYPE_ALERT: + $title .= __('Alert server').' ID: '.$id_server; + break; + + case SERVER_TYPE_NETFLOW: + $title .= __('Netflow server').' ID: '.$id_server; + break; + + default: + $title = __('Update server').' ID: '.$id_server; + break; + } + // Headers. ui_print_standard_header( - __('Update Server'), + $title, 'images/gm_servers.png', false, '', @@ -65,8 +176,6 @@ if (isset($_GET['server']) === true) { ] ); - $sql = sprintf('SELECT name, ip_address, description, server_type, exec_proxy, port FROM tserver WHERE id_server = %d', $id_server); - $row = db_get_row_sql($sql); echo '
'; html_print_input_hidden('server', $id_server); diff --git a/pandora_console/godmode/servers/pending_alerts_list.php b/pandora_console/godmode/servers/pending_alerts_list.php new file mode 100644 index 0000000000..054a48aeb0 --- /dev/null +++ b/pandora_console/godmode/servers/pending_alerts_list.php @@ -0,0 +1,71 @@ + '[PendingAlertsList]'.$e->getMessage() ]); + exit; + } else { + echo '[PendingAlertsList]'.$e->getMessage(); + } + + // Stop this execution, but continue 'globally'. + return; +} + +// AJAX controller. +if (is_ajax()) { + $method = get_parameter('method'); + + if (method_exists($adw, $method) === true) { + if ($adw->ajaxMethod($method) === true) { + $adw->{$method}(); + } else { + $adw->error('Unavailable method.'); + } + } else { + $adw->error('Method not found. ['.$method.']'); + } + + // Stop any execution. + exit; +} else { + // Run. + $adw->run(); +} diff --git a/pandora_console/godmode/servers/servers.build_table.php b/pandora_console/godmode/servers/servers.build_table.php index 35cd540e6a..101a99d955 100644 --- a/pandora_console/godmode/servers/servers.build_table.php +++ b/pandora_console/godmode/servers/servers.build_table.php @@ -28,6 +28,7 @@ // Begin. require_once 'include/functions_clippy.php'; +require_once 'pending_alerts_list.php'; global $config; @@ -247,6 +248,19 @@ foreach ($servers as $server) { $data[8] .= ''; } + if ($server['type'] === 'event' && (bool) check_acl($config['id_user'], 0, 'LM') === true) { + $data[8] .= ''; + $data[8] .= html_print_image( + 'images/alert@svg.svg', + true, + [ + 'title' => __('Pending alerts list'), + 'class' => 'main_menu_icon invert_filter', + ] + ); + $data[8] .= ''; + } + $data[8] .= ''; $data[8] .= html_print_image( 'images/edit.svg', diff --git a/pandora_console/godmode/setup/links.php b/pandora_console/godmode/setup/links.php index b830ede88a..fc27454b48 100644 --- a/pandora_console/godmode/setup/links.php +++ b/pandora_console/godmode/setup/links.php @@ -210,7 +210,10 @@ if ((isset($_GET['form_add'])) or (isset($_GET['form_edit']))) { echo ''.html_print_image( 'images/delete.svg', true, - ['class' => 'invert_filter'] + [ + 'class' => 'invert_filter main_menu_icon', + 'title' => __('Delete'), + ] ).''; } diff --git a/pandora_console/godmode/setup/news.php b/pandora_console/godmode/setup/news.php index 9eb2eb8f45..6ad346586e 100644 --- a/pandora_console/godmode/setup/news.php +++ b/pandora_console/godmode/setup/news.php @@ -419,6 +419,9 @@ ui_require_jquery_file('ui.datepicker-'.get_user_language(), 'include/javascript // Include tiny for wysiwyg editor. ui_require_javascript_file('tinymce', 'vendor/tinymce/tinymce/'); ui_require_javascript_file('pandora'); +if ($config['style'] === 'pandora_black') { + html_print_input_hidden('selected_style_theme', 'pandora_black'); +} ?> diff --git a/pandora_console/godmode/setup/os.list.php b/pandora_console/godmode/setup/os.list.php index ddf2145212..330071353f 100644 --- a/pandora_console/godmode/setup/os.list.php +++ b/pandora_console/godmode/setup/os.list.php @@ -132,7 +132,15 @@ foreach ($osList as $os) { $data[] = html_print_anchor( [ 'href' => $hrefDelete, - 'content' => html_print_image('images/delete.svg', true, ['class' => 'main_menu_icon invert_filter']), + 'content' => html_print_image( + 'images/delete.svg', + true, + [ + 'alt' => __('Delete'), + 'title' => __('Delete'), + 'class' => 'main_menu_icon invert_filter', + ] + ), ], true ); diff --git a/pandora_console/godmode/setup/setup_general.php b/pandora_console/godmode/setup/setup_general.php index 110281096e..aa55893d11 100644 --- a/pandora_console/godmode/setup/setup_general.php +++ b/pandora_console/godmode/setup/setup_general.php @@ -747,6 +747,16 @@ $table->data[$i][] = html_print_label_input_block( ) ); +$table->data[$i++][] = html_print_label_input_block( + __('Max. hours old events comments'), + html_print_input_number( + [ + 'name' => 'max_hours_old_event_comment', + 'min' => 0, + 'value' => $config['max_hours_old_event_comment'], + ] + ) +); $table->data[$i][] = html_print_label_input_block( __('Show experimental features'), html_print_checkbox_switch( diff --git a/pandora_console/godmode/setup/setup_visuals.php b/pandora_console/godmode/setup/setup_visuals.php index a7b64a67d7..cc5d026f35 100755 --- a/pandora_console/godmode/setup/setup_visuals.php +++ b/pandora_console/godmode/setup/setup_visuals.php @@ -1772,7 +1772,9 @@ $table_other->data[$row][] = html_print_label_input_block( 100, true ).ui_print_input_placeholder( - __('Example').': '.date($config['date_format']), + __('Example').': '.date( + str_replace(' ', ' ', $config['date_format']) + ), true ) ); diff --git a/pandora_console/godmode/snmpconsole/snmp_alert.php b/pandora_console/godmode/snmpconsole/snmp_alert.php index dd0190f1ae..d23b65d7ea 100755 --- a/pandora_console/godmode/snmpconsole/snmp_alert.php +++ b/pandora_console/godmode/snmpconsole/snmp_alert.php @@ -786,7 +786,7 @@ if ($create_alert || $update_alert) { 2, 2, $custom_value, - 'class="w100p"', + 'class="w100p" required="required"', true ) ); @@ -804,6 +804,8 @@ if ($create_alert || $update_alert) { '', 50, 255, + true, + false, true ) ); @@ -818,6 +820,8 @@ if ($create_alert || $update_alert) { '', 20, 255, + true, + false, true ) ); @@ -2002,6 +2006,7 @@ if ($create_alert || $update_alert) { 'alt' => __('Update'), 'border' => 0, 'class' => 'main_menu_icon', + 'title' => __('Edit'), ] ), ], @@ -2170,24 +2175,11 @@ if ($create_alert || $update_alert) { echo '
'; } - echo '
'; - echo '
'; - html_print_input_hidden('create_alert', 1); - $submitButton = html_print_submit_button( - __('Create'), - 'alert', - false, - ['icon' => 'wand'], - true - ); - html_print_action_buttons($submitButton.$deleteButton, ['right_content' => $pagination]); - echo '
'; - - $legend = '
'; - $legend .= '
'; - $priorities = get_priorities(); - $half = (count($priorities) / 2); - $count = 0; + $legend = ''; + $legend .= '
'; + $legend .= '
'; + $priorities = get_priorities(); + $half = (count($priorities) / 2); + $count = 0; foreach ($priorities as $num => $name) { if ($count == $half) { $legend .= '
'; @@ -2198,11 +2190,24 @@ if ($create_alert || $update_alert) { $count++; } - $legend .= '
'; - ui_toggle($legend, __('Legend')); + ui_toggle($legend, __('Legend')); - unset($table); + unset($table); + + echo '
'; + echo '
'; + html_print_input_hidden('create_alert', 1); + $submitButton = html_print_submit_button( + __('Create'), + 'alert', + false, + ['icon' => 'wand'], + true + ); + html_print_action_buttons($submitButton.$deleteButton, ['right_content' => $pagination]); + echo '
'; } ui_require_javascript_file('pandora', 'include/javascript/', true); diff --git a/pandora_console/godmode/users/user_management.php b/pandora_console/godmode/users/user_management.php index 241177f2a2..90bf79a50c 100644 --- a/pandora_console/godmode/users/user_management.php +++ b/pandora_console/godmode/users/user_management.php @@ -784,10 +784,12 @@ $userManagementTable->data['fields_addSettings'][1] .= html_print_div( if (isset($CodeQRTable) === true || isset($apiTokenContent) === true) { // QR Code and API Token advice. + $titleQr = ''.__('Contact details (QR)').''; + $titleApi = ''.__('API Token credentials').''; html_print_div( [ 'id' => 'api_qrcode_display', - 'content' => $CodeQRTable.$apiTokenContent, + 'content' => $titleQr.$CodeQRTable.$titleApi.$apiTokenContent, ] ); } diff --git a/pandora_console/godmode/wizards/ManageExtensions.class.php b/pandora_console/godmode/wizards/ManageExtensions.class.php index 03b1bdee7b..e088278eea 100644 --- a/pandora_console/godmode/wizards/ManageExtensions.class.php +++ b/pandora_console/godmode/wizards/ManageExtensions.class.php @@ -682,6 +682,7 @@ class ManageExtensions extends HTML [ 'onclick' => 'if (!confirm(\''.__('Deleting this application will also delete all the discovery tasks using it. Do you want to delete it?').'\')) return false;', 'class' => 'main_menu_icon invert_filter action_button_hidden', + 'title' => 'Delete', ] ); $data[$key]['actions'] .= html_print_input_hidden('short_name', $row['short_name'], true); @@ -697,6 +698,7 @@ class ManageExtensions extends HTML [ 'onclick' => 'if (!confirm(\''.__('Are you sure you want to reapply?').'\')) return false;', 'class' => 'main_menu_icon invert_filter action_button_hidden', + 'title' => 'Refresh', ] ); $data[$key]['actions'] .= html_print_input_hidden('sync_action', 'refresh', true); diff --git a/pandora_console/images/Netflow2@svg.svg b/pandora_console/images/Netflow2@svg.svg new file mode 100644 index 0000000000..c1b66201b3 --- /dev/null +++ b/pandora_console/images/Netflow2@svg.svg @@ -0,0 +1,7 @@ + + + Netflow@svg + + + + \ No newline at end of file diff --git a/pandora_console/include/ajax/audit_log.php b/pandora_console/include/ajax/audit_log.php index 026d8ca881..c0d1c4f73e 100644 --- a/pandora_console/include/ajax/audit_log.php +++ b/pandora_console/include/ajax/audit_log.php @@ -266,19 +266,31 @@ if ($save_filter_modal) { $data = []; $table->rowid[0] = 'update_save_selector'; - $data[0] = html_print_radio_button( - 'filter_mode', - 'new', - __('New filter'), - true, + $data[0] = html_print_div( + [ + 'style' => 'display: flex;', + 'content' => html_print_radio_button( + 'filter_mode', + 'new', + __('New filter'), + true, + true + ), + ], true ); - $data[1] = html_print_radio_button( - 'filter_mode', - 'update', - __('Update filter'), - false, + $data[1] = html_print_div( + [ + 'style' => 'display: flex;', + 'content' => html_print_radio_button( + 'filter_mode', + 'update', + __('Update filter'), + false, + true + ), + ], true ); diff --git a/pandora_console/include/ajax/events.php b/pandora_console/include/ajax/events.php index 666d23d244..571955fd25 100644 --- a/pandora_console/include/ajax/events.php +++ b/pandora_console/include/ajax/events.php @@ -90,86 +90,38 @@ $get_comments = (bool) get_parameter('get_comments', false); $get_events_fired = (bool) get_parameter('get_events_fired'); $get_id_source_event = get_parameter('get_id_source_event'); $node_id = (int) get_parameter('node_id', 0); +$settings_modal = get_parameter('settings', 0); +$parameters_modal = get_parameter('parameters', 0); if ($get_comments === true) { - $event = get_parameter('event', false); - $event_rep = (int) get_parameter_post('event')['event_rep']; - $group_rep = (int) get_parameter_post('event')['group_rep']; + global $config; + $event = json_decode(io_safe_output(base64_decode(get_parameter('event', ''))), true); + $filter = json_decode(io_safe_output(base64_decode(get_parameter('filter', ''))), true); + + $default_hour = (int) $filter['event_view_hr']; + if (isset($config['max_hours_old_event_comment']) === true + && empty($config['max_hours_old_event_comment']) === false + ) { + $default_hour = (int) $config['max_hours_old_event_comment']; + } + + $custom_event_view_hr = (int) get_parameter('custom_event_view_hr', 0); + if (empty($custom_event_view_hr) === false) { + if ($custom_event_view_hr === -2) { + $filter['event_view_hr_cs'] = ($default_hour * 3600); + } else { + $filter['event_view_hr_cs'] = $custom_event_view_hr; + } + } else { + $filter['event_view_hr_cs'] = ($default_hour * 3600); + } if ($event === false) { return __('Failed to retrieve comments'); } - $eventsGrouped = []; - // Consider if the event is grouped. - $whereGrouped = '1=1'; - if ($group_rep === EVENT_GROUP_REP_EVENTS && $event_rep > 1) { - // Default grouped message filtering (evento and estado). - $whereGrouped = sprintf( - '`evento` = "%s"', - $event['evento'] - ); - - // If id_agente is reported, filter the messages by them as well. - if ((int) $event['id_agente'] > 0) { - $whereGrouped .= sprintf( - ' AND `id_agente` = %d', - (int) $event['id_agente'] - ); - } - - if ((int) $event['id_agentmodule'] > 0) { - $whereGrouped .= sprintf( - ' AND `id_agentmodule` = %d', - (int) $event['id_agentmodule'] - ); - } - } else if ($group_rep === EVENT_GROUP_REP_EXTRAIDS) { - $whereGrouped = sprintf( - '`id_extra` = "%s"', - io_safe_output($event['id_extra']) - ); - } else { - $whereGrouped = sprintf('`id_evento` = %d', $event['id_evento']); - } - - try { - if (is_metaconsole() === true - && $event['server_id'] > 0 - ) { - $node = new Node($event['server_id']); - $node->connect(); - } - - $sql = sprintf( - 'SELECT `user_comment` - FROM tevento - WHERE %s', - $whereGrouped - ); - - // Get grouped comments. - $eventsGrouped = db_get_all_rows_sql($sql); - } catch (\Exception $e) { - // Unexistent agent. - if (is_metaconsole() === true - && $event['server_id'] > 0 - ) { - $node->disconnect(); - } - - $eventsGrouped = []; - } finally { - if (is_metaconsole() === true - && $event['server_id'] > 0 - ) { - $node->disconnect(); - } - } - - // End of get_comments. - echo events_page_comments($event, true, $eventsGrouped); - + $eventsGrouped = event_get_comment($event, $filter); + echo events_page_comments($event, $eventsGrouped, $filter); return; } @@ -562,8 +514,13 @@ if ($load_filter_modal) { false ); + $action = 'index.php?sec=eventos&sec2=operation/events/events&pure='; + if ($settings_modal !== 0 && $parameters_modal !== 0) { + $action .= '&settings='.$settings_modal.'¶meters='.$parameters_modal; + } + echo '
'; - echo '
'; + echo ''; $table = new StdClass; $table->id = 'load_filter_form'; @@ -1003,7 +960,7 @@ function save_new_filter() { } else { id_filter_save = data; - + $("#info_box").filter(function(i, item) { if ($(item).data('type_info_box') == "success_create_filter") { return true; @@ -2003,23 +1960,7 @@ if ($get_extended_event) { $js .= '});'; - $js .= ' - $("#link_comments").click(function (){ - $.post ({ - url : "ajax.php", - data : { - page: "include/ajax/events", - get_comments: 1, - event: '.json_encode($event).', - event_rep: '.$event_rep.' - }, - dataType : "html", - success: function (data) { - $("#extended_event_comments_page").empty(); - $("#extended_event_comments_page").html(data); - } - }); - });'; + $js .= '$("#link_comments").click(get_table_events_tabs(\''.base64_encode(json_encode($event)).'\',\''.base64_encode(json_encode($filter)).'\'));'; if (events_has_extended_info($event['id_evento']) === true) { $js .= ' @@ -2525,7 +2466,7 @@ if ($drawConsoleSound === true) { 'label' => __('Start'), 'type' => 'button', 'name' => 'start-search', - 'attributes' => [ 'class' => 'play' ], + 'attributes' => [ 'class' => 'play secondary' ], 'return' => true, ], 'div', @@ -2651,23 +2592,24 @@ if ($get_events_fired) { $return[] = array_merge( $event, [ - 'fired' => $event['id_evento'], - 'message' => ui_print_string_substr( + 'fired' => $event['id_evento'], + 'message' => ui_print_string_substr( strip_tags(io_safe_output($event['evento'])), 75, true, '9' ), - 'priority' => ui_print_event_priority($event['criticity'], true, true), - 'type' => events_print_type_img( + 'priority' => ui_print_event_priority($event['criticity'], true, true), + 'type' => events_print_type_img( $event['event_type'], true ), - 'timestamp' => ui_print_timestamp( + 'timestamp' => ui_print_timestamp( $event['timestamp'], true, ['style' => 'font-size: 9pt; letter-spacing: 0.3pt;'] ), + 'event_timestamp' => $event['timestamp'], ] ); } diff --git a/pandora_console/include/ajax/module.php b/pandora_console/include/ajax/module.php index 8cc2eca4a5..921a1e1bc0 100755 --- a/pandora_console/include/ajax/module.php +++ b/pandora_console/include/ajax/module.php @@ -621,7 +621,7 @@ if (check_login()) { } if (empty($table->data)) { - ui_print_error_message(__('No available data to show')); + ui_print_empty_data(__('No available data to show'), '', false); } else { ui_pagination( count($count), diff --git a/pandora_console/include/api.php b/pandora_console/include/api.php index 0e6083d3e2..b5f6d44ab7 100644 --- a/pandora_console/include/api.php +++ b/pandora_console/include/api.php @@ -328,7 +328,6 @@ if ($correctLogin === true) { break; default: - return false; // Ignore. break; } diff --git a/pandora_console/include/class/AlertsList.class.php b/pandora_console/include/class/AlertsList.class.php new file mode 100644 index 0000000000..843a5fa304 --- /dev/null +++ b/pandora_console/include/class/AlertsList.class.php @@ -0,0 +1,488 @@ +AJAXMethods); + } + + + /** + * Generates a JSON error. + * + * @param string $msg Error message. + * + * @return void + */ + public function error($msg) + { + echo json_encode( + ['error' => $msg] + ); + } + + + /** + * Minor function to dump json message as ajax response. + * + * @param string $type Type: result || error. + * @param string $msg Message. + * @param boolean $delete Deletion messages. + * + * @return void + */ + private function ajaxMsg($type, $msg, $delete=false) + { + if ($type === 'error') { + $msg_title = ($delete === true) ? 'Failed while removing' : 'Failed while saving'; + } else { + $msg_title = ($delete === true) ? 'Successfully deleted' : 'Successfully saved into keystore'; + } + + echo json_encode( + [ $type => __($msg_title).':
'.$msg ] + ); + + exit; + } + + + /** + * Initializes object and validates user access. + * + * @param string $ajax_controller Path of ajaxController, is the 'page' + * variable sent in ajax calls. + * + * @return object + */ + public function __construct($ajax_controller) + { + global $config; + + // Check access. + check_login(); + + if ((bool) check_acl($config['id_user'], 0, 'LM') === false) { + db_pandora_audit( + AUDIT_LOG_ACL_VIOLATION, + 'Trying to access pending alerts list' + ); + + if (is_ajax()) { + echo json_encode(['error' => 'noaccess']); + } else { + include 'general/noaccess.php'; + } + + exit; + } + + $this->ajaxController = $ajax_controller; + + return $this; + } + + + /** + * Prints inputs for modal "Pending alerts list". + * + * @return void + */ + public function loadModal() + { + ob_start(); + echo '
'; + echo $this->getModalContent(); + echo '
'; + echo ob_get_clean(); + } + + + /** + * Run. + * + * @return void + */ + public function run() + { + global $config; + + ui_require_css_file('tables'); + + if ((bool) check_acl($config['id_user'], 0, 'LM') === false) { + db_pandora_audit( + AUDIT_LOG_ACL_VIOLATION, + 'Trying to access pending alerts list.' + ); + include 'general/noaccess.php'; + return; + } + + // Auxiliar div for modal. + echo ''; + + echo $this->loadJS(); + } + + + /** + * Draw table. + * + * @return void + */ + public function drawTable() + { + global $config; + + $start = get_parameter('start', 0); + $length = get_parameter('length', $config['block_size']); + $order = get_datatable_order(true); + + try { + ob_start(); + + $order_by_clause = ''; + + if (in_array($order['field'], ['agentAlias', 'moduleName', 'alertType']) === false) { + $order_by_clause = 'ORDER BY id '.$order['direction']; + } + + if ($length !== '-1') { + $sql = sprintf( + 'SELECT * + FROM talert_execution_queue %s + LIMIT %d, %d', + $order_by_clause, + $start, + $length + ); + } else { + $sql = sprintf( + 'SELECT * FROM talert_execution_queue %s', + $order_by_clause + ); + } + + // Retrieve data and count. + $data = db_get_all_rows_sql($sql); + $count = (int) db_get_sql('SELECT COUNT(*) FROM talert_execution_queue'); + + if ($data) { + $data = array_reduce( + $data, + function ($carry, $item) { + // Check if the item is an array before proceeding. + if (is_array($item) === true) { + // Transforms array of arrays $data into an array + // of objects, making a post-process of certain fields. + $tmp = (object) $item; + $decoded_data = base64_decode($tmp->data); + $decoded_data = json_decode($decoded_data, true); + + if (is_array($decoded_data) === true) { + // Access the second element of $decoded_data (index 1) to get 'alias' and 'type'. + $tmp->agentAlias = isset($decoded_data[1]['alias']) ? $decoded_data[1]['alias'] : null; + $tmp->alertType = isset($decoded_data[3]['type']) ? $decoded_data[3]['type'] : null; + // Access the third element of $decoded_data (index 2) to get 'nombre'. + $tmp->moduleName = isset($decoded_data[2]['nombre']) ? $decoded_data[2]['nombre'] : null; + + $carry[] = $tmp; + } + } + + return $carry; + } + ); + } + + echo json_encode( + [ + 'data' => $data, + 'recordsTotal' => $count, + 'recordsFiltered' => $count, + ] + ); + + // Capture output. + $response = ob_get_clean(); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + exit; + } + + // If not valid, show error with issue. + json_decode($response); + if (json_last_error() == JSON_ERROR_NONE) { + // If valid dump. + echo $response; + } else { + echo json_encode( + ['error' => $response] + ); + } + + exit; + } + + + /** + * Generates content of modal. + * + * @return string Modal content. + */ + public function getModalContent() + { + global $config; + + ob_start(); + + try { + $columns = [ + 'id', + 'agentAlias', + 'moduleName', + 'alertType', + ]; + + $column_names = [ + __('ID'), + __('Agent'), + __('Module'), + __('Type'), + ]; + + $this->tableId = 'pending_alerts'; + ui_print_datatable( + [ + 'id' => $this->tableId, + 'class' => 'info_table', + 'style' => 'width: 99%', + 'columns' => $columns, + 'column_names' => $column_names, + 'ajax_url' => $this->ajaxController, + 'default_pagination' => 7, + 'dom_elements' => 'pfti', + 'ajax_data' => ['method' => 'drawTable'], + 'no_sortable_columns' => [ + 1, + 2, + 3, + ], + 'order' => [ + 'field' => 'id', + 'direction' => 'asc', + ], + ] + ); + } catch (Exception $e) { + echo $e->getMessage(); + } + + return ob_get_clean(); + } + + + /** + * Loads JS content. + * + * @return string JS content. + */ + public function loadJS() + { + ob_start(); + + ui_require_javascript_file('stepper', 'include/javascript/', true); + + // Javascript content. + ?> + + __('Edit'), - 'class' => 'invert_filter', + 'class' => 'invert_filter main_menu_icon', ] ); $tmp->options .= ''; @@ -735,7 +735,7 @@ class CalendarManager true, [ 'title' => __('Delete'), - 'class' => 'invert_filter', + 'class' => 'invert_filter main_menu_icon', ] ); $tmp->options .= ''; diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index f65ddf95ce..353a17b80e 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -2392,7 +2392,9 @@ class NetworkMap unlink($filename_dot); - if (function_exists($this->customParser)) { + if (empty($this->customParser) === false + && function_exists($this->customParser) + ) { try { if (empty($this->customParserArgs)) { $graph = call_user_func( diff --git a/pandora_console/include/config_process.php b/pandora_console/include/config_process.php index 499103c681..d9e2f86fc0 100644 --- a/pandora_console/include/config_process.php +++ b/pandora_console/include/config_process.php @@ -20,7 +20,7 @@ /** * Pandora build version and version */ -$build_version = 'PC230728'; +$build_version = 'PC230808'; $pandora_version = 'v7.0NG.772'; // Do not overwrite default timezone set if defined. diff --git a/pandora_console/include/functions.php b/pandora_console/include/functions.php index e8f0ac3452..4fa87f70cb 100644 --- a/pandora_console/include/functions.php +++ b/pandora_console/include/functions.php @@ -324,7 +324,7 @@ function human_milliseconds_to_string($seconds) } // get the seconds - $seconds = (intval($seconds / 100) % 60); + $seconds = ((intval($seconds) / 100) % 60); if ($seconds > 0) { $ret .= "$seconds seconds"; } diff --git a/pandora_console/include/functions_agents.php b/pandora_console/include/functions_agents.php index 940e9e3e7f..bb5b19a27e 100644 --- a/pandora_console/include/functions_agents.php +++ b/pandora_console/include/functions_agents.php @@ -583,12 +583,6 @@ function agents_get_agents( $status_sql = '( normal_count <> total_count OR total_count = notinit_count)'; - // The AGENT_STATUS_NOT_NORMAL filter must show all agents that are not in normal status - /* - "( - normal_count <> total_count - AND - (normal_count + notinit_count) <> total_count)";*/ break; case AGENT_STATUS_NOT_INIT: @@ -605,32 +599,28 @@ function agents_get_agents( $filter_nogroup = $filter; - // Get user groups + // Get user groups. $groups = array_keys(users_get_groups($config['id_user'], $access, false)); - // If no group specified, get all user groups + // If no group specified, get all user groups. if (empty($filter['id_grupo'])) { $all_groups = true; $filter['id_grupo'] = $groups; } else if (! is_array($filter['id_grupo'])) { $all_groups = false; - // If group is specified but not allowed, return false + // If group is specified but not allowed, return false. if (! in_array($filter['id_grupo'], $groups)) { return false; } $filter['id_grupo'] = (array) $filter['id_grupo']; - // Make an array + // Make an array. } else { $all_groups = true; - // Check each group specified to the user groups, remove unwanted groups - foreach ($filter['id_grupo'] as $key => $id_group) { - if (! in_array($id_group, $groups)) { - unset($filter['id_grupo'][$key]); - } - } - // If no allowed groups are specified return false + $filter['id_grupo'] = array_intersect($groups, $filter['id_grupo']); + + // If no allowed groups are specified return false. if (count($filter['id_grupo']) == 0) { return false; } diff --git a/pandora_console/include/functions_api.php b/pandora_console/include/functions_api.php index 16b0372f74..df92b10086 100644 --- a/pandora_console/include/functions_api.php +++ b/pandora_console/include/functions_api.php @@ -13102,9 +13102,14 @@ function api_set_create_event($id, $trash1, $other, $returnType) $values['custom_data'] = ''; } + $ack_utimestamp = 0; + if ($other['data'][18] != '') { $values['id_extra'] = $other['data'][18]; - $sql_validation = 'SELECT id_evento,estado FROM tevento where estado IN (0,2) and id_extra ="'.$other['data'][18].'";'; + $sql_validation = 'SELECT id_evento,estado,ack_utimestamp,id_usuario + FROM tevento + WHERE estado IN (0,2) AND id_extra ="'.$other['data'][18].'";'; + $validation = db_get_all_rows_sql($sql_validation); if ($validation) { @@ -13114,6 +13119,8 @@ function api_set_create_event($id, $trash1, $other, $returnType) && (int) $values['status'] === 0 ) { $values['status'] = 2; + $ack_utimestamp = $val['ack_utimestamp']; + $values['id_usuario'] = $val['id_usuario']; } api_set_validate_event_by_id($val['id_evento']); @@ -13143,7 +13150,8 @@ function api_set_create_event($id, $trash1, $other, $returnType) $values['tags'], $custom_data, $values['server_id'], - $values['id_extra'] + $values['id_extra'], + $ack_utimestamp ); if ($other['data'][12] != '') { @@ -15755,6 +15763,8 @@ function api_get_cluster_items($cluster_id) */ function api_set_create_event_filter($name, $thrash1, $other, $thrash3) { + global $config; + if ($name == '') { returnError( 'The event filter could not be created. Event filter name cannot be left blank.' diff --git a/pandora_console/include/functions_config.php b/pandora_console/include/functions_config.php index ea0f78b385..1b871d3c93 100644 --- a/pandora_console/include/functions_config.php +++ b/pandora_console/include/functions_config.php @@ -402,6 +402,10 @@ function config_update_config() $error_update[] = __('Check conexion interval'); } + if (config_update_value('max_hours_old_event_comment', get_parameter('max_hours_old_event_comment'), true) === false) { + $error_update[] = __('Max hours old event comments'); + } + if (config_update_value('unique_ip', get_parameter('unique_ip'), true) === false) { $error_update[] = __('Unique IP'); } @@ -2124,6 +2128,12 @@ function config_process_config() if (!isset($config['date_format'])) { config_update_value('date_format', 'F j, Y, g:i a'); + } else { + $config['date_format'] = str_replace( + ' ', + ' ', + $config['date_format'] + ); } if (!isset($config['event_view_hr'])) { @@ -2429,6 +2439,10 @@ function config_process_config() config_update_value('check_conexion_interval', 180); } + if (!isset($config['max_hours_old_event_comment'])) { + config_update_value('max_hours_old_event_comment', 8); + } + if (!isset($config['elasticsearch_ip'])) { config_update_value('elasticsearch_ip', ''); } diff --git a/pandora_console/include/functions_cron.php b/pandora_console/include/functions_cron.php index 052dec9692..2eafd8dccb 100644 --- a/pandora_console/include/functions_cron.php +++ b/pandora_console/include/functions_cron.php @@ -923,16 +923,15 @@ function cron_list_table() } if ($manage_pandora) { - $data[7] .= ''; - $data[7] .= html_print_image( - 'images/delete.svg', - true, + $data[7] .= html_print_menu_button( [ - 'title' => __('Delete'), - 'class' => 'main_menu_icon invert_filter', - ] + 'href' => $url.'delete_task=1&id_user_task='.$task['id'], + 'image' => 'images/delete.svg', + 'title' => __('Delete'), + 'onClick' => 'if (!confirm(\''.__('Are you sure?').'\')) return false;', + ], + true ); - $data[7] .= ''; } } else { if ($write_perms || $manage_pandora) { @@ -949,17 +948,15 @@ function cron_list_table() } if ($manage_perms || $manage_pandora) { - $data[7] .= ''; - $data[7] .= html_print_image( - 'images/delete.svg', - true, + $data[7] .= html_print_menu_button( [ - 'title' => __('Delete'), - 'class' => 'main_menu_icon invert_filter', - ] + 'href' => $url.'delete_task=1&id_user_task='.$task['id'], + 'image' => 'images/delete.svg', + 'title' => __('Delete'), + 'onClick' => 'if (!confirm(\''.__('Are you sure?').'\')) return false;', + ], + true ); - $data[7] .= ''; } } diff --git a/pandora_console/include/functions_events.php b/pandora_console/include/functions_events.php index 3a6128e234..49007aaca1 100644 --- a/pandora_console/include/functions_events.php +++ b/pandora_console/include/functions_events.php @@ -613,6 +613,74 @@ function events_update_status($id_evento, $status, $filter=null) } +/** + * Get filter time. + * + * @param array $filter Filters. + * + * @return array conditions. + */ +function get_filter_date(array $filter) +{ + if (isset($filter['date_from']) === true + && empty($filter['date_from']) === false + && $filter['date_from'] !== '0000-00-00' + ) { + $date_from = $filter['date_from']; + } + + if (isset($filter['time_from']) === true) { + $time_from = (empty($filter['time_from']) === true) ? '00:00:00' : $filter['time_from']; + } + + if (isset($date_from) === true) { + if (isset($time_from) === false) { + $time_from = '00:00:00'; + } + + $from = $date_from.' '.$time_from; + $sql_filters[] = sprintf( + ' AND te.utimestamp >= %d', + strtotime($from) + ); + } + + if (isset($filter['date_to']) === true + && empty($filter['date_to']) === false + && $filter['date_to'] !== '0000-00-00' + ) { + $date_to = $filter['date_to']; + } + + if (isset($filter['time_to']) === true) { + $time_to = (empty($filter['time_to']) === true) ? '23:59:59' : $filter['time_to']; + } + + if (isset($date_to) === true) { + if (isset($time_to) === false) { + $time_to = '23:59:59'; + } + + $to = $date_to.' '.$time_to; + $sql_filters[] = sprintf( + ' AND te.utimestamp <= %d', + strtotime($to) + ); + } + + if (isset($from) === false) { + if (isset($filter['event_view_hr']) === true && ($filter['event_view_hr'] > 0)) { + $sql_filters[] = sprintf( + ' AND te.utimestamp > UNIX_TIMESTAMP(now() - INTERVAL %d HOUR) ', + $filter['event_view_hr'] + ); + } + } + + return $sql_filters; +} + + /** * Retrieve all events filtered. * @@ -700,60 +768,7 @@ function events_get_all( ); } - if (isset($filter['date_from']) === true - && empty($filter['date_from']) === false - && $filter['date_from'] !== '0000-00-00' - ) { - $date_from = $filter['date_from']; - } - - if (isset($filter['time_from']) === true) { - $time_from = (empty($filter['time_from']) === true) ? '00:00:00' : $filter['time_from']; - } - - if (isset($date_from) === true) { - if (isset($time_from) === false) { - $time_from = '00:00:00'; - } - - $from = $date_from.' '.$time_from; - $sql_filters[] = sprintf( - ' AND te.utimestamp >= %d', - strtotime($from) - ); - } - - if (isset($filter['date_to']) === true - && empty($filter['date_to']) === false - && $filter['date_to'] !== '0000-00-00' - ) { - $date_to = $filter['date_to']; - } - - if (isset($filter['time_to']) === true) { - $time_to = (empty($filter['time_to']) === true) ? '23:59:59' : $filter['time_to']; - } - - if (isset($date_to) === true) { - if (isset($time_to) === false) { - $time_to = '23:59:59'; - } - - $to = $date_to.' '.$time_to; - $sql_filters[] = sprintf( - ' AND te.utimestamp <= %d', - strtotime($to) - ); - } - - if (isset($from) === false) { - if (isset($filter['event_view_hr']) === true && ($filter['event_view_hr'] > 0)) { - $sql_filters[] = sprintf( - ' AND utimestamp > UNIX_TIMESTAMP(now() - INTERVAL %d HOUR) ', - $filter['event_view_hr'] - ); - } - } + $sql_filters = get_filter_date($filter); if (isset($filter['id_agent']) === true && $filter['id_agent'] > 0) { $sql_filters[] = sprintf( @@ -1069,7 +1084,6 @@ function events_get_all( $array_search = [ 'te.id_evento', 'lower(te.evento)', - 'lower(te.user_comment)', 'lower(te.id_extra)', 'lower(te.source)', 'lower('.$custom_data_search.')', @@ -1106,7 +1120,6 @@ function events_get_all( ' AND (lower(ta.alias) not like lower("%%%s%%") AND te.id_evento not like "%%%s%%" AND lower(te.evento) not like lower("%%%s%%") - AND lower(te.user_comment) not like lower("%%%s%%") AND lower(te.id_extra) not like lower("%%%s%%") AND lower(te.source) not like lower("%%%s%%") )', array_fill(0, 6, $filter['search_exclude']) @@ -1122,16 +1135,13 @@ function events_get_all( } // User comment. + $event_comment_join = ''; if (empty($filter['user_comment']) === false) { - // For filter field. + $event_comment_join = 'INNER JOIN tevent_comment ON te.id_evento = tevent_comment.id_event'; $sql_filters[] = sprintf( - ' AND lower(te.user_comment) like lower("%%%s%%") ', - io_safe_input($filter['user_comment']) - ); - - // For show comments on event details. - $sql_filters[] = sprintf( - ' OR lower(te.user_comment) like lower("%%%s%%") ', + ' AND (lower(tevent_comment.comment) like lower("%%%s%%") + OR lower(tevent_comment.comment) like lower("%%%s%%"))', + io_safe_input($filter['user_comment']), $filter['user_comment'] ); } @@ -1455,7 +1465,7 @@ function events_get_all( ' LIMIT %d', $config['max_number_of_events_per_node'] ); - } else if (isset($limit, $offset) === true && $limit > 0) { + } else if (isset($limit, $offset) === true && empty($limit) === false && $limit > 0) { $pagination = sprintf(' LIMIT %d OFFSET %d', $limit, $offset); } @@ -1552,36 +1562,20 @@ function events_get_all( $group_selects = ''; if ($group_by != '') { if ($count === false) { - $idx = array_search('te.user_comment', $fields); - if ($idx !== false) { - unset($fields[$idx]); - } - - db_process_sql('SET group_concat_max_len = 9999999'); - $group_selects = sprintf( ',COUNT(id_evento) AS event_rep, - %s - MAX(utimestamp) as timestamp_last, - MIN(utimestamp) as timestamp_first, - MAX(id_evento) as max_id_evento', - ($idx !== false) ? 'GROUP_CONCAT(DISTINCT user_comment SEPARATOR "
") AS comments,' : '' + MAX(te.utimestamp) as timestamp_last, + MIN(te.utimestamp) as timestamp_first, + MAX(id_evento) as max_id_evento' ); $group_selects_trans = sprintf( ',tmax_event.event_rep, - %s tmax_event.timestamp_last, tmax_event.timestamp_first, - tmax_event.max_id_evento', - ($idx !== false) ? 'tmax_event.comments,' : '' + tmax_event.max_id_evento' ); } - } else { - $idx = array_search('te.user_comment', $fields); - if ($idx !== false) { - $fields[$idx] = 'te.user_comment AS comments'; - } } if (((int) $filter['group_rep'] === EVENT_GROUP_REP_EVENTS @@ -1596,11 +1590,12 @@ function events_get_all( FROM %s %s %s + %s %s JOIN %s ta - ON ta.%s = te.id_agente + ON ta.%s = te.id_agente %s %s JOIN tgrupo tg - ON %s + ON %s WHERE 1=1 %s %s @@ -1611,6 +1606,7 @@ function events_get_all( ON te.id_evento = tmax_event.max_id_evento %s %s + %s %s JOIN %s ta ON ta.%s = te.id_agente %s @@ -1625,6 +1621,7 @@ function events_get_all( $tevento, $event_lj, $agentmodule_join, + $event_comment_join, $tagente_join, $tagente_table, $tagente_field, @@ -1638,6 +1635,7 @@ function events_get_all( $having, $event_lj, $agentmodule_join, + $event_comment_join, $tagente_join, $tagente_table, $tagente_field, @@ -1654,6 +1652,7 @@ function events_get_all( FROM %s %s %s + %s %s JOIN %s ta ON ta.%s = te.id_agente %s @@ -1671,6 +1670,7 @@ function events_get_all( $tevento, $event_lj, $agentmodule_join, + $event_comment_join, $tagente_join, $tagente_table, $tagente_field, @@ -1762,9 +1762,11 @@ function events_get_all( } } + $string_metaconsole_connections = implode(',', $metaconsole_connections); + $explode_metaconsole_connections = explode(',', $string_metaconsole_connections); $result_meta = Promise\wait( parallelMap( - $metaconsole_connections, + $explode_metaconsole_connections, function ($node_int) use ($sql, $history) { try { if (is_metaconsole() === true @@ -2238,91 +2240,18 @@ function events_comment( $first_event = reset($id_event); } - $sql = sprintf( - 'SELECT user_comment - FROM tevento - WHERE id_evento = %d', - $first_event + // Update comment. + $ret = db_process_sql_insert( + 'tevent_comment', + [ + 'id_event' => $first_event, + 'comment' => $comment, + 'action' => $action, + 'utimestamp' => time(), + 'id_user' => $config['id_user'], + ], ); - $event_comments = db_get_all_rows_sql($sql); - $event_comments_array = []; - - if ($event_comments[0]['user_comment'] == '') { - $comments_format = 'new'; - } else { - // If comments are not stored in json, the format is old. - $event_comments[0]['user_comment'] = str_replace( - [ - "\n", - ' ', - ], - '
', - $event_comments[0]['user_comment'] - ); - $event_comments_array = json_decode($event_comments[0]['user_comment']); - - if (empty($event_comments_array) === true) { - $comments_format = 'old'; - } else { - $comments_format = 'new'; - } - } - - switch ($comments_format) { - case 'new': - $comment_for_json['comment'] = io_safe_input($comment); - $comment_for_json['action'] = $action; - $comment_for_json['id_user'] = $config['id_user']; - $comment_for_json['utimestamp'] = time(); - $comment_for_json['event_id'] = $first_event; - - $event_comments_array[] = $comment_for_json; - - $event_comments = io_json_mb_encode($event_comments_array); - - // Update comment. - $ret = db_process_sql_update( - 'tevento', - ['user_comment' => $event_comments], - ['id_evento' => implode(',', $id_event)] - ); - break; - - case 'old': - // Give old ugly format to comment. - // Change this method for aux table or json. - $comment = str_replace(["\r\n", "\r", "\n"], '
', $comment); - - if ($comment !== '') { - $commentbox = '
'.io_safe_input($comment).'
'; - } else { - $commentbox = ''; - } - - // Don't translate 'by' word because if multiple users with - // different languages make comments in the same console - // will be a mess. - $comment = '-- '.$action.' by '.$config['id_user'].' ['.date($config['date_format']).'] --
'.$commentbox.'
'; - - // Update comment. - $sql_validation = sprintf( - 'UPDATE %s - SET user_comment = concat("%s", user_comment) - WHERE id_evento in (%s)', - 'tevento', - $comment, - implode(',', $id_event) - ); - - $ret = db_process_sql($sql_validation); - break; - - default: - // Ignore. - break; - } - if (($ret === false) || ($ret === 0)) { return false; } @@ -2407,7 +2336,8 @@ function events_create_event( $tags='', $custom_data='', $server_id=0, - $id_extra='' + $id_extra='', + $ack_utimestamp=0 ) { if ($source === false) { $source = get_product_name(); @@ -2428,7 +2358,6 @@ function events_create_event( 'id_agentmodule' => $id_agent_module, 'id_alert_am' => $id_aam, 'criticity' => $priority, - 'user_comment' => '', 'tags' => $tags, 'source' => $source, 'id_extra' => $id_extra, @@ -2436,7 +2365,7 @@ function events_create_event( 'warning_instructions' => $warning_instructions, 'unknown_instructions' => $unknown_instructions, 'owner_user' => '', - 'ack_utimestamp' => 0, + 'ack_utimestamp' => $ack_utimestamp, 'custom_data' => $custom_data, 'data' => '', 'module_status' => 0, @@ -5059,8 +4988,12 @@ function events_page_general($event) } $data[1] = $user_ack.' ( '; + // hd($config['date_format'], true); + // hd($event['ack_utimestamp_raw'], true); + // TODO: mirar en el manage y en la api que este ack de venir vacio lo herede del anterior que hubiera. if ($event['ack_utimestamp_raw'] !== false && $event['ack_utimestamp_raw'] !== 'false' + && empty($event['ack_utimestamp_raw']) === false ) { $data[1] .= date( $config['date_format'], @@ -5216,7 +5149,7 @@ function events_page_general_acknowledged($event_id) * * @return string HTML. */ -function events_page_comments($event, $ajax=false, $groupedComments=[]) +function events_page_comments($event, $groupedComments=[], $filter=null) { // Comments. global $config; @@ -5227,12 +5160,7 @@ function events_page_comments($event, $ajax=false, $groupedComments=[]) $table_comments->head = []; $table_comments->class = 'table_modal_alternate'; - if (isset($event['user_comment']) === false) { - $event['user_comment'] = ''; - } - - $comments = (empty($groupedComments) === true) ? $event['user_comment'] : $groupedComments; - + $comments = $groupedComments; if (empty($comments) === true) { $table_comments->style[0] = 'text-align:left;'; $table_comments->colspan[0][0] = 2; @@ -5241,49 +5169,7 @@ function events_page_comments($event, $ajax=false, $groupedComments=[]) $table_comments->data[] = $data; } else { if (is_array($comments) === true) { - $comments_array = []; - foreach ($comments as $comm) { - if (empty($comm) === true) { - continue; - } - - // If exists user_comments, come from grouped events and must be handled like this. - if (isset($comm['user_comment']) === true) { - $comm = $comm['user_comment']; - } - - $comm = str_replace(["\n", ' '], '
', $comm); - - $comments_array[] = io_safe_output(json_decode($comm, true)); - } - - // Plain comments. Can be improved. - $sortedCommentsArray = []; - foreach ($comments_array as $comm) { - if (isset($comm) === true - && empty($comm) === false - ) { - foreach ($comm as $subComm) { - $sortedCommentsArray[] = $subComm; - } - } - } - - // Sorting the comments by utimestamp (newer is first). - usort( - $sortedCommentsArray, - function ($a, $b) { - if ($a['utimestamp'] == $b['utimestamp']) { - return 0; - } - - return ($a['utimestamp'] > $b['utimestamp']) ? -1 : 1; - } - ); - - // Clean the unsorted comments and return it to the original array. - $comments_array = []; - $comments_array[] = $sortedCommentsArray; + $comments_array = $comments; } else { $comments = str_replace(["\n", ' '], '
', $comments); // If comments are not stored in json, the format is old. @@ -5291,76 +5177,70 @@ function events_page_comments($event, $ajax=false, $groupedComments=[]) } foreach ($comments_array as $comm) { - $comments_format = (empty($comm) === true && is_array($comments) === false) ? 'old' : 'new'; + $eventIdExplanation = (empty($groupedComments) === false) ? sprintf(' (#%d)', $comm['id_event']) : ''; + $data[0] = sprintf( + '%s %s %s%s', + $comm['action'], + __('by'), + get_user_fullname(io_safe_input($comm['id_user'])).' ('.io_safe_input($comm['id_user']).')', + $eventIdExplanation + ); - switch ($comments_format) { - case 'new': - foreach ($comm as $c) { - $eventIdExplanation = (empty($groupedComments) === false) ? sprintf(' (#%d)', $c['event_id']) : ''; + $data[0] .= sprintf( + '

%s', + date($config['date_format'], $comm['utimestamp']) + ); - $data[0] = sprintf( - '%s %s %s%s', - $c['action'], - __('by'), - get_user_fullname(io_safe_input($c['id_user'])).' ('.io_safe_input($c['id_user']).')', - $eventIdExplanation - ); + $data[1] = '

'.stripslashes(str_replace(['\n', '\r'], '
', $comm['comment'])).'

'; - $data[0] .= sprintf( - '

%s', - date($config['date_format'], $c['utimestamp']) - ); - - $data[1] = '

'.stripslashes(str_replace(['\n', '\r'], '
', $c['comment'])).'

'; - - $table_comments->data[] = $data; - } - break; - - case 'old': - $comm = explode('
', $comments); - - // Split comments and put in table. - $col = 0; - $data = []; - - foreach ($comm as $c) { - switch ($col) { - case 0: - $row_text = preg_replace('/\s*--\s*/', '', $c); - $row_text = preg_replace('/\<\/b\>/', '', $row_text); - $row_text = preg_replace('/\[/', '

[', $row_text); - $row_text = preg_replace('/[\[|\]]/', '', $row_text); - break; - - case 1: - $row_text = preg_replace("/[\r\n|\r|\n]/", '
', io_safe_output(strip_tags($c))); - break; - - default: - // Ignore. - break; - } - - $data[$col] = $row_text; - - $col++; - - if ($col == 2) { - $col = 0; - $table_comments->data[] = $data; - $data = []; - } - } - break; - - default: - // Ignore. - break; - } + $table_comments->data[] = $data; } } + $comments_filter = '
'; + $comments_filter .= html_print_label_input_block( + null, + html_print_extended_select_for_time( + 'comments_events_max_hours_old', + $filter['event_view_hr_cs'], + '', + __('Default'), + -2, + false, + true, + false, + true, + '', + false, + [ + SECONDS_1HOUR => __('1 hour'), + SECONDS_6HOURS => __('6 hours'), + SECONDS_12HOURS => __('12 hours'), + SECONDS_1DAY => __('24 hours'), + SECONDS_2DAY => __('48 hours'), + ], + '', + false, + 0, + [ SECONDS_1HOUR => __('hours') ], + ) + ); + + $eventb64 = base64_encode(json_encode($event)); + $filterb64 = base64_encode(json_encode($filter)); + $comments_filter .= html_print_submit_button( + __('Filter'), + 'filter_comments_button', + false, + [ + 'class' => 'mini mrgn_lft_15px', + 'icon' => 'search', + 'onclick' => 'get_table_events_tabs("'.$eventb64.'","'.$filterb64.'")', + ], + true + ); + $comments_filter .= '
'; + if (((tags_checks_event_acl( $config['id_user'], $event['id_grupo'], @@ -5386,7 +5266,10 @@ function events_page_comments($event, $ajax=false, $groupedComments=[]) true ); - $comments_form .= '
'; + $comments_form .= '
'; + $comments_form .= '
'; + $comments_form .= $comments_filter; + $comments_form .= '
'; $comments_form .= html_print_button( __('Add comment'), 'comment_button', @@ -5398,14 +5281,15 @@ function events_page_comments($event, $ajax=false, $groupedComments=[]) ], true ); - $comments_form .= '

'; + $comments_form .= '
'; + $comments_form .= '
'; + + $comments_form .= '
'; + } else { + $comments_form = $comments_filter; } - if ($ajax === true) { - return $comments_form.html_print_table($table_comments, true); - } - - return '
'.$comments_form.html_print_table($table_comments, true).'
'; + return $comments_form.html_print_table($table_comments, true); } @@ -5540,7 +5424,7 @@ function events_get_sql_order($sort_field='timestamp', $sort='DESC', $group_rep= break; case 'comment': - $sort_field_translated = 'user_comment'; + $sort_field_translated = 'tevent_comment.comment'; break; case 'extra_id': @@ -6112,3 +5996,179 @@ function get_count_event_criticity( return db_get_all_rows_sql($sql_meta); } + + +/** + * Comments for this events. + * + * @param array $event Info event. + * @param integer $mode Mode group by. + * @param integer $event_rep Events. + * + * @return array Comments. + */ +function event_get_comment($event, $filter=null) +{ + $whereGrouped = []; + if (empty($filter) === false) { + if (isset($filter['event_view_hr_cs']) === true && ($filter['event_view_hr_cs'] > 0)) { + $whereGrouped[] = sprintf( + ' AND tevent_comment.utimestamp > UNIX_TIMESTAMP(now() - INTERVAL %d SECOND) ', + $filter['event_view_hr_cs'] + ); + } else if (isset($filter['event_view_hr']) === true && ($filter['event_view_hr'] > 0)) { + $whereGrouped[] = sprintf( + ' AND tevent_comment.utimestamp > UNIX_TIMESTAMP(now() - INTERVAL %d SECOND) ', + ((int) $filter['event_view_hr'] * 3600) + ); + } + } + + $mode = (int) $filter['group_rep']; + + $eventsGrouped = []; + // Consider if the event is grouped. + if ($mode === EVENT_GROUP_REP_EVENTS) { + // Default grouped message filtering (evento and estado). + $whereGrouped[] = sprintf( + 'AND `tevento`.`evento` = "%s"', + io_safe_input(io_safe_output($event['evento'])) + ); + + // If id_agente is reported, filter the messages by them as well. + if ((int) $event['id_agente'] > 0) { + $whereGrouped[] = sprintf( + ' AND `tevento`.`id_agente` = %d', + (int) $event['id_agente'] + ); + } + + if ((int) $event['id_agentmodule'] > 0) { + $whereGrouped[] = sprintf( + ' AND `tevento`.`id_agentmodule` = %d', + (int) $event['id_agentmodule'] + ); + } + } else if ($mode === EVENT_GROUP_REP_EXTRAIDS) { + $whereGrouped[] = sprintf( + 'AND `tevento`.`id_extra` = "%s"', + io_safe_input(io_safe_output($event['id_extra'])) + ); + } else { + $whereGrouped[] = sprintf('AND `tevento`.`id_evento` = %d', $event['id_evento']); + } + + try { + if (is_metaconsole() === true + && $event['server_id'] > 0 + ) { + $node = new Node($event['server_id']); + $node->connect(); + } + + $sql = sprintf( + 'SELECT tevent_comment.* + FROM tevento + INNER JOIN tevent_comment + ON tevento.id_evento = tevent_comment.id_event + WHERE 1=1 %s + ORDER BY tevent_comment.utimestamp DESC', + implode(' ', $whereGrouped) + ); + + // Get grouped comments. + $eventsGrouped = db_get_all_rows_sql($sql); + } catch (\Exception $e) { + // Unexistent agent. + if (is_metaconsole() === true + && $event['server_id'] > 0 + ) { + $node->disconnect(); + } + + $eventsGrouped = []; + } finally { + if (is_metaconsole() === true + && $event['server_id'] > 0 + ) { + $node->disconnect(); + } + } + + return $eventsGrouped; +} + + +/** + * Last comment for this event. + * + * @param array $event Info event. + * + * @return string Comment. + */ +function event_get_last_comment($event, $filter) +{ + $comments = event_get_comment($event, $filter); + if (empty($comments) === false) { + return $comments[0]; + } + + return ''; +} + + +/** + * Get counter events same extraid. + * + * @param array $event Event data. + * @param array $filters Filters. + * + * @return integer Counter. + */ +function event_get_counter_extraId(array $event, ?array $filters) +{ + $counters = 0; + + $where = get_filter_date($filters); + + $where[] = sprintf( + 'AND `te`.`id_extra` = "%s"', + $event['id_extra'] + ); + + try { + if (is_metaconsole() === true + && $event['server_id'] > 0 + ) { + $node = new Node($event['server_id']); + $node->connect(); + } + + $sql = sprintf( + 'SELECT count(*) + FROM tevento te + WHERE 1=1 %s', + implode(' ', $where) + ); + + // Get grouped comments. + $counters = db_get_value_sql($sql); + } catch (\Exception $e) { + // Unexistent agent. + if (is_metaconsole() === true + && $event['server_id'] > 0 + ) { + $node->disconnect(); + } + + $counters = 0; + } finally { + if (is_metaconsole() === true + && $event['server_id'] > 0 + ) { + $node->disconnect(); + } + } + + return $counters; +} diff --git a/pandora_console/include/functions_filemanager.php b/pandora_console/include/functions_filemanager.php index 1611cd705a..50ca449123 100644 --- a/pandora_console/include/functions_filemanager.php +++ b/pandora_console/include/functions_filemanager.php @@ -766,7 +766,18 @@ function filemanager_file_explorer( && ($readOnly === false) ) { $data[4] .= ''; - $data[4] .= ''; + $data[4] .= html_print_input_image( + 'delete', + 'images/delete.svg', + 1, + 'margin-top: 2px;height:21px', + true, + [ + 'title' => __('Delete'), + 'class' => 'invert_filter main_menu_icon', + 'onclick' => 'if (!confirm(\' '.__('Are you sure?').'\')) return false;', + ] + ); $data[4] .= html_print_input_hidden('filename', $fileinfo['realpath'], true); $data[4] .= html_print_input_hidden('hash', md5($fileinfo['realpath'].$config['server_unique_identifier']), true); $data[4] .= html_print_input_hidden('delete_file', 1, true); diff --git a/pandora_console/include/functions_graph.php b/pandora_console/include/functions_graph.php index c35e553235..1892b0cd31 100644 --- a/pandora_console/include/functions_graph.php +++ b/pandora_console/include/functions_graph.php @@ -1003,6 +1003,10 @@ function grafico_modulo_sparse($params) ]; } + if ($data_module_graph === false) { + $data_module_graph = []; + } + $data_module_graph['series_suffix'] = $series_suffix; // Check available data. @@ -4560,6 +4564,10 @@ function graph_netflow_aggregate_pie($data, $aggregate, $ttl=1, $only_image=fals } $labels = array_keys($values); + foreach ($labels as $key => $label) { + $labels[$key] = (string) $label; + } + $values = array_values($values); if ($config['fixed_graph'] == false) { diff --git a/pandora_console/include/functions_html.php b/pandora_console/include/functions_html.php index 6563c78eb6..1962bae211 100644 --- a/pandora_console/include/functions_html.php +++ b/pandora_console/include/functions_html.php @@ -578,6 +578,10 @@ function html_print_select_groups( if (empty($nothing) === false) { $fields[$nothing_value] = $nothing; + if ($include_groups === false) { + $include_groups = []; + } + $include_groups[$nothing_value] = $nothing; } @@ -2162,7 +2166,8 @@ function html_print_extended_select_for_time( $custom_fields=false, $style_icon='', $no_change=false, - $allow_zero=0 + $allow_zero=0, + $units=null ) { global $config; $admin = is_user_admin($config['id_user']); @@ -2188,15 +2193,17 @@ function html_print_extended_select_for_time( $selected = 300; } - $units = [ - 1 => __('seconds'), - SECONDS_1MINUTE => __('minutes'), - SECONDS_1HOUR => __('hours'), - SECONDS_1DAY => __('days'), - SECONDS_1WEEK => __('weeks'), - SECONDS_1MONTH => __('months'), - SECONDS_1YEAR => __('years'), - ]; + if (empty($units) === true) { + $units = [ + 1 => __('seconds'), + SECONDS_1MINUTE => __('minutes'), + SECONDS_1HOUR => __('hours'), + SECONDS_1DAY => __('days'), + SECONDS_1WEEK => __('weeks'), + SECONDS_1MONTH => __('months'), + SECONDS_1YEAR => __('years'), + ]; + } if ($unique_name === true) { $uniq_name = uniqid($name); @@ -3329,9 +3336,23 @@ function html_print_input_image($name, $src, $value, $style='', $return=false, $ 'disabled', ]; + if (isset($options['title']) && $options['title'] != '') { + if (isset($options['class'])) { + $options['class'] .= ' forced_title'; + } else { + $options['class'] = 'forced_title'; + } + + // New way to show the force_title (cleaner and better performance). + $output .= 'data-title="'.io_safe_input_html($options['title']).'" '; + $output .= 'data-use_title_for_force_title="1" '; + } + foreach ($attrs as $attribute) { - if (isset($options[$attribute])) { - $output .= ' '.$attribute.'="'.io_safe_input_html($options[$attribute]).'"'; + if ($attribute !== 'title') { + if (isset($options[$attribute])) { + $output .= ' '.$attribute.'="'.io_safe_input_html($options[$attribute]).'"'; + } } } @@ -3618,6 +3639,7 @@ function html_print_button($label='OK', $name='', $disabled=false, $script='', $ $classes = ''; $fixedId = ''; $iconStyle = ''; + $minimize_arrow = false; // $spanStyle = 'margin-top: 4px;'; $spanStyle = ''; if (empty($name) === true) { @@ -3655,6 +3677,8 @@ function html_print_button($label='OK', $name='', $disabled=false, $script='', $ $buttonType = ($attr_array['type'] ?? 'button'); $buttonAttributes = $value; break; + } else if ($attribute === 'minimize-arrow') { + $minimize_arrow = true; } else { $attributes .= $attribute.'="'.$value.'" '; } @@ -3679,15 +3703,30 @@ function html_print_button($label='OK', $name='', $disabled=false, $script='', $ $iconDiv = ''; } + if ($minimize_arrow === true) { + $minimezeDiv = html_print_div( + [ + 'id' => 'minimize_arrow_event_sound', + 'style' => 'background-color:transparent; right: 1em; margin-left:0.5em; position:relative; display:none;', + 'class' => 'arrow_menu_down w30p', + ], + true + ); + } else { + $minimezeDiv = ''; + } + // Defined id. Is usable for span and button. // TODO. Check if will be proper use button or submit when where appropiate. $mainId = ((empty($fixedId) === false) ? $fixedId : 'button-'.$name); if ($imageButton === false) { - $content = ''.$label.''; + $content = $minimezeDiv; + $content .= ''.$label.''; $content .= $iconDiv; } else { - $content = $iconDiv; + $content = $minimezeDiv; + $content .= $iconDiv; } // In case of not selected button type, in this case, will be normal button. @@ -4531,9 +4570,9 @@ function html_print_checkbox_switch_extended( */ -function html_print_checkbox_switch($name, $value, $checked=false, $return=false, $disabled=false, $script='', $disabled_hidden=false) +function html_print_checkbox_switch($name, $value, $checked=false, $return=false, $disabled=false, $script='', $disabled_hidden=false, $class='') { - $output = html_print_checkbox_switch_extended($name, $value, (bool) $checked, $disabled, $script, '', true); + $output = html_print_checkbox_switch_extended($name, $value, (bool) $checked, $disabled, $script, '', true, '', $class); if (!$disabled_hidden) { $output .= html_print_input_hidden($name.'_sent', 1, true); } @@ -5090,7 +5129,7 @@ function html_print_autocomplete_modules( ob_start(); $text_color = ''; - $module_icon = 'images/search_module.png'; + $module_icon = is_metaconsole() === false ? 'images/search_module.png' : '../../images/search_module.png'; if ($config['style'] === 'pandora_black' && is_metaconsole() === false) { $text_color = 'color: white'; $module_icon = 'images/brick.menu.png'; @@ -5105,7 +5144,7 @@ function html_print_autocomplete_modules( 100, false, '', - ['style' => 'background: url('.$module_icon.') 95% right; '.$text_color.''] + ['style' => 'background: url('.$module_icon.') no-repeat content-box; background-position: center right 5px; '.$text_color.''] ); html_print_input_hidden($name.'_hidden', $id_agent_module); diff --git a/pandora_console/include/functions_io.php b/pandora_console/include/functions_io.php index e4295332fa..6283fdbaed 100755 --- a/pandora_console/include/functions_io.php +++ b/pandora_console/include/functions_io.php @@ -221,6 +221,10 @@ function io_safe_output_array(&$item, $key=false, $utf8=true) */ function io_safe_output($value, $utf8=true) { + if (empty($value) === true) { + return $value; + } + if (is_numeric($value)) { return $value; } @@ -235,16 +239,16 @@ function io_safe_output($value, $utf8=true) $value = utf8_encode($value); } - // Replace the html entitie of ( for the char + // Replace the html entitie of ( for the char. $value = str_replace('(', '(', $value); - // Replace the html entitie of ) for the char + // Replace the html entitie of ) for the char. $value = str_replace(')', ')', $value); - // Replace the html entitie of < for the char + // Replace the html entitie of < for the char. $value = str_replace('<', '<', $value); - // Replace the html entitie of > for the char + // Replace the html entitie of > for the char. $value = str_replace('>', '>', $value); if ($utf8) { diff --git a/pandora_console/include/functions_notifications.php b/pandora_console/include/functions_notifications.php index 170612d1f4..de703861c7 100644 --- a/pandora_console/include/functions_notifications.php +++ b/pandora_console/include/functions_notifications.php @@ -1092,6 +1092,11 @@ function notifications_print_dropdown_element($message_info) $message_info['subject'] = io_safe_input($img); } + if (strlen($body_preview) >= 170) { + $body_preview = substr($body_preview, 0, 150); + $body_preview .= __('. Read More...'); + } + return sprintf( " 0], [ - 'id_agente_modulo' => $module['id_agent_module'], + 'quiet' => 0, + 'quiet_by_downtime' => 0, + ], + [ + 'quiet_by_downtime' => 1, + 'id_agente_modulo' => $module['id_agent_module'], ] ); @@ -672,32 +676,68 @@ function planned_downtimes_stop($downtime) foreach ($agents as $agent) { $result = db_process_sql_update( 'tagente', - [ - 'disabled' => 0, - 'update_module_count' => 1, - ], + ['update_module_count' => 1], ['id_agente' => $agent['id_agent']] ); - if ($result) { + $result_disabled = db_process_sql_update( + 'tagente', + [ + 'disabled' => 0, + 'disabled_by_downtime' => 0, + ], + [ + 'disabled_by_downtime' => 1, + 'id_agente' => $agent['id_agent'], + ] + ); + + if ($result !== false && $result_disabled !== false) { $count++; } } break; case 'disable_agent_modules': - $update_sql = sprintf( - 'UPDATE tagente_modulo tam, tagente ta, tplanned_downtime_modules tpdm - SET tam.disabled = 0, ta.update_module_count = 1 - WHERE tpdm.id_agent_module = tam.id_agente_modulo AND - ta.id_agente = tam.id_agente AND - tpdm.id_downtime = %d', - $id_downtime + $agents = db_get_all_rows_filter( + 'tplanned_downtime_agents', + ['id_downtime' => $id_downtime] ); + if (empty($agents)) { + $agents = []; + } - db_process_sql($update_sql); + $count = 0; + foreach ($agents as $agent) { + $modules = db_get_all_rows_filter( + 'tplanned_downtime_modules', + [ + 'id_agent' => $agent['id_agent'], + 'id_downtime' => $id_downtime, + ] + ); + if (empty($modules)) { + $modules = []; + } - $count = ''; + foreach ($modules as $module) { + $result = db_process_sql_update( + 'tagente_modulo', + [ + 'disabled' => 0, + 'disabled_by_downtime' => 0, + ], + [ + 'disabled_by_downtime' => 1, + 'id_agente_modulo' => $module['id_agent_module'], + ] + ); + + if ($result !== false) { + $count++; + } + } + } break; case 'disable_agents_alerts': @@ -722,13 +762,17 @@ function planned_downtimes_stop($downtime) foreach ($modules as $module) { $result = db_process_sql_update( 'talert_template_modules', - ['disabled' => 0], [ - 'id_agent_module' => $module['id_agente_modulo'], + 'disabled' => 0, + 'disabled_by_downtime' => 0, + ], + [ + 'disabled_by_downtime' => 1, + 'id_agent_module' => $module['id_agente_modulo'], ] ); - if ($result) { + if ($result !== false) { $count++; } } diff --git a/pandora_console/include/functions_servers.php b/pandora_console/include/functions_servers.php index ebc2bb414d..e4d1f655b0 100644 --- a/pandora_console/include/functions_servers.php +++ b/pandora_console/include/functions_servers.php @@ -964,7 +964,7 @@ function servers_get_info($id_server=-1, $sql_limit=-1) case SERVER_TYPE_NETFLOW: $server['img'] = html_print_image( - 'images/netflow@svg.svg', + 'images/Netflow2@svg.svg', true, [ 'title' => __('Netflow server'), diff --git a/pandora_console/include/functions_treeview.php b/pandora_console/include/functions_treeview.php index b408567aeb..025276ecef 100755 --- a/pandora_console/include/functions_treeview.php +++ b/pandora_console/include/functions_treeview.php @@ -892,11 +892,13 @@ function treeview_printTable($id_agente, $server_data=[], $no_head=false) $table_advanced->head = []; $table_advanced->data = []; - // Agent version. - $row = []; + $row = []; + // Agent version. + if (!empty($agent['agent_version'])) { $row['title'] = __('Agent Version'); $row['data'] = $agent['agent_version']; $table_advanced->data['agent_version'] = $row; + } // Position Information. if ($config['activate_gis']) { @@ -976,7 +978,7 @@ function treeview_printTable($id_agente, $server_data=[], $no_head=false) '', '', true, - false, + empty($table_advanced->data), '', 'white-box-content mrgn_top_0 mrgn_btn_0px border-bottom-gray', 'white_table_flex' diff --git a/pandora_console/include/functions_ui.php b/pandora_console/include/functions_ui.php index e7702f2439..0292f548f1 100755 --- a/pandora_console/include/functions_ui.php +++ b/pandora_console/include/functions_ui.php @@ -88,8 +88,16 @@ function ui_bbcode_to_html($text, $allowed_tags=['[url]']) * * @return string Truncated text. */ -function ui_print_truncate_text($text, $numChars=GENERIC_SIZE_TEXT, $showTextInAToopTip=true, $return=true, $showTextInTitle=true, $suffix='…', $style=false) -{ +function ui_print_truncate_text( + $text, + $numChars=GENERIC_SIZE_TEXT, + $showTextInAToopTip=true, + $return=true, + $showTextInTitle=true, + $suffix='…', + $style=false, + $forced_title=false +) { global $config; if (is_string($numChars)) { @@ -190,6 +198,10 @@ function ui_print_truncate_text($text, $numChars=GENERIC_SIZE_TEXT, $showTextInA } } + if ($forced_title === true) { + $truncateText = '', $comments); - if (is_array($comments)) { - foreach ($comments as $comm) { - if (empty($comm)) { - continue; - } - - $comments_array[] = io_safe_output(json_decode($comm, true)); - } - } - - $order_utimestamp = array_reduce( - $comments_array, - function ($carry, $item) { - foreach ($item as $k => $v) { - $carry[$v['utimestamp']] = $v; - } - - return $carry; - } - ); - - $key_max_utimestamp = max(array_keys($order_utimestamp)); - - $last_comment = $order_utimestamp[$key_max_utimestamp]; - - if (empty($last_comment) === true) { + if (empty($comment) === true) { return ''; } // Only show the last comment. If commment its too long,the comment will short with ... // If $config['prominent_time'] is timestamp the date show Month, day, hour and minutes. // Else show comments hours ago - if ($last_comment['action'] != 'Added comment') { - $last_comment['comment'] = $last_comment['action']; + if ($comment['action'] != 'Added comment') { + $comment['comment'] = $comment['action']; } - $short_comment = substr($last_comment['comment'], 0, 20); + $short_comment = substr($comment['comment'], 0, 20); if ($config['prominent_time'] == 'timestamp') { - $comentario = ''.date($config['date_format'], $last_comment['utimestamp']).' ('.$last_comment['id_user'].'): '.$last_comment['comment'].''; + $comentario = ''.date($config['date_format'], $comment['utimestamp']).' ('.$comment['id_user'].'): '.$comment['comment'].''; - if (strlen($comentario) > '200px') { - $comentario = ''.date($config['date_format'], $last_comment['utimestamp']).' ('.$last_comment['id_user'].'): '.$short_comment.'...'; + if (strlen($comentario) > '200px' && $truncate_limit >= 255) { + $comentario = ''.date($config['date_format'], $comment['utimestamp']).' ('.$comment['id_user'].'): '.$short_comment.'...'; } } else { - $rest_time = (time() - $last_comment['utimestamp']); + $rest_time = (time() - $comment['utimestamp']); $time_last = (($rest_time / 60) / 60); - $comentario = ''.number_format($time_last, 0, $config['decimal_separator'], ($config['thousand_separator'] ?? ',')).'  Hours  ('.$last_comment['id_user'].'): '.$last_comment['comment'].''; + $comentario = ''.number_format($time_last, 0, $config['decimal_separator'], ($config['thousand_separator'] ?? ',')).'  Hours  ('.$comment['id_user'].'): '.$comment['comment'].''; - if (strlen($comentario) > '200px') { - $comentario = ''.number_format($time_last, 0, $config['decimal_separator'], ($config['thousand_separator'] ?? ',')).'  Hours  ('.$last_comment['id_user'].'): '.$short_comment.'...'; + if (strlen($comentario) > '200px' && $truncate_limit >= 255) { + $comentario = ''.number_format($time_last, 0, $config['decimal_separator'], ($config['thousand_separator'] ?? ',')).'  Hours  ('.$comment['id_user'].'): '.$short_comment.'...'; } } - return io_safe_output($comentario); + $comentario = io_safe_output($comentario); + if (strlen($comentario) >= $truncate_limit) { + $comentario = ui_print_truncate_text( + $comentario, + $truncate_limit, + false, + true, + false, + '…', + true, + true, + ); + } + + return $comentario; } diff --git a/pandora_console/include/javascript/pandora.js b/pandora_console/include/javascript/pandora.js index af212f454e..738deb0834 100644 --- a/pandora_console/include/javascript/pandora.js +++ b/pandora_console/include/javascript/pandora.js @@ -1448,6 +1448,17 @@ function defineTinyMCE(selector) { }); } +function defineTinyMCEDark(selector) { + tinymce.init({ + selector: selector, + plugins: "preview, searchreplace, table, nonbreaking, link, image", + promotion: false, + branding: false, + skin: "oxide-dark", + content_css: "dark" + }); +} + function UndefineTinyMCE(textarea_id) { tinyMCE.remove(textarea_id); $(textarea_id).show(""); diff --git a/pandora_console/include/javascript/pandora_events.js b/pandora_console/include/javascript/pandora_events.js index 7916b921d6..6c31136c34 100644 --- a/pandora_console/include/javascript/pandora_events.js +++ b/pandora_console/include/javascript/pandora_events.js @@ -55,7 +55,7 @@ function show_event_dialog(event, dialog_page) { title: event.evento, resizable: true, draggable: true, - modal: true, + modal: false, minWidth: 875, minHeight: 600, close: function() { @@ -484,7 +484,7 @@ function event_comment(current_event) { success: function() { $("#button-comment_button").removeAttr("disabled"); $("#response_loading").hide(); - $("#link_comments").click(); + $("#button-filter_comments_button").click(); } }); @@ -943,6 +943,185 @@ function process_buffers(buffers) { } } +function openSoundEventsDialogModal(settings, dialog_parameters, reload) { + let mode = $("#hidden-mode_alert").val(); + if (reload != false) { + if (mode == 0) { + let filter_id = $("#filter_id option:selected").val(); + let interval = $("#interval option:selected").val(); + let time_sound = $("#time_sound option:selected").val(); + let sound_id = $("#sound_id option:selected").val(); + let parameters = { + filter_id: filter_id, + interval: interval, + time_sound: time_sound, + sound_id: sound_id, + mode: mode + }; + parameters = JSON.stringify(parameters); + parameters = btoa(parameters); + let url = + window.location + "&settings=" + settings + "¶meters=" + parameters; + $(location).attr("href", url); + } else { + let url = window.location + "&settings=" + settings; + $(location).attr("href", url); + } + } else { + openSoundEventsDialog(settings, dialog_parameters, reload); + } +} + +function openSoundEventsDialog(settings, dialog_parameters, reload) { + let encode_settings = settings; + if (reload == undefined) { + reload = true; + } + if (dialog_parameters != undefined) { + dialog_parameters = JSON.parse(atob(dialog_parameters)); + } + settings = JSON.parse(atob(settings)); + // Check modal exists and is open. + if ( + $("#modal-sound").hasClass("ui-dialog-content") && + $("#modal-sound").dialog("isOpen") + ) { + $(".ui-dialog-titlebar-minimize").trigger("click"); + return; + } + //Modify button + $("#minimize_arrow_event_sound").removeClass("arrow_menu_up"); + $("#minimize_arrow_event_sound").addClass("arrow_menu_down"); + $("#minimize_arrow_event_sound").show(); + + // Initialize modal. + $("#modal-sound") + .empty() + .dialog({ + title: settings.title, + resizable: false, + modal: false, + width: 600, + height: 600, + open: function() { + $.ajax({ + method: "post", + url: settings.url, + data: { + page: settings.page, + drawConsoleSound: 1 + }, + dataType: "html", + success: function(data) { + $("#modal-sound").append(data); + $("#tabs-sound-modal").tabs({ + disabled: [1] + }); + + // Test sound. + $("#button-melody_sound").click(function() { + var sound = false; + if ($("#id_sound_event").length == 0) { + sound = true; + } + + test_sound_button(sound, settings.urlSound); + }); + + // Play Stop. + $("#button-start-search").click(function() { + if (reload == true) { + openSoundEventsDialogModal(encode_settings, 0, reload); + } + var mode = $("#hidden-mode_alert").val(); + var action = false; + if (mode == 0) { + action = true; + } + if ($("#button-start-search").hasClass("play")) { + $("#modal-sound").css({ + height: "500px" + }); + $("#modal-sound") + .parent() + .css({ + height: "550px" + }); + } else { + $("#modal-sound").css({ + height: "450px" + }); + $("#modal-sound") + .parent() + .css({ + height: "500px" + }); + } + + action_events_sound(action, settings); + }); + + if (reload == false && dialog_parameters != undefined) { + if ($("#button-start-search").hasClass("play")) { + $("#filter_id").val(dialog_parameters["filter_id"]); + $("#interval").val(dialog_parameters["interval"]); + $("#time_sound").val(dialog_parameters["time_sound"]); + $("#sound_id").val(dialog_parameters["sound_id"]); + + $("#filter_id").trigger("change"); + $("#interval").trigger("change"); + $("#time_sound").trigger("change"); + $("#sound_id").trigger("change"); + + $("#button-start-search").trigger("click"); + } + } + + // Silence Alert. + $("#button-no-alerts").click(function() { + if ($("#button-no-alerts").hasClass("silence-alerts") === true) { + // Remove audio. + remove_audio(); + + // Clean events. + $("#tabs-sound-modal .elements-discovered-alerts ul").empty(); + $("#tabs-sound-modal .empty-discovered-alerts").removeClass( + "invisible_important" + ); + + // Clean progress. + $("#progressbar_time").empty(); + + // Change img button. + $("#button-no-alerts") + .removeClass("silence-alerts") + .addClass("alerts"); + // Change value button. + $("#button-no-alerts").val(settings.noAlert); + $("#button-no-alerts > span").text(settings.noAlert); + + // Background button. + $(".container-button-alert").removeClass("fired"); + + // New progress. + listen_event_sound(settings); + } + }); + }, + error: function(error) { + console.error(error); + } + }); + }, + close: function() { + $("#minimize_arrow_event_sound").hide(); + remove_audio(); + $(this).dialog("destroy"); + } + }) + .show(); +} + function openSoundEventModal(settings) { if ($("#hidden-metaconsole_activated").val() === "1") { var win = open( @@ -966,6 +1145,7 @@ function openSoundEventModal(settings) { } settings = JSON.parse(atob(settings)); + // Check modal exists and is open. if ( $("#modal-sound").hasClass("ui-dialog-content") && @@ -1045,10 +1225,12 @@ function add_audio(urlSound) { sound + "' autoplay='true' hidden='true' loop='false'>" ); + $("#button-sound_events_button").addClass("animation-blink"); } function remove_audio() { $(".actions-sound-modal audio").remove(); + $("#button-sound_events_button").removeClass("animation-blink"); } function listen_event_sound(settings) { @@ -1064,6 +1246,37 @@ function listen_event_sound(settings) { } function check_event_sound(settings) { + // Update elements time. + $(".elements-discovered-alerts ul li").each(function() { + let element_time = $(this) + .children(".li-hidden") + .val(); + let obj_time = new Date(element_time); + let current_dt = new Date(); + let timestamp = current_dt.getTime() - obj_time.getTime(); + timestamp = timestamp / 1000; + if (timestamp <= 60) { + timestamp = Math.round(timestamp) + " seconds"; + } else if (timestamp <= 3600) { + let minute = Math.floor((timestamp / 60) % 60); + minute = minute < 10 ? "0" + minute : minute; + let second = Math.floor(timestamp % 60); + second = second < 10 ? "0" + second : second; + timestamp = minute + " minutes " + second + " seconds"; + } else { + let hour = Math.floor(timestamp / 3600); + hour = hour < 10 ? "0" + hour : hour; + let minute = Math.floor((timestamp / 60) % 60); + minute = minute < 10 ? "0" + minute : minute; + let second = Math.round(timestamp % 60); + second = second < 10 ? "0" + second : second; + timestamp = hour + " hours " + minute + " minutes " + second + " seconds"; + } + $(this) + .children(".li-time") + .children("span") + .html(timestamp); + }); jQuery.post( settings.url, { @@ -1117,7 +1330,13 @@ function check_event_sound(settings) { "beforeend", '
' + element.timestamp + "
" ); - $("#tabs-sound-modal .elements-discovered-alerts ul").append(li); + li.insertAdjacentHTML( + "beforeend", + '' + ); + $("#tabs-sound-modal .elements-discovered-alerts ul").prepend(li); }); // -100 delay sound. @@ -1229,3 +1448,285 @@ function removeElement(name_select, id_modal) { .append(option); }); } + +function get_table_events_tabs(event, filter) { + var custom_event_view_hr = $("#hidden-comments_events_max_hours_old").val(); + $.post({ + url: "ajax.php", + data: { + page: "include/ajax/events", + get_comments: 1, + event: event, + filter: filter, + custom_event_view_hr: custom_event_view_hr + }, + dataType: "html", + success: function(data) { + $("#extended_event_comments_page").empty(); + $("#extended_event_comments_page").html(data); + } + }); +} +// Define the minimize button functionality; +function hidden_dialog(dialog) { + setTimeout(function() { + $("#modal-sound").css("visibility", "hidden"); + dialog.css("z-index", "-1"); + }, 200); +} + +function show_dialog(dialog) { + setTimeout(function() { + $("#modal-sound").css("visibility", "visible"); + dialog.css("z-index", "1115"); + }, 50); +} + +/* +############################################################################# +## +## + Compacts the Modal Sound Dialog to a tiny toolbar +## + Dynamically adds a button which can reduce/reapply the dialog size +## + If alarm gets raised & minimized, the dialog window maximizes and the toolbar flashes red for 10 seconds. +## - Works fine until a link/action gets clicked. The Toolbar shifts to the bottom of the Modal-Sound Dialog. +## +############################################################################# +*/ + +$(document).ajaxSend(function(event, jqXHR, ajaxOptions) { + const requestBody = ajaxOptions.data; + try { + if (requestBody && requestBody.includes("drawConsoleSound=1")) { + console.log( + "AJAX request sent with drawConsoleSound=1:", + ajaxOptions.url + ); + + // Find the dialog element by the aria-describedby attribute + var dialog = $('[aria-describedby="modal-sound"]'); + + // Select the close button within the dialog + var closeButton = dialog.find(".ui-dialog-titlebar-close"); + + // Add the minimize button before the close button + var minimizeButton = $("