@oneuptime/common 12.0.34 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/GlobalConfig.ts +12 -12
- package/Models/DatabaseModels/InventoryItem.ts +44 -1
- package/Models/DatabaseModels/NetworkDevice.ts +126 -0
- package/Server/EnvironmentConfig.ts +47 -16
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Infrastructure/Redis.ts +8 -8
- package/Server/Infrastructure/Status.ts +10 -4
- package/Server/Services/DatabaseService.ts +65 -13
- package/Server/Services/InventoryItemService.ts +31 -1
- package/Server/Services/MonitorTemplateService.ts +140 -19
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +349 -41
- package/Server/Services/NetworkDeviceDiscoveryScanService.ts +87 -2
- package/Server/Services/NetworkDeviceService.ts +69 -0
- package/Server/Services/UserNotificationRuleService.ts +76 -25
- package/Server/Types/Database/Permissions/ReadPermission.ts +45 -5
- package/Server/Types/Database/QueryUtil.ts +56 -0
- package/Server/Types/Markdown.ts +93 -1
- package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +82 -17
- package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +10 -1
- package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +2 -2
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +82 -35
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +31 -5
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +202 -37
- package/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.ts +82 -9
- package/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.ts +16 -7
- package/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.ts +29 -17
- package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +107 -48
- package/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.ts +158 -0
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +27 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +11 -1
- package/Server/Utils/Telemetry/TelemetryEntity.ts +83 -9
- package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +32 -0
- package/Tests/App/Dashboard/AdoptedDeviceDrawer.test.tsx +374 -0
- package/Tests/App/Dashboard/DashboardLabelVariables.test.tsx +580 -0
- package/Tests/App/Dashboard/DashboardMonitorLabelVariable.test.tsx +438 -0
- package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +5 -2
- package/Tests/App/Dashboard/DeviceAttachmentCard.test.tsx +273 -0
- package/Tests/App/Dashboard/DiscoveryReviewInventoryRefresh.test.tsx +505 -0
- package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +163 -0
- package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +401 -0
- package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +232 -0
- package/Tests/App/Dashboard/InventoryItems.test.tsx +201 -0
- package/Tests/App/Dashboard/InventoryTypeAndStatusFacets.test.tsx +798 -0
- package/Tests/App/Dashboard/NetworkTopologyLiveView.test.tsx +320 -0
- package/Tests/App/Dashboard/NetworkTopologyToolbar.test.tsx +275 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedEmptyState.test.tsx +975 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedPlanGate.test.tsx +63 -0
- package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +626 -0
- package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +348 -0
- package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +331 -0
- package/Tests/App/Dashboard/UserSettingsEmailPreferences.test.tsx +603 -0
- package/Tests/App/Dashboard/UserSettingsNotificationSettings.test.tsx +324 -0
- package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +13 -4
- package/Tests/App/StatusPage/StatusPageOidcOrigin.test.tsx +223 -0
- package/Tests/Models/InventoryItemStatus.test.ts +147 -0
- package/Tests/Models/NetworkDeviceMacAddressColumn.test.ts +294 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +129 -0
- package/Tests/Server/EnvironmentConfigValkey.test.ts +227 -0
- package/Tests/Server/Infrastructure/Postgres/AddMacAddressToNetworkDeviceMigration.test.ts +365 -0
- package/Tests/Server/Infrastructure/Postgres/CustomFieldValueMappingMigration.test.ts +62 -23
- package/Tests/Server/Infrastructure/ValkeyDeploymentConfig.test.ts +265 -0
- package/Tests/Server/Middleware/HttpMetricsMiddleware.test.ts +382 -0
- package/Tests/Server/Middleware/SCIMAuthorization.test.ts +525 -0
- package/Tests/Server/Services/DatabaseServiceAggregateBy.test.ts +291 -56
- package/Tests/Server/Services/DatabaseServiceSortTiebreaker.test.ts +151 -0
- package/Tests/Server/Services/InventoryItemManualCreate.test.ts +105 -0
- package/Tests/Server/Services/InventoryItemPromotionGate.test.ts +178 -0
- package/Tests/Server/Services/MonitorTemplateServiceCustomFieldSync.test.ts +502 -0
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +1133 -81
- package/Tests/Server/Services/NetworkDeviceDiscoveryScanRegistration.test.ts +520 -0
- package/Tests/Server/Services/NetworkDeviceMacAddressNormalization.test.ts +572 -0
- package/Tests/Server/Types/Database/InventoryStatusPostgres.test.ts +368 -0
- package/Tests/Server/Types/Database/Permissions/ReadBlockPermission.test.ts +261 -14
- package/Tests/Server/Types/Database/QueryUtilIncludesAnyOfGroups.test.ts +169 -0
- package/Tests/Server/Types/Database/QueryUtilIncludesAnyOfGroupsPostgres.test.ts +297 -0
- package/Tests/Server/Types/Markdown.test.ts +194 -1
- package/Tests/Server/Types/Workflow/Components/IncomingWebhookUtils.test.ts +279 -0
- package/Tests/Server/Types/Workflow/Components/TextToJson.test.ts +212 -0
- package/Tests/Server/Utils/CustomField/CustomFieldMappingRegistry.test.ts +436 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +214 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1 -1
- package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +10 -3
- package/Tests/Server/Utils/EventLoop.test.ts +359 -0
- package/Tests/Server/Utils/JsonWebToken.test.ts +30 -0
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteria.test.ts +242 -0
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaAggregation.test.ts +13 -7
- package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +29 -0
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +30 -6
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +246 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEmailEvalLogAgreement.test.ts +280 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +224 -10
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +570 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaExpectationBuilderUnits.test.ts +30 -5
- package/Tests/Server/Utils/Monitor/MonitorCriteriaMessageBuilderUnits.test.ts +68 -21
- package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +36 -19
- package/Tests/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.test.ts +573 -0
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +317 -0
- package/Tests/Server/Utils/Telemetry/ContextSpanProcessor.test.ts +281 -0
- package/Tests/Server/Utils/Telemetry/InventoryDuplicateIdentity.test.ts +316 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +111 -8
- package/Tests/Types/Database/IncludesAnyOfGroups.test.ts +106 -0
- package/Tests/Types/JSONFunctions.test.ts +40 -0
- package/Tests/Types/NetworkAutomation/AutoImportRunMerge.test.ts +235 -0
- package/Tests/Types/NetworkAutomation/RuleRunResult.test.ts +66 -0
- package/Tests/Types/NetworkAutomation/RuleRunResultDescribe.test.ts +309 -1
- package/Tests/Types/Telemetry/InventoryLiveness.test.ts +99 -0
- package/Tests/UI/Components/CustomFields/CustomFieldsDetail.test.tsx +160 -0
- package/Tests/UI/ReactRouterSingletonBuild.test.ts +133 -0
- package/Tests/UI/Rum/ReplayHeader.test.tsx +10 -2
- package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +514 -0
- package/Tests/UI/Rum/ReplayTimeFormat.test.ts +94 -0
- package/Tests/UI/Rum/ReplayUi.test.tsx +559 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +5 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +1 -0
- package/Tests/Utils/Dashboard/Components/DashboardMonitorListComponent.test.ts +11 -1
- package/Tests/Utils/Dashboard/LabelVariable.test.ts +257 -0
- package/Tests/Utils/Dashboard/VariableUrlState.test.ts +144 -14
- package/Tests/Utils/MetricUnitUtil.test.ts +81 -0
- package/Tests/Utils/Monitor/DeviceMacLearningUtil.test.ts +497 -0
- package/Tests/Utils/Monitor/MetricValueFormatter.test.ts +546 -0
- package/Tests/Utils/Monitor/MonitorTemplateCustomFieldUtil.test.ts +218 -0
- package/Tests/Utils/Monitor/NetworkTopologyEndpointAdoption.test.ts +1755 -0
- package/Tests/Utils/NetworkAutomation/AutoImportRunChain.test.ts +320 -0
- package/Types/BaseDatabase/IncludesAnyOfGroups.ts +77 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardMonitorListComponent.ts +1 -0
- package/Types/Dashboard/DashboardVariable.ts +8 -0
- package/Types/JSON.ts +4 -0
- package/Types/JSONFunctions.ts +16 -0
- package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +13 -0
- package/Types/NetworkAutomation/RuleRunResult.ts +402 -13
- package/Types/SerializableObjectDictionary.ts +4 -0
- package/Types/Telemetry/InventoryLiveness.ts +56 -0
- package/UI/Components/CSVFileUpload/CSVFileUpload.tsx +9 -2
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +46 -21
- package/UI/Components/Dashboard/DashboardVariableControl.tsx +285 -0
- package/UI/esbuild-config.js +6 -0
- package/Utils/Dashboard/Components/DashboardMonitorListComponent.ts +12 -1
- package/Utils/Dashboard/LabelVariable.ts +152 -0
- package/Utils/Dashboard/VariableUrlState.ts +27 -5
- package/Utils/MetricUnitUtil.ts +34 -0
- package/Utils/Monitor/DeviceMacLearningUtil.ts +177 -0
- package/Utils/Monitor/MetricValueFormatter.ts +342 -0
- package/Utils/Monitor/MonitorTemplateCustomFieldUtil.ts +124 -0
- package/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.ts +7 -2
- package/Utils/Monitor/NetworkTopologyUtil.ts +693 -0
- package/Utils/NetworkAutomation/AutoImportRunChain.ts +138 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +12 -12
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/InventoryItem.js +34 -1
- package/build/dist/Models/DatabaseModels/InventoryItem.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +128 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +44 -12
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Redis.js +8 -8
- package/build/dist/Server/Infrastructure/Redis.js.map +1 -1
- package/build/dist/Server/Infrastructure/Status.js +10 -4
- package/build/dist/Server/Infrastructure/Status.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +58 -13
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/InventoryItemService.js +28 -1
- package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +116 -17
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +270 -37
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +65 -0
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +54 -0
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +60 -25
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/ReadPermission.js +29 -4
- package/build/dist/Server/Types/Database/Permissions/ReadPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryUtil.js +36 -0
- package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +75 -0
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +53 -18
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +10 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +2 -2
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +58 -35
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +29 -5
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +166 -35
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.js +58 -9
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.js +9 -3
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.js +26 -12
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +74 -33
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.js +114 -0
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +25 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +9 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +70 -13
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Types/BaseDatabase/IncludesAnyOfGroups.js +54 -0
- package/build/dist/Types/BaseDatabase/IncludesAnyOfGroups.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardVariable.js +1 -0
- package/build/dist/Types/Dashboard/DashboardVariable.js.map +1 -1
- package/build/dist/Types/JSON.js +1 -0
- package/build/dist/Types/JSON.js.map +1 -1
- package/build/dist/Types/JSONFunctions.js +13 -0
- package/build/dist/Types/JSONFunctions.js.map +1 -1
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js +291 -6
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -1
- package/build/dist/Types/SerializableObjectDictionary.js +4 -0
- package/build/dist/Types/SerializableObjectDictionary.js.map +1 -1
- package/build/dist/Types/Telemetry/InventoryLiveness.js +37 -0
- package/build/dist/Types/Telemetry/InventoryLiveness.js.map +1 -0
- package/build/dist/UI/Components/CSVFileUpload/CSVFileUpload.js +7 -0
- package/build/dist/UI/Components/CSVFileUpload/CSVFileUpload.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +9 -2
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js +137 -0
- package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardMonitorListComponent.js +9 -1
- package/build/dist/Utils/Dashboard/Components/DashboardMonitorListComponent.js.map +1 -1
- package/build/dist/Utils/Dashboard/LabelVariable.js +96 -0
- package/build/dist/Utils/Dashboard/LabelVariable.js.map +1 -0
- package/build/dist/Utils/Dashboard/VariableUrlState.js +19 -4
- package/build/dist/Utils/Dashboard/VariableUrlState.js.map +1 -1
- package/build/dist/Utils/MetricUnitUtil.js +26 -0
- package/build/dist/Utils/MetricUnitUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/DeviceMacLearningUtil.js +112 -0
- package/build/dist/Utils/Monitor/DeviceMacLearningUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MetricValueFormatter.js +276 -0
- package/build/dist/Utils/Monitor/MetricValueFormatter.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorTemplateCustomFieldUtil.js +101 -0
- package/build/dist/Utils/Monitor/MonitorTemplateCustomFieldUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.js +7 -2
- package/build/dist/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +484 -0
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkAutomation/AutoImportRunChain.js +59 -0
- package/build/dist/Utils/NetworkAutomation/AutoImportRunChain.js.map +1 -0
- package/jest.config.json +2 -0
- package/package.json +1 -1
- package/test-setup.sh +9 -9
- package/tsconfig.json +51 -11
- package/Tests/App/Dashboard/NotificationEmailPreferences.test.tsx +0 -399
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import DatabaseService from "./DatabaseService";
|
|
2
|
-
import Model
|
|
3
|
-
|
|
2
|
+
import Model, {
|
|
3
|
+
DiscoveredNetworkDevice,
|
|
4
|
+
} from "../../Models/DatabaseModels/NetworkDeviceDiscoveryScan";
|
|
5
|
+
import { OnCreate, OnFind, OnUpdate } from "../Types/Database/Hooks";
|
|
4
6
|
import CreateBy from "../Types/Database/CreateBy";
|
|
5
7
|
import UpdateBy from "../Types/Database/UpdateBy";
|
|
6
8
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
@@ -20,6 +22,7 @@ import SnmpScanConfigUtil, {
|
|
|
20
22
|
} from "../../Utils/NetworkDiscovery/SnmpScanConfigUtil";
|
|
21
23
|
import { getNextScanAt } from "../../Utils/NetworkDiscovery/RescanIntervalUtil";
|
|
22
24
|
import ScanModeUtil from "../../Utils/NetworkDiscovery/ScanModeUtil";
|
|
25
|
+
import NetworkDeviceService from "./NetworkDeviceService";
|
|
23
26
|
|
|
24
27
|
/*
|
|
25
28
|
* The two spellings a many-to-one reference reaches a hook under: the
|
|
@@ -175,6 +178,88 @@ export class Service extends DatabaseService<Model> {
|
|
|
175
178
|
super(Model);
|
|
176
179
|
}
|
|
177
180
|
|
|
181
|
+
@CaptureSpan()
|
|
182
|
+
protected override async onFindSuccess(
|
|
183
|
+
onFind: OnFind<Model>,
|
|
184
|
+
items: Array<Model>,
|
|
185
|
+
): Promise<OnFind<Model>> {
|
|
186
|
+
/*
|
|
187
|
+
* Registration is current inventory state, not a fact about the scan.
|
|
188
|
+
* Refresh both directions so old results can be used after a deletion.
|
|
189
|
+
*/
|
|
190
|
+
const hostnamesByProject: Map<string, Set<string>> = new Map();
|
|
191
|
+
|
|
192
|
+
for (const scan of items) {
|
|
193
|
+
const projectId: ObjectID | undefined =
|
|
194
|
+
scan.projectId || onFind.findBy.props.tenantId;
|
|
195
|
+
|
|
196
|
+
if (!projectId || !Array.isArray(scan.discoveredDevices)) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
for (const host of scan.discoveredDevices) {
|
|
201
|
+
const hostname: string = this.getDiscoveredHostname(host);
|
|
202
|
+
if (!hostname) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const projectKey: string = projectId.toString();
|
|
207
|
+
if (!hostnamesByProject.has(projectKey)) {
|
|
208
|
+
hostnamesByProject.set(projectKey, new Set());
|
|
209
|
+
}
|
|
210
|
+
hostnamesByProject.get(projectKey)!.add(hostname);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const registeredByProject: Map<string, Set<string>> = new Map();
|
|
215
|
+
for (const [projectId, hostnames] of hostnamesByProject) {
|
|
216
|
+
registeredByProject.set(
|
|
217
|
+
projectId,
|
|
218
|
+
await NetworkDeviceService.getRegisteredHostnames({
|
|
219
|
+
projectId: new ObjectID(projectId),
|
|
220
|
+
hostnames: Array.from(hostnames),
|
|
221
|
+
/*
|
|
222
|
+
* The scan read has already passed its access checks. Return only
|
|
223
|
+
* the same existence flag as probe ingest, scoped to this project.
|
|
224
|
+
*/
|
|
225
|
+
props: { isRoot: true },
|
|
226
|
+
}),
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
...onFind,
|
|
232
|
+
carryForward: items.map((scan: Model): Model => {
|
|
233
|
+
const projectId: ObjectID | undefined =
|
|
234
|
+
scan.projectId || onFind.findBy.props.tenantId;
|
|
235
|
+
const registered: Set<string> | undefined = projectId
|
|
236
|
+
? registeredByProject.get(projectId.toString())
|
|
237
|
+
: undefined;
|
|
238
|
+
|
|
239
|
+
if (!registered || !Array.isArray(scan.discoveredDevices)) {
|
|
240
|
+
return scan;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return Object.assign(new Model(), scan, {
|
|
244
|
+
discoveredDevices: scan.discoveredDevices.map(
|
|
245
|
+
(host: DiscoveredNetworkDevice): DiscoveredNetworkDevice => {
|
|
246
|
+
const hostname: string = this.getDiscoveredHostname(host);
|
|
247
|
+
return hostname
|
|
248
|
+
? { ...host, isAlreadyRegistered: registered.has(hostname) }
|
|
249
|
+
: host;
|
|
250
|
+
},
|
|
251
|
+
),
|
|
252
|
+
});
|
|
253
|
+
}),
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
private getDiscoveredHostname(host: DiscoveredNetworkDevice): string {
|
|
258
|
+
return host && typeof host.ipAddress === "string"
|
|
259
|
+
? host.ipAddress.trim()
|
|
260
|
+
: "";
|
|
261
|
+
}
|
|
262
|
+
|
|
178
263
|
/*
|
|
179
264
|
* Validate the scan target at write time, with the same parser the probe
|
|
180
265
|
* expands it with (Common/Utils/NetworkDiscovery/ScanTargetUtil).
|
|
@@ -30,6 +30,7 @@ import NotAuthorizedException from "../../Types/Exception/NotAuthorizedException
|
|
|
30
30
|
import ObjectID from "../../Types/ObjectID";
|
|
31
31
|
import OneUptimeDate from "../../Types/Date";
|
|
32
32
|
import CidrMatchUtil from "../../Utils/NetworkSite/CidrMatchUtil";
|
|
33
|
+
import { normalizeMac } from "../../Utils/Monitor/EndpointAttachmentUtil";
|
|
33
34
|
import { SiteAssignmentRuleRunResult } from "../../Types/NetworkAutomation/RuleRunResult";
|
|
34
35
|
import { NetworkDeviceMonitoringMethodUtil } from "../../Types/NetworkDevice/NetworkDeviceMonitoringMethod";
|
|
35
36
|
import RelationIdUtil from "../Utils/Database/RelationIdUtil";
|
|
@@ -96,6 +97,61 @@ const SITE_KEYS: Array<string> = ["siteId", "site"];
|
|
|
96
97
|
* otherwise a no-op rewrite of sysName on every SNMP walk would look like a
|
|
97
98
|
* change and re-run the rules for the whole fleet every polling cycle.
|
|
98
99
|
*/
|
|
100
|
+
/*
|
|
101
|
+
* The MAC address column, normalised on the way in.
|
|
102
|
+
*
|
|
103
|
+
* Every spelling an operator is likely to paste - AA-BB-CC-DD-EE-FF,
|
|
104
|
+
* aabb.ccdd.eeff, aa:bb:cc:dd:ee:ff, twelve bare hex digits, with or
|
|
105
|
+
* without 0x - is stored as lowercase colon form, because that is the form
|
|
106
|
+
* every endpoint row already holds and the topology builder compares the
|
|
107
|
+
* two as plain strings. Anything that is not twelve hex digits once the
|
|
108
|
+
* separators are gone is refused outright rather than stored to match
|
|
109
|
+
* nothing forever. Blank clears the column, so "delete what I typed"
|
|
110
|
+
* works from a form that cannot post null.
|
|
111
|
+
*
|
|
112
|
+
* Shared by create and update, so it takes the raw payload: a create's
|
|
113
|
+
* data is a model instance and an update's is a QueryDeepPartialEntity, and
|
|
114
|
+
* on the latter a column may hold a SQL-expression function, which is left
|
|
115
|
+
* alone - nothing in the tree writes this column that way, and refusing it
|
|
116
|
+
* would only make a future caller's life harder for no safety gained.
|
|
117
|
+
*
|
|
118
|
+
* Every value that lands this way is the operator's, so the provenance flag
|
|
119
|
+
* is cleared beside it: the ARP pass writes hook-free and never comes
|
|
120
|
+
* through here, and it may only correct a value it wrote itself.
|
|
121
|
+
*/
|
|
122
|
+
function normalizeMacAddressOnWrite(data: Record<string, unknown>): void {
|
|
123
|
+
if (!("macAddress" in data)) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const raw: unknown = data["macAddress"];
|
|
128
|
+
|
|
129
|
+
// TypeORM drops undefined before it builds the SET list; null clears.
|
|
130
|
+
if (raw === undefined || raw === null || typeof raw === "function") {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (typeof raw !== "string") {
|
|
135
|
+
throw new BadDataException("MAC Address must be text.");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (raw.trim().length === 0) {
|
|
139
|
+
data["macAddress"] = null;
|
|
140
|
+
data["isMacAddressLearned"] = false;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const normalized: string | undefined = normalizeMac(raw);
|
|
145
|
+
if (!normalized) {
|
|
146
|
+
throw new BadDataException(
|
|
147
|
+
"MAC Address must be six pairs of hex digits, for example aa:bb:cc:dd:ee:ff. Dashes, dots and bare hex are accepted too.",
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
data["macAddress"] = normalized;
|
|
152
|
+
data["isMacAddressLearned"] = false;
|
|
153
|
+
}
|
|
154
|
+
|
|
99
155
|
function normalizeIdentityValue(value: unknown): string {
|
|
100
156
|
if (value === null || value === undefined) {
|
|
101
157
|
return "";
|
|
@@ -1239,6 +1295,10 @@ export class Service extends DatabaseService<Model> {
|
|
|
1239
1295
|
protected override async onBeforeCreate(
|
|
1240
1296
|
createBy: CreateBy<Model>,
|
|
1241
1297
|
): Promise<OnCreate<Model>> {
|
|
1298
|
+
normalizeMacAddressOnWrite(
|
|
1299
|
+
createBy.data as unknown as Record<string, unknown>,
|
|
1300
|
+
);
|
|
1301
|
+
|
|
1242
1302
|
/*
|
|
1243
1303
|
* Read both spellings: the dashboard posts the `site` relation, not the
|
|
1244
1304
|
* `siteId` column, so guarding only `siteId` let a UI-created device
|
|
@@ -1523,6 +1583,15 @@ export class Service extends DatabaseService<Model> {
|
|
|
1523
1583
|
): Promise<OnUpdate<Model>> {
|
|
1524
1584
|
const dataKeys: Array<string> = Object.keys(updateBy.data || {});
|
|
1525
1585
|
|
|
1586
|
+
/*
|
|
1587
|
+
* Above the early return, like the id guards below it: a malformed
|
|
1588
|
+
* MAC is refused on every write shape, not only on the ones that
|
|
1589
|
+
* happen to need the snapshot.
|
|
1590
|
+
*/
|
|
1591
|
+
normalizeMacAddressOnWrite(
|
|
1592
|
+
updateBy.data as unknown as Record<string, unknown>,
|
|
1593
|
+
);
|
|
1594
|
+
|
|
1526
1595
|
/*
|
|
1527
1596
|
* Switching a device to monitor-backed turns polling off with it. The
|
|
1528
1597
|
* two are one decision, not two: a monitor-backed device's health is
|
|
@@ -982,6 +982,16 @@ export class Service extends DatabaseService<Model> {
|
|
|
982
982
|
rootCause: true,
|
|
983
983
|
incidentNumber: true,
|
|
984
984
|
incidentNumberWithPrefix: true,
|
|
985
|
+
/*
|
|
986
|
+
* AcknowledgeIncident.hbs asks for a Resources Affected row and
|
|
987
|
+
* the generator had nothing to build it from, so the row was
|
|
988
|
+
* silently dropped — the same `{{#if}}` swallow that hid the
|
|
989
|
+
* alert's Root Cause.
|
|
990
|
+
*/
|
|
991
|
+
monitors: {
|
|
992
|
+
_id: true,
|
|
993
|
+
name: true,
|
|
994
|
+
},
|
|
985
995
|
},
|
|
986
996
|
});
|
|
987
997
|
}
|
|
@@ -1012,6 +1022,20 @@ export class Service extends DatabaseService<Model> {
|
|
|
1012
1022
|
},
|
|
1013
1023
|
alertNumber: true,
|
|
1014
1024
|
alertNumberWithPrefix: true,
|
|
1025
|
+
/*
|
|
1026
|
+
* AcknowledgeAlert.hbs has always asked for a Root Cause row, but
|
|
1027
|
+
* this select never loaded the column and the template's
|
|
1028
|
+
* `{{#if text}}` guard silently dropped the row — so the one
|
|
1029
|
+
* person being woken up for the alert was the only one who could
|
|
1030
|
+
* not see why it fired. The other three on-call templates already
|
|
1031
|
+
* select it.
|
|
1032
|
+
*/
|
|
1033
|
+
rootCause: true,
|
|
1034
|
+
// Same story for the template's Resources Affected row.
|
|
1035
|
+
monitor: {
|
|
1036
|
+
_id: true,
|
|
1037
|
+
name: true,
|
|
1038
|
+
},
|
|
1015
1039
|
},
|
|
1016
1040
|
});
|
|
1017
1041
|
}
|
|
@@ -4589,6 +4613,11 @@ export class Service extends DatabaseService<Model> {
|
|
|
4589
4613
|
MarkdownContentType.Email,
|
|
4590
4614
|
),
|
|
4591
4615
|
alertSeverity: alert.alertSeverity!.name!,
|
|
4616
|
+
resourcesAffected: alert.monitor?.name || "No resources identified",
|
|
4617
|
+
rootCause: await Markdown.convertToHTML(
|
|
4618
|
+
alert.rootCause || "No root cause identified for this alert",
|
|
4619
|
+
MarkdownContentType.Email,
|
|
4620
|
+
),
|
|
4592
4621
|
alertViewLink: (
|
|
4593
4622
|
await AlertService.getAlertLinkInDashboard(alert.projectId!, alert.id!)
|
|
4594
4623
|
).toString(),
|
|
@@ -4634,8 +4663,19 @@ export class Service extends DatabaseService<Model> {
|
|
|
4634
4663
|
MarkdownContentType.Email,
|
|
4635
4664
|
),
|
|
4636
4665
|
incidentSeverity: incident.incidentSeverity!.name!,
|
|
4637
|
-
|
|
4666
|
+
resourcesAffected:
|
|
4667
|
+
(incident.monitors || [])
|
|
4668
|
+
.map((monitor: Monitor): string => {
|
|
4669
|
+
return monitor.name || "";
|
|
4670
|
+
})
|
|
4671
|
+
.filter((name: string): boolean => {
|
|
4672
|
+
return name.length > 0;
|
|
4673
|
+
})
|
|
4674
|
+
.join(", ") || "No resources identified",
|
|
4675
|
+
rootCause: await Markdown.convertToHTML(
|
|
4638
4676
|
incident.rootCause || "No root cause identified for this incident",
|
|
4677
|
+
MarkdownContentType.Email,
|
|
4678
|
+
),
|
|
4639
4679
|
incidentViewLink: (
|
|
4640
4680
|
await IncidentService.getIncidentLinkInDashboard(
|
|
4641
4681
|
incident.projectId!,
|
|
@@ -4738,7 +4778,9 @@ export class Service extends DatabaseService<Model> {
|
|
|
4738
4778
|
if (alerts.length > 0) {
|
|
4739
4779
|
const alertRows: string[] = [];
|
|
4740
4780
|
for (const alert of alerts) {
|
|
4741
|
-
const alertTitle: string =
|
|
4781
|
+
const alertTitle: string = Markdown.escapeHtml(
|
|
4782
|
+
alert.title || "Untitled Alert",
|
|
4783
|
+
);
|
|
4742
4784
|
const alertNumber: string =
|
|
4743
4785
|
alert.alertNumberWithPrefix ||
|
|
4744
4786
|
(alert.alertNumber ? `#${alert.alertNumber}` : "");
|
|
@@ -4748,20 +4790,22 @@ export class Service extends DatabaseService<Model> {
|
|
|
4748
4790
|
alert.id!,
|
|
4749
4791
|
)
|
|
4750
4792
|
).toString();
|
|
4751
|
-
const monitorName: string =
|
|
4793
|
+
const monitorName: string = Markdown.escapeHtml(
|
|
4794
|
+
alert.monitor?.name || "",
|
|
4795
|
+
);
|
|
4752
4796
|
|
|
4753
4797
|
alertRows.push(`
|
|
4754
4798
|
<tr>
|
|
4755
|
-
<td style="padding:
|
|
4756
|
-
<table cellpadding="0" cellspacing="0" width="100%">
|
|
4799
|
+
<td style="padding: 16px 20px; border-bottom: 1px solid #e2e8f0; overflow-wrap: anywhere; word-break: break-word;">
|
|
4800
|
+
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="width: 100%; table-layout: fixed;">
|
|
4757
4801
|
<tr>
|
|
4758
4802
|
<td style="vertical-align: middle;">
|
|
4759
|
-
<span style="display: inline-block; background-color: #
|
|
4760
|
-
<a href="${alertLink}" style="color: #
|
|
4761
|
-
${monitorName ? `<span style="display: block; color: #64748b; font-size:
|
|
4803
|
+
<span style="display: inline-block; background-color: #f1f5f9; color: #111111; font-size: 12px; font-weight: 600; padding: 2px 8px; border-radius: 4px; margin-right: 8px;">${alertNumber}</span>
|
|
4804
|
+
<a href="${alertLink}" style="color: #111111; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 15px; line-height: 24px; font-weight: 600; text-decoration: underline; text-underline-offset: 3px;">${alertTitle}</a>
|
|
4805
|
+
${monitorName ? `<span style="display: block; color: #64748b; font-size: 13px; line-height: 20px; margin-top: 6px;">Monitor: ${monitorName}</span>` : ""}
|
|
4762
4806
|
</td>
|
|
4763
|
-
<td style="text-align: right; vertical-align: middle;">
|
|
4764
|
-
<a href="${alertLink}" style="color: #
|
|
4807
|
+
<td width="52" style="text-align: right; vertical-align: middle; padding-left: 8px;">
|
|
4808
|
+
<a href="${alertLink}" style="color: #111111; font-size: 13px; line-height: 20px; text-decoration: underline;">View →</a>
|
|
4765
4809
|
</td>
|
|
4766
4810
|
</tr>
|
|
4767
4811
|
</table>
|
|
@@ -4771,7 +4815,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
4771
4815
|
}
|
|
4772
4816
|
if (alertRows.length > 0) {
|
|
4773
4817
|
alertsListHtml = `
|
|
4774
|
-
<table cellpadding="0" cellspacing="0" width="100%" style="
|
|
4818
|
+
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="width: 100%; table-layout: fixed; background-color: #f8fafc; border-radius: 12px; border: 1px solid #e2e8f0; margin: 8px 0 16px 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
|
|
4775
4819
|
<tbody>
|
|
4776
4820
|
${alertRows.join("")}
|
|
4777
4821
|
</tbody>
|
|
@@ -4795,9 +4839,11 @@ export class Service extends DatabaseService<Model> {
|
|
|
4795
4839
|
),
|
|
4796
4840
|
alertEpisodeSeverity: alertEpisode.alertSeverity!.name!,
|
|
4797
4841
|
resourcesAffected: resourcesAffected,
|
|
4798
|
-
rootCause:
|
|
4842
|
+
rootCause: await Markdown.convertToHTML(
|
|
4799
4843
|
alertEpisode.rootCause ||
|
|
4800
|
-
|
|
4844
|
+
"No root cause identified for this alert episode",
|
|
4845
|
+
MarkdownContentType.Email,
|
|
4846
|
+
),
|
|
4801
4847
|
alertsList: alertsListHtml,
|
|
4802
4848
|
alertsCount: alerts.length.toString(),
|
|
4803
4849
|
alertEpisodeViewLink: (
|
|
@@ -4908,7 +4954,9 @@ export class Service extends DatabaseService<Model> {
|
|
|
4908
4954
|
if (incidents.length > 0) {
|
|
4909
4955
|
const incidentRows: string[] = [];
|
|
4910
4956
|
for (const incident of incidents) {
|
|
4911
|
-
const incidentTitle: string =
|
|
4957
|
+
const incidentTitle: string = Markdown.escapeHtml(
|
|
4958
|
+
incident.title || "Untitled Incident",
|
|
4959
|
+
);
|
|
4912
4960
|
const incidentNumber: string =
|
|
4913
4961
|
incident.incidentNumberWithPrefix ||
|
|
4914
4962
|
(incident.incidentNumber ? `#${incident.incidentNumber}` : "");
|
|
@@ -4918,7 +4966,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
4918
4966
|
incident.id!,
|
|
4919
4967
|
)
|
|
4920
4968
|
).toString();
|
|
4921
|
-
const monitorName: string =
|
|
4969
|
+
const monitorName: string = Markdown.escapeHtml(
|
|
4922
4970
|
(incident.monitors || [])
|
|
4923
4971
|
.map((monitor: Monitor): string => {
|
|
4924
4972
|
return monitor.name || "";
|
|
@@ -4926,20 +4974,21 @@ export class Service extends DatabaseService<Model> {
|
|
|
4926
4974
|
.filter((name: string): boolean => {
|
|
4927
4975
|
return name.length > 0;
|
|
4928
4976
|
})
|
|
4929
|
-
.join(", ") || ""
|
|
4977
|
+
.join(", ") || "",
|
|
4978
|
+
);
|
|
4930
4979
|
|
|
4931
4980
|
incidentRows.push(`
|
|
4932
4981
|
<tr>
|
|
4933
|
-
<td style="padding:
|
|
4934
|
-
<table cellpadding="0" cellspacing="0" width="100%">
|
|
4982
|
+
<td style="padding: 16px 20px; border-bottom: 1px solid #e2e8f0; overflow-wrap: anywhere; word-break: break-word;">
|
|
4983
|
+
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="width: 100%; table-layout: fixed;">
|
|
4935
4984
|
<tr>
|
|
4936
4985
|
<td style="vertical-align: middle;">
|
|
4937
4986
|
<span style="display: inline-block; background-color: #fee2e2; color: #991b1b; font-size: 12px; font-weight: 600; padding: 2px 8px; border-radius: 4px; margin-right: 8px;">${incidentNumber}</span>
|
|
4938
|
-
<a href="${incidentLink}" style="color: #
|
|
4939
|
-
${monitorName ? `<span style="display: block; color: #64748b; font-size:
|
|
4987
|
+
<a href="${incidentLink}" style="color: #111111; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 15px; line-height: 24px; font-weight: 600; text-decoration: underline; text-underline-offset: 3px;">${incidentTitle}</a>
|
|
4988
|
+
${monitorName ? `<span style="display: block; color: #64748b; font-size: 13px; line-height: 20px; margin-top: 6px;">Monitor: ${monitorName}</span>` : ""}
|
|
4940
4989
|
</td>
|
|
4941
|
-
<td style="text-align: right; vertical-align: middle;">
|
|
4942
|
-
<a href="${incidentLink}" style="color: #
|
|
4990
|
+
<td width="52" style="text-align: right; vertical-align: middle; padding-left: 8px;">
|
|
4991
|
+
<a href="${incidentLink}" style="color: #111111; font-size: 13px; line-height: 20px; text-decoration: underline;">View →</a>
|
|
4943
4992
|
</td>
|
|
4944
4993
|
</tr>
|
|
4945
4994
|
</table>
|
|
@@ -4949,7 +4998,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
4949
4998
|
}
|
|
4950
4999
|
if (incidentRows.length > 0) {
|
|
4951
5000
|
incidentsListHtml = `
|
|
4952
|
-
<table cellpadding="0" cellspacing="0" width="100%" style="
|
|
5001
|
+
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="width: 100%; table-layout: fixed; background-color: #f8fafc; border-radius: 12px; border: 1px solid #e2e8f0; margin: 8px 0 16px 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
|
|
4953
5002
|
<tbody>
|
|
4954
5003
|
${incidentRows.join("")}
|
|
4955
5004
|
</tbody>
|
|
@@ -4975,9 +5024,11 @@ export class Service extends DatabaseService<Model> {
|
|
|
4975
5024
|
),
|
|
4976
5025
|
incidentEpisodeSeverity: incidentEpisode.incidentSeverity!.name!,
|
|
4977
5026
|
resourcesAffected: resourcesAffected,
|
|
4978
|
-
rootCause:
|
|
5027
|
+
rootCause: await Markdown.convertToHTML(
|
|
4979
5028
|
incidentEpisode.rootCause ||
|
|
4980
|
-
|
|
5029
|
+
"No root cause identified for this incident episode",
|
|
5030
|
+
MarkdownContentType.Email,
|
|
5031
|
+
),
|
|
4981
5032
|
incidentsList: incidentsListHtml,
|
|
4982
5033
|
incidentsCount: incidents.length.toString(),
|
|
4983
5034
|
incidentEpisodeViewLink: (
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import DatabaseRequestType from "../../BaseDatabase/DatabaseRequestType";
|
|
2
2
|
import Query from "../Query";
|
|
3
3
|
import QueryHelper from "../QueryHelper";
|
|
4
|
+
import QueryUtil from "../QueryUtil";
|
|
4
5
|
import RelationSelect from "../RelationSelect";
|
|
5
6
|
import Select from "../Select";
|
|
6
7
|
import SelectUtil from "../SelectUtil";
|
|
@@ -12,8 +13,11 @@ import DatabaseCommonInteractionPropsUtil, {
|
|
|
12
13
|
PermissionType,
|
|
13
14
|
} from "../../../../Types/BaseDatabase/DatabaseCommonInteractionPropsUtil";
|
|
14
15
|
import ObjectID from "../../../../Types/ObjectID";
|
|
16
|
+
import BadDataException from "../../../../Types/Exception/BadDataException";
|
|
15
17
|
import Permission, { UserPermission } from "../../../../Types/Permission";
|
|
16
18
|
import CaptureSpan from "../../../Utils/Telemetry/CaptureSpan";
|
|
19
|
+
import { combineWithPrivacyClause } from "../../../Utils/PrivacyFilterUtil";
|
|
20
|
+
import { FindOperator } from "typeorm";
|
|
17
21
|
|
|
18
22
|
export interface CheckReadPermissionType<TBaseModel extends BaseModel>
|
|
19
23
|
extends CheckPermissionBaseInterface<TBaseModel> {
|
|
@@ -119,13 +123,49 @@ export default class ReadPermission {
|
|
|
119
123
|
}
|
|
120
124
|
}
|
|
121
125
|
|
|
122
|
-
// now add these to query
|
|
123
|
-
|
|
124
126
|
const model: TBaseModel = new modelType();
|
|
127
|
+
const accessControlColumn: string | null = model.getAccessControlColumn();
|
|
128
|
+
const manyToManyMeta: ReturnType<
|
|
129
|
+
typeof QueryUtil.getManyToManyRelationMetadata
|
|
130
|
+
> = accessControlColumn
|
|
131
|
+
? QueryUtil.getManyToManyRelationMetadata(modelType, accessControlColumn)
|
|
132
|
+
: null;
|
|
133
|
+
|
|
134
|
+
if (!manyToManyMeta) {
|
|
135
|
+
throw new BadDataException(
|
|
136
|
+
"Cannot apply read label restrictions without access-control relation metadata.",
|
|
137
|
+
);
|
|
138
|
+
}
|
|
125
139
|
|
|
126
|
-
|
|
127
|
-
_id:
|
|
128
|
-
};
|
|
140
|
+
const idQuery: Query<TBaseModel> = QueryUtil.serializeQuery(modelType, {
|
|
141
|
+
_id: query._id,
|
|
142
|
+
} as Query<TBaseModel>);
|
|
143
|
+
const existingIdFilter: unknown = idQuery._id;
|
|
144
|
+
if (
|
|
145
|
+
existingIdFilter !== undefined &&
|
|
146
|
+
typeof existingIdFilter !== "string" &&
|
|
147
|
+
!(existingIdFilter instanceof FindOperator)
|
|
148
|
+
) {
|
|
149
|
+
throw new BadDataException(
|
|
150
|
+
"Cannot combine read label restrictions with an unsupported ID filter.",
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/*
|
|
155
|
+
* Keep the caller's label selection intact. Blocking labels is a separate
|
|
156
|
+
* condition on the owner: it must have none of the blocked label links.
|
|
157
|
+
* Applying that condition to _id also lets grouped dashboard label filters
|
|
158
|
+
* and existing record selectors reach QueryUtil without being replaced.
|
|
159
|
+
* Serialize the ID condition first because QueryUtil does not descend into
|
|
160
|
+
* the database AND operator to convert application query operators later.
|
|
161
|
+
*/
|
|
162
|
+
(query as any)._id = combineWithPrivacyClause(
|
|
163
|
+
existingIdFilter,
|
|
164
|
+
QueryHelper.noneEntitiesInManyToMany({
|
|
165
|
+
values: labelIds,
|
|
166
|
+
...manyToManyMeta,
|
|
167
|
+
}),
|
|
168
|
+
);
|
|
129
169
|
|
|
130
170
|
return { query };
|
|
131
171
|
}
|
|
@@ -7,6 +7,7 @@ import GreaterThanOrEqual from "../../../Types/BaseDatabase/GreaterThanOrEqual";
|
|
|
7
7
|
import InBetween from "../../../Types/BaseDatabase/InBetween";
|
|
8
8
|
import Includes from "../../../Types/BaseDatabase/Includes";
|
|
9
9
|
import IncludesAll from "../../../Types/BaseDatabase/IncludesAll";
|
|
10
|
+
import IncludesAnyOfGroups from "../../../Types/BaseDatabase/IncludesAnyOfGroups";
|
|
10
11
|
import IncludesNone from "../../../Types/BaseDatabase/IncludesNone";
|
|
11
12
|
import StartsWith from "../../../Types/BaseDatabase/StartsWith";
|
|
12
13
|
import EndsWith from "../../../Types/BaseDatabase/EndsWith";
|
|
@@ -24,6 +25,7 @@ import { TableColumnMetadata } from "../../../Types/Database/TableColumn";
|
|
|
24
25
|
import TableColumnType from "../../../Types/Database/TableColumnType";
|
|
25
26
|
import { JSONObject } from "../../../Types/JSON";
|
|
26
27
|
import ObjectID from "../../../Types/ObjectID";
|
|
28
|
+
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
27
29
|
import Typeof from "../../../Types/Typeof";
|
|
28
30
|
import { And, DataSource } from "typeorm";
|
|
29
31
|
import { FindOperator } from "typeorm/find-options/FindOperator";
|
|
@@ -45,6 +47,7 @@ export default class QueryUtil {
|
|
|
45
47
|
const model: BaseModel = new modelType();
|
|
46
48
|
|
|
47
49
|
query = query as Query<TBaseModel>;
|
|
50
|
+
const groupedRelationFilters: Array<FindOperator<unknown>> = [];
|
|
48
51
|
|
|
49
52
|
/*
|
|
50
53
|
* Multi-field text search:
|
|
@@ -126,6 +129,37 @@ export default class QueryUtil {
|
|
|
126
129
|
const tableColumnMetadata: TableColumnMetadata =
|
|
127
130
|
model.getTableColumnMetadata(key);
|
|
128
131
|
|
|
132
|
+
if (query[key] instanceof IncludesAnyOfGroups) {
|
|
133
|
+
if (tableColumnMetadata?.type !== TableColumnType.EntityArray) {
|
|
134
|
+
throw new BadDataException(
|
|
135
|
+
"IncludesAnyOfGroups requires a many-to-many entity relation.",
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const relation: {
|
|
140
|
+
joinTableName: string;
|
|
141
|
+
ownerColumnName: string;
|
|
142
|
+
relationColumnName: string;
|
|
143
|
+
} | null = QueryUtil.getManyToManyRelationMetadata(modelType, key);
|
|
144
|
+
|
|
145
|
+
if (!relation) {
|
|
146
|
+
throw new BadDataException(
|
|
147
|
+
"IncludesAnyOfGroups requires available many-to-many relation metadata.",
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
for (const group of (query[key] as IncludesAnyOfGroups).groups) {
|
|
152
|
+
groupedRelationFilters.push(
|
|
153
|
+
QueryHelper.anyOfEntitiesInManyToMany({
|
|
154
|
+
...relation,
|
|
155
|
+
values: group,
|
|
156
|
+
}) as FindOperator<unknown>,
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
delete query[key];
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
|
|
129
163
|
if (tableColumnMetadata && query[key] === null) {
|
|
130
164
|
query[key] = QueryHelper.isNull();
|
|
131
165
|
} else if (
|
|
@@ -634,6 +668,28 @@ export default class QueryUtil {
|
|
|
634
668
|
}
|
|
635
669
|
}
|
|
636
670
|
|
|
671
|
+
if (groupedRelationFilters.length > 0) {
|
|
672
|
+
/*
|
|
673
|
+
* Apply these only after scalar operators have been serialized, so an
|
|
674
|
+
* existing id condition survives regardless of the query's key order.
|
|
675
|
+
*/
|
|
676
|
+
const existingIdFilter: unknown = query._id;
|
|
677
|
+
if (existingIdFilter !== undefined) {
|
|
678
|
+
if (existingIdFilter instanceof FindOperator) {
|
|
679
|
+
groupedRelationFilters.unshift(existingIdFilter);
|
|
680
|
+
} else if (typeof existingIdFilter === "string") {
|
|
681
|
+
groupedRelationFilters.unshift(
|
|
682
|
+
QueryHelper.equalTo(existingIdFilter) as FindOperator<unknown>,
|
|
683
|
+
);
|
|
684
|
+
} else {
|
|
685
|
+
throw new BadDataException(
|
|
686
|
+
"IncludesAnyOfGroups cannot combine an unsupported id filter.",
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
query._id = And(...groupedRelationFilters) as any;
|
|
691
|
+
}
|
|
692
|
+
|
|
637
693
|
return query;
|
|
638
694
|
}
|
|
639
695
|
|