diff --git a/pandora_console/api/v2/config/container.php b/pandora_console/api/v2/config/container.php index 4a267619fc..c2c3107b8a 100644 --- a/pandora_console/api/v2/config/container.php +++ b/pandora_console/api/v2/config/container.php @@ -6,6 +6,8 @@ use PandoraFMS\Modules\Events\Repositories\EventRepository; use PandoraFMS\Modules\Events\Repositories\EventRepositoryMySQL; use PandoraFMS\Modules\Groups\Repositories\GroupRepository; use PandoraFMS\Modules\Groups\Repositories\GroupRepositoryMySQL; +use PandoraFMS\Modules\PandoraITSM\Inventories\Repositories\PandoraITSMInventoryRepository; +use PandoraFMS\Modules\PandoraITSM\Inventories\Repositories\PandoraITSMInventoryRepositoryMySQL; use PandoraFMS\Modules\Shared\Repositories\Repository; use PandoraFMS\Modules\Shared\Repositories\RepositoryMySQL; use PandoraFMS\Modules\Users\Repositories\UserRepository; @@ -15,10 +17,10 @@ use Slim\App; use Slim\Factory\AppFactory; return [ - 'settings' => function () { + 'settings' => function () { return include __DIR__.'/settings.php'; }, - App::class => function (ContainerInterface $container) { + App::class => function (ContainerInterface $container) { AppFactory::setContainer($container); $app = AppFactory::create(); @@ -39,19 +41,22 @@ return [ return $app; }, - Repository::class => function (ContainerInterface $container) { + Repository::class => function (ContainerInterface $container) { return $container->get(RepositoryMySQL::class); }, - TokenRepository::class => function (ContainerInterface $container) { + TokenRepository::class => function (ContainerInterface $container) { return $container->get(TokenRepositoryMySQL::class); }, - UserRepository::class => function (ContainerInterface $container) { + UserRepository::class => function (ContainerInterface $container) { return $container->get(UserRepositoryMySQL::class); }, - GroupRepository::class => function (ContainerInterface $container) { + GroupRepository::class => function (ContainerInterface $container) { return $container->get(GroupRepositoryMySQL::class); }, - EventRepository::class => function (ContainerInterface $container) { + EventRepository::class => function (ContainerInterface $container) { return $container->get(EventRepositoryMySQL::class); }, + PandoraITSMInventoryRepository::class => function (ContainerInterface $container) { + return $container->get(PandoraITSMInventoryRepositoryMySQL::class); + }, ]; diff --git a/pandora_console/api/v2/config/routes.php b/pandora_console/api/v2/config/routes.php index c36454d725..3ef7a03f15 100644 --- a/pandora_console/api/v2/config/routes.php +++ b/pandora_console/api/v2/config/routes.php @@ -9,4 +9,5 @@ return function (App $app) { (include __DIR__.'/../../../include/lib/Modules/Profiles/routes.php')($app); (include __DIR__.'/../../../include/lib/Modules/Tags/routes.php')($app); (include __DIR__.'/../../../include/lib/Modules/Users/routes.php')($app); + (include __DIR__.'/../../../include/lib/Modules/PandoraITSM/routes.php')($app); }; diff --git a/pandora_console/api/v2/public/swagger.json b/pandora_console/api/v2/public/swagger.json index a7a514bedb..c432271fef 100644 --- a/pandora_console/api/v2/public/swagger.json +++ b/pandora_console/api/v2/public/swagger.json @@ -1118,6 +1118,110 @@ ] } }, + "/pandoraITSM/inventory/{idPandoraITSMInventory}": { + "get": { + "tags": ["PandoraITSM"], + "summary": "Show pandoraITSMInventory", + "operationId": "09b6d1f91536441fc65dc66142a6f9cb", + "parameters": [ + { + "$ref": "#/components/parameters/parameterIdPandoraITSMInventory" + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/ResponsePandoraITSMInventory" + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "500": { + "$ref": "#/components/responses/InternalServerError" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/pandoraITSM/inventory/list": { + "post": { + "tags": ["PandoraITSM"], + "summary": "List pandoraITSMInventories", + "operationId": "149f20397779ed681c1f7680c1214974", + "parameters": [ + { + "$ref": "#/components/parameters/parameterPage" + }, + { + "$ref": "#/components/parameters/parameterSizePage" + }, + { + "$ref": "#/components/parameters/parameterSortField" + }, + { + "$ref": "#/components/parameters/parameterSortDirection" + } + ], + "requestBody": { + "$ref": "#/components/requestBodies/requestBodyPandoraITSMInventoryFilter" + }, + "responses": { + "200": { + "description": "List PandoraITSM Inventories Object", + "content": { + "application/json": { + "schema": { + "properties": { + "paginationData": { + "$ref": "#/components/schemas/paginationData" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PandoraITSMInventory" + } + } + }, + "type": "object" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "500": { + "$ref": "#/components/responses/InternalServerError" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, "/profile": { "post": { "tags": ["Profiles"], @@ -2081,6 +2185,192 @@ } ] }, + "Event": { + "properties": { + "idEvent": { + "description": "Id event", + "type": "integer", + "readOnly": true, + "nullable": false + }, + "idAgent": { + "description": "Id agent", + "type": "integer", + "default": null, + "nullable": true + }, + "idUser": { + "description": "Id user", + "type": "string", + "default": null, + "nullable": true + }, + "idGroup": { + "description": "Id group", + "type": "integer", + "default": null, + "nullable": true + }, + "status": { + "description": "Event status, the available status are: new, validated, inprocess", + "type": "integer", + "default": "new", + "enum": ["new", "validated", "inprocess"], + "nullable": false + }, + "timestamp": { + "description": "Event registration date", + "type": "string", + "default": null, + "readOnly": true, + "example": "2023-02-21 08:34:16", + "nullable": true + }, + "event": { + "description": "Description event", + "type": "string", + "default": "Event created for api", + "nullable": false + }, + "utimestamp": { + "description": "Event registration date", + "type": "integer", + "default": null, + "readOnly": true, + "example": "1704898868", + "nullable": true + }, + "eventType": { + "description": "Event status, the available status are: going_unknown, unknown, alert_fired, alert_recovered, alert_ceased, alert_manual_validation, recon_host_detected, system, error, new_agent, going_up_critical, going_down_critical, going_up_warning, going_down_warning, going_up_normal, going_down_normal, configuration_change, ncm", + "type": "string", + "default": "unknown", + "enum": [ + "going_unknown", + "unknown", + "alert_fired", + "alert_recovered", + "alert_ceased", + "alert_manual_validation", + "recon_host_detected", + "system", + "error", + "new_agent", + "going_up_critical", + "going_down_critical", + "going_up_warning", + "going_down_warning", + "going_up_normal", + "going_down_normal", + "configuration_change", + "ncm" + ], + "nullable": false + }, + "idAgentModule": { + "description": "Id agent module", + "type": "integer", + "default": null, + "nullable": true + }, + "idAlertAm": { + "description": "Id alert action", + "type": "integer", + "default": null, + "nullable": true + }, + "severity": { + "description": "Event severity, the available severity are: maintenance, informational, normal, warning, critical, minor, major", + "type": "integer", + "default": "maintenance", + "enum": [ + "maintenance", + "informational", + "normal", + "warning", + "critical", + "minor", + "major" + ], + "nullable": false + }, + "tags": { + "description": "Tags", + "type": "string", + "default": null, + "nullable": true + }, + "source": { + "description": "Source", + "type": "string", + "default": null, + "nullable": true + }, + "idExtra": { + "description": "Extra id", + "type": "string", + "default": null, + "nullable": true + }, + "criticalInstructions": { + "description": "Critical instructions", + "type": "string", + "default": null, + "nullable": true + }, + "warningInstructions": { + "description": "Warning instructions", + "type": "string", + "default": null, + "nullable": true + }, + "unknownInstructions": { + "description": "Unknows instructions", + "type": "string", + "default": null, + "nullable": true + }, + "ownerUser": { + "description": "Id user", + "type": "string", + "default": null, + "nullable": true + }, + "ackUtimestamp": { + "description": "Event ack utimestamp", + "type": "integer", + "default": null, + "readOnly": true, + "example": "1704898868", + "nullable": true + }, + "customData": { + "description": "Custom data", + "type": "string", + "default": null, + "nullable": true + }, + "data": { + "description": "Data", + "type": "string", + "default": null, + "nullable": true + }, + "moduleStatus": { + "description": "Module status", + "type": "integer", + "default": null, + "readOnly": true, + "nullable": true + }, + "eventCustomId": { + "description": "Events Custom Id", + "type": "string", + "default": null, + "nullable": true + } + }, + "type": "object" + }, "EventFilter": { "properties": { "idEventFilter": { @@ -2529,6 +2819,96 @@ } ] }, + "PandoraITSMInventory": { + "properties": { + "idPandoraITSMInventory": { + "description": "Id Agent pandoraITSMInventory", + "type": "integer", + "readOnly": true, + "nullable": false + }, + "agentAlias": { + "description": "Agent Name pandoraITSMInventory", + "type": "string", + "default": null, + "nullable": true + }, + "osVersion": { + "description": "Agent os version pandoraITSMInventory", + "type": "string", + "default": null, + "nullable": true + }, + "agentAddress": { + "description": "Agent address pandoraITSMInventory", + "type": "string", + "default": null, + "nullable": true + }, + "agentUrlAddress": { + "description": "Agent url address pandoraITSMInventory", + "type": "string", + "default": null, + "nullable": true + }, + "agentDisabled": { + "description": "Agent disable pandoraITSMInventory", + "type": "boolean", + "default": null, + "nullable": true + }, + "groupName": { + "description": "Agent group name pandoraITSMInventory", + "type": "string", + "default": null, + "nullable": true + }, + "groupId": { + "description": "Agent group id pandoraITSMInventory", + "type": "integer", + "default": null, + "nullable": true + }, + "osName": { + "description": "Agent OS name pandoraITSMInventory", + "type": "string", + "default": null, + "nullable": true + } + }, + "type": "object" + }, + "PandoraITSMInventoryFilter": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/PandoraITSMInventory" + }, + { + "properties": { + "idPandoraITSMInventory": { + "default": null, + "readOnly": false + }, + "freeSearch": { + "description": "Find word in name field.", + "type": "string", + "default": null, + "nullable": true + } + }, + "type": "object" + }, + { + "properties": { + "multipleSearch": { + "$ref": "#/components/schemas/multipleSearch" + } + }, + "type": "object" + } + ] + }, "Profile": { "properties": { "idProfile": { @@ -2707,6 +3087,42 @@ } ] }, + "multipleSearch": { + "properties": { + "field": { + "description": "Field to search of query", + "type": "string", + "nullable": true + }, + "data": { + "description": "Values to search of query IN()", + "type": "array", + "items": { + "type": "integer" + }, + "nullable": true + } + }, + "type": "object" + }, + "multipleSearchString": { + "properties": { + "field": { + "description": "Field to search of query", + "type": "string", + "nullable": true + }, + "data": { + "description": "Values to search of query IN()", + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "type": "object" + }, "paginationData": { "description": "Info pagination data", "properties": { @@ -3196,12 +3612,14 @@ "type": "string", "default": null, "nullable": true - }, + } + }, + "type": "object" + }, + { + "properties": { "multipleSearchString": { - "description": "search string in field.", - "type": "string", - "default": null, - "nullable": true + "$ref": "#/components/schemas/multipleSearch" } }, "type": "object" @@ -3316,6 +3734,16 @@ } } }, + "ResponseEvent": { + "description": "Event object", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event" + } + } + } + }, "ResponseEventFilter": { "description": "EventFilter object", "content": { @@ -3336,6 +3764,16 @@ } } }, + "ResponsePandoraITSMInventory": { + "description": "PandoraITSMInventory object", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PandoraITSMInventory" + } + } + } + }, "ResponseProfile": { "description": "Profile object", "content": { @@ -3499,6 +3937,16 @@ "default": 1 } }, + "parameterIdEvent": { + "name": "idEvent", + "in": "path", + "description": "Event id", + "required": true, + "schema": { + "type": "integer", + "default": 1 + } + }, "parameterIdEventFilter": { "name": "idEventFilter", "in": "path", @@ -3519,6 +3967,16 @@ "default": 1 } }, + "parameterIdPandoraITSMInventory": { + "name": "idPandoraITSMInventory", + "in": "path", + "description": "PandoraITSMInventory id", + "required": true, + "schema": { + "type": "integer", + "default": 1 + } + }, "parameterIdProfile": { "name": "idProfile", "in": "path", @@ -3642,6 +4100,16 @@ } } }, + "requestBodyEvent": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event" + } + } + } + }, "requestBodyEventFilter": { "required": true, "content": { @@ -3682,6 +4150,26 @@ } } }, + "requestBodyPandoraITSMInventory": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PandoraITSMInventory" + } + } + } + }, + "requestBodyPandoraITSMInventoryFilter": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PandoraITSMInventoryFilter" + } + } + } + }, "requestBodyProfile": { "required": true, "content": { @@ -3797,6 +4285,10 @@ { "name": "Users", "description": "API Endpoints of users" + }, + { + "name": "PandoraITSM", + "description": "API Endpoints of integration pandoraITSM" } ] } diff --git a/pandora_console/godmode/setup/setup_ITSM.php b/pandora_console/godmode/setup/setup_ITSM.php index e199960988..dfb7f96491 100644 --- a/pandora_console/godmode/setup/setup_ITSM.php +++ b/pandora_console/godmode/setup/setup_ITSM.php @@ -56,11 +56,18 @@ try { $status_values = $ITSM->getStatus(); $object_types_values = $ITSM->getObjectypes(); if ((bool) get_parameter('update_config', 0) === true) { + $ITSM_groups_agents_sync_base = null; + if (empty($config['ITSM_groups_agents_sync']) === false) { + $ITSM_groups_agents_sync_base = base64_encode($config['ITSM_groups_agents_sync']); + } + $set_config_inventories = $ITSM->createNode( [ - 'serverAuth' => $config['server_unique_identifier'], - 'apiPass' => $config['api_password'], + 'serverAuth' => md5($config['server_unique_identifier']), + 'apiPass' => md5($config['api_password']), 'agentsForExecution' => $config['ITSM_agents_sync'], + 'groups' => $ITSM_groups_agents_sync_base, + 'mode' => $config['ITSM_mode_agents_sync'], 'path' => $config['ITSM_public_url'], 'label' => array_keys(servers_get_names())[0], 'nodeId' => $config['metaconsole_node_id'], @@ -69,7 +76,7 @@ try { } try { - $node = $ITSM->getNode($config['server_unique_identifier']); + $node = $ITSM->getNode(md5($config['server_unique_identifier'])); } catch (\Throwable $th) { $node = []; } @@ -123,7 +130,7 @@ $table_remote->data['ITSM_user_level_conf'] = $row; $row = []; $row['hostname'] = html_print_label_input_block( __('URL to Pandora ITSM setup').ui_print_help_tip( - __('Full URL to your Pandora ITSM setup (e.g., http://192.168.1.20/integria/api/v2).'), + __('Full URL (e.g., http://192.168.1.20/XXX/api/v2).'), true ), html_print_input_text( @@ -207,7 +214,7 @@ if (empty($itsm_public_url) === true) { $row['publicUrl'] = html_print_label_input_block( __('URL connect to API %s', get_product_name()).ui_print_help_tip( - __('Full URL to your Pandora FMS (e.g., http://192.168.1.20).'), + __('Full URL (e.g., http://192.168.1.20/XXX/api/v2).'), true ), html_print_input_text( @@ -237,6 +244,55 @@ $row['agentsSync'] = html_print_label_input_block( $table_remote->data['ITSM_sync_inventory'] = $row; +$row = []; +$itsm_groups_agents_sync = []; +if (empty($config['ITSM_groups_agents_sync']) === false) { + $itsm_groups_agents_sync = json_decode( + io_safe_output($config['ITSM_groups_agents_sync']), + true + ); +} + +$mode_values = [ + 1 => __('Enable'), + 2 => __('Disable'), +]; + +$row['modeAgentsSync'] = html_print_label_input_block( + __('Synchronize agents mode'), + html_print_select( + $mode_values, + 'ITSM_mode_agents_sync', + $config['ITSM_mode_agents_sync'], + '', + __('All'), + 0, + true, + false, + true, + '', + false + ) +); + +$row['groupsAgentsSync'] = html_print_label_input_block( + __('Agent groups to synchronize'), + html_print_select_groups( + false, + 'AW', + false, + 'ITSM_groups_agents_sync[]', + $itsm_groups_agents_sync, + '', + '', + '', + true, + true + ) +); + +$table_remote->data['ITSM_sync_inventory_filters'] = $row; + // Test. $row = []; $button_test_pandora = html_print_button( diff --git a/pandora_console/include/functions_config.php b/pandora_console/include/functions_config.php index 416ad69e8b..baf09bd9fc 100644 --- a/pandora_console/include/functions_config.php +++ b/pandora_console/include/functions_config.php @@ -1972,6 +1972,27 @@ function config_update_config() $error_update[] = __('Pandora ITSM API agents sync'); } + $ITSM_mode_agents_sync = (int) get_parameter( + 'ITSM_mode_agents_sync', + $config['ITSM_mode_agents_sync'] + ); + if (config_update_value('ITSM_mode_agents_sync', $ITSM_mode_agents_sync, true) === false) { + $error_update[] = __('Pandora ITSM mode agents to synch'); + } + + $ITSM_groups_agents_sync = get_parameter( + 'ITSM_groups_agents_sync', + null + ); + + if (empty($ITSM_groups_agents_sync) === false) { + $ITSM_groups_agents_sync = json_encode($ITSM_groups_agents_sync); + } + + if (config_update_value('ITSM_groups_agents_sync', $ITSM_groups_agents_sync, true) === false) { + $error_update[] = __('Pandora ITSM groups agents to synch'); + } + $incident_default_group = (int) get_parameter('default_group', $config['default_group']); if (empty($incident_default_group) === true) { try { @@ -3919,6 +3940,14 @@ function config_process_config() config_update_value('ITSM_agents_sync', 20); } + if (!isset($config['ITSM_mode_agents_sync'])) { + config_update_value('ITSM_mode_agents_sync', 0); + } + + if (!isset($config['ITSM_groups_agents_sync'])) { + config_update_value('ITSM_groups_agents_sync', null); + } + // Module Library. if (!isset($config['module_library_user'])) { config_update_value('module_library_user', ''); diff --git a/pandora_console/include/javascript/ITSM.js b/pandora_console/include/javascript/ITSM.js index fa3802fffb..c6c162cd58 100644 --- a/pandora_console/include/javascript/ITSM.js +++ b/pandora_console/include/javascript/ITSM.js @@ -179,6 +179,7 @@ function testConectionApiItsmToPandora(path) { } else { showFailureImage(); showMessage(); + $("span#ITSM-message-pandora").html(data); } }) .fail(function() { diff --git a/pandora_console/include/lib/ITSM/ITSM.php b/pandora_console/include/lib/ITSM/ITSM.php index 14792e99ee..78229e7766 100644 --- a/pandora_console/include/lib/ITSM/ITSM.php +++ b/pandora_console/include/lib/ITSM/ITSM.php @@ -594,7 +594,7 @@ class ITSM * * @return boolean */ - public function pingItsmtoPandora(string $path): bool + public function pingItsmtoPandora(string $path): array { global $config; @@ -603,12 +603,12 @@ class ITSM [], [ 'path' => $path, - 'apiPass' => $config['api_password'], - 'serverAuth' => $config['server_unique_identifier'], + 'apiPass' => md5($config['api_password']), + 'serverAuth' => md5($config['server_unique_identifier']), ] ); - return (bool) $result['valid']; + return $result; } diff --git a/pandora_console/include/lib/ITSM/Manager.php b/pandora_console/include/lib/ITSM/Manager.php index eebf3f665e..d20c563182 100644 --- a/pandora_console/include/lib/ITSM/Manager.php +++ b/pandora_console/include/lib/ITSM/Manager.php @@ -1500,12 +1500,10 @@ class Manager $ITSM = new ITSM(); $result = $ITSM->pingItsmtoPandora($path); } catch (Throwable $e) { - echo $e->getMessage(); - $result = false; - exit; + $result = $e->getMessage(); } - echo json_encode(['valid' => ($result !== false) ? 1 : 0]); + echo json_encode($result); exit; } diff --git a/pandora_console/include/lib/Modules/Authentication/Repositories/TokenRepositoryMySQL.php b/pandora_console/include/lib/Modules/Authentication/Repositories/TokenRepositoryMySQL.php index d5de91d1e9..bd2cabca85 100644 --- a/pandora_console/include/lib/Modules/Authentication/Repositories/TokenRepositoryMySQL.php +++ b/pandora_console/include/lib/Modules/Authentication/Repositories/TokenRepositoryMySQL.php @@ -136,7 +136,7 @@ final class TokenRepositoryMySQL extends RepositoryMySQL implements TokenReposit $filters = $this->buildQueryFilters($filter, $mapper); // Check ACL for user list. - if (\users_is_admin() === false) { + if (empty($this->config->get('id_user')) === false && \users_is_admin() === false) { // No admin. $filters .= sprintf( ' AND ttoken.id_user = "%s"', diff --git a/pandora_console/include/lib/Modules/Events/Entities/Event.php b/pandora_console/include/lib/Modules/Events/Entities/Event.php index 2c9b9e8ef7..cc3c1d13a0 100644 --- a/pandora_console/include/lib/Modules/Events/Entities/Event.php +++ b/pandora_console/include/lib/Modules/Events/Entities/Event.php @@ -16,7 +16,7 @@ use PandoraFMS\Modules\Shared\Entities\Entity; * property="idEvent", * type="integer", * nullable=false, - * description="Id event" + * description="Id event", * readOnly=true * ), * @OA\Property( @@ -212,7 +212,7 @@ use PandoraFMS\Modules\Shared\Entities\Entity; * nullable=true, * default=null, * description="Module status", - * readonly=true + * readOnly=true * ), * @OA\Property( * property="eventCustomId", diff --git a/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Actions/GetPandoraITSMInventoryAction.php b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Actions/GetPandoraITSMInventoryAction.php new file mode 100644 index 0000000000..58fc8133db --- /dev/null +++ b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Actions/GetPandoraITSMInventoryAction.php @@ -0,0 +1,19 @@ +getPandoraITSMInventoryService->__invoke($idPandoraITSMInventory); + } +} diff --git a/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Actions/ListPandoraITSMInventoryAction.php b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Actions/ListPandoraITSMInventoryAction.php new file mode 100644 index 0000000000..c0ef30b766 --- /dev/null +++ b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Actions/ListPandoraITSMInventoryAction.php @@ -0,0 +1,28 @@ +getPage(), + $pandoraITSMInventoryFilter->getSizePage(), + $this->countPandoraITSMInventoryService->__invoke($pandoraITSMInventoryFilter), + $this->listPandoraITSMInventoryService->__invoke($pandoraITSMInventoryFilter) + ))->toArray(); + } +} diff --git a/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Controllers/GetPandoraITSMInventoryController.php b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Controllers/GetPandoraITSMInventoryController.php new file mode 100644 index 0000000000..5e50f2ebf3 --- /dev/null +++ b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Controllers/GetPandoraITSMInventoryController.php @@ -0,0 +1,44 @@ +getParam($request, 'idPandoraITSMInventory'); + + $this->acl->validate(0, 'AR', ' tried to read agents for pandoraITSMInventories'); + + $result = $this->getPandoraITSMInventoryAction->__invoke($idPandoraITSMInventory); + return $this->getResponse($response, $result); + } +} diff --git a/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Controllers/ListPandoraITSMInventoryController.php b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Controllers/ListPandoraITSMInventoryController.php new file mode 100644 index 0000000000..3bf06c69f2 --- /dev/null +++ b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Controllers/ListPandoraITSMInventoryController.php @@ -0,0 +1,74 @@ +fromRequest($request, PandoraITSMInventoryFilter::class); + + $this->acl->validate(0, 'AR', ' tried to read agents for pandoraITSMInventories'); + + $result = $this->listPandoraITSMInventoryAction->__invoke($pandoraITSMInventoryFilter); + return $this->getResponse($response, $result); + } +} diff --git a/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Entities/PandoraITSMInventory.php b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Entities/PandoraITSMInventory.php new file mode 100644 index 0000000000..8fd6ed4d9c --- /dev/null +++ b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Entities/PandoraITSMInventory.php @@ -0,0 +1,264 @@ + $this->getIdPandoraITSMInventory(), + 'agentAlias' => $this->getAgentAlias(), + 'osVersion' => $this->getOsVersion(), + 'agentAddress' => $this->getAgentAddress(), + 'agentUrlAddress' => $this->getAgentUrlAddress(), + 'agentDisabled' => $this->getAgentDisabled(), + 'groupName' => $this->getGroupName(), + 'groupId' => $this->getGroupId(), + 'osName' => $this->getOsName(), + ]; + } + + public function getValidations(): array + { + return [ + 'idPandoraITSMInventory' => [ + Validator::INTEGER, + Validator::GREATERTHAN, + ], + 'agentAlias' => Validator::STRING, + 'osVersion' => Validator::STRING, + 'agentAddress' => Validator::STRING, + 'agentUrlAddress' => Validator::STRING, + 'agentDisabled' => Validator::BOOLEAN, + 'groupName' => Validator::STRING, + 'groupId' => [ + Validator::INTEGER, + Validator::GREATERTHAN, + ], + 'osName' => Validator::STRING, + ]; + } + + public function validateFields(array $filters): array + { + return (new Validator())->validate($filters); + } + + public function getIdPandoraITSMInventory(): ?int + { + return $this->idPandoraITSMInventory; + } + public function setIdPandoraITSMInventory(?int $idPandoraITSMInventory): self + { + $this->idPandoraITSMInventory = $idPandoraITSMInventory; + return $this; + } + + public function getAgentAlias(): ?string + { + return $this->agentAlias; + } + public function setAgentAlias(?string $agentAlias): self + { + $this->agentAlias = $agentAlias; + return $this; + } + + public function getOsVersion(): ?string + { + return $this->osVersion; + } + public function setOsVersion(?string $osVersion): self + { + $this->osVersion = $osVersion; + return $this; + } + + public function getAgentAddress(): ?string + { + return $this->agentAddress; + } + public function setAgentAddress(?string $agentAddress): self + { + $this->agentAddress = $agentAddress; + return $this; + } + + public function getAgentUrlAddress(): ?string + { + return $this->agentUrlAddress; + } + public function setAgentUrlAddress(?string $agentUrlAddress): self + { + $this->agentUrlAddress = $agentUrlAddress; + return $this; + } + + public function getGroupName(): ?string + { + return $this->groupName; + } + public function setGroupName(?string $groupName): self + { + $this->groupName = $groupName; + return $this; + } + + public function getOsName(): ?string + { + return $this->osName; + } + public function setOsName(?string $osName): self + { + $this->osName = $osName; + return $this; + } + + public function getGroupId(): ?int + { + return $this->groupId; + } + public function setGroupId(?int $groupId): self + { + $this->groupId = $groupId; + return $this; + } + + public function getAgentDisabled(): ?bool + { + return $this->agentDisabled; + } + public function setAgentDisabled(?bool $agentDisabled): self + { + $this->agentDisabled = $agentDisabled; + return $this; + } +} diff --git a/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Entities/PandoraITSMInventoryFilter.php b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Entities/PandoraITSMInventoryFilter.php new file mode 100644 index 0000000000..95fa1120ec --- /dev/null +++ b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Entities/PandoraITSMInventoryFilter.php @@ -0,0 +1,159 @@ +setDefaultFieldOrder('tagente.id_agente'); + $this->setDefaultDirectionOrder($this::ASC); + $this->setEntityFilter(new PandoraITSMInventory()); + } + + public function fieldsTranslate(): array + { + return [ + 'idPandoraITSMInventory' => 'tagente.id_agente', + 'agentAlias' => 'tagente.alias', + 'osVersion' => 'tagente.os_version', + 'agentAddress' => 'tagente.direccion', + 'agentUrlAddress' => 'tagente.url_address', + 'agentDisabled' => 'tagente.disabled', + 'groupId' => 'tgrupo.id_grupo', + 'groupName' => 'tgrupo.nombre', + 'osName' => 'tconfig_os.name', + ]; + } + + public function fieldsReadOnly(): array + { + return []; + } + + public function jsonSerialize(): mixed + { + return [ + 'freeSearch' => $this->getFreeSearch(), + 'multipleSearch' => $this->getMultipleSearch(), + ]; + } + + public function getValidations(): array + { + $validations = []; + if($this->getEntityFilter() !== null) { + $validations = $this->getEntityFilter()->getValidations(); + } + $validations['freeSearch'] = Validator::STRING; + $validations['multipleSearch'] = Validator::ARRAY; + return $validations; + } + + public function validateFields(array $filters): array + { + return (new Validator())->validate($filters); + } + + /** + * Get the value of freeSearch. + * + * @return ?string + */ + public function getFreeSearch(): ?string + { + return $this->freeSearch; + } + + /** + * Set the value of freeSearch. + * + * @param ?string $freeSearch + * + */ + public function setFreeSearch(?string $freeSearch): self + { + $this->freeSearch = $freeSearch; + return $this; + } + + /** + * Get the value of fieldsFreeSearch. + * + * @return ?array + */ + public function getFieldsFreeSearch(): ?array + { + return [ + 'tagente.alias', + 'tagente.id_agente', + ]; + } + + /** + * Get the value of multipleSearchString. + * + * @return ?array + */ + public function getMultipleSearch(): ?array + { + return $this->multipleSearch; + } + + /** + * Set the value of multipleSearchString. + * + * @param ?array $multipleSearch + */ + public function setMultipleSearch(?array $multipleSearch): self + { + $this->multipleSearch = $multipleSearch; + return $this; + } +} diff --git a/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Repositories/PandoraITSMInventoryRepository.php b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Repositories/PandoraITSMInventoryRepository.php new file mode 100644 index 0000000000..760636d3fa --- /dev/null +++ b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Repositories/PandoraITSMInventoryRepository.php @@ -0,0 +1,24 @@ +getPandoraITSMInventoriesQuery($pandoraITSMInventoryFilter); + } catch (\Throwable $th) { + // Capture errors mysql. + throw new InvalidArgumentException( + strip_tags($th->getMessage()), + HttpCodesEnum::INTERNAL_SERVER_ERROR + ); + } + + if (is_array($result) === false) { + throw new NotFoundException(__('Pandora itsm inventory not found')); + } + + return $result; + } + + public function count(PandoraITSMInventoryFilter $pandoraITSMInventoryFilter): int + { + $result = $this->getPandoraITSMInventoriesQuery($pandoraITSMInventoryFilter, true); + try { + $count = 0; + if (empty($result) === false && isset($result[0]) === true) { + $count = $result[0]['count']; + } + } catch (\Throwable $th) { + // Capture errors mysql. + throw new InvalidArgumentException( + strip_tags($th->getMessage()), + HttpCodesEnum::INTERNAL_SERVER_ERROR + ); + } + + return (int) $count; + } + + public function getOne(PandoraITSMInventoryFilter $pandoraITSMInventoryFilter): array + { + try { + $result_array = $this->getPandoraITSMInventoriesQuery($pandoraITSMInventoryFilter); + + $result = []; + if (empty($result_array) === false) { + $result = array_shift($result_array); + } + + } catch (\Throwable $th) { + // Capture errors mysql. + throw new InvalidArgumentException( + strip_tags($th->getMessage()), + HttpCodesEnum::INTERNAL_SERVER_ERROR + ); + } + + if (empty($result) === true) { + throw new NotFoundException(__('Pandora itsm inventory not found')); + } + + return $result; + } + + public function create(PandoraITSMInventory $pandoraITSMInventory): PandoraITSMInventory + { + return $pandoraITSMInventory; + } + + public function update(PandoraITSMInventory $pandoraITSMInventory): PandoraITSMInventory + { + return $pandoraITSMInventory; + } + + public function delete(int $id): void + { + } + + private function getPandoraITSMInventoriesQuery( + FilterAbstract $filter, + bool $count = false + ): array { + $pagination = ''; + $orderBy = ''; + $fields = 'COUNT(DISTINCT tagente.id_agente) as count'; + $filters = $this->buildQueryFilters($filter); + $groupBy = ''; + + if ($count === false) { + $pagination = $this->buildQueryPagination($filter); + $orderBy = $this->buildQueryOrderBy($filter); + $groupBy = 'GROUP BY tagente.id_agente'; + + $custom_fields = \db_get_all_fields_in_table('tagent_custom_fields'); + if ($custom_fields === false) { + $custom_fields = []; + } + + $count_custom_fields = count($custom_fields); + $custom_field_sql = ''; + $index_name_custom_fields = []; + foreach ($custom_fields as $key => $field) { + $index_name_custom_fields[$field['name']] = $field; + if ($key !== $count_custom_fields) { + $custom_field_sql .= ', '; + } + + $custom_field_sql .= sprintf( + 'MAX(CASE WHEN tagent_custom_fields.name = "%s" THEN tagent_custom_data.description END) AS "%s"', + $field['name'], + $field['name'] + ); + } + + $fields = sprintf( + 'tagente.alias, + tagente.id_agente AS "ID Agent", + tagente.os_version AS "OS Version", + tagente.direccion AS "IP Address", + tagente.url_address AS "URL Address", + tgrupo.nombre AS "Group", + tconfig_os.name AS "OS" + %s', + $custom_field_sql + ); + } + + $sql = sprintf( + 'SELECT %s + FROM tagente + LEFT JOIN tagent_custom_data + ON tagent_custom_data.id_agent = tagente.id_agente + LEFT JOIN tagent_custom_fields + ON tagent_custom_data.id_field = tagent_custom_fields.id_field + INNER JOIN tgrupo + ON tgrupo.id_grupo = tagente.id_grupo + INNER JOIN tconfig_os + ON tconfig_os.id_os = tagente.id_os + LEFT JOIN tagent_secondary_group + ON tagente.id_agente = tagent_secondary_group.id_agent + WHERE %s + %s + %s + %s', + $fields, + $filters, + $groupBy, + $orderBy, + $pagination + ); + + $data = $this->dbGetAllRowsSql($sql); + if ($data === false) { + $data = []; + } + + $result = []; + if ($count === false) { + foreach ($data as $key => $agent_fields) { + foreach ($agent_fields as $name_field => $value_field) { + $type = 'text'; + if (isset($index_name_custom_fields[$name_field]) === true) { + if ($index_name_custom_fields[$name_field]['is_password_type']) { + $type = 'password'; + } elseif ($index_name_custom_fields[$name_field]['is_link_enabled']) { + $type = 'link'; + } + } + + $result[$agent_fields['ID Agent']][$name_field] = [ + 'data' => $value_field, + 'type' => $type, + ]; + } + } + } else { + $result = $data; + } + + return $result; + } +} diff --git a/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Services/CountPandoraITSMInventoryService.php b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Services/CountPandoraITSMInventoryService.php new file mode 100644 index 0000000000..d19b3d775d --- /dev/null +++ b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Services/CountPandoraITSMInventoryService.php @@ -0,0 +1,19 @@ +pandoraITSMInventoryRepository->count($pandoraITSMInventoryFilter); + } +} diff --git a/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Services/GetPandoraITSMInventoryService.php b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Services/GetPandoraITSMInventoryService.php new file mode 100644 index 0000000000..f69e91bf78 --- /dev/null +++ b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Services/GetPandoraITSMInventoryService.php @@ -0,0 +1,25 @@ +getEntityFilter(); + $entityFilter->setIdPandoraITSMInventory($idPandoraITSMInventory); + + return $this->pandoraITSMInventoryRepository->getOne($pandoraITSMInventoryFilter); + } +} diff --git a/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Services/ListPandoraITSMInventoryService.php b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Services/ListPandoraITSMInventoryService.php new file mode 100644 index 0000000000..6719707004 --- /dev/null +++ b/pandora_console/include/lib/Modules/PandoraITSM/Inventories/Services/ListPandoraITSMInventoryService.php @@ -0,0 +1,19 @@ +pandoraITSMInventoryRepository->list($pandoraITSMInventoryFilter); + } +} diff --git a/pandora_console/include/lib/Modules/PandoraITSM/routes.php b/pandora_console/include/lib/Modules/PandoraITSM/routes.php new file mode 100644 index 0000000000..41d40bb821 --- /dev/null +++ b/pandora_console/include/lib/Modules/PandoraITSM/routes.php @@ -0,0 +1,10 @@ +map(['GET', 'POST'], '/pandoraITSM/inventory/list', ListPandoraITSMInventoryController::class); + $app->get('/pandoraITSM/inventory/{idPandoraITSMInventory}', GetPandoraITSMInventoryController::class); +}; diff --git a/pandora_console/include/lib/Modules/Shared/Documentation/OpenApi.php b/pandora_console/include/lib/Modules/Shared/Documentation/OpenApi.php index a2b15588f2..967ca79b4a 100644 --- a/pandora_console/include/lib/Modules/Shared/Documentation/OpenApi.php +++ b/pandora_console/include/lib/Modules/Shared/Documentation/OpenApi.php @@ -60,6 +60,10 @@ More useful links: * name="Users", * description="API Endpoints of users" * ), +* @OA\Tag( + * name="PandoraITSM", + * description="API Endpoints of integration pandoraITSM" + * ), * @OA\Parameter( * parameter="parameterPage", * name="page", @@ -223,7 +227,43 @@ More useful links: * ) * } * ) - * + * + * @OA\Schema( + * schema="multipleSearch", + * type="object", + * @OA\Property( + * property="field", + * type="string", + * nullable=true, + * description="Field to search of query" + * ), + * @OA\Property( + * property="data", + * type="array", + * nullable=true, + * @OA\Items(type="integer"), + * description="Values to search of query IN()" + * ) + * ) + * + * @OA\Schema( + * schema="multipleSearchString", + * type="object", + * @OA\Property( + * property="field", + * type="string", + * nullable=true, + * description="Field to search of query" + * ), + * @OA\Property( + * property="data", + * type="array", + * nullable=true, + * @OA\Items(type="string"), + * description="Values to search of query IN()" + * ) + * ) + * * @OA\Schema( * schema="paginationData", * type="object", diff --git a/pandora_console/include/lib/Modules/Shared/Middlewares/UserTokenMiddleware.php b/pandora_console/include/lib/Modules/Shared/Middlewares/UserTokenMiddleware.php index 237293e2b2..8b92c41b86 100644 --- a/pandora_console/include/lib/Modules/Shared/Middlewares/UserTokenMiddleware.php +++ b/pandora_console/include/lib/Modules/Shared/Middlewares/UserTokenMiddleware.php @@ -30,22 +30,23 @@ final class UserTokenMiddleware $token = null; try { $authorization = str_replace('Bearer ', '', $authorization); - preg_match( - '/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/', - $authorization, - $matches - ); - - $uuid = ($matches[0] ?? ''); - if (empty($uuid) === true) { - return false; - } - $strToken = str_replace($uuid.'-', '', $authorization); - $validTokenUiniqueServerIdentifier = $this->validateServerIdentifierTokenService->__invoke($strToken); + $validTokenUiniqueServerIdentifier = $this->validateServerIdentifierTokenService->__invoke($authorization); if ($validTokenUiniqueServerIdentifier === false) { + preg_match( + '/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/', + $authorization, + $matches + ); + + $uuid = ($matches[0] ?? ''); + if (empty($uuid) === true) { + return false; + } + $strToken = str_replace($uuid.'-', '', $authorization); $validToken = $this->validateUserTokenService->__invoke($uuid, $strToken); $token = $this->getUserTokenService->__invoke($uuid); if ($token !== null && $validToken) { + $this->config->set('id_user', $token->getIdUser()); $oldToken = clone $token; $token->setLastUsage($this->timestamp->getMysqlCurrentTimestamp(0)); $this->updateTokenService->__invoke($token, $oldToken); diff --git a/pandora_console/include/lib/Modules/Shared/Repositories/RepositoryMySQL.php b/pandora_console/include/lib/Modules/Shared/Repositories/RepositoryMySQL.php index fb5e4717d9..03de753d74 100644 --- a/pandora_console/include/lib/Modules/Shared/Repositories/RepositoryMySQL.php +++ b/pandora_console/include/lib/Modules/Shared/Repositories/RepositoryMySQL.php @@ -165,16 +165,32 @@ class RepositoryMySQL extends Repository return $result; } - public function buildQueryFilters(FilterAbstract $filter, DataMapperAbstract $mapper): string + public function buildQueryFilters(FilterAbstract $filter, ?DataMapperAbstract $mapper = null): string { $where_clause = '1=1'; - if ($filter->getEntityFilter() !== null) { + if ($mapper !== null && $filter->getEntityFilter() !== null) { $searchEntity = $mapper->toDatabase($filter->getEntityFilter()); $searchEntity = array_filter($searchEntity, fn ($value) => !is_null($value) && $value !== '' && $value !== 'null'); if (empty($searchEntity) === false) { $where_clause .= ' AND '.$this->dbFormatWhereClauseSQL($searchEntity, '`'.$mapper->getTableName().'`.'); } + } else { + $searchEntity = $filter->getEntityFilter()->toArray(); + $translates = $filter->fieldsTranslate(); + $searchEntity = array_filter($searchEntity, fn ($value) => !is_null($value) && $value !== '' && $value !== 'null'); + if(empty($searchEntity) === false) { + $resultEntity = []; + foreach ($searchEntity as $key => $value) { + if (isset($translates[$key]) === true) { + $resultEntity[$translates[$key]] = $value; + } + } + + if (empty($resultEntity) === false) { + $where_clause .= ' AND '.$this->dbFormatWhereClauseSQL($resultEntity); + } + } } if (empty($filter->getFieldsFreeSearch()) === false @@ -222,15 +238,31 @@ class RepositoryMySQL extends Repository { $fields = $filter->fieldsTranslate(); $field = ''; - if (empty($fields) === false) { + if (empty($fields) === false + && isset($fields[($filter->getMultipleSearch()['field'])]) === true) { $field = ($fields[($filter->getMultipleSearch()['field'] ?? '')] ?? ''); + } else { + throw new Exception( + __( + 'Bad request, multiple field %s is not a valid field', + $filter->getMultipleSearch()['field'] + ) + ); } if (empty($field) === true) { return ''; } - $clause = ' AND '.$field.' IN ('.implode(',', $filter->getMultipleSearch()['data']).')'; + $clause = ' AND ('.$field.' IN ('.implode(',', $filter->getMultipleSearch()['data']).')'; + + if(isset($filter->getMultipleSearch()['secondaryGroup']) === true + && $filter->getMultipleSearch()['secondaryGroup'] === true + ) { + $clause .= ' OR tagent_secondary_group.id_group IN ('.implode(',', $filter->getMultipleSearch()['data']).')'; + } + $clause .= ')'; + return $clause; } @@ -238,8 +270,17 @@ class RepositoryMySQL extends Repository { $fields = $filter->fieldsTranslate(); $field = ''; - if (empty($fields) === false) { + if (empty($fields) === false + && isset($fields[($filter->getMultipleSearchString()['field'])]) === true + ) { $field = ($fields[($filter->getMultipleSearchString()['field'] ?? '')] ?? ''); + } else { + throw new Exception( + __( + 'Bad request, multiple field %s is not a valid field', + $filter->getMultipleSearchString()['field'] + ) + ); } if (empty($field) === true) { diff --git a/pandora_console/include/lib/Modules/Users/Entities/UserFilter.php b/pandora_console/include/lib/Modules/Users/Entities/UserFilter.php index eb3b5ca3b7..632913ce05 100644 --- a/pandora_console/include/lib/Modules/Users/Entities/UserFilter.php +++ b/pandora_console/include/lib/Modules/Users/Entities/UserFilter.php @@ -18,13 +18,14 @@ use PandoraFMS\Modules\Users\Validators\UserValidator; * nullable=true, * default=null, * description="Find word in fullname and comments fields." - * ), + * ) + * ), + * @OA\Schema( * @OA\Property( * property="multipleSearchString", - * type="string", - * nullable=true, - * default=null, - * description="search string in field." + * type="object", + * ref="#/components/schemas/multipleSearch", + * description="Multiple search object", * ) * ) * }