diff --git a/config/packages/Centreon.yaml b/config/packages/Centreon.yaml index 7e19c9b5ea7..e0e1cf96319 100644 --- a/config/packages/Centreon.yaml +++ b/config/packages/Centreon.yaml @@ -10,6 +10,9 @@ jms_serializer: infrastructure: namespace_prefix: "Centreon\\Infrastructure" path: '%kernel.project_dir%/config/packages/serializer/Infrastructure' + core: + namespace_prefix: "Core\\" + path: '%kernel.project_dir%/config/packages/serializer/Core' parameters: api.header: "Api-Version" api.version.latest: "22.10" diff --git a/config/packages/serializer/Centreon/Monitoring.Resource.yml b/config/packages/serializer/Centreon/Monitoring.Resource.yml index 4d11c161fb1..e22497f8f41 100644 --- a/config/packages/serializer/Centreon/Monitoring.Resource.yml +++ b/config/packages/serializer/Centreon/Monitoring.Resource.yml @@ -91,10 +91,6 @@ Centreon\Domain\Monitoring\Resource: groups: - 'resource_main' - 'resource_parent' - severityLevel: - type: int - groups: - - 'resource_main' chartUrl: type: string groups: @@ -123,3 +119,7 @@ Centreon\Domain\Monitoring\Resource: type: bool groups: - 'resource_main' + severity: + type: Core\Severity\RealTime\Domain\Model\Severity + groups: + - 'resource_main' diff --git a/config/packages/serializer/Centreon/Monitoring.ResourceFilter.yml b/config/packages/serializer/Centreon/Monitoring.ResourceFilter.yml index 444a46733d2..1ad515a8b36 100644 --- a/config/packages/serializer/Centreon/Monitoring.ResourceFilter.yml +++ b/config/packages/serializer/Centreon/Monitoring.ResourceFilter.yml @@ -16,6 +16,14 @@ Centreon\Domain\Monitoring\ResourceFilter: type: array monitoringServerNames: type: array + serviceSeverityNames: + type: array + hostSeverityNames: + type: array + serviceSeverityLevels: + type: array + hostSeverityLevels: + type: array statusTypes: type: array onlyWithPerformanceData: diff --git a/config/packages/serializer/Core/Domain.RealTime.Model.Icon.yml b/config/packages/serializer/Core/Domain.RealTime.Model.Icon.yml new file mode 100644 index 00000000000..2397956dbe1 --- /dev/null +++ b/config/packages/serializer/Core/Domain.RealTime.Model.Icon.yml @@ -0,0 +1,14 @@ +Core\Domain\RealTime\Model\Icon: + properties: + id: + type: integer + groups: + - 'core_icon_main' + name: + type: string + groups: + - 'core_icon_main' + url: + type: string + groups: + - 'core_icon_main' \ No newline at end of file diff --git a/config/packages/serializer/Core/Severity.RealTime.Domain.Model.Severity.yml b/config/packages/serializer/Core/Severity.RealTime.Domain.Model.Severity.yml new file mode 100644 index 00000000000..ff67d373ce5 --- /dev/null +++ b/config/packages/serializer/Core/Severity.RealTime.Domain.Model.Severity.yml @@ -0,0 +1,25 @@ +Core\Severity\RealTime\Domain\Model\Severity: + virtual_properties: + getTypeAsString: + name: getTypeAsString + serialized_name: type + type: string + groups: + - 'severity_main' + properties: + id: + type: integer + groups: + - 'severity_main' + name: + type: string + groups: + - 'severity_main' + level: + type: integer + groups: + - 'severity_main' + icon: + type: Core\Domain\RealTime\Model\Icon + groups: + - 'severity_main' \ No newline at end of file diff --git a/config/packages/validator/validation.yaml b/config/packages/validator/validation.yaml index 4458f8ecec2..791e46f8417 100644 --- a/config/packages/validator/validation.yaml +++ b/config/packages/validator/validation.yaml @@ -263,6 +263,38 @@ Centreon\Domain\Monitoring\ResourceFilter: - Type: type: string groups: [Default] + serviceSeverityNames: + - Type: + type: array + groups: [Default] + - All: + - Type: + type: string + groups: [Default] + hostSeverityNames: + - Type: + type: array + groups: [Default] + - All: + - Type: + type: string + groups: [Default] + serviceSeverityLevels: + - Type: + type: array + groups: [Default] + - All: + - Type: + type: integer + groups: [Default] + hostSeverityLevels: + - Type: + type: array + groups: [Default] + - All: + - Type: + type: integer + groups: [Default] statusTypes: - Type: type: array diff --git a/config/routes/Centreon/monitoring/severity.yaml b/config/routes/Centreon/monitoring/severity.yaml new file mode 100644 index 00000000000..d6de697ab29 --- /dev/null +++ b/config/routes/Centreon/monitoring/severity.yaml @@ -0,0 +1,14 @@ +--- +centreon.severity.realtime.findHostSeverities: + methods: "GET" + path: "/monitoring/severities/host" + controller: >- + Core\Severity\RealTime\Infrastructure\API\FindSeverity\FindHostSeverityController + condition: "request.attributes.get('version') >= 22.04" + +centreon.severity.realtime.findServiceSeverities: + methods: "GET" + path: "/monitoring/severities/service" + controller: >- + Core\Severity\RealTime\Infrastructure\API\FindSeverity\FindServiceSeverityController + condition: "request.attributes.get('version') >= 22.04" diff --git a/doc/API/ResourceHostDetail.yaml b/doc/API/ResourceHostDetail.yaml index a68f5fe4f1d..a11c2172cbc 100644 --- a/doc/API/ResourceHostDetail.yaml +++ b/doc/API/ResourceHostDetail.yaml @@ -121,11 +121,6 @@ Monitoring.HostDetail: type: boolean description: "Indicates whether the check script is active or not" example: true - severity_level: - type: integer - nullable: true - description: "Indicates the severity level" - example: 1 parent: null icon: type: object @@ -145,12 +140,67 @@ Monitoring.HostDetail: id: type: integer format: int64 - description: "ID of the hostgroup" + description: "ID of the host group" example: 28 name: type: string - description: "Name of the hostgroup" + description: "Name of the host group" example: "Linux-Servers" + categories: + type: object + properties: + id: + type: integer + format: int64 + description: "ID of the host category" + example: 28 + name: + type: string + description: "Name of the host category" + example: "All-Cpu-Services" + configuration_uri: + type: string + nullable: true + description: "Internal URI to reach category configuration" + severity: + type: object + nullable: true + properties: + id: + type: integer + format: int64 + description: "ID of the severity" + example: 28 + name: + type: string + description: "Name of the severity" + example: "High" + type: + type: string + description: "Type of the severity" + enum: ['host', 'service'] + level: + type: integer + description: "Level of the severity" + minimum: 0 + maximum: 100 + example: 50 + icon: + type: object + properties: + id: + type: integer + format: int64 + description: "ID of the icon" + example: 10 + name: + type: string + description: "Name of the icon" + example: "dog.png" + url: + type: string + description: "URL of the icon" + example: "baseUri/ppm/dog.png" acknowledgement: type: object nullable: true diff --git a/doc/API/ResourceServiceDetail.yaml b/doc/API/ResourceServiceDetail.yaml index 2b532e1e392..5abee1d6520 100644 --- a/doc/API/ResourceServiceDetail.yaml +++ b/doc/API/ResourceServiceDetail.yaml @@ -123,16 +123,10 @@ Monitoring.ServiceDetail: type: boolean description: "Indicates whether the check script is active or not" example: true - severity_level: - type: integer - nullable: true - description: "Indicates the severity level" - example: 1 parent: $ref: './ResourceHostDetail.yaml' icon: type: object - nullable: true properties: name: type: string @@ -148,12 +142,71 @@ Monitoring.ServiceDetail: id: type: integer format: int64 - description: "ID of the servicegroup" + description: "ID of the service group" + example: 28 + name: + type: string + description: "Name of the service group" + example: "All-Cpu-Services" + configuration_uri: + type: string + nullable: true + description: "Internal URI to reach group configuration" + categories: + type: object + properties: + id: + type: integer + format: int64 + description: "ID of the service category" example: 28 name: type: string - description: "Name of the servicegroup" + description: "Name of the service category" example: "All-Cpu-Services" + configuration_uri: + type: string + nullable: true + description: "Internal URI to reach category configuration" + severity: + type: object + nullable: true + properties: + id: + type: integer + format: int64 + description: "ID of the severity" + example: 28 + name: + type: string + description: "Name of the severity" + example: "High" + type: + type: string + description: "Type of the severity" + enum: ['host', 'service'] + level: + type: integer + description: "Level of the severity" + minimum: 0 + maximum: 100 + example: 50 + icon: + type: object + properties: + id: + type: integer + format: int64 + description: "ID of the icon" + example: 10 + name: + type: string + description: "Name of the icon" + example: "dog.png" + url: + type: string + description: "URL of the icon" + example: "baseUri/ppm/dog.png" acknowledgement: type: object nullable: true diff --git a/doc/API/centreon-api-v22.10.yaml b/doc/API/centreon-api-v22.10.yaml index 00b403076f0..671bc909cbd 100644 --- a/doc/API/centreon-api-v22.10.yaml +++ b/doc/API/centreon-api-v22.10.yaml @@ -63,6 +63,7 @@ tags: - name: Service group - name: Service category - name: Host category + - name: Severity - name: Topology security: - Token: [] @@ -1255,7 +1256,6 @@ paths: * notes_url * parent_name * parent_status - * severity_level * in_downtime * acknowledged * last_status_change @@ -1286,6 +1286,10 @@ paths: - $ref: '#/components/parameters/ResourceFilterServicegroupName' - $ref: '#/components/parameters/ResourceFilterServiceCategoryName' - $ref: '#/components/parameters/ResourceFilterHostCategoryName' + - $ref: '#/components/parameters/ResourceFilterHostSeverityName' + - $ref: '#/components/parameters/ResourceFilterServiceSeverityName' + - $ref: '#/components/parameters/ResourceFilterHostSeverityLevel' + - $ref: '#/components/parameters/ResourceFilterServiceSeverityLevel' - $ref: '#/components/parameters/ResourceFilterMonitoringServerName' - $ref: '#/components/parameters/ResourceFilterStatusTypes' responses: @@ -1689,6 +1693,78 @@ paths: $ref: '#/components/responses/Forbidden' '500': $ref: '#/components/responses/InternalServerError' + /monitoring/severities/service: + get: + tags: + - Severity + summary: "List all service severities from the realtime" + description: | + List all the service severities in real-time monitoring. + + The available parameters to **search** / **sort_by** are: + + * name + * level + parameters: + - $ref: '#/components/parameters/Search' + - $ref: '#/components/parameters/Limit' + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/SortBy' + responses: + '200': + description: "OK" + content: + application/json: + schema: + type: object + properties: + result: + type: array + items: + allOf: + - $ref: '#/components/schemas/Monitoring.Severity' + meta: + $ref: '#/components/schemas/Meta' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' + /monitoring/severities/host: + get: + tags: + - Severity + summary: "List all host severities from real-time data" + description: | + List all the host severities in real-time monitoring. + + The available parameters to **search** / **sort_by** are: + + * name + * level + parameters: + - $ref: '#/components/parameters/Search' + - $ref: '#/components/parameters/Limit' + - $ref: '#/components/parameters/Page' + - $ref: '#/components/parameters/SortBy' + responses: + '200': + description: "OK" + content: + application/json: + schema: + type: object + properties: + result: + type: array + items: + allOf: + - $ref: '#/components/schemas/Monitoring.Severity' + meta: + $ref: '#/components/schemas/Meta' + '403': + $ref: '#/components/responses/Forbidden' + '500': + $ref: '#/components/responses/InternalServerError' /monitoring/acknowledgements: get: tags: @@ -4099,6 +4175,46 @@ components: items: type: string example: '["Linux", "Windows"]' + ResourceFilterServiceSeverityName: + in: query + name: service_severity_names + required: false + description: "Filter the resources by service severity names" + schema: + type: array + items: + type: string + example: '["Ping", "CPUs"]' + ResourceFilterHostSeverityName: + in: query + name: host_severity_names + required: false + description: "Filter the resources by host severity names" + schema: + type: array + items: + type: string + example: '["Linux", "Windows"]' + ResourceFilterHostSeverityLevel: + in: query + name: host_severity_levels + required: false + description: "Filter the resources by host severity levels" + schema: + type: array + items: + type: integer + example: '[50, 75]' + ResourceFilterServiceSeverityLevel: + in: query + name: service_severity_levels + required: false + description: "Filter the resources by service severity levels" + schema: + type: array + items: + type: integer + example: '[50, 75]' ResourceFilterMonitoringServerName: in: query name: monitoring_server_names @@ -6038,11 +6154,6 @@ components: type: boolean description: "Indicates whether resource is acknowledged" example: false - severity_level: - type: integer - nullable: true - description: "level of the severity" - example: 1 duration: type: string nullable: true @@ -6479,6 +6590,39 @@ components: type: string description: "Name of the service group" example: "MySG" + Monitoring.Severity: + type: object + properties: + id: + type: integer + format: int64 + description: "ID of the severity" + example: 13 + name: + type: string + description: "Name of the severity" + example: "severity-name" + level: + type: integer + format: int64 + description: "Level defined for the severity" + example: 50 + type: + type: string + enum: [host, service] + description: "Type of the severity" + example: "host|service" + icon: + type: object + properties: + name: + type: string + description: "Name of the icon" + example: "centreon.png" + url: + type: string + description: "URL of the icon" + example: "img/centreon.png" Monitoring.ServiceMin: type: object properties: diff --git a/lang/es_ES.UTF-8/LC_MESSAGES/messages.po b/lang/es_ES.UTF-8/LC_MESSAGES/messages.po index 0224128058d..1495dc53c7a 100644 --- a/lang/es_ES.UTF-8/LC_MESSAGES/messages.po +++ b/lang/es_ES.UTF-8/LC_MESSAGES/messages.po @@ -15171,3 +15171,15 @@ msgstr "Se ha producido un error al recuperar los categorías de hosts" # msgid "Warning, maximum size exceeded for input '%s' (max: %d), it will be truncated upon saving" # msgstr "" + +msgid "Service severity" +msgstr "Criticidad del servicio" + +msgid "Service severity level" +msgstr "Nivel de criticidad del servicio" + +msgid "Host severity" +msgstr "Criticidad del host" + +msgid "Host severity level" +msgstr "Nivel de criticidad del host" \ No newline at end of file diff --git a/lang/fr_FR.UTF-8/LC_MESSAGES/messages.po b/lang/fr_FR.UTF-8/LC_MESSAGES/messages.po index 1445913e5f2..16415736deb 100644 --- a/lang/fr_FR.UTF-8/LC_MESSAGES/messages.po +++ b/lang/fr_FR.UTF-8/LC_MESSAGES/messages.po @@ -16958,3 +16958,15 @@ msgstr "Les informations de version de la base de données n'ont pas pu être r msgid "MariaDB version %s required (%s installed)" msgstr "La version %s de MariaDB est requise (%s installée)" + +msgid "Service severity" +msgstr "Criticité du service" + +msgid "Service severity level" +msgstr "Niveau de criticité du service" + +msgid "Host severity" +msgstr "Criticité d'hôte" + +msgid "Host severity level" +msgstr "Niveau de criticité d'hôte" diff --git a/lang/pt_BR.UTF-8/LC_MESSAGES/messages.po b/lang/pt_BR.UTF-8/LC_MESSAGES/messages.po index 44a04b7cf01..4abac3ccb40 100644 --- a/lang/pt_BR.UTF-8/LC_MESSAGES/messages.po +++ b/lang/pt_BR.UTF-8/LC_MESSAGES/messages.po @@ -15622,3 +15622,15 @@ msgstr "Ocorreu um erro durante a recuperação das categorias de hosts" # msgid "Warning, maximum size exceeded for input '%s' (max: %d), it will be truncated upon saving" # msgstr "" + +msgid "Service severity" +msgstr "Severidade de serviço" + +msgid "Service severity level" +msgstr "Nível de Severidade de serviço" + +msgid "Host severity" +msgstr "Severidade de host" + +msgid "Host severity level" +msgstr "Nível de Severidade de host" diff --git a/lang/pt_PT.UTF-8/LC_MESSAGES/messages.po b/lang/pt_PT.UTF-8/LC_MESSAGES/messages.po index 6b3deb08e42..0e63ac7490e 100644 --- a/lang/pt_PT.UTF-8/LC_MESSAGES/messages.po +++ b/lang/pt_PT.UTF-8/LC_MESSAGES/messages.po @@ -15610,3 +15610,15 @@ msgstr "Se ha producido un error al recuperar los categorías de hosts" # msgid "Warning, maximum size exceeded for input '%s' (max: %d), it will be truncated upon saving" # msgstr "" + +msgid "Service severity" +msgstr "Severidade de serviço" + +msgid "Service severity level" +msgstr "Nível de Severidade de serviço" + +msgid "Host severity" +msgstr "Severidade de host" + +msgid "Host severity level" +msgstr "Nível de Severidade de host" diff --git a/src/Centreon/Application/Controller/MonitoringResourceController.php b/src/Centreon/Application/Controller/MonitoringResourceController.php index 5b78736b859..e8ef963dd12 100644 --- a/src/Centreon/Application/Controller/MonitoringResourceController.php +++ b/src/Centreon/Application/Controller/MonitoringResourceController.php @@ -31,6 +31,8 @@ use Symfony\Component\HttpFoundation\Request; use Centreon\Domain\Monitoring\ResourceFilter; use Centreon\Domain\Monitoring\ResourceStatus; +use Core\Severity\RealTime\Domain\Model\Severity; +use Core\Domain\RealTime\Model\Icon as NewIconModel; use Centreon\Application\Normalizer\IconUrlNormalizer; use JMS\Serializer\Exception\ValidationFailedException; use Centreon\Domain\RequestParameters\RequestParameters; @@ -62,6 +64,10 @@ class MonitoringResourceController extends AbstractController 'monitoring_server_names', 'service_category_names', 'host_category_names', + 'service_severity_names', + 'host_severity_names', + 'host_severity_levels', + 'service_severity_levels', 'status_types', ]; @@ -123,10 +129,14 @@ class MonitoringResourceController extends AbstractController ResourceEntity::SERIALIZER_GROUP_PARENT, Icon::SERIALIZER_GROUP_MAIN, ResourceStatus::SERIALIZER_GROUP_MAIN, + self::ICON_GROUP_MAIN, + self::SEVERITY_GROUP_MAIN, ]; // Groups for validation public const VALIDATION_GROUP_MAIN = 'resource_id_main'; + public const SEVERITY_GROUP_MAIN = 'severity_main'; + public const ICON_GROUP_MAIN = 'core_icon_main'; /** * @var ResourceServiceInterface @@ -239,6 +249,10 @@ public function list( $this->iconUrlNormalizer->normalize($resource->getParent()->getIcon()); } + if ($resource->getSeverity() !== null && $resource->getSeverity()->getIcon() instanceof NewIconModel) { + $this->iconUrlNormalizer->normalize($resource->getSeverity()->getIcon()); + } + // add shortcuts $this->provideLinks($resource, $contact); } diff --git a/src/Centreon/Domain/Common/Assertion/AssertionException.php b/src/Centreon/Domain/Common/Assertion/AssertionException.php index 32c90e64057..4d16219826d 100644 --- a/src/Centreon/Domain/Common/Assertion/AssertionException.php +++ b/src/Centreon/Domain/Common/Assertion/AssertionException.php @@ -212,12 +212,12 @@ public static function notNull(string $propertyPath = null): self /** * Exception when the value is not expected. * - * @param string|null $propertyPath Property's path (ex: Host::name) - * @param string $value + * @param mixed $value * @param mixed[] $expectedValues + * @param string|null $propertyPath Property's path (ex: Host::name) * @return self */ - public static function inArray(string $value, array $expectedValues, string $propertyPath = null): self + public static function inArray($value, array $expectedValues, string $propertyPath = null): self { return new self( sprintf( diff --git a/src/Centreon/Domain/Monitoring/Resource.php b/src/Centreon/Domain/Monitoring/Resource.php index 7687f74adff..879e52c9220 100644 --- a/src/Centreon/Domain/Monitoring/Resource.php +++ b/src/Centreon/Domain/Monitoring/Resource.php @@ -28,6 +28,7 @@ use Centreon\Domain\Monitoring\ResourceGroup; use Centreon\Domain\Monitoring\ResourceLinks; use Centreon\Domain\Monitoring\ResourceStatus; +use Core\Severity\RealTime\Domain\Model\Severity; use Centreon\Domain\Acknowledgement\Acknowledgement; /** @@ -56,6 +57,11 @@ class Resource public const TYPE_HOST = 'host'; public const TYPE_META = 'metaservice'; + /** + * @var int|null + */ + private $resourceId; + /** * @var int|null */ @@ -161,11 +167,6 @@ class Resource */ private $links; - /** - * @var int|null - */ - private $severityLevel; - /** * @var string|null */ @@ -267,6 +268,11 @@ class Resource */ private $hasGraph = false; + /** + * @var Severity|null + */ + private $severity; + /** * Resource constructor. */ @@ -726,25 +732,6 @@ public function setLinks(ResourceLinks $links): self return $this; } - /** - * @return int|null - */ - public function getSeverityLevel(): ?int - { - return $this->severityLevel; - } - - /** - * @param int|null $severityLevel - * @return \Centreon\Domain\Monitoring\Resource - */ - public function setSeverityLevel(?int $severityLevel): self - { - $this->severityLevel = $severityLevel; - - return $this; - } - /** * @return string|null */ @@ -1104,4 +1091,42 @@ public function hasGraph(): bool { return $this->hasGraph; } + + /** + * @param integer|null $resourceId + * @return self + */ + public function setResourceId(?int $resourceId): self + { + $this->resourceId = $resourceId; + + return $this; + } + + /** + * @return integer|null + */ + public function getResourceId(): ?int + { + return $this->resourceId; + } + + /** + * @param Severity|null $severity + * @return self + */ + public function setSeverity(?Severity $severity): self + { + $this->severity = $severity; + + return $this; + } + + /** + * @return Severity|null + */ + public function getSeverity(): ?Severity + { + return $this->severity; + } } diff --git a/src/Centreon/Domain/Monitoring/ResourceFilter.php b/src/Centreon/Domain/Monitoring/ResourceFilter.php index 9aea46c9740..4701c4dd74f 100644 --- a/src/Centreon/Domain/Monitoring/ResourceFilter.php +++ b/src/Centreon/Domain/Monitoring/ResourceFilter.php @@ -158,6 +158,26 @@ class ResourceFilter */ private $statusTypes = []; + /** + * @var string[] + */ + private array $serviceSeverityNames = []; + + /** + * @var string[] + */ + private array $hostSeverityNames = []; + + /** + * @var int[] + */ + private array $serviceSeverityLevels = []; + + /** + * @var int[] + */ + private array $hostSeverityLevels = []; + /** * Transform result by map * @@ -439,6 +459,18 @@ public function setStatusTypes(array $statusTypes): self public function setServiceCategoryNames(array $serviceCategoryNames): self { $this->serviceCategoryNames = $serviceCategoryNames; + + return $this; + } + + /** + * @param string[] $serviceSeverityNames + * @return self + */ + public function setServiceSeverityNames(array $serviceSeverityNames): self + { + $this->serviceSeverityNames = $serviceSeverityNames; + return $this; } @@ -457,6 +489,26 @@ public function getServiceCategoryNames(): array public function setHostCategoryNames(array $hostCategoryNames): self { $this->hostCategoryNames = $hostCategoryNames; + + return $this; + } + + /** + * @return array + */ + public function getServiceSeverityNames(): array + { + return $this->serviceSeverityNames; + } + + /** + * @param string[] $hostSeverityNames + * @return self + */ + public function setHostSeverityNames(array $hostSeverityNames): self + { + $this->hostSeverityNames = $hostSeverityNames; + return $this; } @@ -467,4 +519,50 @@ public function getHostCategoryNames(): array { return $this->hostCategoryNames; } + + /** + * @return string[] + */ + public function getHostSeverityNames(): array + { + return $this->hostSeverityNames; + } + + /** + * @param int[] $serviceSeverityLevels + * @return self + */ + public function setServiceSeverityLevels(array $serviceSeverityLevels): self + { + $this->serviceSeverityLevels = $serviceSeverityLevels; + + return $this; + } + + /** + * @return int[] + */ + public function getServiceSeverityLevels(): array + { + return $this->serviceSeverityLevels; + } + + /** + * @param int[] $hostSeverityLevels + * @return self + */ + public function setHostSeverityLevels(array $hostSeverityLevels): self + { + $this->hostSeverityLevels = $hostSeverityLevels; + + return $this; + } + + /** + * @return int[] + */ + public function getHostSeverityLevels(): array + { + return $this->hostSeverityLevels; + } } diff --git a/src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php b/src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php index 3e6f0c15b6c..a47e7bc3b0b 100644 --- a/src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php +++ b/src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php @@ -36,11 +36,18 @@ use Centreon\Domain\Monitoring\Interfaces\ResourceRepositoryInterface; use Centreon\Infrastructure\RequestParameters\SqlRequestParametersTranslator; use Centreon\Infrastructure\RequestParameters\RequestParametersTranslatorException; +use Core\Infrastructure\RealTime\Repository\Icon\DbIconFactory; +use Core\Severity\RealTime\Domain\Model\Severity; class DbReadResourceRepository extends AbstractRepositoryDRB implements ResourceRepositoryInterface { use LoggerTrait; + /** + * @var ResourceEntity[] + */ + private array $resources = []; + private const RESOURCE_TYPE_SERVICE = 0, RESOURCE_TYPE_HOST = 1, RESOURCE_TYPE_METASERVICE = 2; @@ -134,10 +141,10 @@ public function filterByAccessGroups(?array $accessGroups): ResourceRepositoryIn */ public function findResources(ResourceFilter $filter): array { - $resources = []; + $this->resources = []; if ($this->hasNotEnoughRightsToContinue()) { - return $resources; + return $this->resources; } $collector = new StatementCollector(); @@ -156,7 +163,11 @@ public function findResources(ResourceFilter $filter): array parent_resource.status AS `parent_status`, parent_resource.alias AS `parent_alias`, parent_resource.status_ordered AS `parent_status_ordered`, + severities.id AS `severity_id`, severities.level AS `severity_level`, + severities.name AS `severity_name`, + severities.type AS `severity_type`, + severities.icon_id AS `severity_icon_id`, resources.type, resources.status, resources.status_ordered, @@ -178,7 +189,8 @@ public function findResources(ResourceFilter $filter): array resources.has_graph, instances.name AS `monitoring_server_name`, resources.enabled, - resources.icon_id + resources.icon_id, + resources.severity_id FROM `:dbstg`.`resources` LEFT JOIN `:dbstg`.`resources` parent_resource ON parent_resource.id = resources.parent_id @@ -255,6 +267,11 @@ function (AccessGroup $accessGroup) { */ $request .= $this->addMonitoringServerSubRequest($filter, $collector); + /** + * Severity filter (levels and/or names) + */ + $request .= $this->addSeveritySubRequest($filter, $collector); + /** * Resource tag filter by name * - servicegroups @@ -293,15 +310,204 @@ function (AccessGroup $accessGroup) { } while ($resourceRecord = $statement->fetch(\PDO::FETCH_ASSOC)) { - $resources[] = DbResourceFactory::createFromRecord($resourceRecord); + $this->resources[] = DbResourceFactory::createFromRecord($resourceRecord); } - /** - * Loop on resources on a private method to get icon ids and add them to the entity - */ - $resources = $this->getIconsForResources($resources); + $iconIds = $this->getIconIdsFromResources(); + $icons = $this->getIconsDataForResources($iconIds); + $this->completeResourcesWithIcons($icons); + + return $this->resources; + } + + /** + * @param array> $icons + * @return void + */ + private function completeResourcesWithIcons(array $icons): void + { + foreach ($this->resources as $resource) { + if ($resource->getIcon() !== null) { + $resourceIconId = $resource->getIcon()->getId(); + $resource->getIcon() + ->setName($icons[$resourceIconId]['name']) + ->setUrl($icons[$resourceIconId]['url']); + } + + if ($resource->getSeverity() !== null) { + $resourceSeverityIconId = $resource->getSeverity()->getIcon()->getId(); + $resource->getSeverity()->getIcon() + ->setName($icons[$resourceSeverityIconId]['name']) + ->setUrl($icons[$resourceSeverityIconId]['url']); + } + } + } + + /** + * @return array + */ + private function getIconIdsFromResources(): array + { + $resourceIconIds = $this->getResourceIconIdsFromResources(); + $severityIconIds = $this->getSeverityIconIdsFromResources(); + + return array_unique(array_merge($resourceIconIds, $severityIconIds)); + } + + /** + * @return array + */ + private function getResourceIconIdsFromResources(): array + { + $resourcesWithIcons = array_filter( + $this->resources, + fn (ResourceEntity $resource) => $resource->getIcon() !== null + ); + + return array_map( + fn (ResourceEntity $resource) => $resource->getIcon()?->getId(), + $resourcesWithIcons + ); + } + + /** + * @return array + */ + private function getSeverityIconIdsFromResources(): array + { + $resourcesWithSeverities = array_filter( + $this->resources, + fn (ResourceEntity $resource) => $resource->getSeverity() !== null + ); + + return array_map( + fn (ResourceEntity $resource) => $resource->getSeverity()?->getIcon()?->getId(), + $resourcesWithSeverities + ); + } + + /** + * @param ResourceFilter $filter + * @return int[] + */ + private function getSeverityLevelsFromFilter(ResourceFilter $filter): array + { + $levels = []; + if (! empty($filter->getHostSeverityLevels())) { + foreach ($filter->getHostSeverityLevels() as $level) { + $levels[] = $level; + } + } + + if (! empty($filter->getServiceSeverityLevels())) { + foreach ($filter->getServiceSeverityLevels() as $level) { + $levels[] = $level; + } + } + return array_unique($levels); + } + + /** + * @param ResourceFilter $filter + * @return int[] + */ + private function getSeverityTypesFromFilter(ResourceFilter $filter): array + { + $types = []; + if ( + ! empty($filter->getHostSeverityLevels()) + || ! empty($filter->getHostSeverityNames()) + ) { + $types[] = Severity::HOST_SEVERITY_TYPE_ID; + } + + if ( + ! empty($filter->getServiceSeverityLevels()) + || ! empty($filter->getServiceSeverityNames()) + ) { + $types[] = Severity::SERVICE_SEVERITY_TYPE_ID; + } + + return $types; + } + + /** + * @param ResourceFilter $filter + * @return string[] + */ + private function getSeverityNamesFromFilter(ResourceFilter $filter): array + { + $names = []; + if (! empty($filter->getHostSeverityNames())) { + foreach ($filter->getHostSeverityNames() as $hostSeverityName) { + $names[] = $hostSeverityName; + } + } + + if (! empty($filter->getServiceSeverityNames())) { + foreach ($filter->getServiceSeverityNames() as $serviceSeverityName) { + $names[] = $serviceSeverityName; + } + } + + return array_unique($names); + } + + /** + * @param ResourceFilter $filter + * @param StatementCollector $collector + * @return string + */ + private function addSeveritySubRequest(ResourceFilter $filter, StatementCollector $collector): string + { + $subRequest = ''; + $filteredNames = []; + $filteredTypes = []; + $filteredLevels = []; + + $names = $this->getSeverityNamesFromFilter($filter); + $levels = $this->getSeverityLevelsFromFilter($filter); + $types = $this->getSeverityTypesFromFilter($filter); + + foreach ($names as $index => $name) { + $key = ":severityName_{$index}"; + $filteredNames[] = $key; + $collector->addValue($key, $name, \PDO::PARAM_STR); + } + + foreach ($levels as $index => $level) { + $key = ":severityLevel_{$index}"; + $filteredLevels[] = $key; + $collector->addValue($key, $level, \PDO::PARAM_INT); + } + + foreach ($types as $index => $type) { + $key = ":severityType_{$index}"; + $filteredTypes[] = $key; + $collector->addValue($key, $type, \PDO::PARAM_INT); + } + + if ( + ! empty($filteredNames) + || ! empty($filteredLevels) + ) { + $subRequest = ' AND EXISTS ( + SELECT 1 FROM `:dbstg`.severities + WHERE severities.severity_id = resources.severity_id + AND severities.type IN (' . implode(', ', $filteredTypes) . ')'; - return $resources; + $subRequest .= ! empty($filteredNames) + ? ' AND severities.name IN (' . implode(', ', $filteredNames) . ')' + : ''; + + $subRequest .= ! empty($filteredLevels) + ? ' AND severities.level IN (' . implode(', ', $filteredLevels) . ')' + : ''; + + $subRequest .= ' LIMIT 1)'; + } + + return $subRequest; } /** @@ -535,18 +741,12 @@ private function addMonitoringServerSubRequest(ResourceFilter $filter, Statement /** * Get icons for resources * - * @param ResourceEntity[] $resources - * @return ResourceEntity[] + * @param array $iconIds + * @return array> */ - private function getIconsForResources(array $resources): array + private function getIconsDataForResources(array $iconIds): array { - $iconIds = []; - foreach ($resources as $index => $resource) { - if ($resource->getIcon() !== null) { - $iconIds[$index] = $resource->getIcon()->getId(); - } - } - + $icons = []; if (! empty($iconIds)) { $request = 'SELECT img_id AS `icon_id`, @@ -564,16 +764,13 @@ private function getIconsForResources(array $resources): array $statement->execute(array_values($iconIds)); while ($record = $statement->fetch(\PDO::FETCH_ASSOC)) { - $resourceIndexes = array_keys($iconIds, (int) $record['icon_id']); - - foreach ($resourceIndexes as $resourceIndex) { - $resources[$resourceIndex]->getIcon() - ?->setName($record['icon_name']) - ->setUrl($record['icon_directory'] . DIRECTORY_SEPARATOR . $record['icon_path']); - } + $icons[(int) $record['icon_id']] = [ + 'name' => $record['icon_name'], + 'url' => $record['icon_directory'] . DIRECTORY_SEPARATOR . $record['icon_path'] + ]; } } - return $resources; + return $icons; } } diff --git a/src/Centreon/Infrastructure/Monitoring/Resource/DbResourceFactory.php b/src/Centreon/Infrastructure/Monitoring/Resource/DbResourceFactory.php index 12429634493..ee21ea04407 100644 --- a/src/Centreon/Infrastructure/Monitoring/Resource/DbResourceFactory.php +++ b/src/Centreon/Infrastructure/Monitoring/Resource/DbResourceFactory.php @@ -22,9 +22,11 @@ namespace Centreon\Infrastructure\Monitoring\Resource; -use Centreon\Domain\Monitoring\Icon; +use Core\Domain\RealTime\Model\Icon; use Centreon\Domain\Monitoring\Notes; use Centreon\Domain\Monitoring\ResourceStatus; +use Core\Severity\RealTime\Domain\Model\Severity; +use Centreon\Domain\Monitoring\Icon as LegacyIconModel; use Centreon\Domain\Monitoring\Resource as ResourceEntity; use Core\Infrastructure\Common\Repository\DbFactoryUtilitiesTrait; @@ -69,6 +71,21 @@ public static function createFromRecord(array $record): ResourceEntity $tries = $record['check_attempts'] . '/' . $record['max_check_attempts'] . ' (' . $statusConfirmedAsString . ')'; + + $severity = null; + if (! empty($record['severity_id'])) { + $severityIcon = (new Icon()) + ->setId((int) $record['severity_icon_id']); + + $severity = new Severity( + (int) $record['severity_id'], + $record['severity_name'], + (int) $record['severity_level'], + (int) $record['severity_type'], + $severityIcon + ); + } + $resource = (new ResourceEntity()) ->setType($resourceType) ->setParent($parent) @@ -92,7 +109,7 @@ public static function createFromRecord(array $record): ResourceEntity ->setMonitoringServerName($record['monitoring_server_name']) ->setLastStatusChange(self::createDateTimeFromTimestamp((int) $record['last_status_change'])) ->setHasGraph((int) $record['has_graph'] === 1) - ->setSeverityLevel((int) $record['severity_level']); + ->setSeverity($severity); /** * Handle special case of Meta Service resource type @@ -107,7 +124,7 @@ public static function createFromRecord(array $record): ResourceEntity $resource->getLinks()->getExternals()->setNotes($notes); if (empty($record['icon_id']) === false) { - $resource->setIcon((new Icon())->setId((int) $record['icon_id'])); + $resource->setIcon((new LegacyIconModel())->setId((int) $record['icon_id'])); } return $resource; diff --git a/src/Core/Application/RealTime/Common/RealTimeResponseTrait.php b/src/Core/Application/RealTime/Common/RealTimeResponseTrait.php index f181ece7f6d..d50ace16e47 100644 --- a/src/Core/Application/RealTime/Common/RealTimeResponseTrait.php +++ b/src/Core/Application/RealTime/Common/RealTimeResponseTrait.php @@ -27,6 +27,7 @@ use Core\Tag\RealTime\Domain\Model\Tag; use Core\Domain\RealTime\Model\Downtime; use Core\Domain\RealTime\Model\Acknowledgement; +use Core\Severity\RealTime\Domain\Model\Severity; trait RealTimeResponseTrait { @@ -51,13 +52,14 @@ private function tagsToArray(array $tags): array * Converts an Icon model into an array * * @param Icon|null $icon - * @return array + * @return array */ public function iconToArray(?Icon $icon): array { return is_null($icon) ? [] : [ + 'id' => $icon->getId(), 'name' => $icon->getName(), 'url' => $icon->getUrl() ]; @@ -139,4 +141,21 @@ private function statusToArray(Status $status): array 'type' => $status->getType() ]; } + + /** + * Converts Severity model into an array for DTO + * + * @param Severity $severity + * @return array + */ + private function severityToArray(Severity $severity): array + { + return [ + 'id' => $severity->getId(), + 'name' => $severity->getName(), + 'level' => $severity->getLevel(), + 'type' => $severity->getTypeAsString(), + 'icon' => $this->iconToArray($severity->getIcon()) + ]; + } } diff --git a/src/Core/Application/RealTime/UseCase/FindHost/FindHost.php b/src/Core/Application/RealTime/UseCase/FindHost/FindHost.php index d410f376497..62926736943 100644 --- a/src/Core/Application/RealTime/UseCase/FindHost/FindHost.php +++ b/src/Core/Application/RealTime/UseCase/FindHost/FindHost.php @@ -28,6 +28,7 @@ use Core\Tag\RealTime\Domain\Model\Tag; use Core\Domain\RealTime\Model\Downtime; use Core\Domain\RealTime\Model\Acknowledgement; +use Core\Severity\RealTime\Domain\Model\Severity; use Centreon\Domain\Monitoring\Host as LegacyHost; use Core\Application\Common\UseCase\NotFoundResponse; use Centreon\Domain\Contact\Interfaces\ContactInterface; @@ -40,6 +41,7 @@ use Core\Application\RealTime\UseCase\FindHost\FindHostPresenterInterface; use Core\Security\Application\Repository\ReadAccessGroupRepositoryInterface; use Core\Application\RealTime\Repository\ReadAcknowledgementRepositoryInterface; +use Core\Severity\RealTime\Application\Repository\ReadSeverityRepositoryInterface; class FindHost { @@ -54,6 +56,7 @@ class FindHost * @param ReadAcknowledgementRepositoryInterface $acknowledgementRepository * @param MonitoringServiceInterface $monitoringService * @param ReadTagRepositoryInterface $tagRepository + * @param ReadSeverityRepositoryInterface $severityRepository */ public function __construct( private ReadHostRepositoryInterface $repository, @@ -64,6 +67,7 @@ public function __construct( private ReadAcknowledgementRepositoryInterface $acknowledgementRepository, private MonitoringServiceInterface $monitoringService, private ReadTagRepositoryInterface $tagRepository, + private ReadSeverityRepositoryInterface $severityRepository ) { } @@ -110,6 +114,22 @@ public function __invoke(int $hostId, FindHostPresenterInterface $presenter): vo $host->setCategories($categories); + $this->info( + 'Fetching severity from the database for host', + [ + 'hostId' => $hostId, + 'typeId' => Severity::HOST_SEVERITY_TYPE_ID + ] + ); + + $severity = $this->severityRepository->findByResourceAndTypeId( + $hostId, + 0, + Severity::HOST_SEVERITY_TYPE_ID + ); + + $host->setSeverity($severity); + /** * Obfuscate the passwords in Host commandLine * @todo Re-write this code when monitoring repository will be migrated to new architecture @@ -163,6 +183,7 @@ private function createResponse(Host $host, array $downtimes, ?Acknowledgement $ $downtimes, $acknowledgement, $host->getCategories(), + $host->getSeverity() ); $findHostResponse->timezone = $host->getTimezone(); @@ -184,7 +205,6 @@ private function createResponse(Host $host, array $downtimes, ?Acknowledgement $ $findHostResponse->hasPassiveChecks = $host->hasPassiveChecks(); $findHostResponse->hasActiveChecks = $host->hasActiveChecks(); $findHostResponse->lastTimeUp = $host->getLastTimeUp(); - $findHostResponse->severityLevel = $host->getSeverityLevel(); $findHostResponse->checkAttempts = $host->getCheckAttempts(); $findHostResponse->maxCheckAttempts = $host->getMaxCheckAttempts(); diff --git a/src/Core/Application/RealTime/UseCase/FindHost/FindHostResponse.php b/src/Core/Application/RealTime/UseCase/FindHost/FindHostResponse.php index b1c73fdba88..b9a1c5be3d9 100644 --- a/src/Core/Application/RealTime/UseCase/FindHost/FindHostResponse.php +++ b/src/Core/Application/RealTime/UseCase/FindHost/FindHostResponse.php @@ -28,6 +28,7 @@ use Core\Domain\RealTime\Model\Hostgroup; use Core\Domain\RealTime\Model\HostStatus; use Core\Domain\RealTime\Model\Acknowledgement; +use Core\Severity\RealTime\Domain\Model\Severity; use Core\Application\RealTime\Common\RealTimeResponseTrait; class FindHostResponse @@ -129,11 +130,6 @@ class FindHostResponse */ public $lastTimeUp; - /** - * @var int|null - */ - public $severityLevel; - /** * @var int|null */ @@ -172,7 +168,12 @@ class FindHostResponse /** * @var array> */ - public $categories; + public array $categories = []; + + /** + * @var array|null + */ + public ?array $severity = null; /** * @param int $id @@ -185,6 +186,7 @@ class FindHostResponse * @param Downtime[] $downtimes * @param Acknowledgement|null $acknowledgement, * @param Tag[] $categories + * @param Severity|null $severity */ public function __construct( public int $id, @@ -197,6 +199,7 @@ public function __construct( array $downtimes, ?Acknowledgement $acknowledgement, array $categories, + ?Severity $severity ) { $this->icon = $this->iconToArray($icon); $this->status = $this->statusToArray($status); @@ -204,6 +207,7 @@ public function __construct( $this->downtimes = $this->downtimesToArray($downtimes); $this->acknowledgement = $this->acknowledgementToArray($acknowledgement); $this->categories = $this->tagsToArray($categories); + $this->severity = is_null($severity) ? $severity : $this->severityToArray($severity); } /** diff --git a/src/Core/Application/RealTime/UseCase/FindService/FindService.php b/src/Core/Application/RealTime/UseCase/FindService/FindService.php index 6793fddd259..48786ee5a91 100644 --- a/src/Core/Application/RealTime/UseCase/FindService/FindService.php +++ b/src/Core/Application/RealTime/UseCase/FindService/FindService.php @@ -29,6 +29,7 @@ use Core\Tag\RealTime\Domain\Model\Tag; use Core\Domain\RealTime\Model\Downtime; use Core\Domain\RealTime\Model\Acknowledgement; +use Core\Severity\RealTime\Domain\Model\Severity; use Centreon\Domain\Monitoring\Host as LegacyHost; use Core\Application\Common\UseCase\NotFoundResponse; use Core\Security\Domain\AccessGroup\Model\AccessGroup; @@ -44,6 +45,7 @@ use Core\Application\RealTime\Repository\ReadServicegroupRepositoryInterface; use Core\Application\RealTime\Repository\ReadAcknowledgementRepositoryInterface; use Core\Application\RealTime\UseCase\FindService\FindServicePresenterInterface; +use Core\Severity\RealTime\Application\Repository\ReadSeverityRepositoryInterface; class FindService { @@ -70,6 +72,7 @@ public function __construct( private ReadAcknowledgementRepositoryInterface $acknowledgementRepository, private MonitoringServiceInterface $monitoringService, private ReadTagRepositoryInterface $tagRepository, + private ReadSeverityRepositoryInterface $severityRepository ) { } @@ -147,6 +150,23 @@ public function __invoke( $service->setCategories($serviceCategories); + $this->info( + 'Fetching severity from the database for service', + [ + 'hostId' => $hostId, + 'serviceId' => $serviceId, + 'typeId' => Severity::SERVICE_SEVERITY_TYPE_ID + ] + ); + + $severity = $this->severityRepository->findByResourceAndTypeId( + $serviceId, + $hostId, + Severity::SERVICE_SEVERITY_TYPE_ID + ); + + $service->setSeverity($severity); + /** * Obfuscate the passwords in Service commandLine */ @@ -225,6 +245,7 @@ public function createResponse( $acknowledgement, $host, $service->getCategories(), + $service->getSeverity() ); $findServiceResponse->isFlapping = $service->isFlapping(); @@ -244,7 +265,6 @@ public function createResponse( $findServiceResponse->hasPassiveChecks = $service->hasPassiveChecks(); $findServiceResponse->hasActiveChecks = $service->hasActiveChecks(); $findServiceResponse->lastTimeOk = $service->getLastTimeOk(); - $findServiceResponse->severityLevel = $service->getSeverityLevel(); $findServiceResponse->checkAttempts = $service->getCheckAttempts(); $findServiceResponse->maxCheckAttempts = $service->getMaxCheckAttempts(); $findServiceResponse->hasGraphData = $service->hasGraphData(); diff --git a/src/Core/Application/RealTime/UseCase/FindService/FindServiceResponse.php b/src/Core/Application/RealTime/UseCase/FindService/FindServiceResponse.php index 6c1425f7950..0d2041f6cb8 100644 --- a/src/Core/Application/RealTime/UseCase/FindService/FindServiceResponse.php +++ b/src/Core/Application/RealTime/UseCase/FindService/FindServiceResponse.php @@ -29,6 +29,7 @@ use Core\Domain\RealTime\Model\Servicegroup; use Core\Domain\RealTime\Model\ServiceStatus; use Core\Domain\RealTime\Model\Acknowledgement; +use Core\Severity\RealTime\Domain\Model\Severity; use Core\Application\RealTime\Common\RealTimeResponseTrait; class FindServiceResponse @@ -120,11 +121,6 @@ class FindServiceResponse */ public $lastTimeOk; - /** - * @var int|null - */ - public $severityLevel; - /** * @var int|null */ @@ -175,6 +171,11 @@ class FindServiceResponse */ public $hasGraphData; + /** + * @var array|null + */ + public ?array $severity = null; + /** * @param int $id * @param int $hostId @@ -186,6 +187,7 @@ class FindServiceResponse * @param Acknowledgement|null $acknowledgement * @param Host $host * @param Tag[] $serviceCategories + * @param Severity|null $severity */ public function __construct( public int $id, @@ -197,7 +199,8 @@ public function __construct( array $downtimes, ?Acknowledgement $acknowledgement, Host $host, - array $serviceCategories + array $serviceCategories, + ?Severity $severity ) { $this->groups = $this->servicegroupsToArray($servicegroups); $this->status = $this->statusToArray($status); @@ -206,6 +209,7 @@ public function __construct( $this->acknowledgement = $this->acknowledgementToArray($acknowledgement); $this->host = $this->hostToArray($host); $this->categories = $this->tagsToArray($serviceCategories); + $this->severity = is_null($severity) ? $severity : $this->severityToArray($severity); } /** diff --git a/src/Core/Domain/RealTime/Model/Host.php b/src/Core/Domain/RealTime/Model/Host.php index 2da4aed5bcd..1668225f49d 100644 --- a/src/Core/Domain/RealTime/Model/Host.php +++ b/src/Core/Domain/RealTime/Model/Host.php @@ -27,6 +27,7 @@ use Core\Domain\RealTime\Model\Hostgroup; use Core\Domain\RealTime\Model\HostStatus; use Centreon\Domain\Common\Assertion\Assertion; +use Core\Severity\RealTime\Domain\Model\Severity; /** * Class representing a host entity in real time context. @@ -139,11 +140,6 @@ class Host */ private $lastTimeUp; - /** - * @var int|null - */ - private $severityLevel; - /** * @var Hostgroup[] */ @@ -169,6 +165,11 @@ class Host */ private array $categories = []; + /** + * @var Severity|null + */ + private ?Severity $severity; + /** * Host constructor * @@ -589,24 +590,6 @@ public function getLastTimeUp(): ?\DateTime return $this->lastTimeUp; } - /** - * @param int|null $severityLevel - * @return self - */ - public function setSeverityLevel(?int $severityLevel): self - { - $this->severityLevel = $severityLevel; - return $this; - } - - /** - * @return int|null - */ - public function getSeverityLevel(): ?int - { - return $this->severityLevel; - } - /** * @param Hostgroup $group * @return self @@ -734,4 +717,24 @@ public function setGroups(array $groups): self return $this; } + + /** + * @param Severity|null $severity + * @return self + * @throws \TypeError + */ + public function setSeverity(?Severity $severity): self + { + $this->severity = $severity; + + return $this; + } + + /** + * @return Severity|null + */ + public function getSeverity(): ?Severity + { + return $this->severity; + } } diff --git a/src/Core/Domain/RealTime/Model/Icon.php b/src/Core/Domain/RealTime/Model/Icon.php index d334bcc7fb5..4d81da9da20 100644 --- a/src/Core/Domain/RealTime/Model/Icon.php +++ b/src/Core/Domain/RealTime/Model/Icon.php @@ -24,6 +24,11 @@ class Icon { + /** + * @var int|null + */ + private $id; + /** * @var string|null */ @@ -69,4 +74,23 @@ public function setUrl(?string $url): self $this->url = $url; return $this; } + + /** + * @param integer|null $id + * @return self + */ + public function setId(?int $id): self + { + $this->id = $id; + + return $this; + } + + /** + * @return integer|null + */ + public function getId(): ?int + { + return $this->id; + } } diff --git a/src/Core/Domain/RealTime/Model/Service.php b/src/Core/Domain/RealTime/Model/Service.php index 88b4d0b95ea..fb233ce6911 100644 --- a/src/Core/Domain/RealTime/Model/Service.php +++ b/src/Core/Domain/RealTime/Model/Service.php @@ -27,6 +27,7 @@ use Core\Domain\RealTime\Model\Servicegroup; use Core\Domain\RealTime\Model\ServiceStatus; use Centreon\Domain\Common\Assertion\Assertion; +use Core\Severity\RealTime\Domain\Model\Severity; class Service { @@ -122,11 +123,6 @@ class Service */ private $lastTimeOk; - /** - * @var int|null - */ - private $severityLevel; - /** * @var Icon|null */ @@ -157,6 +153,11 @@ class Service */ private array $categories = []; + /** + * @var Severity|null + */ + private ?Severity $severity; + /** * @param int $id * @param int $hostId @@ -541,24 +542,6 @@ public function getLastTimeOk(): ?\DateTime return $this->lastTimeOk; } - /** - * @param int|null $severityLevel - * @return self - */ - public function setSeverityLevel(?int $severityLevel): self - { - $this->severityLevel = $severityLevel; - return $this; - } - - /** - * @return int|null - */ - public function getSeverityLevel(): ?int - { - return $this->severityLevel; - } - /** * * @param ?Icon $icon @@ -687,4 +670,24 @@ public function setGroups(array $groups): self return $this; } + + /** + * @param Severity|null $severity + * @return self + * @throws \TypeError + */ + public function setSeverity(?Severity $severity): self + { + $this->severity = $severity; + + return $this; + } + + /** + * @return Severity|null + */ + public function getSeverity(): ?Severity + { + return $this->severity; + } } diff --git a/src/Core/Infrastructure/RealTime/Api/FindHost/FindHostPresenter.php b/src/Core/Infrastructure/RealTime/Api/FindHost/FindHostPresenter.php index fb19787a6b2..a4a64c9e51a 100644 --- a/src/Core/Infrastructure/RealTime/Api/FindHost/FindHostPresenter.php +++ b/src/Core/Infrastructure/RealTime/Api/FindHost/FindHostPresenter.php @@ -28,12 +28,14 @@ use Core\Application\Common\UseCase\ResponseStatusInterface; use Core\Application\Common\UseCase\AbstractPresenter; use Core\Application\RealTime\UseCase\FindHost\FindHostPresenterInterface; +use Core\Infrastructure\Common\Api\HttpUrlTrait; use Core\Infrastructure\Common\Presenter\PresenterFormatterInterface; use Core\Infrastructure\Common\Presenter\PresenterTrait; class FindHostPresenter extends AbstractPresenter implements FindHostPresenterInterface { use PresenterTrait; + use HttpUrlTrait; /** * @var ResponseStatusInterface|null @@ -77,13 +79,21 @@ public function present(mixed $response): void 'passive_checks' => $response->hasPassiveChecks, 'execution_time' => $response->executionTime, 'active_checks' => $response->hasActiveChecks, - 'severity_level' => $response->severityLevel, 'parent' => null, 'icon' => $response->icon, 'groups' => $this->hypermediaCreator->convertGroupsForPresenter($response), - 'categories' => $this->hypermediaCreator->convertCategoriesForPresenter($response) + 'categories' => $this->hypermediaCreator->convertCategoriesForPresenter($response), + 'severity' => $response->severity, ]; + if ($presenterResponse['severity'] !== null) { + /** + * normalize the URL to the severity icon + */ + $presenterResponse['severity']['icon']['url'] = $this->getBaseUri() + . '/img/media/' . $response->severity['icon']['url']; + } + $acknowledgement = null; if (!empty($response->acknowledgement)) { @@ -153,6 +163,7 @@ public function present(mixed $response): void 'uris' => $this->hypermediaCreator->createInternalUris($response), 'endpoints' => $this->hypermediaCreator->createEndpoints($response), ]; + $this->presenterFormatter->present($presenterResponse); } diff --git a/src/Core/Infrastructure/RealTime/Api/FindService/FindServicePresenter.php b/src/Core/Infrastructure/RealTime/Api/FindService/FindServicePresenter.php index 8a47b55ab9b..516e550a270 100644 --- a/src/Core/Infrastructure/RealTime/Api/FindService/FindServicePresenter.php +++ b/src/Core/Infrastructure/RealTime/Api/FindService/FindServicePresenter.php @@ -27,12 +27,14 @@ use Core\Application\Common\UseCase\ResponseStatusInterface; use Core\Application\Common\UseCase\AbstractPresenter; use Core\Application\RealTime\UseCase\FindService\FindServicePresenterInterface; +use Core\Infrastructure\Common\Api\HttpUrlTrait; use Core\Infrastructure\Common\Presenter\PresenterFormatterInterface; use Core\Infrastructure\Common\Presenter\PresenterTrait; class FindServicePresenter extends AbstractPresenter implements FindServicePresenterInterface { use PresenterTrait; + use HttpUrlTrait; /** * @var ResponseStatusInterface|null @@ -73,14 +75,22 @@ public function present(mixed $response): void 'passive_checks' => $response->hasPassiveChecks, 'execution_time' => $response->executionTime, 'active_checks' => $response->hasActiveChecks, - 'severity_level' => $response->severityLevel, 'icon' => $response->icon, 'groups' => $this->hypermediaCreator->convertGroupsForPresenter($response), 'parent' => $response->host, 'monitoring_server_name' => $response->host['monitoring_server_name'], 'categories' => $this->hypermediaCreator->convertCategoriesForPresenter($response), + 'severity' => $response->severity, ]; + if ($presenterResponse['severity'] !== null) { + /** + * normalize the URL to the severity icon + */ + $presenterResponse['severity']['icon']['url'] = $this->getBaseUri() + . '/img/media/' . $response->severity['icon']['url']; + } + $acknowledgement = null; if (!empty($response->acknowledgement)) { diff --git a/src/Core/Infrastructure/RealTime/Repository/Host/DbHostFactory.php b/src/Core/Infrastructure/RealTime/Repository/Host/DbHostFactory.php index ee62ab4f976..f1409c51349 100644 --- a/src/Core/Infrastructure/RealTime/Repository/Host/DbHostFactory.php +++ b/src/Core/Infrastructure/RealTime/Repository/Host/DbHostFactory.php @@ -57,7 +57,6 @@ public static function createFromRecord(array $data): Host ->setLatency(self::getFloatOrNull($data['latency'])) ->setExecutionTime(self::getFloatOrNull($data['execution_time'])) ->setStatusChangePercentage(self::getFloatOrNull($data['status_change_percentage'])) - ->setSeverityLevel(self::getIntOrNull($data['severity_level'])) ->setNotificationEnabled((int) $data['notify'] === 1) ->setNotificationNumber(self::getIntOrNull($data['notification_number'])) ->setLastStatusChange(self::createDateTimeFromTimestamp((int) $data['last_status_change'])) diff --git a/src/Core/Infrastructure/RealTime/Repository/Service/DbServiceFactory.php b/src/Core/Infrastructure/RealTime/Repository/Service/DbServiceFactory.php index 89462bc22cb..c7d20028e92 100644 --- a/src/Core/Infrastructure/RealTime/Repository/Service/DbServiceFactory.php +++ b/src/Core/Infrastructure/RealTime/Repository/Service/DbServiceFactory.php @@ -54,7 +54,6 @@ public static function createFromRecord(array $data): Service ->setLatency(self::getFloatOrNull($data['latency'])) ->setExecutionTime(self::getFloatOrNull($data['execution_time'])) ->setStatusChangePercentage(self::getFloatOrNull($data['status_change_percentage'])) - ->setSeverityLevel(self::getIntOrNull($data['severity_level'])) ->setNotificationEnabled((int) $data['notify'] === 1) ->setNotificationNumber(self::getIntOrNull($data['notification_number'])) ->setLastStatusChange(self::createDateTimeFromTimestamp((int) $data['last_status_change'])) diff --git a/src/Core/Severity/RealTime/Application/Repository/ReadSeverityRepositoryInterface.php b/src/Core/Severity/RealTime/Application/Repository/ReadSeverityRepositoryInterface.php new file mode 100644 index 00000000000..d7c28b4678d --- /dev/null +++ b/src/Core/Severity/RealTime/Application/Repository/ReadSeverityRepositoryInterface.php @@ -0,0 +1,46 @@ +info('Searching for severities in the realtime', ['typeId' => $severityTypeId]); + $severities = []; + try { + $severities = $this->repository->findAllByTypeId($severityTypeId); + } catch (\Throwable $ex) { + $this->error( + 'An error occured while retrieving severities from real-time data', + [ + 'typeId' => $severityTypeId, + 'trace' => $ex->getTraceAsString() + ] + ); + + $presenter->setResponseStatus( + new ErrorResponse('An error occured while retrieving severities') + ); + return; + } + + $presenter->present($this->createResponse($severities)); + } + + /** + * @param Severity[] $severities + * @return FindSeverityResponse + */ + private function createResponse(array $severities): FindSeverityResponse + { + return new FindSeverityResponse($severities); + } +} diff --git a/src/Core/Severity/RealTime/Application/UseCase/FindSeverity/FindSeverityPresenterInterface.php b/src/Core/Severity/RealTime/Application/UseCase/FindSeverity/FindSeverityPresenterInterface.php new file mode 100644 index 00000000000..52eccf106b6 --- /dev/null +++ b/src/Core/Severity/RealTime/Application/UseCase/FindSeverity/FindSeverityPresenterInterface.php @@ -0,0 +1,30 @@ +> + */ + public array $severities; + + /** + * @param Severity[] $severities + */ + public function __construct(array $severities) + { + $this->severities = $this->severitiesToArray($severities); + } + + /** + * @param Severity[] $severities + * @return array> + */ + private function severitiesToArray(array $severities): array + { + return array_map( + fn (Severity $severity) => [ + 'id' => $severity->getId(), + 'name' => $severity->getName(), + 'level' => $severity->getLevel(), + 'type' => $severity->getTypeAsString(), + 'icon' => $this->iconToArray($severity->getIcon()), + ], + $severities + ); + } +} diff --git a/src/Core/Severity/RealTime/Domain/Model/Severity.php b/src/Core/Severity/RealTime/Domain/Model/Severity.php new file mode 100644 index 00000000000..52d1fb278ed --- /dev/null +++ b/src/Core/Severity/RealTime/Domain/Model/Severity.php @@ -0,0 +1,114 @@ + 'host', + self::SERVICE_SEVERITY_TYPE_ID => 'service' + ]; + + /** + * @param integer $id + * @param string $name + * @param integer $level + * @param integer $type + * @param Icon $icon + * @throws \Assert\AssertionFailedException + */ + public function __construct( + private int $id, + private string $name, + private int $level, + private int $type, + private Icon $icon + ) { + Assertion::maxLength($name, self::MAX_NAME_LENGTH, 'Severity::name'); + Assertion::notEmpty($name, 'Severity::name'); + Assertion::min($level, 0, 'Severity::level'); + Assertion::max($level, 100, 'Severity::level'); + Assertion::inArray( + $type, + [self::HOST_SEVERITY_TYPE_ID, self::SERVICE_SEVERITY_TYPE_ID], + 'Severity::type' + ); + } + + /** + * @return integer + */ + public function getId(): int + { + return $this->id; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return integer + */ + public function getLevel(): int + { + return $this->level; + } + + /** + * @return Icon + */ + public function getIcon(): Icon + { + return $this->icon; + } + + /** + * @return integer + */ + public function getType(): int + { + return $this->type; + } + + /** + * @return string + */ + public function getTypeAsString(): string + { + return self::TYPES_AS_STRING[$this->type]; + } +} diff --git a/src/Core/Severity/RealTime/Infrastructure/API/FindSeverity/FindHostSeverityController.php b/src/Core/Severity/RealTime/Infrastructure/API/FindSeverity/FindHostSeverityController.php new file mode 100644 index 00000000000..9960ee47faa --- /dev/null +++ b/src/Core/Severity/RealTime/Infrastructure/API/FindSeverity/FindHostSeverityController.php @@ -0,0 +1,44 @@ +denyAccessUnlessGrantedForApiRealtime(); + $useCase(Severity::HOST_SEVERITY_TYPE_ID, $presenter); + return $presenter->show(); + } +} diff --git a/src/Core/Severity/RealTime/Infrastructure/API/FindSeverity/FindServiceSeverityController.php b/src/Core/Severity/RealTime/Infrastructure/API/FindSeverity/FindServiceSeverityController.php new file mode 100644 index 00000000000..06d77b41dc7 --- /dev/null +++ b/src/Core/Severity/RealTime/Infrastructure/API/FindSeverity/FindServiceSeverityController.php @@ -0,0 +1,44 @@ +denyAccessUnlessGrantedForApiRealtime(); + $useCase(Severity::SERVICE_SEVERITY_TYPE_ID, $presenter); + return $presenter->show(); + } +} diff --git a/src/Core/Severity/RealTime/Infrastructure/API/FindSeverity/FindSeverityPresenter.php b/src/Core/Severity/RealTime/Infrastructure/API/FindSeverity/FindSeverityPresenter.php new file mode 100644 index 00000000000..c9fdf8abd90 --- /dev/null +++ b/src/Core/Severity/RealTime/Infrastructure/API/FindSeverity/FindSeverityPresenter.php @@ -0,0 +1,53 @@ + $data->severities, + 'meta' => $this->requestParameters->toArray() + ]); + } +} diff --git a/src/Core/Severity/RealTime/Infrastructure/Repository/DbReadSeverityRepository.php b/src/Core/Severity/RealTime/Infrastructure/Repository/DbReadSeverityRepository.php new file mode 100644 index 00000000000..8aafba3418e --- /dev/null +++ b/src/Core/Severity/RealTime/Infrastructure/Repository/DbReadSeverityRepository.php @@ -0,0 +1,166 @@ +db = $db; + $this->sqlRequestTranslator = $sqlRequestTranslator; + $this->sqlRequestTranslator + ->getRequestParameters() + ->setConcordanceStrictMode(RequestParameters::CONCORDANCE_MODE_STRICT); + $this->sqlRequestTranslator->setConcordanceArray([ + 'id' => 's.id', + 'name' => 's.name', + 'level' => 's.level' + ]); + } + + /** + * @inheritDoc + */ + public function findAllByTypeId(int $typeId): array + { + $this->info( + 'Fetching severities from the database by typeId', + [ + 'typeId' => $typeId + ] + ); + + $request = 'SELECT SQL_CALC_FOUND_ROWS + severity_id, + s.id, + s.name, + s.type, + s.level, + s.icon_id, + img_id AS `icon_id`, + img_name AS `icon_name`, + img_path AS `icon_path`, + imgd.dir_name AS `icon_directory` + FROM `:dbstg`.severities s + INNER JOIN `:db`.view_img img + ON s.icon_id = img.img_id + LEFT JOIN `:db`.view_img_dir_relation imgdr + ON imgdr.img_img_id = img.img_id + INNER JOIN `:db`.view_img_dir imgd + ON imgd.dir_id = imgdr.dir_dir_parent_id'; + + $searchRequest = $this->sqlRequestTranslator->translateSearchParameterToSql(); + $request .= $searchRequest === null ? ' WHERE ' : $searchRequest . ' AND '; + $request .= 's.type = :typeId AND img.img_id = s.icon_id'; + + // Handle sort + $sortRequest = $this->sqlRequestTranslator->translateSortParameterToSql(); + $request .= $sortRequest !== null ? $sortRequest : ' ORDER BY name ASC'; + + // Handle pagination + $request .= $this->sqlRequestTranslator->translatePaginationToSql(); + $statement = $this->db->prepare($this->translateDbName($request)); + + foreach ($this->sqlRequestTranslator->getSearchValues() as $key => $data) { + $type = key($data); + $value = $data[$type]; + $statement->bindValue($key, $value, $type); + } + + $statement->bindValue(':typeId', $typeId, \PDO::PARAM_INT); + $statement->execute(); + + // Set total + $result = $this->db->query('SELECT FOUND_ROWS()'); + if ($result !== false && ($total = $result->fetchColumn()) !== false) { + $this->sqlRequestTranslator->getRequestParameters()->setTotal((int) $total); + } + + $severities = []; + while ($record = $statement->fetch(\PDO::FETCH_ASSOC)) { + $severities[] = DbSeverityFactory::createFromRecord($record); + } + + return $severities; + } + + /** + * @inheritDoc + */ + public function findByResourceAndTypeId(int $resourceId, int $parentResourceId, int $typeId): ?Severity + { + $request = 'SELECT + resources.severity_id, + s.id, + s.name, + s.level, + s.type, + s.icon_id, + img_name AS `icon_name`, + img_path AS `icon_path`, + imgd.dir_name AS `icon_directory` + FROM `:dbstg`.resources + INNER JOIN `:dbstg`.severities s + ON s.severity_id = resources.severity_id + INNER JOIN `:db`.view_img img + ON s.icon_id = img.img_id + LEFT JOIN `:db`.view_img_dir_relation imgdr + ON imgdr.img_img_id = img.img_id + INNER JOIN `:db`.view_img_dir imgd + ON imgd.dir_id = imgdr.dir_dir_parent_id + WHERE resources.id = :resourceId AND resources.parent_id = :parentResourceId AND s.type = :typeId'; + + $statement = $this->db->prepare($this->translateDbName($request)); + + $statement->bindValue(':resourceId', $resourceId, \PDO::PARAM_INT); + $statement->bindValue(':parentResourceId', $parentResourceId, \PDO::PARAM_INT); + $statement->bindValue(':typeId', $typeId, \PDO::PARAM_INT); + + $statement->execute(); + + if (($record = $statement->fetch(\PDO::FETCH_ASSOC))) { + return DbSeverityFactory::createFromRecord($record); + } + + return null; + } +} diff --git a/src/Core/Severity/RealTime/Infrastructure/Repository/DbSeverityFactory.php b/src/Core/Severity/RealTime/Infrastructure/Repository/DbSeverityFactory.php new file mode 100644 index 00000000000..e898ddc1a9c --- /dev/null +++ b/src/Core/Severity/RealTime/Infrastructure/Repository/DbSeverityFactory.php @@ -0,0 +1,49 @@ + $record + * @return Severity + */ + public static function createFromRecord(array $record): Severity + { + $icon = (new Icon()) + ->setId((int) $record['icon_id']) + ->setName($record['icon_name']) + ->setUrl($record['icon_directory'] . DIRECTORY_SEPARATOR . $record['icon_path']); + + return new Severity( + (int) $record['id'], + $record['name'], + (int) $record['level'], + (int) $record['type'], + $icon + ); + } +} diff --git a/tests/api/Context/RealTimeSeverityContext.php b/tests/api/Context/RealTimeSeverityContext.php new file mode 100644 index 00000000000..55db5abe32d --- /dev/null +++ b/tests/api/Context/RealTimeSeverityContext.php @@ -0,0 +1,28 @@ + - */ - private array $record; +beforeEach(function () { + $this->record = [ + 'resource_id' => '9', + 'name' => 'Ping', + 'alias' => null, + 'address' => null, + 'id' => '104', + 'internal_id' => null, + 'parent_id' => '14', + 'parent_name' => 'Database', + 'parent_status' => '2', + 'parent_alias' => 'Database', + 'parent_status_ordered' => '2', + 'type' => '0', + 'status' => '0', + 'status_ordered' => '0', + 'status_confirmed' => '1', + 'in_downtime' => '0', + 'acknowledged' => '0', + 'passive_checks_enabled' => '0', + 'active_checks_enabled' => '1', + 'notifications_enabled' => '1', + 'last_check' => '1651218259', + 'last_status_change' => '1651211193', + 'check_attempts' => '1', + 'max_check_attempts' => '3', + 'notes' => 'Notes label', + 'notes_url' => 'https://www.centreon.com', + 'action_url' => 'https://www.centreon.com', + 'output' => 'OK - localhost rta 0.257ms lost 0%', + 'poller_id' => '1', + 'has_graph' => '1', + 'monitoring_server_name' => 'Central', + 'enabled' => '1', + 'icon_id' => '0', + 'severity_id' => '10', + 'severity_name' => 'High', + 'severity_level' => '50', + 'severity_icon_id' => '1', + 'severity_type' => '0', + ]; +}); - public function setUp(): void - { - $this->record = [ - 'resource_id' => '9', - 'name' => 'Ping', - 'alias' => null, - 'address' => null, - 'id' => '104', - 'internal_id' => null, - 'parent_id' => '14', - 'parent_name' => 'Database', - 'parent_status' => '2', - 'parent_alias' => 'Database', - 'parent_status_ordered' => '2', - 'severity_level' => '10', - 'type' => '0', - 'status' => '0', - 'status_ordered' => '0', - 'status_confirmed' => '1', - 'in_downtime' => '0', - 'acknowledged' => '0', - 'passive_checks_enabled' => '0', - 'active_checks_enabled' => '1', - 'notifications_enabled' => '1', - 'last_check' => '1651218259', - 'last_status_change' => '1651211193', - 'check_attempts' => '1', - 'max_check_attempts' => '3', - 'notes' => 'Notes label', - 'notes_url' => 'https://www.centreon.com', - 'action_url' => 'https://www.centreon.com', - 'output' => 'OK - localhost rta 0.257ms lost 0%', - 'poller_id' => '1', - 'has_graph' => '1', - 'monitoring_server_name' => 'Central', - 'enabled' => '1', - 'icon_id' => '0' - ]; - } +it('should create a resource model from record', function () { + $resource = DbResourceFactory::createFromRecord($this->record); + expect($resource->getId())->toBe((int) $this->record['id']); + expect($resource->getParent()?->getId())->toBe((int) $this->record['parent_id']); + expect($resource->getName())->toBe($this->record['name']); + expect($resource->getAlias())->toBeNull(); + expect($resource->getFqdn())->toBeNull(); + expect($resource->getParent()?->getName())->toBe($this->record['parent_name']); + expect($resource->getParent()?->getStatus()?->getCode())->toBe((int) $this->record['parent_status']); + expect(ResourceStatus::SEVERITY_LOW)->toBe($resource->getParent()?->getStatus()?->getSeverityCode()); + expect($this->record['parent_alias'])->toBe($resource->getParent()?->getAlias()); + expect(ResourceEntity::TYPE_SERVICE)->toBe($resource->getType()); + expect(ResourceStatus::STATUS_NAME_OK)->toBe($resource->getStatus()?->getName()); + expect((int) $this->record['status'])->toBe($resource->getStatus()?->getCode()); + expect(ResourceStatus::SEVERITY_OK)->toBe($resource->getStatus()?->getSeverityCode()); - /** - * Test that resource is properly created - */ - public function testResourceCreation(): void - { - $resource = DbResourceFactory::createFromRecord($this->record); + $statusConfirmedAsString = (int) $this->record['status_confirmed'] === 1 ? 'H' : 'S'; + $tries = $this->record['check_attempts'] + . '/' . $this->record['max_check_attempts'] . ' (' . $statusConfirmedAsString . ')'; - $this->assertEquals((int) $this->record['id'], $resource->getId()); - $this->assertEquals((int) $this->record['parent_id'], $resource->getParent()->getId()); - $this->assertEquals($this->record['name'], $resource->getName()); - $this->assertNull($resource->getAlias()); - $this->assertNull($resource->getFqdn()); - $this->assertEquals($this->record['parent_name'], $resource->getParent()->getName()); - $this->assertEquals((int) $this->record['parent_status'], $resource->getParent()->getStatus()->getCode()); - $this->assertEquals(ResourceStatus::SEVERITY_LOW, $resource->getParent()->getStatus()->getSeverityCode()); - $this->assertEquals($this->record['parent_alias'], $resource->getParent()->getAlias()); - $this->assertEquals((int) $this->record['severity_level'], $resource->getSeverityLevel()); - $this->assertEquals(ResourceEntity::TYPE_SERVICE, $resource->getType()); - $this->assertEquals(ResourceStatus::STATUS_NAME_OK, $resource->getStatus()->getName()); - $this->assertEquals((int) $this->record['status'], $resource->getStatus()->getCode()); - $this->assertEquals(ResourceStatus::SEVERITY_OK, $resource->getStatus()->getSeverityCode()); - - $statusConfirmedAsString = (int) $this->record['status_confirmed'] === 1 ? 'H' : 'S'; - $tries = $this->record['check_attempts'] - . '/' . $this->record['max_check_attempts'] . ' (' . $statusConfirmedAsString . ')'; - - $this->assertEquals($tries, $resource->getTries()); - $this->assertFalse($resource->getInDowntime()); - $this->assertFalse($resource->getAcknowledged()); - $this->assertFalse($resource->getPassiveChecks()); - $this->assertTrue($resource->getActiveChecks()); - $this->assertTrue($resource->isNotificationEnabled()); - $this->assertEquals((int) $this->record['last_check'], $resource->getLastCheck()->getTimestamp()); - $this->assertEquals( - (int) $this->record['last_status_change'], - $resource->getLastStatusChange()->getTimestamp() - ); - - $this->assertEquals($this->record['notes'], $resource->getLinks()->getExternals()->getNotes()->getLabel()); - $this->assertEquals($this->record['notes_url'], $resource->getLinks()->getExternals()->getNotes()->getUrl()); - $this->assertEquals($this->record['action_url'], $resource->getLinks()->getExternals()->getActionUrl()); - $this->assertEquals($this->record['output'], $resource->getInformation()); - $this->assertEquals($this->record['monitoring_server_name'], $resource->getMonitoringServerName()); - $this->assertTrue($resource->hasGraph()); - } -} + expect($resource->getTries())->toBe($tries); + expect($resource->getInDowntime())->toBeFalse(); + expect($resource->getAcknowledged())->toBeFalse(); + expect($resource->getPassiveChecks())->toBeFalse(); + expect($resource->getActiveChecks())->toBeTrue(); + expect($resource->isNotificationEnabled())->toBeTrue(); + expect($resource->getLastCheck()?->getTimestamp())->toBe((int) $this->record['last_check']); + expect($resource->getLastStatusChange()?->getTimestamp())->toBe((int) $this->record['last_status_change']); + expect($resource->getLinks()->getExternals()->getNotes()?->getLabel())->toBe($this->record['notes']); + expect($resource->getLinks()->getExternals()->getNotes()?->getUrl())->toBe($this->record['notes_url']); + expect($resource->getLinks()->getExternals()->getActionUrl())->toBe($this->record['action_url']); + expect($resource->getInformation())->toBe($this->record['output']); + expect($resource->getMonitoringServerName())->toBe($this->record['monitoring_server_name']); + expect($resource->hasGraph())->toBeTrue(); + expect($resource->getSeverity()?->getName())->toBe($this->record['severity_name']); + expect($resource->getSeverity()?->getId())->toBe((int) $this->record['severity_id']); + expect($resource->getSeverity()?->getLevel())->toBe((int) $this->record['severity_level']); + expect($resource->getSeverity()?->getType())->toBe((int) $this->record['severity_type']); + expect($resource->getSeverity()?->getIcon()->getId())->toBe((int) $this->record['severity_icon_id']); +}); diff --git a/tests/php/Core/Application/RealTime/UseCase/FindHost/FindHostTest.php b/tests/php/Core/Application/RealTime/UseCase/FindHost/FindHostTest.php index d991e450f76..cc8a6d7965e 100644 --- a/tests/php/Core/Application/RealTime/UseCase/FindHost/FindHostTest.php +++ b/tests/php/Core/Application/RealTime/UseCase/FindHost/FindHostTest.php @@ -22,11 +22,13 @@ namespace Tests\Core\Application\RealTime\UseCase\FindHost; +use Core\Domain\RealTime\Model\Icon; use Core\Tag\RealTime\Domain\Model\Tag; use Core\Domain\RealTime\Model\Downtime; use Core\Domain\RealTime\Model\Hostgroup; use Tests\Core\Domain\RealTime\Model\HostTest; use Core\Domain\RealTime\Model\Acknowledgement; +use Core\Severity\RealTime\Domain\Model\Severity; use Core\Application\Common\UseCase\NotFoundResponse; use Centreon\Domain\Contact\Interfaces\ContactInterface; use Core\Application\RealTime\UseCase\FindHost\FindHost; @@ -40,6 +42,7 @@ use Core\Application\RealTime\Repository\ReadHostgroupRepositoryInterface; use Core\Security\Application\Repository\ReadAccessGroupRepositoryInterface; use Core\Application\RealTime\Repository\ReadAcknowledgementRepositoryInterface; +use Core\Severity\RealTime\Application\Repository\ReadSeverityRepositoryInterface; beforeEach(function () { $this->repository = $this->createMock(ReadHostRepositoryInterface::class); @@ -51,6 +54,7 @@ $this->presenterFormatter = $this->createMock(PresenterFormatterInterface::class); $this->monitoringService = $this->createMock(MonitoringServiceInterface::class); $this->tagRepository = $this->createMock(ReadTagRepositoryInterface::class); + $this->severityRepository = $this->createMock(ReadSeverityRepositoryInterface::class); $this->acknowledgement = new Acknowledgement(1, 1, 10, new \DateTime('1991-09-10')); $this->host = HostTest::createHostModel(); @@ -60,6 +64,9 @@ $this->category = new Tag(1, 'host-category-name', Tag::HOST_CATEGORY_TYPE_ID); $this->downtime = (new Downtime(1, 1, 10)) ->setCancelled(false); + + $icon = (new Icon())->setId(1)->setName('centreon')->setUrl('ppm/centreon.png'); + $this->severity = new Severity(1, 'severityName', 10, Severity::HOST_SEVERITY_TYPE_ID, $icon); }); it('FindHost not found response as admin', function () { @@ -71,7 +78,8 @@ $this->downtimeRepository, $this->acknowledgementRepository, $this->monitoringService, - $this->tagRepository + $this->tagRepository, + $this->severityRepository ); $this->contact @@ -102,7 +110,8 @@ $this->downtimeRepository, $this->acknowledgementRepository, $this->monitoringService, - $this->tagRepository + $this->tagRepository, + $this->severityRepository ); $this->contact @@ -138,7 +147,8 @@ $this->downtimeRepository, $this->acknowledgementRepository, $this->monitoringService, - $this->tagRepository + $this->tagRepository, + $this->severityRepository ); $this->contact @@ -171,6 +181,11 @@ ->method('findAllByResourceAndTypeId') ->willReturn([$this->category]); + $this->severityRepository + ->expects($this->once()) + ->method('findByResourceAndTypeId') + ->willReturn($this->severity); + $presenter = new FindHostPresenterStub(); $findHost(1, $presenter); @@ -193,7 +208,6 @@ expect($presenter->response->statusChangePercentage)->toBe($this->host->getStatusChangePercentage()); expect($presenter->response->hasActiveChecks)->toBe($this->host->hasActiveChecks()); expect($presenter->response->hasPassiveChecks)->toBe($this->host->hasPassiveChecks()); - expect($presenter->response->severityLevel)->toBe($this->host->getSeverityLevel()); expect($presenter->response->checkAttempts)->toBe($this->host->getCheckAttempts()); expect($presenter->response->maxCheckAttempts)->toBe($this->host->getMaxCheckAttempts()); expect($presenter->response->lastTimeUp)->toBe($this->host->getLastTimeUp()); @@ -217,6 +231,18 @@ expect($presenter->response->acknowledgement['host_id'])->toBe($this->acknowledgement->getHostId()); expect($presenter->response->categories[0]['id'])->toBe($this->category->getId()); expect($presenter->response->categories[0]['name'])->toBe($this->category->getName()); + + /** + * @var array $severity + */ + $severity = $presenter->response->severity; + expect($severity['id'])->toBe($this->severity->getId()); + expect($severity['name'])->toBe($this->severity->getName()); + expect($severity['type'])->toBe($this->severity->getTypeAsString()); + expect($severity['level'])->toBe($this->severity->getLevel()); + expect($severity['icon']['id'])->toBe($this->severity->getIcon()->getId()); + expect($severity['icon']['name'])->toBe($this->severity->getIcon()->getName()); + expect($severity['icon']['url'])->toBe($this->severity->getIcon()->getUrl()); }); it('should find the host as non admin', function () { @@ -228,7 +254,8 @@ $this->downtimeRepository, $this->acknowledgementRepository, $this->monitoringService, - $this->tagRepository + $this->tagRepository, + $this->severityRepository ); $this->contact @@ -261,6 +288,11 @@ ->method('findAllByResourceAndTypeId') ->willReturn([$this->category]); + $this->severityRepository + ->expects($this->once()) + ->method('findByResourceAndTypeId') + ->willReturn($this->severity); + $presenter = new FindHostPresenterStub(); $findHost(1, $presenter); @@ -283,7 +315,6 @@ expect($presenter->response->statusChangePercentage)->toBe($this->host->getStatusChangePercentage()); expect($presenter->response->hasActiveChecks)->toBe($this->host->hasActiveChecks()); expect($presenter->response->hasPassiveChecks)->toBe($this->host->hasPassiveChecks()); - expect($presenter->response->severityLevel)->toBe($this->host->getSeverityLevel()); expect($presenter->response->checkAttempts)->toBe($this->host->getCheckAttempts()); expect($presenter->response->maxCheckAttempts)->toBe($this->host->getMaxCheckAttempts()); expect($presenter->response->lastTimeUp)->toBe($this->host->getLastTimeUp()); @@ -308,4 +339,16 @@ expect($presenter->response->acknowledgement['entry_time'])->toBe($this->acknowledgement->getEntryTime()); expect($presenter->response->categories[0]['id'])->toBe($this->category->getId()); expect($presenter->response->categories[0]['name'])->toBe($this->category->getName()); + + /** + * @var array $severity + */ + $severity = $presenter->response->severity; + expect($severity['id'])->toBe($this->severity->getId()); + expect($severity['name'])->toBe($this->severity->getName()); + expect($severity['type'])->toBe($this->severity->getTypeAsString()); + expect($severity['level'])->toBe($this->severity->getLevel()); + expect($severity['icon']['id'])->toBe($this->severity->getIcon()->getId()); + expect($severity['icon']['name'])->toBe($this->severity->getIcon()->getName()); + expect($severity['icon']['url'])->toBe($this->severity->getIcon()->getUrl()); }); diff --git a/tests/php/Core/Application/RealTime/UseCase/FindService/FindServiceTest.php b/tests/php/Core/Application/RealTime/UseCase/FindService/FindServiceTest.php index a9953979788..f8ec463f8a7 100644 --- a/tests/php/Core/Application/RealTime/UseCase/FindService/FindServiceTest.php +++ b/tests/php/Core/Application/RealTime/UseCase/FindService/FindServiceTest.php @@ -22,11 +22,13 @@ namespace Tests\Core\Application\RealTime\UseCase\FindService; +use Core\Domain\RealTime\Model\Icon; use Core\Tag\RealTime\Domain\Model\Tag; use Core\Domain\RealTime\Model\Downtime; use Core\Domain\RealTime\Model\Servicegroup; use Tests\Core\Domain\RealTime\Model\HostTest; use Core\Domain\RealTime\Model\Acknowledgement; +use Core\Severity\RealTime\Domain\Model\Severity; use Tests\Core\Domain\RealTime\Model\ServiceTest; use Core\Application\Common\UseCase\NotFoundResponse; use Centreon\Domain\Contact\Interfaces\ContactInterface; @@ -43,6 +45,7 @@ use Core\Application\RealTime\Repository\ReadServicegroupRepositoryInterface; use Core\Application\RealTime\Repository\ReadAcknowledgementRepositoryInterface; use Tests\Core\Application\RealTime\UseCase\FindService\FindServicePresenterStub; +use Core\Severity\RealTime\Application\Repository\ReadSeverityRepositoryInterface; beforeEach(function () { $this->repository = $this->createMock(ReadServiceRepositoryInterface::class); @@ -55,6 +58,7 @@ $this->monitoringService = $this->createMock(MonitoringServiceInterface::class); $this->hostRepository = $this->createMock(ReadHostRepositoryInterface::class); $this->tagRepository = $this->createMock(ReadTagRepositoryInterface::class); + $this->severityRepository = $this->createMock(ReadSeverityRepositoryInterface::class); $this->downtime = (new Downtime(1, 1, 10)) ->setCancelled(false); @@ -67,6 +71,8 @@ $this->service = ServiceTest::createServiceModel(); $this->servicegroup = new Servicegroup(1, 'ALL'); $this->category = new Tag(1, 'service-category-name', Tag::SERVICE_CATEGORY_TYPE_ID); + $icon = (new Icon())->setId(1)->setName('centreon')->setUrl('ppm/centreon.png'); + $this->severity = new Severity(1, 'severityName', 10, Severity::SERVICE_SEVERITY_TYPE_ID, $icon); }); it('should present a NotFoundResponse if host not found as admin', function () { @@ -80,6 +86,7 @@ $this->acknowledgementRepository, $this->monitoringService, $this->tagRepository, + $this->severityRepository ); $this->contact @@ -113,6 +120,7 @@ $this->acknowledgementRepository, $this->monitoringService, $this->tagRepository, + $this->severityRepository ); $this->contact @@ -151,6 +159,7 @@ $this->acknowledgementRepository, $this->monitoringService, $this->tagRepository, + $this->severityRepository ); $this->contact @@ -189,6 +198,7 @@ $this->acknowledgementRepository, $this->monitoringService, $this->tagRepository, + $this->severityRepository ); $this->contact @@ -232,6 +242,7 @@ $this->acknowledgementRepository, $this->monitoringService, $this->tagRepository, + $this->severityRepository ); $this->contact @@ -269,6 +280,11 @@ ->method('findOnGoingAcknowledgementByHostIdAndServiceId') ->willReturn($this->acknowledgement); + $this->severityRepository + ->expects($this->once()) + ->method('findByResourceAndTypeId') + ->willReturn($this->severity); + $presenter = new FindServicePresenterStub(); $findService(1, 10, $presenter); @@ -289,7 +305,6 @@ expect($presenter->response->statusChangePercentage)->toBe($this->service->getStatusChangePercentage()); expect($presenter->response->hasActiveChecks)->toBe($this->service->hasActiveChecks()); expect($presenter->response->hasPassiveChecks)->toBe($this->service->hasPassiveChecks()); - expect($presenter->response->severityLevel)->toBe($this->service->getSeverityLevel()); expect($presenter->response->checkAttempts)->toBe($this->service->getCheckAttempts()); expect($presenter->response->maxCheckAttempts)->toBe($this->service->getMaxCheckAttempts()); expect($presenter->response->lastTimeOk)->toBe($this->service->getLastTimeOk()); @@ -314,6 +329,18 @@ expect($presenter->response->acknowledgement['service_id']) ->toBe($this->acknowledgement->getServiceId()); expect($presenter->response->acknowledgement['host_id'])->toBe($this->acknowledgement->getHostId()); + + /** + * @var array $severity + */ + $severity = $presenter->response->severity; + expect($severity['id'])->toBe($this->severity->getId()); + expect($severity['name'])->toBe($this->severity->getName()); + expect($severity['type'])->toBe($this->severity->getTypeAsString()); + expect($severity['level'])->toBe($this->severity->getLevel()); + expect($severity['icon']['id'])->toBe($this->severity->getIcon()->getId()); + expect($severity['icon']['name'])->toBe($this->severity->getIcon()->getName()); + expect($severity['icon']['url'])->toBe($this->severity->getIcon()->getUrl()); }); it('FindService service found as non admin', function () { @@ -327,6 +354,7 @@ $this->acknowledgementRepository, $this->monitoringService, $this->tagRepository, + $this->severityRepository ); $this->contact @@ -359,6 +387,11 @@ ->method('findOnGoingAcknowledgementByHostIdAndServiceId') ->willReturn($this->acknowledgement); + $this->severityRepository + ->expects($this->once()) + ->method('findByResourceAndTypeId') + ->willReturn($this->severity); + $presenter = new FindServicePresenterStub(); $findService(1, 10, $presenter); @@ -379,7 +412,6 @@ expect($presenter->response->statusChangePercentage)->toBe($this->service->getStatusChangePercentage()); expect($presenter->response->hasActiveChecks)->toBe($this->service->hasActiveChecks()); expect($presenter->response->hasPassiveChecks)->toBe($this->service->hasPassiveChecks()); - expect($presenter->response->severityLevel)->toBe($this->service->getSeverityLevel()); expect($presenter->response->checkAttempts)->toBe($this->service->getCheckAttempts()); expect($presenter->response->maxCheckAttempts)->toBe($this->service->getMaxCheckAttempts()); expect($presenter->response->lastTimeOk)->toBe($this->service->getLastTimeOk()); @@ -404,4 +436,16 @@ expect($presenter->response->acknowledgement['service_id']) ->toBe($this->acknowledgement->getServiceId()); expect($presenter->response->acknowledgement['host_id'])->toBe($this->acknowledgement->getHostId()); + + /** + * @var array $severity + */ + $severity = $presenter->response->severity; + expect($severity['id'])->toBe($this->severity->getId()); + expect($severity['name'])->toBe($this->severity->getName()); + expect($severity['type'])->toBe($this->severity->getTypeAsString()); + expect($severity['level'])->toBe($this->severity->getLevel()); + expect($severity['icon']['id'])->toBe($this->severity->getIcon()->getId()); + expect($severity['icon']['name'])->toBe($this->severity->getIcon()->getName()); + expect($severity['icon']['url'])->toBe($this->severity->getIcon()->getUrl()); }); diff --git a/tests/php/Core/Domain/RealTime/Model/HostTest.php b/tests/php/Core/Domain/RealTime/Model/HostTest.php index 3965ed27923..80bd7b5bb3a 100644 --- a/tests/php/Core/Domain/RealTime/Model/HostTest.php +++ b/tests/php/Core/Domain/RealTime/Model/HostTest.php @@ -118,7 +118,6 @@ public static function createHostModel(): Host ->setIsAcknowledged(false) ->setActiveChecks(true) ->setPassiveChecks(false) - ->setSeverityLevel(10) ->setLastStatusChange(new \DateTime('1991-09-10')) ->setLastNotification(new \DateTime('1991-09-10')) ->setLastTimeUp(new \DateTime('1991-09-10')) diff --git a/tests/php/Core/Domain/RealTime/Model/ServiceTest.php b/tests/php/Core/Domain/RealTime/Model/ServiceTest.php index 969ae4df11d..0b89482eb82 100644 --- a/tests/php/Core/Domain/RealTime/Model/ServiceTest.php +++ b/tests/php/Core/Domain/RealTime/Model/ServiceTest.php @@ -83,7 +83,6 @@ public static function createServiceModel(): Service ->setIsAcknowledged(false) ->setActiveChecks(true) ->setPassiveChecks(false) - ->setSeverityLevel(10) ->setLastStatusChange(new \DateTime('1991-09-10')) ->setLastNotification(new \DateTime('1991-09-10')) ->setLastTimeOk(new \DateTime('1991-09-10')) diff --git a/tests/php/Core/Severity/RealTime/Application/UseCase/FindSeverity/FindSeverityPresenterStub.php b/tests/php/Core/Severity/RealTime/Application/UseCase/FindSeverity/FindSeverityPresenterStub.php new file mode 100644 index 00000000000..5d6af41dbd6 --- /dev/null +++ b/tests/php/Core/Severity/RealTime/Application/UseCase/FindSeverity/FindSeverityPresenterStub.php @@ -0,0 +1,54 @@ +response = $response; + } + + /** + * @return Response + */ + public function show(): Response + { + return new Response(); + } +} diff --git a/tests/php/Core/Severity/RealTime/Application/UseCase/FindSeverity/FindSeverityTest.php b/tests/php/Core/Severity/RealTime/Application/UseCase/FindSeverity/FindSeverityTest.php new file mode 100644 index 00000000000..12a7c1e33ee --- /dev/null +++ b/tests/php/Core/Severity/RealTime/Application/UseCase/FindSeverity/FindSeverityTest.php @@ -0,0 +1,87 @@ +repository = $this->createMock(ReadSeverityRepositoryInterface::class); + $this->presenterFormatter = $this->createMock(PresenterFormatterInterface::class); +}); + +it('should present an ErrorResponse when an exception is thrown', function () { + $useCase = new FindSeverity($this->repository); + $this->repository + ->expects($this->once()) + ->method('findAllByTypeId') + ->with(Severity::HOST_SEVERITY_TYPE_ID) + ->willThrowException(new \Exception()); + + $presenter = new FindSeverityPresenterStub($this->presenterFormatter); + $useCase(Severity::HOST_SEVERITY_TYPE_ID, $presenter); + + expect($presenter->getResponseStatus())->toBeInstanceOf(ErrorResponse::class) + ->and($presenter->getResponseStatus()?->getMessage()) + ->toBe('An error occured while retrieving severities'); +}); + +it('should present a FindSeverityResponse', function () { + $useCase = new FindSeverity($this->repository); + + $icon = (new Icon()) + ->setId(1) + ->setName('icon-name') + ->setUrl('ppm/icon-name.png'); + + $severity = new Severity(1, 'name', 50, Severity::HOST_SEVERITY_TYPE_ID, $icon); + + $this->repository + ->expects($this->once()) + ->method('findAllByTypeId') + ->willReturn([$severity]); + + $presenter = new FindSeverityPresenterStub($this->presenterFormatter); + $useCase(Severity::HOST_SEVERITY_TYPE_ID, $presenter); + expect($presenter->response) + ->toBeInstanceOf(FindSeverityResponse::class) + ->and($presenter->response->severities[0])->toBe( + [ + 'id' => 1, + 'name' => 'name', + 'level' => 50, + 'type' => 'host', + 'icon' => [ + 'id' => 1, + 'name' => 'icon-name', + 'url' => 'ppm/icon-name.png' + ] + ] + ); +}); diff --git a/tests/php/Core/Severity/RealTime/Domain/Model/SeverityTest.php b/tests/php/Core/Severity/RealTime/Domain/Model/SeverityTest.php new file mode 100644 index 00000000000..e2a482df192 --- /dev/null +++ b/tests/php/Core/Severity/RealTime/Domain/Model/SeverityTest.php @@ -0,0 +1,72 @@ +icon = (new Icon()) + ->setName('icon-name') + ->setUrl('ppm/icon-name.png'); +}); + +it('should throw an exception when severity name is empty', function () { + new Severity(1, '', 50, Severity::HOST_SEVERITY_TYPE_ID, $this->icon); +})->throws( + \Assert\InvalidArgumentException::class, + AssertionException::notEmpty('Severity::name') + ->getMessage() +); + +it('should throw an exception when severity name is too long', function () { + new Severity(1, str_repeat('a', Severity::MAX_NAME_LENGTH + 1), 50, Severity::HOST_SEVERITY_TYPE_ID, $this->icon); +})->throws( + \Assert\InvalidArgumentException::class, + AssertionException::maxLength( + str_repeat('a', Severity::MAX_NAME_LENGTH + 1), + Severity::MAX_NAME_LENGTH + 1, + Severity::MAX_NAME_LENGTH, + 'Severity::name' + )->getMessage() +); + +it('should throw an exception when severity level is lower than 0', function () { + new Severity(1, 'name', -1, Severity::HOST_SEVERITY_TYPE_ID, $this->icon); +})->throws(\Assert\InvalidArgumentException::class, AssertionException::min(-1, 0, 'Severity::level')->getMessage()); + +it('should throw an exception when severity level is greater than 100', function () { + new Severity(1, 'name', 200, Severity::HOST_SEVERITY_TYPE_ID, $this->icon); +})->throws(\Assert\InvalidArgumentException::class, AssertionException::max(200, 100, 'Severity::level')->getMessage()); + +it('should throw an exception when severity type is not handled', function () { + new Severity(1, 'name', 60, 2, $this->icon); +})->throws( + \Assert\InvalidArgumentException::class, + AssertionException::inArray( + 2, + [Severity::HOST_SEVERITY_TYPE_ID, Severity::SERVICE_SEVERITY_TYPE_ID], + 'Severity::type' + )->getMessage() +); diff --git a/www/front_src/src/Resources/Details/Header.tsx b/www/front_src/src/Resources/Details/Header.tsx index 5ff5a548904..047a46acd1d 100644 --- a/www/front_src/src/Resources/Details/Header.tsx +++ b/www/front_src/src/Resources/Details/Header.tsx @@ -105,7 +105,7 @@ type Props = { const Header = ({ details, onSelectParent }: Props): JSX.Element => { const classes = useStyles({ - displaySeverity: not(isNil(details?.severity_level)), + displaySeverity: not(isNil(details?.severity)), }); const { t } = useTranslation(); @@ -137,10 +137,12 @@ const Header = ({ details, onSelectParent }: Props): JSX.Element => { return (
- {details?.severity_level && ( - )} { }); await waitFor(() => { - expect(getByText('10')).toBeInTheDocument(); + expect(getByText('Critical')).toBeInTheDocument(); }); - expect(getByText('Critical')).toBeInTheDocument(); expect(getByText('Centreon')).toBeInTheDocument(); const fqdnText = await findByText(labelFqdn); diff --git a/www/front_src/src/Resources/Details/models.ts b/www/front_src/src/Resources/Details/models.ts index 5b91403281e..2051a268324 100644 --- a/www/front_src/src/Resources/Details/models.ts +++ b/www/front_src/src/Resources/Details/models.ts @@ -7,6 +7,7 @@ import { ResourceLinks, NamedEntity, ResourceType, + Severity, } from '../models'; import { CustomTimePeriod, TimePeriodId } from './tabs/Graph/models'; @@ -47,6 +48,7 @@ export interface ResourceDetails extends NamedEntity { passive_checks?: boolean; percent_state_change: number; performance_data?: string; + severity: Severity; severity_level: number; status: Status; timezone?: string; diff --git a/www/front_src/src/Resources/Details/tabs/Details/DetailsCard/SeverityCard.tsx b/www/front_src/src/Resources/Details/tabs/Details/DetailsCard/SeverityCard.tsx new file mode 100644 index 00000000000..edb1e96f097 --- /dev/null +++ b/www/front_src/src/Resources/Details/tabs/Details/DetailsCard/SeverityCard.tsx @@ -0,0 +1,64 @@ +import { ReactNode } from 'react'; + +import { useTranslation } from 'react-i18next'; + +import { makeStyles } from '@mui/styles'; +import { Typography } from '@mui/material'; + +import { ResourceDetails } from '../../../models'; +import { labelSeverity } from '../../../../translatedLabels'; + +const useStyles = makeStyles((theme) => ({ + container: { + display: 'flex', + flexDirection: 'column', + padding: theme.spacing(1, 2, 2), + }, + item: { + alignItems: 'center', + display: 'flex', + flexDirection: 'row', + }, + label: { + display: 'flex', + width: '10%', + }, +})); + +interface Props { + details: ResourceDetails; +} + +interface Line { + className?: string; + data: ReactNode; +} + +const Line = ({ data, className }: Line): JSX.Element => ( + + {data} + +); + +const SeverityCard = ({ details }: Props): JSX.Element => { + const classes = useStyles(); + const { t } = useTranslation(); + + return ( +
+ + {t(labelSeverity)} + +
+ + +
+
+ + +
+
+ ); +}; + +export default SeverityCard; diff --git a/www/front_src/src/Resources/Details/tabs/Details/DetailsCard/cards.tsx b/www/front_src/src/Resources/Details/tabs/Details/DetailsCard/cards.tsx index 670c04d3eb0..fbcca0bb868 100644 --- a/www/front_src/src/Resources/Details/tabs/Details/DetailsCard/cards.tsx +++ b/www/front_src/src/Resources/Details/tabs/Details/DetailsCard/cards.tsx @@ -27,6 +27,7 @@ import { labelCommand, labelLastCheckWithOkStatus, labelCategories, + labelSeverity, } from '../../../../translatedLabels'; import { ResourceDetails } from '../../../models'; import ExpandableCard from '../ExpandableCard'; @@ -40,6 +41,7 @@ import DowntimesCard from './DowntimesCard'; import AcknowledgementCard from './AcknowledegmentCard'; import CommandLineCard from './CommandLineCard'; import GroupChips from './GroupChips'; +import SeverityCard from './SeverityCard'; export interface DetailCardLine { active?: boolean; @@ -101,6 +103,13 @@ const getDetailCardLines = ({ title: labelAcknowledgement, xs: 12, }, + { + isCustomCard: true, + line: , + shouldBeDisplayed: !isNil(details.severity), + title: labelSeverity, + xs: 12, + }, { line: , shouldBeDisplayed: !isNil(details.fqdn), @@ -187,7 +196,7 @@ const getDetailCardLines = ({ title: labelCalculationType, }, { - line: , + line: , shouldBeDisplayed: !isNil(details.calculation_type), title: labelCalculationType, }, diff --git a/www/front_src/src/Resources/Filter/Criterias/Criteria.tsx b/www/front_src/src/Resources/Filter/Criterias/Criteria.tsx index 460bf298264..034c80c694e 100644 --- a/www/front_src/src/Resources/Filter/Criterias/Criteria.tsx +++ b/www/front_src/src/Resources/Filter/Criterias/Criteria.tsx @@ -23,7 +23,6 @@ interface Props { const CriteriaContent = ({ name, value }: Props): JSX.Element => { const { t } = useTranslation(); - const setCriteriaAndNewFilter = useUpdateAtom( setCriteriaAndNewFilterDerivedAtom, ); @@ -56,7 +55,9 @@ const CriteriaContent = ({ name, value }: Props): JSX.Element => { if (isNil(options)) { const isOptionEqualToValue = (option, selectedValue): boolean => - isNil(option) ? false : equals(option.name, selectedValue.name); + isNil(option) + ? false + : equals(option.name.toString(), selectedValue.name); const getEndpoint = ({ search, page }): string => buildAutocompleteEndpoint({ @@ -65,6 +66,8 @@ const CriteriaContent = ({ name, value }: Props): JSX.Element => { search, }); + const displayedColumn = label.includes('level') ? 'level' : ''; + return ( { field="name" getEndpoint={getEndpoint} isOptionEqualToValue={isOptionEqualToValue} + labelKey={displayedColumn} value={value} onChange={(_, updatedValue): void => { changeCriteria(updatedValue); diff --git a/www/front_src/src/Resources/Filter/Criterias/default.ts b/www/front_src/src/Resources/Filter/Criterias/default.ts index bdd55463d44..95d22c8dcac 100644 --- a/www/front_src/src/Resources/Filter/Criterias/default.ts +++ b/www/front_src/src/Resources/Filter/Criterias/default.ts @@ -7,10 +7,14 @@ import { Criteria } from './models'; interface DefaultCriteriaValues { hostCategories?: Array; hostGroups?: Array; + hostSeverities?: Array; + hostSeverityLevels?: Array; monitoringServers?: Array; resourceTypes?: Array; serviceCategories?: Array; serviceGroups?: Array; + serviceSeverities?: Array; + serviceSeverityLevels?: Array; states?: Array; statusTypes?: Array; statuses?: Array; @@ -23,6 +27,10 @@ const getDefaultCriterias = ( { resourceTypes = [], states = [], + serviceSeverities = [], + serviceSeverityLevels = [], + hostSeverities = [], + hostSeverityLevels = [], statuses = [], hostGroups = [], serviceGroups = [], @@ -33,10 +41,14 @@ const getDefaultCriterias = ( }: DefaultCriteriaValues = { hostCategories: [], hostGroups: [], + hostSeverities: [], + hostSeverityLevels: [], monitoringServers: [], resourceTypes: [], serviceCategories: [], serviceGroups: [], + serviceSeverities: [], + serviceSeverityLevels: [], states: [], statusTypes: [], statuses: [], @@ -97,6 +109,30 @@ const getDefaultCriterias = ( type: 'multi_select', value: serviceCategories, }, + { + name: 'host_severities', + object_type: 'host_severities', + type: 'multi_select', + value: hostSeverities, + }, + { + name: 'host_severity_levels', + object_type: 'host_severity_levels', + type: 'multi_select', + value: hostSeverityLevels, + }, + { + name: 'service_severities', + object_type: 'service_severities', + type: 'multi_select', + value: serviceSeverities, + }, + { + name: 'service_severity_levels', + object_type: 'service_severity_levels', + type: 'multi_select', + value: serviceSeverityLevels, + }, { name: 'search', object_type: null, diff --git a/www/front_src/src/Resources/Filter/Criterias/models.ts b/www/front_src/src/Resources/Filter/Criterias/models.ts index 18db2ef0d4f..a81c61e3706 100644 --- a/www/front_src/src/Resources/Filter/Criterias/models.ts +++ b/www/front_src/src/Resources/Filter/Criterias/models.ts @@ -27,6 +27,10 @@ import { labelSoft, labelHostCategory, labelServiceCategory, + labelServiceSeverity, + labelHostSeverity, + labelHostSeverityLevel, + labelServiceSeverityLevel, } from '../../translatedLabels'; import { buildHostGroupsEndpoint, @@ -34,6 +38,8 @@ import { buildServiceCategoriesEndpoint, buildMonitoringServersEndpoint, buildServiceGroupsEndpoint, + buildHostServeritiesEndpoint, + buildServiceSeveritiesEndpoint, } from '../api/endpoint'; export type CriteriaValue = Array | string | [string, SortOrder]; @@ -189,10 +195,14 @@ export interface CriteriaById { export enum CriteriaNames { hostCategories = 'host_categories', hostGroups = 'host_groups', + hostSeverities = 'host_severities', + hostSeverityLevels = 'host_severity_levels', monitoringServers = 'monitoring_servers', resourceTypes = 'resource_types', serviceCategories = 'service_categories', serviceGroups = 'service_groups', + serviceSeverities = 'service_severities', + serviceSeverityLevels = 'service_severity_levels', states = 'states', statusTypes = 'status_types', statuses = 'statuses', @@ -236,6 +246,22 @@ const selectableCriterias: CriteriaById = { buildAutocompleteEndpoint: buildServiceCategoriesEndpoint, label: labelServiceCategory, }, + [CriteriaNames.hostSeverities]: { + buildAutocompleteEndpoint: buildHostServeritiesEndpoint, + label: labelHostSeverity, + }, + [CriteriaNames.serviceSeverities]: { + buildAutocompleteEndpoint: buildServiceSeveritiesEndpoint, + label: labelServiceSeverity, + }, + [CriteriaNames.hostSeverityLevels]: { + buildAutocompleteEndpoint: buildHostServeritiesEndpoint, + label: labelHostSeverityLevel, + }, + [CriteriaNames.serviceSeverityLevels]: { + buildAutocompleteEndpoint: buildServiceSeveritiesEndpoint, + label: labelServiceSeverityLevel, + }, }; export { diff --git a/www/front_src/src/Resources/Filter/Criterias/searchQueryLanguage/index.test.ts b/www/front_src/src/Resources/Filter/Criterias/searchQueryLanguage/index.test.ts index 5625c74b4a2..8121152e3cc 100644 --- a/www/front_src/src/Resources/Filter/Criterias/searchQueryLanguage/index.test.ts +++ b/www/front_src/src/Resources/Filter/Criterias/searchQueryLanguage/index.test.ts @@ -69,6 +69,30 @@ const parsedSearch = [ type: 'multi_select', value: [], }, + { + name: 'host_severities', + object_type: 'host_severities', + type: 'multi_select', + value: [], + }, + { + name: 'host_severity_levels', + object_type: 'host_severity_levels', + type: 'multi_select', + value: [], + }, + { + name: 'service_severities', + object_type: 'service_severities', + type: 'multi_select', + value: [], + }, + { + name: 'service_severity_levels', + object_type: 'service_severity_levels', + type: 'multi_select', + value: [], + }, { name: 'search', object_type: null, diff --git a/www/front_src/src/Resources/Filter/Criterias/searchQueryLanguage/models.ts b/www/front_src/src/Resources/Filter/Criterias/searchQueryLanguage/models.ts index 5e1dfe495d5..9cbdb7b0daa 100644 --- a/www/front_src/src/Resources/Filter/Criterias/searchQueryLanguage/models.ts +++ b/www/front_src/src/Resources/Filter/Criterias/searchQueryLanguage/models.ts @@ -27,6 +27,10 @@ export const criteriaNameSortOrder = { [CriteriaNames.statusTypes]: 4, [CriteriaNames.serviceCategories]: 9, [CriteriaNames.hostCategories]: 8, + [CriteriaNames.hostSeverities]: 10, + [CriteriaNames.hostSeverityLevels]: 11, + [CriteriaNames.serviceSeverities]: 12, + [CriteriaNames.serviceSeverityLevels]: 13, }; export interface AutocompleteSuggestionProps { @@ -72,6 +76,10 @@ export const dynamicCriteriaValuesByName = [ CriteriaNames.serviceGroups, CriteriaNames.serviceCategories, CriteriaNames.hostCategories, + CriteriaNames.hostSeverities, + CriteriaNames.serviceSeverities, + CriteriaNames.hostSeverityLevels, + CriteriaNames.serviceSeverityLevels, ]; export const getSelectableCriteriasByName = ( diff --git a/www/front_src/src/Resources/Filter/api/endpoint.ts b/www/front_src/src/Resources/Filter/api/endpoint.ts index 53abe0000d1..c621b2e486b 100644 --- a/www/front_src/src/Resources/Filter/api/endpoint.ts +++ b/www/front_src/src/Resources/Filter/api/endpoint.ts @@ -12,6 +12,8 @@ const serviceCategoriesEndpoint = `${monitoringEndpoint}/services/categories`; const hostgroupsEndpoint = `${monitoringEndpoint}/hostgroups`; const serviceGroupsEndpoint = `${monitoringEndpoint}/servicegroups`; const monitoringServersEndpoint = `${baseEndpoint}/monitoring/servers`; +const hostSeveritiesEndpoint = `${monitoringEndpoint}/severities/host`; +const serviceSeveritiesEndpoint = `${monitoringEndpoint}/severities/service`; const buildHostGroupsEndpoint = (parameters: ListingParameters): string => { return buildListingEndpoint({ @@ -55,6 +57,19 @@ const buildServiceCategoriesEndpoint = ( parameters, }); }; +const buildHostServeritiesEndpoint = (parameters): string => { + return buildListingEndpoint({ + baseEndpoint: hostSeveritiesEndpoint, + parameters, + }); +}; + +const buildServiceSeveritiesEndpoint = (parameters): string => { + return buildListingEndpoint({ + baseEndpoint: serviceSeveritiesEndpoint, + parameters, + }); +}; export { buildHostCategoriesEndpoint, @@ -62,4 +77,6 @@ export { buildHostGroupsEndpoint, buildServiceGroupsEndpoint, buildMonitoringServersEndpoint, + buildHostServeritiesEndpoint, + buildServiceSeveritiesEndpoint, }; diff --git a/www/front_src/src/Resources/Filter/index.tsx b/www/front_src/src/Resources/Filter/index.tsx index 8517ae8c8ae..c0f018c85da 100644 --- a/www/front_src/src/Resources/Filter/index.tsx +++ b/www/front_src/src/Resources/Filter/index.tsx @@ -100,7 +100,7 @@ const renderClearFilter = (onClear) => (): JSX.Element => { ); }; interface DynamicCriteriaResult { - result: Array<{ name: string }>; + result: Array<{ level: string; name: string }>; } const useStyles = makeStyles((theme) => ({ @@ -170,7 +170,7 @@ const Filter = (): JSX.Element => { criteria, values, }: DynamicCriteriaParametersAndValues): void => { - const { buildAutocompleteEndpoint, autocompleteSearch } = criteria; + const { buildAutocompleteEndpoint, autocompleteSearch, label } = criteria; const lastValue = last(values); @@ -197,13 +197,17 @@ const Filter = (): JSX.Element => { }, }), }).then(({ result }): void => { - const names = pluck('name', result); + const results = label.includes('severity level') + ? pluck('level', result) + : pluck('name', result); - const lastValueEqualsToAResult = find(equals(lastValue), names); + const formattedResult = results.map((item) => item.toString()); - const notSelectedValues = difference(names, values); + const lastValueEqualsToAResult = find(equals(lastValue), formattedResult); - if (or(lastValueEqualsToAResult, isEmpty(names))) { + const notSelectedValues = difference(formattedResult, values); + + if (or(lastValueEqualsToAResult, isEmpty(formattedResult))) { const res = [ ...notSelectedValues, ...map(concat(','), notSelectedValues), @@ -214,7 +218,7 @@ const Filter = (): JSX.Element => { return; } - setAutoCompleteSuggestions(names); + setAutoCompleteSuggestions(formattedResult); }); }; diff --git a/www/front_src/src/Resources/Listing/api/endpoint.ts b/www/front_src/src/Resources/Listing/api/endpoint.ts index 63392625d40..341c0e2c509 100644 --- a/www/front_src/src/Resources/Listing/api/endpoint.ts +++ b/www/front_src/src/Resources/Listing/api/endpoint.ts @@ -5,11 +5,15 @@ import { resourcesEndpoint } from '../../api/endpoint'; export type ListResourcesProps = { hostCategories: Array; hostGroups: Array; + hostSeverities: Array; + hostSeverityLevels: Array; monitoringServers: Array; onlyWithPerformanceData?: boolean; resourceTypes: Array; serviceCategories: Array; serviceGroups: Array; + serviceSeverities: Array; + serviceSeverityLevels: Array; states: Array; statusTypes: Array; statuses: Array; @@ -35,6 +39,13 @@ const buildResourcesEndpoint = (parameters: ListResourcesProps): string => { name: 'only_with_performance_data', value: parameters.onlyWithPerformanceData, }, + { name: 'service_severity_names', value: parameters.serviceSeverities }, + { + name: 'service_severity_levels', + value: parameters.serviceSeverityLevels, + }, + { name: 'host_severity_names', value: parameters.hostSeverities }, + { name: 'host_severity_levels', value: parameters.hostSeverityLevels }, ], parameters, }); diff --git a/www/front_src/src/Resources/Listing/columns/Severity.tsx b/www/front_src/src/Resources/Listing/columns/Severity.tsx index 292441fd9dc..aa2eef9893e 100644 --- a/www/front_src/src/Resources/Listing/columns/Severity.tsx +++ b/www/front_src/src/Resources/Listing/columns/Severity.tsx @@ -1,13 +1,93 @@ +import { ReactNode } from 'react'; + +import { isNil } from 'ramda'; + +import Tooltip, { TooltipProps } from '@mui/material/Tooltip'; +import { makeStyles } from '@mui/styles'; + import { ComponentColumnProps } from '@centreon/ui'; -import ShortTypeChip from '../../ShortTypeChip'; +import { Severity } from '../../models'; + +const useStyles = makeStyles((theme) => ({ + container: { + display: 'flex', + }, + firstColumn: { + display: 'flex', + minWidth: theme.spacing(5), + }, + root: { + display: 'flex', + flexDirection: 'column', + }, + rowContainer: { + alignItems: 'center', + display: 'flex', + flexWrap: 'wrap', + }, + text: { + display: 'flex', + }, +})); + +interface Props { + children: ReactNode; + className?: string; + title: TooltipProps['title']; +} + +const WrapperTooltip = ({ title, children, className }: Props): JSX.Element => { + return ( + +
{children}
+
+ ); +}; + +const Title = ({ severity }: { severity: Severity }): JSX.Element => { + const classes = useStyles(); + + return ( +
+
+
name:
+
{severity.name}
+
+ +
+
level:
+
{severity.level}
+
+
+ ); +}; const SeverityColumn = ({ row }: ComponentColumnProps): JSX.Element | null => { - if (!row.severity_level) { + const classes = useStyles(); + const isSeverityIcon = !isNil(row?.severity?.icon?.url); + + if (!row?.severity) { return null; } - return ; + return ( +
+ {isSeverityIcon && ( + } + > + severity + + )} +
+ ); }; export default SeverityColumn; diff --git a/www/front_src/src/Resources/Listing/useLoadResources/index.ts b/www/front_src/src/Resources/Listing/useLoadResources/index.ts index 3e3ae35d6f1..8b312988ab5 100644 --- a/www/front_src/src/Resources/Listing/useLoadResources/index.ts +++ b/www/front_src/src/Resources/Listing/useLoadResources/index.ts @@ -97,7 +97,6 @@ const useLoadResources = (): LoadResources => { const setSending = useUpdateAtom(sendingAtom); const setSendingDetails = useUpdateAtom(sendingDetailsAtom); const clearSelectedResource = useUpdateAtom(clearSelectedResourceDerivedAtom); - const refreshIntervalRef = useRef(); const refreshIntervalMs = refreshInterval * 1000; @@ -163,6 +162,16 @@ const useLoadResources = (): LoadResources => { return criteriaValue?.map(prop('name')) as Array; }; + const getCriteriaLevels = (name: string): Array => { + const criteriaValue = getCriteriaValue(name) as + | Array + | undefined; + + const results = criteriaValue?.map(prop('name')); + + return results?.map((item) => Number(item)) as Array; + }; + if (getUrlQueryParameters().fromTopCounter) { return; } @@ -170,6 +179,8 @@ const useLoadResources = (): LoadResources => { sendRequest({ hostCategories: getCriteriaNames('host_categories'), hostGroups: getCriteriaNames('host_groups'), + hostSeverities: getCriteriaNames('host_severities'), + hostSeverityLevels: getCriteriaLevels('host_severity_levels'), limit, monitoringServers: getCriteriaNames('monitoring_servers'), page, @@ -177,6 +188,8 @@ const useLoadResources = (): LoadResources => { search, serviceCategories: getCriteriaNames('service_categories'), serviceGroups: getCriteriaNames('service_groups'), + serviceSeverities: getCriteriaNames('service_severities'), + serviceSeverityLevels: getCriteriaLevels('service_severity_levels'), sort: getSort(), states: getCriteriaIds('states'), statusTypes: getCriteriaIds('status_types'), diff --git a/www/front_src/src/Resources/decoders.ts b/www/front_src/src/Resources/decoders.ts index 8801752a605..82b947ea436 100644 --- a/www/front_src/src/Resources/decoders.ts +++ b/www/front_src/src/Resources/decoders.ts @@ -12,6 +12,7 @@ import { ResourceType, ResourceUris, Status, + Severity, } from './models'; const statusDecoder = JsonDecoder.object( @@ -22,6 +23,26 @@ const statusDecoder = JsonDecoder.object( 'Status', ); +const severityIcon = JsonDecoder.object( + { + id: JsonDecoder.number, + name: JsonDecoder.string, + url: JsonDecoder.string, + }, + 'SeverityIcon', +); + +const severityDecoder = JsonDecoder.object( + { + icon: severityIcon, + id: JsonDecoder.number, + level: JsonDecoder.number, + name: JsonDecoder.string, + type: JsonDecoder.string, + }, + 'Severity', +); + const commonDecoders = { acknowledged: JsonDecoder.optional(JsonDecoder.boolean), active_checks: JsonDecoder.optional(JsonDecoder.boolean), @@ -29,6 +50,7 @@ const commonDecoders = { icon: JsonDecoder.optional( JsonDecoder.object( { + id: JsonDecoder.optional(JsonDecoder.number), name: JsonDecoder.string, url: JsonDecoder.string, }, @@ -85,6 +107,7 @@ const commonDecoders = { name: JsonDecoder.string, notification_enabled: JsonDecoder.optional(JsonDecoder.boolean), passive_checks: JsonDecoder.optional(JsonDecoder.boolean), + severity: JsonDecoder.optional(severityDecoder), severity_level: JsonDecoder.optional(JsonDecoder.number), short_type: JsonDecoder.oneOf( [ diff --git a/www/front_src/src/Resources/models.ts b/www/front_src/src/Resources/models.ts index fc1b99a5fe3..85a77251da4 100644 --- a/www/front_src/src/Resources/models.ts +++ b/www/front_src/src/Resources/models.ts @@ -15,10 +15,19 @@ export interface NamedEntity { } export interface Icon { + id?: number; name: string; url: string; } +export interface Severity { + icon: Icon; + id: number; + level: number; + name: string; + type: string; +} + export type Parent = Omit; export interface Status { name: string; diff --git a/www/front_src/src/Resources/testUtils/index.ts b/www/front_src/src/Resources/testUtils/index.ts index c8cdc7ee16a..ce91ac6fdff 100644 --- a/www/front_src/src/Resources/testUtils/index.ts +++ b/www/front_src/src/Resources/testUtils/index.ts @@ -9,6 +9,8 @@ import { SortOrder } from '../models'; interface EndpointParams { hostCategories?: Array; hostGroups?: Array; + hostSeverities?: Array; + hostSeverityLevels?: Array; limit?: number; monitoringServers?: Array; page?: number; @@ -16,6 +18,8 @@ interface EndpointParams { search?: string; serviceCategories?: Array; serviceGroups?: Array; + serviceSeverities?: Array; + serviceSeverityLevels?: Array; sort?; states?: Array; statusTypes?: Array; @@ -41,8 +45,12 @@ const getListingEndpoint = ({ resourceTypes = defaultResourceTypes, hostGroups = [], hostCategories = [], + hostSeverities = [], + hostSeverityLevels = [], serviceCategories = [], serviceGroups = [], + serviceSeverities = [], + serviceSeverityLevels = [], monitoringServers = [], search, statusTypes = defaultStateTypes, @@ -50,6 +58,8 @@ const getListingEndpoint = ({ buildResourcesEndpoint({ hostCategories, hostGroups, + hostSeverities, + hostSeverityLevels, limit, monitoringServers, page, @@ -64,6 +74,8 @@ const getListingEndpoint = ({ : undefined, serviceCategories, serviceGroups, + serviceSeverities, + serviceSeverityLevels, sort, states, statusTypes, diff --git a/www/front_src/src/Resources/translatedLabels.ts b/www/front_src/src/Resources/translatedLabels.ts index 25215595375..1ebb6d9f0fd 100644 --- a/www/front_src/src/Resources/translatedLabels.ts +++ b/www/front_src/src/Resources/translatedLabels.ts @@ -253,3 +253,7 @@ export const labelParentAlias = 'Parent alias'; export const labelCategories = 'Categories'; export const labelHostCategory = 'Host category'; export const labelServiceCategory = 'Service category'; +export const labelServiceSeverity = 'Service severity'; +export const labelHostSeverity = 'Host severity'; +export const labelHostSeverityLevel = 'Host severity level'; +export const labelServiceSeverityLevel = 'Service severity level'; diff --git a/www/include/configuration/configObject/host_dependency/DB-Func.php b/www/include/configuration/configObject/host_dependency/DB-Func.php index a7b09cbeeaf..57209f88c74 100644 --- a/www/include/configuration/configObject/host_dependency/DB-Func.php +++ b/www/include/configuration/configObject/host_dependency/DB-Func.php @@ -123,11 +123,14 @@ function multipleHostDependencyInDB($dependencies = array(), $nbrDup = array()) "WHERE dependency_dep_id = " . $key; $dbResult = $pearDB->query($query); $fields["dep_serviceChilds"] = ""; + $statement = $pearDB->prepare("INSERT INTO dependency_serviceChild_relation " . + " VALUES (:max_dep_id, :service_id, :host_host_id)"); while ($service = $dbResult->fetch()) { - $query = "INSERT INTO dependency_serviceChild_relation VALUES ('" . - $maxId["MAX(dep_id)"] . "', '" . $service["service_service_id"] . "', '" . - $service["host_host_id"] . "')"; - $pearDB->query($query); + $statement->bindValue(':max_dep_id', (int)$maxId["MAX(dep_id)"], \PDO::PARAM_INT); + $statement->bindValue(':service_id', (int)$service["service_service_id"], \PDO::PARAM_INT); + $statement->bindValue(':host_host_id', (int)$service["host_host_id"], \PDO::PARAM_INT); + $statement->execute(); + $fields["dep_serviceChilds"] .= $service["host_host_id"] . '-' . $service["service_service_id"] . ","; } @@ -136,10 +139,12 @@ function multipleHostDependencyInDB($dependencies = array(), $nbrDup = array()) "WHERE dependency_dep_id = '" . $key . "'"; $dbResult = $pearDB->query($query); $fields["dep_hostParents"] = ""; + $statement = $pearDB->prepare("INSERT INTO dependency_hostParent_relation " . + "VALUES (:max_dep_id, :host_host_id)"); while ($host = $dbResult->fetch()) { - $query = "INSERT INTO dependency_hostParent_relation " . - "VALUES ('" . $maxId["MAX(dep_id)"] . "', '" . $host["host_host_id"] . "')"; - $pearDB->query($query); + $statement->bindValue(':max_dep_id', (int)$maxId["MAX(dep_id)"], \PDO::PARAM_INT); + $statement->bindValue(':host_host_id', (int)$host["host_host_id"], \PDO::PARAM_INT); + $statement->execute(); $fields["dep_hostParents"] .= $host["host_host_id"] . ","; } $fields["dep_hostParents"] = trim($fields["dep_hostParents"], ","); @@ -148,10 +153,12 @@ function multipleHostDependencyInDB($dependencies = array(), $nbrDup = array()) "WHERE dependency_dep_id = '" . $key . "'"; $dbResult = $pearDB->query($query); $fields["dep_hostChilds"] = ""; + $statement = $pearDB->prepare("INSERT INTO dependency_hostChild_relation " . + "VALUES (:max_dep_id, :host_host_id)"); while ($host = $dbResult->fetch()) { - $query = "INSERT INTO dependency_hostChild_relation " . - "VALUES ('" . $maxId["MAX(dep_id)"] . "', '" . $host["host_host_id"] . "')"; - $pearDB->query($query); + $statement->bindValue(':max_dep_id', (int)$maxId["MAX(dep_id)"], \PDO::PARAM_INT); + $statement->bindValue(':host_host_id', (int)$host["host_host_id"], \PDO::PARAM_INT); + $statement->execute(); $fields["dep_hostChilds"] .= $host["host_host_id"] . ","; } $fields["dep_hostChilds"] = trim($fields["dep_hostChilds"], ",");