diff --git a/pandora_console/extras/mr/37.sql b/pandora_console/extras/mr/37.sql index cc35df6ab0..a3aef948b8 100644 --- a/pandora_console/extras/mr/37.sql +++ b/pandora_console/extras/mr/37.sql @@ -36,11 +36,11 @@ CREATE TABLE `tdiscovery_tmp_connections` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `tpen` ( - `id_np` int(10) unsigned NOT NULL, `pen` int(10) unsigned NOT NULL, - `manufacturer` TEXT NOT NULL, - `description` TEXT NULL, - PRIMARY KEY (`id_np`,`pen`), + `manufacturer` TEXT, + `description` TEXT, + `id_np` int(10) unsigned, + PRIMARY KEY (`pen`), CONSTRAINT `fk_np_id` FOREIGN KEY (`id_np`) REFERENCES `tnetwork_profile` (`id_np`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 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 86eecd0ae7..4de9b6a1f3 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 @@ -1480,11 +1480,11 @@ ALTER TABLE `tnetwork_component` MODIFY COLUMN `ff_type` tinyint(1) unsigned NUL -- Table `tpen` -- ---------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS `tpen` ( - `id_np` int(10) unsigned NOT NULL, `pen` int(10) unsigned NOT NULL, - `manufacturer` TEXT NOT NULL, - `description` TEXT NULL, - PRIMARY KEY (`id_np`,`pen`), + `manufacturer` TEXT, + `description` TEXT, + `id_np` int(10) unsigned, + PRIMARY KEY (`pen`), CONSTRAINT `fk_np_id` FOREIGN KEY (`id_np`) REFERENCES `tnetwork_profile` (`id_np`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/pandora_console/godmode/modules/private_enterprise_numbers.php b/pandora_console/godmode/modules/private_enterprise_numbers.php index 286142628a..ca6add6640 100644 --- a/pandora_console/godmode/modules/private_enterprise_numbers.php +++ b/pandora_console/godmode/modules/private_enterprise_numbers.php @@ -1,127 +1,68 @@ run(); -} catch (Exception $ex) { - ui_print_error_message(__('Something went wrong. Please, take a look in the Pandora FMS log')); - echo '[PEN Configuration]'.$ex->getMessage(); + // User access and validation is being processed on class constructor. + $obj = new ConfigPEN($ajaxPage); +} catch (Exception $e) { + if (is_ajax()) { + echo json_encode(['error' => '[ConfigPEN]'.$e->getMessage() ]); + exit; + } else { + echo '[ConfigPEN]'.$e->getMessage(); + } + + // Stop this execution, but continue 'globally'. + return; } -?> - + // Stop any execution. + exit; +} else { + // Run. + $obj->run(); +} diff --git a/pandora_console/include/class/ConfigPEN.class.php b/pandora_console/include/class/ConfigPEN.class.php index c254a0fe60..4a051d170c 100644 --- a/pandora_console/include/class/ConfigPEN.class.php +++ b/pandora_console/include/class/ConfigPEN.class.php @@ -35,6 +35,13 @@ require_once $config['homedir'].'/include/class/HTML.class.php'; class ConfigPEN extends HTML { + /** + * Url of controller. + * + * @var string + */ + public $ajaxController; + /** * URL Base * @@ -44,9 +51,11 @@ class ConfigPEN extends HTML /** - * Constructor + * Contructor. + * + * @param string $ajax_page Target ajax page. */ - public function __construct() + public function __construct($ajax_page) { global $config; @@ -63,8 +72,228 @@ class ConfigPEN extends HTML exit; } + $this->ajaxController = $ajax_page; $this->offset = ''; - $this->baseUrl = 'index.php?sec=configuration_wizard_setup&sec2=godmode/modules/private_enterprise_numbers'; + $this->baseUrl = ui_get_full_url( + 'index.php?sec=configuration_wizard_setup&sec2=godmode/modules/private_enterprise_numbers' + ); + + } + + + /** + * Returns an array with all the credentials matching filter and ACL. + * + * @param array $fields Fields array or 'count' keyword to retrieve count. + * @param array $filter Filters to be applied. + * @param integer $offset Offset (pagination). + * @param integer $limit Limit (pagination). + * @param string $order Sort order. + * @param string $sort_field Sort field. + * + * @return array With all results or false if error. + * @throws Exception On error. + */ + public static function getAll( + $fields, + $filter=null, + $offset=null, + $limit=null, + $order=null, + $sort_field=null + ) { + $sql_filters = []; + $order_by = ''; + $pagination = ''; + + $count = false; + if (!is_array($fields) && $fields == 'count') { + $fields = ['*']; + $count = true; + } else if (!is_array($fields)) { + error_log('[configPEN.getAll] Fields must be an array or "count".'); + throw new Exception('[configPEN.getAll] Fields must be an array or "count".'); + } + + if (is_array($filter)) { + if (!empty($filter['free_search'])) { + $sql_filters[] = vsprintf( + ' AND (lower(`manufacturer`) like lower("%%%s%%") + OR pen = "%s") ', + array_fill(0, 2, $filter['free_search']) + ); + } + + if (!empty($filter['pen'])) { + $sql_filters[] = sprintf( + ' AND `pen` = %d', + $filter['pen'] + ); + } + } + + if (isset($order)) { + $dir = 'asc'; + if ($order == 'desc') { + $dir = 'desc'; + }; + + if (in_array( + $sort_field, + [ + 'pen', + 'manufacturer', + 'description', + ] + ) + ) { + $order_by = sprintf( + 'ORDER BY `%s` %s', + $sort_field, + $dir + ); + } + } + + if (isset($limit) && $limit > 0 + && isset($offset) && $offset >= 0 + ) { + $pagination = sprintf( + ' LIMIT %d OFFSET %d ', + $limit, + $offset + ); + } + + $sql = sprintf( + 'SELECT %s + FROM `tpen` + WHERE 1=1 + %s + %s + %s', + join(',', $fields), + join(' ', $sql_filters), + $order_by, + $pagination + ); + + if ($count) { + $sql = sprintf('SELECT count(*) as n FROM ( %s ) tt', $sql); + + return db_get_value_sql($sql); + } + + return db_get_all_rows_sql($sql); + } + + + /** + * AJAX: Return JSON content for datatable. + * + * @return void + */ + function draw() + { + global $config; + + // Datatables offset, limit and order. + $filter = get_parameter('filter', []); + $start = get_parameter('start', 0); + $length = get_parameter('length', $config['block_size']); + $order = get_datatable_order(true); + try { + ob_start(); + + $fields = ['*']; + + // Retrieve data. + $data = $this->getAll( + // Fields. + $fields, + // Filter. + $filter, + // Offset. + $start, + // Limit. + $length, + // Order. + $order['direction'], + // Sort field. + $order['field'] + ); + + // Retrieve counter. + $count = $this->getAll( + 'count', + $filter + ); + + if ($data) { + $data = array_reduce( + $data, + function ($carry, $item) { + // Transforms array of arrays $data into an array + // of objects, making a post-process of certain fields. + $tmp = (object) $item; + + $tmp->description = io_safe_output($tmp->description); + $tmp->manufacturer = io_safe_output($tmp->manufacturer); + + $tmp->options = ''; + + $tmp->options = ''; + $tmp->options .= html_print_image( + 'images/eye.png', + true, + ['title' => __('Show')] + ); + $tmp->options .= ''; + $tmp->options .= ''; + $tmp->options .= html_print_image( + 'images/cross.png', + true, + ['title' => __('Delete')] + ); + $tmp->options .= ''; + + $carry[] = $tmp; + return $carry; + } + ); + } + + // Datatables format: RecordsTotal && recordsfiltered. + 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; } @@ -79,6 +308,7 @@ class ConfigPEN extends HTML // Require specific CSS and JS. ui_require_css_file('wizard'); ui_require_css_file('discovery'); + ui_require_css_file('pen'); // Header section. // Breadcrums. @@ -120,6 +350,12 @@ class ConfigPEN extends HTML ui_get_full_url('ajax.php', false, false, false) ); + // Ajax page (hidden). + html_print_input_hidden( + 'ajax_page', + $this->ajaxController + ); + // Allow message area. html_print_div(['id' => 'message_show_area']); // Prints the main table. @@ -132,6 +368,175 @@ class ConfigPEN extends HTML } + /** + * Load modal information for PEN management. + * + * Ajax. Direct HTML. + * + * @return void + */ + public function loadModal() + { + $values = []; + $id = (int) get_parameter('pen', 0); + if ($id > 0) { + $values = $this->getAll( + // Fields. + ['*'], + // Filter. + ['pen' => $id] + ); + if (is_array($values)) { + $values = $values[0]; + } + } + + $form = [ + 'action' => '#', + 'id' => 'modal_form', + 'onsubmit' => 'return false;', + 'class' => '', + ]; + + $inputs = []; + + $inputs[] = [ + 'label' => __('PEN'), + 'class' => 'flex-row', + 'id' => 'div-pen', + 'arguments' => [ + 'name' => 'pen', + 'type' => 'number', + 'value' => $values['pen'], + 'required' => true, + 'return' => true, + 'size' => 50, + ], + ]; + + $inputs[] = [ + 'label' => __('Manufacturer'), + 'class' => 'flex-row', + 'arguments' => [ + 'name' => 'manufacturer', + 'id' => 'manufacturer', + 'type' => 'text', + 'required' => true, + 'value' => io_safe_output($values['manufacturer']), + 'return' => true, + ], + ]; + + $inputs[] = [ + 'label' => __('Description'), + 'class' => 'flex-row', + 'arguments' => [ + 'name' => 'description', + 'id' => 'description', + 'type' => 'textarea', + 'value' => io_safe_output($values['description']), + 'return' => true, + 'rows' => 50, + 'columns' => 30, + ], + ]; + + echo '
'; + echo parent::printForm( + [ + 'form' => $form, + 'inputs' => $inputs, + ], + true + ); + echo '
'; + } + + + /** + * Delete a manufacturer register from db. + * + * @return void + */ + public function delete() + { + $pen = get_parameter('pen', 0); + + if (empty($pen)) { + echo json_encode(['error' => __('PEN is required')]); + } else { + if (db_process_sql_delete('tpen', ['pen' => $pen]) !== false) { + echo json_encode(['result' => __('Successfully deleted')]); + } else { + global $config; + echo json_encode(['error' => $config['dbconnection']->error]); + } + } + + } + + + /** + * Add a manufacturer to private enterprise numbers. + * + * @return void + */ + public function add() + { + $pen = get_parameter('pen', 0); + $manufacturer = get_parameter('manufacturer', ''); + $description = get_parameter('description', ''); + + if (empty($pen)) { + $error = __('PEN is required.'); + } + + if (empty($manufacturer)) { + $error = __('Manufacturer is required'); + } + + if (!empty($error)) { + echo json_encode( + ['error' => $error] + ); + } + + // Add if not exists. + $current = $this->getAll(['pen'], ['pen' => $pen]); + + if ($current === false) { + // New. + $rs = db_process_sql_insert( + 'tpen', + [ + 'pen' => $pen, + 'manufacturer' => io_safe_input($manufacturer), + 'description' => io_safe_input($description), + ] + ); + $str = __('created'); + } else { + // Update. + $rs = db_process_sql_update( + 'tpen', + [ + 'manufacturer' => io_safe_input($manufacturer), + 'description' => io_safe_input($description), + ], + ['pen' => $pen] + ); + $str = __('updated'); + } + + if ($rs === false) { + global $config; + echo json_encode(['error' => $config['dbconnection']->error]); + } else { + echo json_encode(['result' => __('Succesfully %s', $str)]); + } + } + + /** * Create the main table with the PENs info * @@ -140,110 +545,217 @@ class ConfigPEN extends HTML public function createMainTable() { global $config; - // Get the count of PENs. - $countPENs = db_get_value( - 'count(*)', - 'tpen' - ); - // Get all the data. - $resultPENs = db_get_all_rows_filter( - 'tpen', - [ - 'order' => 'id_np', - 'limit' => $config['block_size'], - ] - ); + $output = ''; - $output = ui_pagination($countPENs, false, $this->offset, 0, true); - // Create the table with Module Block list. - $table = new StdClasS(); - $table->class = 'databox data'; - $table->width = '75%'; - $table->styleTable = 'margin: 2em auto 0;border: 1px solid #ddd;background: white;'; - $table->rowid = []; - $table->data = []; + // Datatables list. + try { + $columns = [ + 'pen', + 'manufacturer', + 'description', + 'options', + ]; - $table->cellpadding = 0; - $table->cellspacing = 0; - $table->width = '100%'; - $table->class = 'info_table'; - - $table->head = []; - $table->head[0] = html_print_checkbox('all_delete', 0, false, true, false); - $table->head[1] = __('PEN'); - $table->head[2] = __('Manufacturer ID'); - $table->head[3] = __('Description'); - $table->head[4] = ''.__('Action').''; - - $table->size = []; - $table->size[0] = '20px'; - $table->size[1] = '10%'; - $table->size[2] = '25%'; - $table->size[4] = '70px'; - - $table->align = []; - $table->align[3] = 'left'; - - $table->data = []; - - foreach ($resultPENs as $row) { - $data = []; - $data[0] = html_print_checkbox_extended('delete_multiple[]', $row['pen'], false, false, '', 'class="check_delete"', true); - $data[1] = ''.$row['pen'].''; - $data[2] = ''.$row['manufacturer'].''; - $data[3] = ''.ui_print_truncate_text(io_safe_output($row['description']), 'description', true, true, true, '[…]').''; - $table->cellclass[][4] = 'action_buttons'; - $data[4] = html_print_input_image( - 'edit_pen_', - 'images/edit.png', - $row['pen'], - 'max-width: 27px;', - true, + $column_names = [ + __('PEN'), + __('Manufacturer'), + __('Description'), [ - 'title' => 'Edit', - 'onclick' => 'modifyPENLine(event)', + 'text' => __('Options'), + 'class' => 'action_buttons', + ], + ]; + + $this->tableId = 'keystore'; + // Load datatables user interface. + $output .= ui_print_datatable( + [ + 'id' => $this->tableId, + 'return' => true, + 'class' => 'info_table', + 'style' => 'width: 100%', + 'columns' => $columns, + 'column_names' => $column_names, + 'ajax_url' => $this->ajaxController, + 'ajax_data' => ['method' => 'draw'], + 'no_sortable_columns' => [-1], + 'order' => [ + 'field' => 'pen', + 'direction' => 'asc', + ], + 'search_button_class' => 'sub filter float-right', + 'form' => [ + 'inputs' => [ + [ + 'label' => __('Free search'), + 'type' => 'text', + 'class' => 'mw250px', + 'id' => 'free_search', + 'name' => 'free_search', + ], + ], + ], ] ); - $data[4] .= html_print_input_image( - 'delete_pen_', - 'images/cross.png', - $row['pen'], - '', - true, - [ - 'title' => 'Delete PEN', - 'onclick' => 'if (confirm(\''.sprintf(__('Are you sure to remove the PEN: %s?'), $row['pen']).'\')) deletePEN(event);', - ] - ); - - array_push($table->data, $data); + } catch (Exception $e) { + echo $e->getMessage(); } - // Last line for adding new PENs. - $data = []; - $data[0] = ''; - $data[1] = html_print_input_text('pen_number', '', '', 10, 255, true); - $data[2] = html_print_input_text('pen_manufacturer', '', '', 30, 255, true); - $data[3] = html_print_input_text('pen_description', '', '', 80, 255, true); - $table->cellclass[][4] = 'action_buttons'; - $data[4] = html_print_input_image( - 'add_new_pen', - 'images/add_mc.png', - '', - 'margin: 0 auto; display: block;', - true, + // Auxiliar div. + $output .= ''; + $output .= ''; + $output .= ''; + + // Create button. + $output .= parent::printInput( [ - 'title' => 'Add new PEN', - 'onclick' => 'addNewPEN()', + 'type' => 'submit', + 'name' => 'create', + 'label' => __('Register manufacturer'), + 'attributes' => 'class="sub next"', + 'return' => true, ] ); - // Add last line. - array_push($table->data, $data); - // Return the entire table. - $output .= html_print_table($table, true); - // $output = 'mis huevos morenos'; + ob_start(); + ?> + + label:not(.p-switch) { + width: auto; +} + +form.top-action-buttons ul.wizard { + display: flex; + flex-direction: row; +} + +ul.wizard li { + margin-right: 1em; +} + +form.modal ul.wizard li { + display: flex; + flex-direction: row; + width: 90%; + margin: 0 auto; + justify-items: center; +} + +form.modal ul.wizard li * { + flex: 1; +} + +ul.wizard li.flex-indep { + flex: 1; + margin: 0; +} + +div#div-form { + padding: 0 2em; +} + +div#div-form textarea { + width: 100%; + margin-top: 1em; +} diff --git a/pandora_console/pandoradb.sql b/pandora_console/pandoradb.sql index e0b064e0f2..1c88e65d43 100644 --- a/pandora_console/pandoradb.sql +++ b/pandora_console/pandoradb.sql @@ -944,16 +944,6 @@ CREATE TABLE IF NOT EXISTS `tnetwork_profile` ( PRIMARY KEY (`id_np`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; --- ---------------------------------------------------------------------- --- Table `tpen` --- ---------------------------------------------------------------------- -CREATE TABLE `tpen` ( - `id_np` int(10) unsigned NOT NULL, - `pen` int(10) unsigned NOT NULL, - PRIMARY KEY (`id_np`,`pen`), - CONSTRAINT `fk_np_id` FOREIGN KEY (`id_np`) REFERENCES `tnetwork_profile` (`id_np`) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -- ---------------------------------------------------------------------- -- Table `tnetwork_profile_component` -- ---------------------------------------------------------------------- @@ -967,11 +957,11 @@ CREATE TABLE IF NOT EXISTS `tnetwork_profile_component` ( -- Table `tpen` -- ---------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS `tpen` ( - `id_np` int(10) unsigned NOT NULL, `pen` int(10) unsigned NOT NULL, - `manufacturer` TEXT NOT NULL, - `description` TEXT NULL, - PRIMARY KEY (`id_np`,`pen`), + `manufacturer` TEXT, + `description` TEXT, + `id_np` int(10) unsigned, + PRIMARY KEY (`pen`), CONSTRAINT `fk_np_id` FOREIGN KEY (`id_np`) REFERENCES `tnetwork_profile` (`id_np`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8;