From acabe543c4119d82a68fdae060fb9703c9090f07 Mon Sep 17 00:00:00 2001
From: fbsanchez <fborja.sanchez@artica.es>
Date: Mon, 30 Mar 2020 19:44:44 +0200
Subject: [PATCH] csv recon0

---
 pandora_console/extras/mr/37.sql              |   2 +
 .../pandoradb_migrate_6.0_to_7.0.mysql.sql    |   3 +-
 .../godmode/wizards/HostDevices.class.php     | 124 ++++++++++++++++--
 .../godmode/wizards/Wizard.main.php           |  48 ++-----
 pandora_console/include/functions_html.php    |   8 +-
 pandora_console/include/javascript/pandora.js |  12 +-
 pandora_console/include/styles/wizard.css     |  55 +++++++-
 pandora_console/pandoradb.sql                 |   1 +
 pandora_server/lib/PandoraFMS/Core.pm         |   6 -
 9 files changed, 195 insertions(+), 64 deletions(-)

diff --git a/pandora_console/extras/mr/37.sql b/pandora_console/extras/mr/37.sql
index fedc4b477e..b879112ff3 100644
--- a/pandora_console/extras/mr/37.sql
+++ b/pandora_console/extras/mr/37.sql
@@ -2,6 +2,8 @@ START TRANSACTION;
 
 ALTER TABLE trecon_task MODIFY COLUMN `id_network_profile` TEXT;
 ALTER TABLE `trecon_task` CHANGE COLUMN `create_incident` `review_mode` TINYINT(1) UNSIGNED DEFAULT 0;
+ALTER TABLE `trecon_task` ADD COLUMN `subnet_csv` TINYINT(1) UNSIGNED DEFAULT 0;
+
 UPDATE `trecon_task` SET `review_mode` = 1;
 ALTER TABLE trecon_task add column `auto_monitor` TINYINT(1) UNSIGNED DEFAULT 1 AFTER `auth_strings`;
 UPDATE `trecon_task` SET `auto_monitor` = 0;
diff --git a/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql b/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql
index f3a3f612a1..9e5382c2b5 100644
--- a/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql
+++ b/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql
@@ -1686,7 +1686,8 @@ ALTER TABLE `trecon_task` ADD COLUMN `type` int(11) NOT NULL DEFAULT '0',
 	MODIFY COLUMN `autoconfiguration_enabled` tinyint(1) unsigned NULL DEFAULT '0',
 	MODIFY COLUMN `summary` text NULL,
 	MODIFY COLUMN `id_network_profile` text,
-	CHANGE COLUMN `create_incident` `review_mode` TINYINT(1) UNSIGNED DEFAULT 0;
+	CHANGE COLUMN `create_incident` `review_mode` TINYINT(1) UNSIGNED DEFAULT 0,
+	ADD COLUMN `subnet_csv` TINYINT(1) UNSIGNED DEFAULT 0;
 
 -- Old recon always report.
 UPDATE `trecon_task` SET `review_mode` = 1;
diff --git a/pandora_console/godmode/wizards/HostDevices.class.php b/pandora_console/godmode/wizards/HostDevices.class.php
index 43825c31e5..ff2c10b0ed 100755
--- a/pandora_console/godmode/wizards/HostDevices.class.php
+++ b/pandora_console/godmode/wizards/HostDevices.class.php
@@ -300,9 +300,50 @@ class HostDevices extends Wizard
             $comment = get_parameter('comment', '');
             $server_id = get_parameter('id_recon_server', '');
             $network = get_parameter('network', '');
+            $network_csv_enabled = (bool) get_parameter_switch(
+                'network_csv_enabled',
+                false
+            );
             $id_group = get_parameter('id_group', '');
             $interval = get_parameter('interval', 0);
 
+            if ($network_csv_enabled) {
+                if ($_FILES['network_csv']['type'] != 'text/csv') {
+                    $this->msg = __(
+                        'Invalid mimetype for csv file: %s',
+                        $_FILES['network_csv']['type']
+                    );
+                    return false;
+                }
+
+                $network = preg_split(
+                    "/\n|,|;/",
+                    trim(
+                        file_get_contents(
+                            $_FILES['network_csv']['tmp_name']
+                        )
+                    )
+                );
+                unlink($_FILES['network_csv']['tmp_name']);
+                if (empty($network) || is_array($network) === false) {
+                    $this->msg = __(
+                        'Invalid content readed from csv file: %s',
+                        $_FILES['network_csv']['name']
+                    );
+                    return false;
+                }
+
+                // Sanitize.
+                $network = array_unique($network);
+                $network = array_filter(
+                    $network,
+                    function ($item) {
+                        return (!empty($item));
+                    }
+                );
+                $network = join(',', $network);
+            }
+
             if (isset($task_id) === true) {
                 // We're updating this task.
                 $task = db_get_row(
@@ -338,6 +379,7 @@ class HostDevices extends Wizard
                 && $server_id == null
                 && empty($id_group) === true
                 && empty($network) === true
+                && empty($network_csv) === true
                 && $interval === 0
             ) {
                 // Default values, no data received.
@@ -385,6 +427,7 @@ class HostDevices extends Wizard
                 $this->task['id_recon_server'] = $server_id;
                 $this->task['id_group'] = $id_group;
                 $this->task['interval_sweep'] = $interval;
+                $this->task['subnet_csv'] = $network_csv_enabled;
 
                 if (isset($this->task['id_rt']) === false) {
                     // Create.
@@ -701,7 +744,7 @@ class HostDevices extends Wizard
 
                 $form['rows'][0]['columns'][0] = [
                     'width'  => '30%',
-                    'style'  => 'padding: 9px;',
+                    'style'  => 'padding: 9px;min-width: 250px;',
                     'inputs' => [
                         '0' => [
                             'arguments' => [
@@ -728,7 +771,10 @@ class HostDevices extends Wizard
                                 'name'     => 'interval_manual_defined',
                                 'return'   => true,
                             ],
-                            'extra'     => '<span id="interval_manual_container">'.html_print_extended_select_for_time(
+                            'extra'     => '<div id="interval_manual_container"><div class="time_selection_container">'.ui_print_help_tip(
+                                __('The minimum recomended interval for Recon Task is 5 minutes'),
+                                true
+                            ).html_print_extended_select_for_time(
                                 'interval',
                                 $this->task['interval_sweep'],
                                 '',
@@ -738,10 +784,7 @@ class HostDevices extends Wizard
                                 true,
                                 false,
                                 false
-                            ).ui_print_help_tip(
-                                __('The minimum recomended interval for Recon Task is 5 minutes'),
-                                true
-                            ).'</span>',
+                            ).'</div></div>',
 
                         ],
                     ],
@@ -751,6 +794,7 @@ class HostDevices extends Wizard
                     'width'         => '40%',
                     'padding-right' => '12%',
                     'padding-left'  => '5%',
+                    'style'         => 'min-width: 350px',
                     'inputs'        => [
                         '0' => [
                             'label'     => '<b>'.__('Task name').':</b>',
@@ -783,6 +827,54 @@ class HostDevices extends Wizard
                             ],
                         ],
                         '2' => [
+                            'label'     => '<b>'.__('Use CSV file definition').':</b>'.ui_print_help_tip(
+                                __('Define targets using csv o network definition.'),
+                                true
+                            ),
+                            'class'     => 'no-margin',
+                            'arguments' => [
+                                'name'    => 'network_csv_enabled',
+                                'value'   => $this->task['subnet_csv'],
+                                'type'    => 'switch',
+                                'inline'  => true,
+                                'class'   => 'discovery_full_width_input',
+                                'onclick' => 'toggleNetwork(this);',
+                            ],
+                        ],
+                        '3' => [
+                            'hidden'        => (($this->task['subnet_csv'] == '1') ? 0 : 1),
+                            'block_id'      => 'csv_subnet',
+                            'block_content' => [
+                                [
+                                    'label'     => '<b>'.__('Networks (csv)').':</b>'.ui_print_help_tip(
+                                        __('You can upload a CSV file. Each line must contain a network in IP/MASK format. For instance: 192.168.1.1/32'),
+                                        true
+                                    ),
+                                    'arguments' => [
+                                        'name'    => 'network_csv',
+                                        'type'    => 'file',
+                                        'columns' => 25,
+                                        'rows'    => 10,
+                                        'class'   => 'discovery_full_width_input',
+                                    ],
+                                ],
+                                [
+                                    'label'     => '<b>'.__('Networks (current)').':</b>'.ui_print_help_tip(
+                                        __('Plese upload a new file to overwrite this content.'),
+                                        true
+                                    ),
+                                    'arguments' => [
+                                        'attributes' => 'readonly',
+                                        'type'       => 'textarea',
+                                        'size'       => 25,
+                                        'value'      => $this->task['subnet'],
+                                    ],
+                                ],
+                            ],
+                        ],
+                        '4' => [
+                            'hidden'    => (($this->task['subnet_csv'] == '1') ? 1 : 0),
+                            'id'        => 'std_subnet',
                             'label'     => '<b>'.__('Network').':</b>'.ui_print_help_tip(
                                 __('You can specify several networks, separated by commas, for example: 192.168.50.0/24,192.168.60.0/24'),
                                 true
@@ -817,6 +909,7 @@ class HostDevices extends Wizard
 
                 $form['rows'][0]['columns'][2] = [
                     'width'  => '30%',
+                    'style'  => 'min-width: 250px',
                     'inputs' => ['0' => $group_select],
                 ];
 
@@ -846,8 +939,9 @@ class HostDevices extends Wizard
                 }
 
                 $form['form'] = [
-                    'method' => 'POST',
-                    'action' => $this->url.'&mode=netscan&page='.($this->page + 1).$task_url,
+                    'method'  => 'POST',
+                    'enctype' => 'multipart/form-data',
+                    'action'  => $this->url.'&mode=netscan&page='.($this->page + 1).$task_url,
                 ];
 
                 // Default.
@@ -871,7 +965,19 @@ class HostDevices extends Wizard
                             $("#hidden-interval").val('.$interval.');
                             $("#interval_units").val('.$unit.');
                         }
-                    }).change();';
+                    }).change();
+                    
+                    function toggleNetwork(e) {
+                        if (e.checked) {
+                            $(\'#csv_subnet\').removeClass("hidden");
+                            $(\'#std_subnet\').addClass("hidden");
+                        } else {
+                            $(\'#csv_subnet\').addClass("hidden");
+                            $(\'#std_subnet\').removeClass("hidden");
+                        }
+                    };
+                    
+                    ';
 
                 $this->printFormAsGrid($form);
                 $this->printGoBackButton($this->url.'&page='.($this->page - 1));
diff --git a/pandora_console/godmode/wizards/Wizard.main.php b/pandora_console/godmode/wizards/Wizard.main.php
index 13da3c269d..7320934826 100644
--- a/pandora_console/godmode/wizards/Wizard.main.php
+++ b/pandora_console/godmode/wizards/Wizard.main.php
@@ -587,66 +587,40 @@ class Wizard
 
         if (is_array($input['block_content']) === true) {
             // Print independent block of inputs.
-            $output .= '<li id="'.$input['block_id'].'" class="'.$class.'">';
+            $output .= '<div id="'.$input['block_id'].'" class="wizard '.$class.'">';
             $output .= '<ul class="wizard '.$input['block_class'].'">';
             foreach ($input['block_content'] as $input) {
                 $output .= $this->printBlockAsGrid($input, $return);
             }
 
-            $output .= '</ul></li>';
+            $output .= '</ul></div>';
         } else {
             if ($input['arguments']['type'] != 'hidden'
                 && $input['arguments']['type'] != 'hidden_extended'
             ) {
-                if ($input['arguments']['inline'] != 'true') {
-                    $output .= '<div class="edit_discovery_input">';
-                } else {
-                    $output .= '<div style="display: flex; margin-bottom: 25px; flex-wrap: wrap;">';
-                    if (!isset($input['extra'])) {
-                        $output .= '<div style="width: 50%;">';
-                    }
-
-                    if (isset($input['extra'])) {
-                        $output .= '<div style="display: flex; margin-right:10px;">';
-                    }
+                $id = '';
+                if ($input['id']) {
+                    $id = $input['id'];
                 }
 
-                if ($input['arguments']['inline'] == 'true' && isset($input['extra'])) {
-                    $output .= '<div style="margin-right:10px;">';
+                if ($input['arguments']['inline'] != 'true') {
+                    $output .= '<div id="'.$id.'" class="std_input '.$class.'">';
+                } else {
+                    $output .= '<div id="'.$id.'" class="inline_input '.$class.'">';
                 }
 
                 $output .= '<div class="label_select">';
                 $output .= $input['label'];
                 $output .= '</div>';
 
-                if ($input['arguments']['inline'] == 'true' && isset($input['extra'])) {
-                    $output .= '</div>';
-                }
-
-                if ($input['arguments']['inline'] == 'true' && !isset($input['extra'])) {
-                    $output .= '</div>';
-                }
-
                 if ($input['arguments']['type'] == 'text' || $input['arguments']['type'] == 'text_extended') {
                     $output .= '<div class="discovery_text_input">';
                     $output .= $this->printInput($input['arguments']);
                     $output .= '</div>';
                 } else if ($input['arguments']['inline'] == 'true') {
-                    if (isset($input['extra'])) {
-                        $output .= '<div style="">';
-                        $output .= '<div style="float: left;">';
-                    } else {
-                        $output .= '<div style="width:50%;">';
-                        $output .= '<div style="float: right;">';
-                    }
-
+                    $output .= '<div class="discovery_inline_input">';
                     $output .= $this->printInput($input['arguments']);
                     $output .= '</div>';
-                    $output .= '</div>';
-
-                    if (isset($input['extra'])) {
-                        $output .= '</div>';
-                    }
                 } else {
                     $output .= $this->printInput($input['arguments']);
                 }
@@ -821,7 +795,7 @@ class Wizard
         $cb_function = $data['cb_function'];
         $cb_args = $data['cb_args'];
 
-        $output_head = '<form class="discovery" onsubmit="'.$form['onsubmit'].'"  enctype="'.$form['enctype'].'" action="'.$form['action'].'" method="'.$form['method'];
+        $output_head = '<form class="discovery wizard" onsubmit="'.$form['onsubmit'].'"  enctype="'.$form['enctype'].'" action="'.$form['action'].'" method="'.$form['method'];
         $output_head .= '" '.$form['extra'].'>';
 
         if ($return === false) {
diff --git a/pandora_console/include/functions_html.php b/pandora_console/include/functions_html.php
index 237d7457f9..f578cc9ed2 100644
--- a/pandora_console/include/functions_html.php
+++ b/pandora_console/include/functions_html.php
@@ -1087,7 +1087,7 @@ function html_print_extended_select_for_time(
 
     ob_start();
     // Use the no_meta parameter because this image is only in the base console
-    echo '<div id="'.$uniq_name.'_default" style="width:100%;display:inline;">';
+    echo '<div id="'.$uniq_name.'_default" style="width:100%;display:flex;align-items: baseline;">';
         html_print_select(
             $fields,
             $uniq_name.'_select',
@@ -1121,7 +1121,7 @@ function html_print_extended_select_for_time(
 
     echo '</div>';
 
-    echo '<div id="'.$uniq_name.'_manual" style="width:100%;display:inline;">';
+    echo '<div id="'.$uniq_name.'_manual" style="width:100%;display:flex;">';
         html_print_input_text($uniq_name.'_text', $selected, '', $size, 255, false, $readonly, false, '', $class);
 
         html_print_input_hidden($name, $selected, false, $uniq_name);
@@ -1159,8 +1159,8 @@ function html_print_extended_select_for_time(
 			$('#text-".$uniq_name."_text').val(seconds);
 			adjustTextUnits('".$uniq_name."');
 			calculateSeconds('".$uniq_name."');
-			$('#".$uniq_name."_manual').show();
-			$('#".$uniq_name."_default').hide();
+			$('#".$uniq_name."_manual').css('display', 'flex');
+			$('#".$uniq_name."_default').css('display', 'none');
 		}
 	</script>";
     $returnString = ob_get_clean();
diff --git a/pandora_console/include/javascript/pandora.js b/pandora_console/include/javascript/pandora.js
index 9a9c8bcba0..c91339f0c6 100644
--- a/pandora_console/include/javascript/pandora.js
+++ b/pandora_console/include/javascript/pandora.js
@@ -837,8 +837,8 @@ function post_process_select_events(name) {
  */
 function period_select_init(name, allow_zero) {
   // Manual mode is hidden by default
-  $("#" + name + "_manual").hide();
-  $("#" + name + "_default").show();
+  $("#" + name + "_manual").css("display", "none");
+  $("#" + name + "_default").css("display", "flex");
 
   // If the text input is empty, we put on it 5 minutes by default
   if ($("#text-" + name + "_text").val() == "") {
@@ -852,8 +852,8 @@ function period_select_init(name, allow_zero) {
     }
   } else if ($("#text-" + name + "_text").val() == 0 && allow_zero != true) {
     $("#" + name + "_units option:last").prop("selected", false);
-    $("#" + name + "_manual").show();
-    $("#" + name + "_default").hide();
+    $("#" + name + "_manual").css("display", "flex");
+    $("#" + name + "_default").css("display", "none");
   }
 }
 
@@ -941,13 +941,13 @@ function selectFirst(name) {
  */
 function toggleBoth(name) {
   if ($("#" + name + "_default").css("display") == "none") {
-    $("#" + name + "_default").css("display", "inline");
+    $("#" + name + "_default").css("display", "flex");
   } else {
     $("#" + name + "_default").css("display", "none");
   }
 
   if ($("#" + name + "_manual").css("display") == "none") {
-    $("#" + name + "_manual").css("display", "inline");
+    $("#" + name + "_manual").css("display", "flex");
   } else {
     $("#" + name + "_manual").css("display", "none");
   }
diff --git a/pandora_console/include/styles/wizard.css b/pandora_console/include/styles/wizard.css
index 366c60c1ae..572c3496bf 100644
--- a/pandora_console/include/styles/wizard.css
+++ b/pandora_console/include/styles/wizard.css
@@ -2,7 +2,11 @@
  * Discovery > Wizard css global style
  */
 
+#main > form.discovery.wizard > .white_box {
+  min-width: 1024px;
+}
 ul.wizard {
+  list-style-type: none;
 }
 
 ul.wizard li {
@@ -24,13 +28,50 @@ ul.wizard li > textarea {
 }
 
 .wizard .hidden {
-  display: none;
+  display: none !important;
 }
 
 .wizard .indented {
   margin-left: 2em;
 }
 
+.wizard .std_input {
+  display: flex;
+  margin-bottom: 25px;
+  flex-wrap: wrap;
+  justify-content: space-between;
+}
+
+.wizard .std_input > .label_select {
+  flex: 1 1 100%;
+}
+.wizard .std_input > * {
+  flex: 1 1 auto;
+  align-self: baseline;
+}
+
+.wizard .inline_input.no-margin {
+  margin-bottom: 0px;
+}
+.wizard .inline_input {
+  display: flex;
+  margin-bottom: 25px;
+  flex-wrap: wrap;
+  justify-content: space-between;
+  align-items: baseline;
+}
+
+.wizard .inline_input * {
+  flex: 1 1 auto;
+}
+
+.wizard .discovery_inline_input {
+  display: flex;
+  align-content: end;
+  flex: 0;
+  align-self: flex-start;
+}
+
 /* override tag-editor styles */
 .wizard .tag-editor.ui-sortable {
   width: 450px;
@@ -57,3 +98,15 @@ ul.wizard li > textarea {
   padding: 5px;
   background: #e63c52;
 }
+
+.wizard .time_selection_container {
+  display: flex;
+  align-items: baseline;
+  justify-items: center;
+  align-content: space-between;
+  margin-top: 1em;
+}
+
+.wizard #interval_manual_container #interval_manual > * {
+  flex: 1 1 auto;
+}
diff --git a/pandora_console/pandoradb.sql b/pandora_console/pandoradb.sql
index fa8f8d3043..7d91216d11 100644
--- a/pandora_console/pandoradb.sql
+++ b/pandora_console/pandoradb.sql
@@ -810,6 +810,7 @@ CREATE TABLE IF NOT EXISTS `trecon_task` (
 	`autoconfiguration_enabled` tinyint(1) unsigned default 0,
 	`summary` text,
 	`type` int NOT NULL default 0,
+	`subnet_csv` TINYINT(1) UNSIGNED DEFAULT 0,
 	PRIMARY KEY  (`id_rt`),
 	KEY `recon_task_daemon` (`id_recon_server`)
 ) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
diff --git a/pandora_server/lib/PandoraFMS/Core.pm b/pandora_server/lib/PandoraFMS/Core.pm
index b387de5283..6cf2204ff3 100644
--- a/pandora_server/lib/PandoraFMS/Core.pm
+++ b/pandora_server/lib/PandoraFMS/Core.pm
@@ -6275,9 +6275,6 @@ sub notification_get_users {
 		',
 		safe_input($source)
 	);
-
-	@results = map { $_->{'id_user'} } @results;
-	return @results;
 }
 
 ##########################################################################
@@ -6299,9 +6296,6 @@ sub notification_get_groups {
 		',
 		safe_input($source)
 	);
-
-	@results = map { $_->{'id_group'} } @results;
-	return @results;
 }