@oneuptime/common 14.0.6 → 14.0.8
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/Incident.ts +267 -1
- package/Models/DatabaseModels/IncidentCustomField.ts +202 -0
- package/Models/DatabaseModels/IncidentEpisode.ts +30 -0
- package/Models/DatabaseModels/IncidentTemplate.ts +126 -1
- package/Models/DatabaseModels/InventoryItem.ts +23 -12
- package/Models/DatabaseModels/StatusPage.ts +55 -0
- package/Models/DatabaseModels/StatusPageSubscriber.ts +128 -0
- package/Server/API/IncidentAPI.ts +162 -0
- package/Server/API/StatusPageAPI.ts +487 -171
- package/Server/API/StatusPageSubscriberAPI.ts +63 -15
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.ts +217 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.ts +49 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.ts +108 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.ts +51 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.ts +168 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.ts +44 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +16 -0
- package/Server/Infrastructure/Semaphore.ts +10 -0
- package/Server/Middleware/IdentityRateLimit.ts +108 -3
- package/Server/Middleware/SubscriberNotificationPreviewRateLimit.ts +237 -0
- package/Server/Middleware/SubscriberNotificationTestSendRateLimit.ts +304 -0
- package/Server/Services/AlertService.ts +32 -36
- package/Server/Services/DatabaseService.ts +93 -10
- package/Server/Services/IncidentAlertService.ts +609 -2
- package/Server/Services/IncidentCustomFieldService.ts +276 -1
- package/Server/Services/IncidentEpisodePublicNoteService.ts +28 -0
- package/Server/Services/IncidentEpisodeService.ts +15 -0
- package/Server/Services/IncidentEpisodeStateTimelineService.ts +27 -1
- package/Server/Services/IncidentPublicNoteService.ts +30 -1
- package/Server/Services/IncidentService.ts +1663 -103
- package/Server/Services/IncidentStateTimelineService.ts +13 -0
- package/Server/Services/IncidentTemplateService.ts +109 -0
- package/Server/Services/InventoryItemService.ts +38 -0
- package/Server/Services/IoTDeviceCredentialService.ts +13 -4
- package/Server/Services/ScheduledMaintenancePublicNoteService.ts +30 -1
- package/Server/Services/ScheduledMaintenanceService.ts +118 -64
- package/Server/Services/SmsService.ts +10 -0
- package/Server/Services/StatusPageService.ts +65 -8
- package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +299 -37
- package/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.ts +129 -0
- package/Server/Services/StatusPageSubscriberService.ts +1161 -64
- package/Server/Services/UserNotificationRuleService.ts +55 -53
- package/Server/Services/WorkspaceNotificationSummaryService.ts +38 -20
- package/Server/Types/Markdown.ts +153 -6
- package/Server/Types/Workflow/Components/Email.ts +61 -2
- package/Server/Utils/AffectedResources/LinkedAffectedResources.ts +576 -0
- package/Server/Utils/Alert/AlertStateChangeAuthorization.ts +129 -0
- package/Server/Utils/CustomField/CustomFieldRename.ts +378 -0
- package/Server/Utils/DataSource/EgressGuard.ts +66 -21
- package/Server/Utils/Inventory/InventoryOverviewAggregation.ts +111 -0
- package/Server/Utils/Mail/PinnedSmtpSocket.ts +130 -0
- package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +10 -0
- package/Server/Utils/Response.ts +31 -0
- package/Server/Utils/SSRFProtection.ts +76 -16
- package/Server/Utils/StatusPage/IncidentStatusPageScope.ts +948 -0
- package/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.ts +656 -0
- package/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.ts +805 -0
- package/Server/Utils/StatusPage/StatusPageExclusion.ts +18 -0
- package/Server/Utils/StatusPage/StatusPageReadAccess.ts +125 -0
- package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.ts +151 -0
- package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.ts +70 -0
- package/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.ts +421 -0
- package/Server/Utils/StatusPage/SubscriberNotificationClaim.ts +107 -0
- package/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.ts +1049 -0
- package/Server/Utils/StatusPage/SubscriberNotificationFanOut.ts +180 -0
- package/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.ts +839 -0
- package/Server/Utils/StatusPage/SubscriberNotificationResendAccess.ts +393 -0
- package/Server/Utils/StatusPage/SubscriberNotificationRunLimit.ts +246 -0
- package/Server/Utils/StatusPage/SubscriberNotificationTiming.ts +133 -0
- package/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.ts +215 -0
- package/Server/Utils/StatusPageResource.ts +51 -20
- package/Server/Utils/Topology/TopologyConcurrencyLimiter.ts +229 -0
- package/Server/Utils/Topology/TopologyQueries.ts +1350 -0
- package/Server/Utils/Topology/TopologyRequest.ts +463 -0
- package/Server/Utils/Topology/TopologyResponseCache.ts +183 -0
- package/Server/Utils/Topology/TopologySql.ts +1024 -0
- package/Server/Utils/VM/VMAPI.ts +1 -0
- package/Server/Utils/VM/VMRunner.ts +10 -0
- package/Server/Utils/Workflow/OAuth2TokenClient.ts +10 -0
- package/Server/Views/Partials/SensitiveUrlToken.ejs +8 -5
- package/Tests/App/Accounts/RegisterVerifyEmail.test.tsx +748 -0
- package/Tests/App/Accounts/ResendVerificationEmail.test.tsx +1222 -0
- package/Tests/App/Accounts/VerificationEmailResendUtils.test.ts +797 -0
- package/Tests/App/Accounts/VerifyEmailPending.test.tsx +538 -0
- package/Tests/App/Accounts/VerifyEmailResend.test.tsx +779 -0
- package/Tests/App/Dashboard/AcknowledgeAlertsOnDeclare.test.ts +369 -0
- package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +1 -1
- package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +510 -123
- package/Tests/App/Dashboard/AlertsTableAffectedResources.test.tsx +490 -0
- package/Tests/App/Dashboard/ChangeAlertStateDeclareIncident.test.tsx +886 -0
- package/Tests/App/Dashboard/CreateReviewStepRoleSummary.test.tsx +1250 -0
- package/Tests/App/Dashboard/CreateReviewStepSelectionSummary.test.tsx +738 -0
- package/Tests/App/Dashboard/CustomFieldsSettingsIncidentOptions.test.tsx +357 -0
- package/Tests/App/Dashboard/DeclareIncidentFromAlert.test.ts +417 -0
- package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +1948 -229
- package/Tests/App/Dashboard/EntityDetailPanelLifecycle.test.tsx +493 -0
- package/Tests/App/Dashboard/EntityDetailPanelNavigation.test.tsx +439 -0
- package/Tests/App/Dashboard/EventNotes.test.tsx +776 -0
- package/Tests/App/Dashboard/EventNotesPages.test.tsx +119 -0
- package/Tests/App/Dashboard/EventNotesUtil.test.ts +116 -17
- package/Tests/App/Dashboard/EventOverviewPages.test.tsx +534 -6
- package/Tests/App/Dashboard/EventStatusPanel.test.tsx +798 -2
- package/Tests/App/Dashboard/FetchStateAndSeverityElements.test.tsx +669 -0
- package/Tests/App/Dashboard/FetchUsers.test.tsx +230 -0
- package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +91 -1
- package/Tests/App/Dashboard/IncidentCreateAcknowledgeAlerts.test.tsx +1611 -0
- package/Tests/App/Dashboard/IncidentCreateDetailsStep.test.tsx +643 -0
- package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +8 -1
- package/Tests/App/Dashboard/IncidentCreateStatusPageScope.test.tsx +601 -0
- package/Tests/App/Dashboard/IncidentCustomFieldTemplateVariables.test.tsx +386 -0
- package/Tests/App/Dashboard/IncidentNoteTemplatePlaceholders.test.tsx +124 -0
- package/Tests/App/Dashboard/IncidentNoteTemplateVariablesLoader.test.ts +305 -0
- package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +112 -0
- package/Tests/App/Dashboard/IncidentSettingsRenotifyOnPublish.test.tsx +674 -0
- package/Tests/App/Dashboard/IncidentSettingsStatusPageScope.test.tsx +1051 -0
- package/Tests/App/Dashboard/IncidentTemplateCustomFields.test.tsx +384 -0
- package/Tests/App/Dashboard/IncidentTemplateStatusPageScopeCard.test.tsx +215 -0
- package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +1365 -57
- package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +964 -23
- package/Tests/App/Dashboard/InventoryRelationships.test.tsx +885 -0
- package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +113 -1
- package/Tests/App/Dashboard/ServiceMapDatabaseLink.test.tsx +201 -15
- package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +508 -36
- package/Tests/App/Dashboard/SubscriberAudienceSummary.test.tsx +512 -0
- package/Tests/App/Dashboard/SubscriberNotificationPreviewModal.test.tsx +837 -0
- package/Tests/App/Dashboard/SubscriberNotificationStatusLabel.test.tsx +88 -0
- package/Tests/App/Dashboard/SubscriberNotificationStatusResend.test.tsx +473 -0
- package/Tests/App/Dashboard/SubscriberTemplateLivePreview.test.tsx +196 -0
- package/Tests/App/Dashboard/TeamAddedSubscribersUnsubscribedNotice.test.tsx +248 -0
- package/Tests/App/Dashboard/TopologyDataLifecycle.test.tsx +583 -0
- package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +982 -218
- package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +818 -114
- package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +64 -3
- package/Tests/App/StatusPage/StatusPageUnsubscribePage.test.tsx +412 -0
- package/Tests/Models/IncidentCustomFieldApiSchemaContract.test.ts +217 -0
- package/Tests/Models/IncidentCustomFieldCreateSettingsColumns.test.ts +252 -0
- package/Tests/Models/StatusPageSubscriberUnsubscribeColumns.test.ts +218 -0
- package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +7 -0
- package/Tests/Server/API/IncidentSubscriberAudienceAPI.test.ts +1408 -0
- package/Tests/Server/API/StatusPageIncidentScope.test.ts +1868 -0
- package/Tests/Server/API/StatusPageIncidentScopePostgres.test.ts +790 -0
- package/Tests/Server/API/StatusPageManageSubscriptionRecipient.test.ts +10 -1
- package/Tests/Server/API/StatusPageManageSubscriptionTemplateVariables.test.ts +206 -18
- package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +14 -2
- package/Tests/Server/API/StatusPageSubscriberCreateResponse.test.ts +217 -0
- package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +103 -2
- package/Tests/Server/API/StatusPageUnsubscribeAPI.test.ts +396 -0
- package/Tests/Server/Infrastructure/Postgres/AddIncidentStatusPageScopeMigration.test.ts +395 -0
- package/Tests/Server/Infrastructure/Postgres/AddIncidentTemplateStatusPageScopeFlagMigration.test.ts +150 -0
- package/Tests/Server/Infrastructure/Postgres/AddSubscriberNotificationClaimedAtMigration.test.ts +156 -0
- package/Tests/Server/Infrastructure/Postgres/RenameInventoryItemMigration.test.ts +90 -21
- package/Tests/Server/Infrastructure/Postgres/SkipHiddenIncidentCreatedNotificationsMigration.test.ts +410 -0
- package/Tests/Server/Middleware/IdentityRateLimit.test.ts +551 -1
- package/Tests/Server/Middleware/SubscriberNotificationPreviewRateLimit.test.ts +238 -0
- package/Tests/Server/Middleware/SubscriberNotificationTestSendRateLimit.test.ts +245 -0
- package/Tests/Server/Services/AddStatusPageSubscriberUnsubscribeTokenMigration.test.ts +152 -0
- package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +221 -36
- package/Tests/Server/Services/DatabaseServiceCompareAndSetColumns.test.ts +191 -0
- package/Tests/Server/Services/DomainService.test.ts +525 -0
- package/Tests/Server/Services/IncidentAlertAcknowledgeOnDeclare.test.ts +2630 -0
- package/Tests/Server/Services/IncidentAlertPostgres.test.ts +1625 -1
- package/Tests/Server/Services/IncidentCreatedRenotifyOnPublish.test.ts +681 -0
- package/Tests/Server/Services/IncidentCreatedResend.test.ts +775 -0
- package/Tests/Server/Services/IncidentCustomFieldRenamePostgres.test.ts +713 -0
- package/Tests/Server/Services/IncidentCustomFieldService.test.ts +751 -0
- package/Tests/Server/Services/IncidentCustomFieldValueValidation.test.ts +556 -0
- package/Tests/Server/Services/IncidentDeclareAcknowledgeAlerts.test.ts +2189 -0
- package/Tests/Server/Services/IncidentStatusPageScope.test.ts +2971 -0
- package/Tests/Server/Services/IncidentStatusPageScopeFeed.test.ts +131 -0
- package/Tests/Server/Services/IncidentStatusPageScopePostgres.test.ts +625 -0
- package/Tests/Server/Services/IncidentTemplateCustomFieldsCopy.test.ts +311 -0
- package/Tests/Server/Services/IncidentTemplateStatusPageScope.test.ts +363 -0
- package/Tests/Server/Services/InventoryItemServiceOverviewCounts.test.ts +345 -0
- package/Tests/Server/Services/InventoryOverviewPostgres.test.ts +254 -0
- package/Tests/Server/Services/IoTDeviceCredentialService.test.ts +819 -0
- package/Tests/Server/Services/LinkedAffectedResourcesCreatedFeed.test.ts +420 -0
- package/Tests/Server/Services/PublicNoteEditFeedEventType.test.ts +213 -0
- package/Tests/Server/Services/PublicNoteResendAccess.test.ts +994 -0
- package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +289 -9
- package/Tests/Server/Services/SloAffectedResourceCreatedFeed.test.ts +92 -36
- package/Tests/Server/Services/SmsServiceFailIfNotSent.test.ts +67 -0
- package/Tests/Server/Services/StatusPageReportIncidentCounts.test.ts +610 -0
- package/Tests/Server/Services/StatusPageSubscriberAudienceCounts.test.ts +201 -0
- package/Tests/Server/Services/StatusPageSubscriberAudienceCountsPostgres.test.ts +271 -0
- package/Tests/Server/Services/StatusPageSubscriberConfirmationTemplateEscaping.test.ts +200 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationLogRedaction.test.ts +54 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateCompile.test.ts +37 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateIncidentRecordAccess.test.ts +772 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookup.test.ts +506 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookupPostgres.test.ts +261 -0
- package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +21 -5
- package/Tests/Server/Services/StatusPageSubscriberUnsubscribe.test.ts +1618 -0
- package/Tests/Server/Services/StatusPageSubscriberUnsubscribeLinkSenders.test.ts +373 -0
- package/Tests/Server/Services/StatusPageSubscriberUnsubscribePostgres.test.ts +388 -0
- package/Tests/Server/Services/SubscriberNotificationInFlightRequeue.test.ts +500 -0
- package/Tests/Server/Types/MarkdownEmailLinks.test.ts +320 -0
- package/Tests/Server/Types/Workflow/Components/Email.test.ts +491 -1
- package/Tests/Server/Types/Workflow/Components/EmailSmtpPinning.test.ts +398 -0
- package/Tests/Server/Utils/AffectedResources/LinkedAffectedResources.test.ts +858 -0
- package/Tests/Server/Utils/Alert/AlertStateChangeAuthorization.test.ts +1172 -0
- package/Tests/Server/Utils/CustomField/CustomFieldRename.test.ts +586 -0
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +246 -10
- package/Tests/Server/Utils/DataSource/EgressGuardDeploymentConfig.test.ts +226 -0
- package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +131 -0
- package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +4 -0
- package/Tests/Server/Utils/EgressPolicyEnvironment.ts +45 -0
- package/Tests/Server/Utils/Mail/PinnedSmtpSocket.test.ts +409 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +23 -0
- package/Tests/Server/Utils/SSRFProtection.test.ts +4 -0
- package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +4 -0
- package/Tests/Server/Utils/SSRFProtectionPrivateNetwork.test.ts +4 -0
- package/Tests/Server/Utils/SSRFProtectionResolutionDetail.test.ts +314 -0
- package/Tests/Server/Utils/StatusPage/IncidentStatusPageScope.test.ts +1699 -0
- package/Tests/Server/Utils/StatusPage/IncidentStatusPageScopeQueriesPostgres.test.ts +508 -0
- package/Tests/Server/Utils/StatusPage/IncidentSubscriberAudienceCallerPermission.test.ts +246 -0
- package/Tests/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.test.ts +1348 -0
- package/Tests/Server/Utils/StatusPage/StatusPageReadAccess.test.ts +221 -0
- package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.test.ts +132 -0
- package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.test.ts +155 -0
- package/Tests/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.test.ts +708 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaim.test.ts +255 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaimPostgres.test.ts +528 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.test.ts +1238 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationFanOut.test.ts +472 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.test.ts +1168 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationRunLimit.test.ts +275 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationTiming.test.ts +131 -0
- package/Tests/Server/Utils/StatusPageResource.test.ts +98 -0
- package/Tests/Server/Utils/Topology/InventoryItemEntityKeyIndexMigration.test.ts +386 -0
- package/Tests/Server/Utils/Topology/InventoryItemEntityKeyIndexMigrationPostgres.test.ts +430 -0
- package/Tests/Server/Utils/Topology/TopologyActivityParityPostgres.test.ts +279 -0
- package/Tests/Server/Utils/Topology/TopologyConcurrencyLimiter.test.ts +534 -0
- package/Tests/Server/Utils/Topology/TopologyEstateGenerator.ts +624 -0
- package/Tests/Server/Utils/Topology/TopologyJsonResponse.test.ts +90 -0
- package/Tests/Server/Utils/Topology/TopologyQueries.test.ts +1634 -0
- package/Tests/Server/Utils/Topology/TopologyQueriesDifferentialPostgres.test.ts +683 -0
- package/Tests/Server/Utils/Topology/TopologyQueriesPostgres.test.ts +2624 -0
- package/Tests/Server/Utils/Topology/TopologyReference.ts +1018 -0
- package/Tests/Server/Utils/Topology/TopologyRequest.test.ts +643 -0
- package/Tests/Server/Utils/Topology/TopologyResponseCache.test.ts +305 -0
- package/Tests/Server/Utils/Topology/TopologySql.test.ts +973 -0
- package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +17 -0
- package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +75 -0
- package/Tests/Types/CustomField/CustomFieldSavedViews.test.ts +247 -0
- package/Tests/Types/CustomField/CustomFieldTemplateValues.test.ts +186 -0
- package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +48 -0
- package/Tests/Types/CustomField/CustomFieldValueFormat.test.ts +215 -0
- package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +343 -0
- package/Tests/Types/CustomField/CustomFieldVariableKey.test.ts +364 -0
- package/Tests/Types/SafeHtml.test.ts +102 -0
- package/Tests/Types/StatusPage/IncidentCreatedRenotify.test.ts +419 -0
- package/Tests/Types/StatusPage/IncidentCreatedResend.test.ts +118 -0
- package/Tests/Types/StatusPage/IncidentScopeAddedPagesNotification.test.ts +558 -0
- package/Tests/Types/StatusPage/IncidentSubscriberAudience.test.ts +284 -0
- package/Tests/Types/StatusPage/StatusPageSubscriberUnsubscribe.test.ts +341 -0
- package/Tests/Types/StatusPage/SubscriberNotificationPreview.test.ts +196 -0
- package/Tests/Types/StatusPage/SubscriberNotificationResend.test.ts +201 -0
- package/Tests/Types/StatusPage/SubscriberNotificationTemplateCompiler.test.ts +277 -0
- package/Tests/Types/StatusPage/SubscriberNotificationTemplatePreview.test.ts +179 -0
- package/Tests/Types/StatusPage/SubscriberNotificationTemplateVariables.test.ts +324 -0
- package/Tests/Types/StatusPage/SubscriberUpdateNotification.test.ts +60 -13
- package/Tests/Types/Topology/TopologyTypeRules.test.ts +176 -0
- package/Tests/UI/Components/CustomFields/CustomFieldFormFields.test.ts +432 -0
- package/Tests/UI/Components/CustomFields/CustomFieldModelFormFields.test.tsx +685 -0
- package/Tests/UI/Components/CustomFields/CustomFieldsDetailOrder.test.tsx +469 -0
- package/Tests/UI/Components/Forms/ModelFormCustomFieldInputs.test.tsx +325 -0
- package/Tests/UI/Components/Forms/ModelFormDropdownOptionsRefused.test.tsx +358 -0
- package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +22 -0
- package/Tests/UI/Monitor/NetworkPathView.test.tsx +289 -0
- package/Tests/Utils/Incident/IncidentFromAlerts.test.ts +302 -0
- package/Tests/Utils/Incident/IncidentNoteTemplateVariables.test.ts +623 -0
- package/Tests/Utils/Markdown/MarkdownEscape.test.ts +89 -0
- package/Tests/Utils/ProbeNetworkFailureUtil.test.ts +992 -0
- package/Tests/Utils/RequestFailedDetails.test.ts +575 -0
- package/Types/CustomField/CustomFieldOrder.ts +55 -0
- package/Types/CustomField/CustomFieldSavedViews.ts +225 -0
- package/Types/CustomField/CustomFieldTemplateMerge.ts +71 -0
- package/Types/CustomField/CustomFieldType.ts +14 -0
- package/Types/CustomField/CustomFieldValueFormat.ts +161 -0
- package/Types/CustomField/CustomFieldValueValidator.ts +488 -0
- package/Types/CustomField/CustomFieldVariableKey.ts +211 -0
- package/Types/Incident/IncidentAlertLink.ts +19 -0
- package/Types/SafeHtml.ts +93 -0
- package/Types/StatusPage/IncidentCreatedRenotify.ts +224 -0
- package/Types/StatusPage/IncidentCreatedResend.ts +108 -0
- package/Types/StatusPage/IncidentScopeAddedPagesNotification.ts +343 -0
- package/Types/StatusPage/IncidentSubscriberAudience.ts +332 -0
- package/Types/StatusPage/StatusPageSubscriberUnsubscribe.ts +405 -0
- package/Types/StatusPage/SubscriberNotificationInterruption.ts +32 -0
- package/Types/StatusPage/SubscriberNotificationPreview.ts +322 -0
- package/Types/StatusPage/SubscriberNotificationResend.ts +132 -0
- package/Types/StatusPage/SubscriberNotificationTemplateCompiler.ts +180 -0
- package/Types/StatusPage/SubscriberNotificationTemplatePreview.ts +301 -0
- package/Types/StatusPage/SubscriberNotificationTemplateVariables.ts +217 -4
- package/Types/StatusPage/SubscriberUpdateNotification.ts +32 -11
- package/Types/Telemetry/InventoryLiveness.ts +26 -0
- package/Types/Topology/TopologyApi.ts +428 -0
- package/Types/Topology/TopologyTypeRules.ts +191 -0
- package/UI/Components/CustomFields/CustomFieldFormFields.ts +317 -0
- package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +395 -0
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +95 -55
- package/UI/Components/Forms/ModelForm.tsx +70 -8
- package/UI/Components/Forms/Validation.ts +1 -1
- package/UI/Components/ModelFormModal/ModelFormModal.tsx +2 -4
- package/UI/Components/ModelTable/AnalyticsModelTable.tsx +2 -6
- package/UI/Components/ModelTable/BaseModelTable.tsx +9 -8
- package/UI/Components/ModelTable/CustomFieldColumns.tsx +14 -1
- package/UI/Components/ModelTable/ModelTable.tsx +6 -7
- package/UI/Utils/SensitiveUrlToken.ts +10 -5
- package/Utils/API.ts +247 -2
- package/Utils/Incident/IncidentFromAlerts.ts +78 -0
- package/Utils/Incident/IncidentNoteTemplateVariables.ts +304 -0
- package/Utils/Markdown/MarkdownEscape.ts +65 -0
- package/Utils/ProbeNetworkFailureUtil.ts +673 -0
- package/build/dist/Models/DatabaseModels/Incident.js +267 -1
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentCustomField.js +207 -1
- package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js +31 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js +124 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/InventoryItem.js +20 -11
- package/build/dist/Models/DatabaseModels/InventoryItem.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +56 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +131 -0
- package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
- package/build/dist/Server/API/IncidentAPI.js +100 -1
- package/build/dist/Server/API/IncidentAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +417 -176
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageSubscriberAPI.js +52 -13
- package/build/dist/Server/API/StatusPageSubscriberAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.js +165 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js +41 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js +57 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js +23 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js +40 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js +89 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js +29 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Semaphore.js +3 -0
- package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
- package/build/dist/Server/Middleware/IdentityRateLimit.js +89 -3
- package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
- package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js +149 -0
- package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js.map +1 -0
- package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js +190 -0
- package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js.map +1 -0
- package/build/dist/Server/Services/AlertService.js +21 -33
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +56 -7
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentAlertService.js +457 -3
- package/build/dist/Server/Services/IncidentAlertService.js.map +1 -1
- package/build/dist/Server/Services/IncidentCustomFieldService.js +204 -8
- package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +24 -0
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js +14 -0
- package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +26 -0
- package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js +26 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +1148 -42
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentTemplateService.js +83 -0
- package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
- package/build/dist/Server/Services/InventoryItemService.js +31 -0
- package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
- package/build/dist/Server/Services/IoTDeviceCredentialService.js +12 -5
- package/build/dist/Server/Services/IoTDeviceCredentialService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +26 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +84 -57
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/SmsService.js +2 -22
- package/build/dist/Server/Services/SmsService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +47 -9
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +237 -32
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js +109 -0
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberService.js +925 -99
- package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +55 -51
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js +42 -25
- package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +110 -6
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Email.js +55 -6
- package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
- package/build/dist/Server/Utils/AffectedResources/LinkedAffectedResources.js +405 -0
- package/build/dist/Server/Utils/AffectedResources/LinkedAffectedResources.js.map +1 -0
- package/build/dist/Server/Utils/Alert/AlertStateChangeAuthorization.js +112 -0
- package/build/dist/Server/Utils/Alert/AlertStateChangeAuthorization.js.map +1 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldRename.js +211 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldRename.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/EgressGuard.js +41 -12
- package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
- package/build/dist/Server/Utils/Inventory/InventoryOverviewAggregation.js +81 -0
- package/build/dist/Server/Utils/Inventory/InventoryOverviewAggregation.js.map +1 -0
- package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js +101 -0
- package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +9 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Response.js +30 -0
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/SSRFProtection.js +48 -6
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
- package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js +631 -0
- package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js +403 -0
- package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js +451 -0
- package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js +13 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js +91 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js +101 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js +47 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js +273 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js +73 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js +722 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js +102 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js +527 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js +278 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js +137 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js +103 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js +114 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js.map +1 -0
- package/build/dist/Server/Utils/StatusPageResource.js +39 -7
- package/build/dist/Server/Utils/StatusPageResource.js.map +1 -1
- package/build/dist/Server/Utils/Topology/TopologyConcurrencyLimiter.js +178 -0
- package/build/dist/Server/Utils/Topology/TopologyConcurrencyLimiter.js.map +1 -0
- package/build/dist/Server/Utils/Topology/TopologyQueries.js +884 -0
- package/build/dist/Server/Utils/Topology/TopologyQueries.js.map +1 -0
- package/build/dist/Server/Utils/Topology/TopologyRequest.js +275 -0
- package/build/dist/Server/Utils/Topology/TopologyRequest.js.map +1 -0
- package/build/dist/Server/Utils/Topology/TopologyResponseCache.js +146 -0
- package/build/dist/Server/Utils/Topology/TopologyResponseCache.js.map +1 -0
- package/build/dist/Server/Utils/Topology/TopologySql.js +688 -0
- package/build/dist/Server/Utils/Topology/TopologySql.js.map +1 -0
- package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
- package/build/dist/Server/Utils/VM/VMRunner.js +1 -0
- package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
- package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +3 -0
- package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -1
- package/build/dist/Types/CustomField/CustomFieldOrder.js +36 -0
- package/build/dist/Types/CustomField/CustomFieldOrder.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldSavedViews.js +135 -0
- package/build/dist/Types/CustomField/CustomFieldSavedViews.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js +27 -0
- package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldType.js +12 -0
- package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
- package/build/dist/Types/CustomField/CustomFieldValueFormat.js +126 -0
- package/build/dist/Types/CustomField/CustomFieldValueFormat.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldValueValidator.js +280 -0
- package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldVariableKey.js +150 -0
- package/build/dist/Types/CustomField/CustomFieldVariableKey.js.map +1 -0
- package/build/dist/Types/Incident/IncidentAlertLink.js +17 -0
- package/build/dist/Types/Incident/IncidentAlertLink.js.map +1 -1
- package/build/dist/Types/SafeHtml.js +84 -0
- package/build/dist/Types/SafeHtml.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js +117 -0
- package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentCreatedResend.js +86 -0
- package/build/dist/Types/StatusPage/IncidentCreatedResend.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js +246 -0
- package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js +183 -0
- package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js.map +1 -0
- package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js +277 -0
- package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js +27 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js +190 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationResend.js +102 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationResend.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js +97 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js +175 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js +144 -4
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js.map +1 -1
- package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js +29 -9
- package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js.map +1 -1
- package/build/dist/Types/Telemetry/InventoryLiveness.js +23 -0
- package/build/dist/Types/Telemetry/InventoryLiveness.js.map +1 -1
- package/build/dist/Types/Topology/TopologyApi.js +55 -0
- package/build/dist/Types/Topology/TopologyApi.js.map +1 -0
- package/build/dist/Types/Topology/TopologyTypeRules.js +165 -0
- package/build/dist/Types/Topology/TopologyTypeRules.js.map +1 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js +169 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js.map +1 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +212 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +64 -49
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/Forms/ModelForm.js +39 -5
- package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/Validation.js +1 -1
- package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
- package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/AnalyticsModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +2 -2
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +13 -1
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ModelTable.js +1 -1
- package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
- package/build/dist/UI/Utils/SensitiveUrlToken.js +10 -5
- package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -1
- package/build/dist/Utils/API.js +177 -1
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Incident/IncidentFromAlerts.js +38 -0
- package/build/dist/Utils/Incident/IncidentFromAlerts.js.map +1 -1
- package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js +155 -0
- package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js.map +1 -0
- package/build/dist/Utils/Markdown/MarkdownEscape.js +48 -0
- package/build/dist/Utils/Markdown/MarkdownEscape.js.map +1 -1
- package/build/dist/Utils/ProbeNetworkFailureUtil.js +460 -0
- package/build/dist/Utils/ProbeNetworkFailureUtil.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import Redis, { ClientType } from "../Infrastructure/Redis";
|
|
2
|
+
import {
|
|
3
|
+
ExpressRequest,
|
|
4
|
+
ExpressResponse,
|
|
5
|
+
NextFunction,
|
|
6
|
+
OneUptimeRequest,
|
|
7
|
+
} from "../Utils/Express";
|
|
8
|
+
import logger from "../Utils/Logger";
|
|
9
|
+
import Response from "../Utils/Response";
|
|
10
|
+
import ObjectID from "../../Types/ObjectID";
|
|
11
|
+
import ServiceUnavailableException from "../../Types/Exception/ServiceUnavailableException";
|
|
12
|
+
import TooManyRequestsException from "../../Types/Exception/TooManyRequestsException";
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* Request limiting for "Send test to me" (POST /send-test on the subscriber
|
|
16
|
+
* notification preview router), which emails the signed-in user the status
|
|
17
|
+
* page subscriber email they are previewing.
|
|
18
|
+
*
|
|
19
|
+
* The route only ever sends to the caller's own verified account email, so
|
|
20
|
+
* what this bounds is volume: every allowed request is a real email, through
|
|
21
|
+
* the status page's own SMTP server or the instance's mail provider, and
|
|
22
|
+
* nothing else stops a script (or a held-down button) from sending hundreds.
|
|
23
|
+
* The counter is per user, across every project, status page and incident:
|
|
24
|
+
* a user is one inbox.
|
|
25
|
+
*
|
|
26
|
+
* THIS FAILS CLOSED
|
|
27
|
+
*
|
|
28
|
+
* If Redis is unreachable, the test is refused with "try again later". That
|
|
29
|
+
* is the opposite of the choice VerificationCodeRateLimit makes, and the
|
|
30
|
+
* difference is what else bounds the requests: there, the code's expiry, its
|
|
31
|
+
* attempt counter and the resend cooldown all live in Postgres and stay in
|
|
32
|
+
* force; here this counter is the only bound on how much mail is sent. A
|
|
33
|
+
* test email is a convenience, and a Redis blip costs nothing but a retry.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
export enum SubscriberNotificationTestSendRateLimitOutcome {
|
|
37
|
+
Allowed = "allowed",
|
|
38
|
+
RateLimited = "rate-limited",
|
|
39
|
+
|
|
40
|
+
// Redis is unreachable, so the limit cannot be honoured.
|
|
41
|
+
CounterUnavailable = "counter-unavailable",
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface SubscriberNotificationTestSendRateLimitDecision {
|
|
45
|
+
outcome: SubscriberNotificationTestSendRateLimitOutcome;
|
|
46
|
+
retryAfterSeconds?: number | undefined;
|
|
47
|
+
/*
|
|
48
|
+
* True only on the request that first crossed the line in this window, so
|
|
49
|
+
* a flood produces one log line per user per window.
|
|
50
|
+
*/
|
|
51
|
+
isFirstRejectionInWindow?: boolean | undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface SubscriberNotificationTestSendRateLimitConfig {
|
|
55
|
+
windowSeconds: number;
|
|
56
|
+
perUserLimit: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const KEY_PREFIX: string = "subnotiftest:rl:";
|
|
60
|
+
|
|
61
|
+
/*
|
|
62
|
+
* Counter keys outlive their window by one full window, so a request landing
|
|
63
|
+
* on a boundary cannot read a key that was reclaimed mid-window.
|
|
64
|
+
*/
|
|
65
|
+
const TTL_MULTIPLIER: number = 2;
|
|
66
|
+
|
|
67
|
+
// How often the "counter unavailable" condition may be logged.
|
|
68
|
+
const COUNTER_UNAVAILABLE_LOG_INTERVAL_MS: number = 60 * 1000;
|
|
69
|
+
|
|
70
|
+
export default class SubscriberNotificationTestSendRateLimit {
|
|
71
|
+
/*
|
|
72
|
+
* Ten test emails a quarter of an hour: someone checking each status
|
|
73
|
+
* page's email in turn, or trying a template change a few times, is
|
|
74
|
+
* nowhere near it.
|
|
75
|
+
*/
|
|
76
|
+
private static readonly config: SubscriberNotificationTestSendRateLimitConfig =
|
|
77
|
+
{
|
|
78
|
+
windowSeconds: 15 * 60,
|
|
79
|
+
perUserLimit: 10,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
private static counterUnavailableLastLoggedAt: number = 0;
|
|
83
|
+
|
|
84
|
+
// The limit in force, for tests and for operators' diagnostics.
|
|
85
|
+
public static getConfig(): SubscriberNotificationTestSendRateLimitConfig {
|
|
86
|
+
return { ...SubscriberNotificationTestSendRateLimit.config };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/*
|
|
90
|
+
* The signed-in user the request is billed to. The route sits behind
|
|
91
|
+
* UserMiddleware.requireUserAuthentication, so there always is one; if
|
|
92
|
+
* somehow there is not, every such request shares one bucket rather than
|
|
93
|
+
* each getting its own.
|
|
94
|
+
*/
|
|
95
|
+
public static resolveUserKey(req: ExpressRequest): string {
|
|
96
|
+
const userId: ObjectID | undefined = (req as OneUptimeRequest)
|
|
97
|
+
?.userAuthorization?.userId;
|
|
98
|
+
|
|
99
|
+
if (!userId) {
|
|
100
|
+
return "anonymous";
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const key: string = userId.toString().toLowerCase();
|
|
104
|
+
|
|
105
|
+
return ObjectID.isValidUUID(key) ? key : "invalid";
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/*
|
|
109
|
+
* Count this request against the user and decide. The counter is
|
|
110
|
+
* incremented on every request, a rejected one included, so a caller who
|
|
111
|
+
* keeps trying keeps their window pinned rather than getting a fresh
|
|
112
|
+
* allowance for free.
|
|
113
|
+
*/
|
|
114
|
+
public static async consume(data: {
|
|
115
|
+
userKey: string;
|
|
116
|
+
}): Promise<SubscriberNotificationTestSendRateLimitDecision> {
|
|
117
|
+
const client: ClientType | null = Redis.getClient();
|
|
118
|
+
|
|
119
|
+
if (!client || !Redis.isConnected()) {
|
|
120
|
+
return {
|
|
121
|
+
outcome:
|
|
122
|
+
SubscriberNotificationTestSendRateLimitOutcome.CounterUnavailable,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const config: SubscriberNotificationTestSendRateLimitConfig =
|
|
127
|
+
SubscriberNotificationTestSendRateLimit.config;
|
|
128
|
+
const windowMs: number = config.windowSeconds * 1000;
|
|
129
|
+
const windowIndex: number = Math.floor(Date.now() / windowMs);
|
|
130
|
+
const counterKey: string = `${KEY_PREFIX}u:${data.userKey}:${windowIndex}`;
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const count: number = await client.incr(counterKey);
|
|
134
|
+
|
|
135
|
+
if (typeof count !== "number") {
|
|
136
|
+
throw new Error("Rate limit counter returned a non-numeric value");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/*
|
|
140
|
+
* The expiry is set only by the request that created the key: setting
|
|
141
|
+
* it on every increment would slide the window for as long as the
|
|
142
|
+
* requests keep coming.
|
|
143
|
+
*/
|
|
144
|
+
if (count === 1) {
|
|
145
|
+
await client.expire(counterKey, config.windowSeconds * TTL_MULTIPLIER);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (count > config.perUserLimit) {
|
|
149
|
+
return {
|
|
150
|
+
outcome: SubscriberNotificationTestSendRateLimitOutcome.RateLimited,
|
|
151
|
+
retryAfterSeconds:
|
|
152
|
+
SubscriberNotificationTestSendRateLimit.getSecondsUntilWindowEnd(
|
|
153
|
+
config.windowSeconds,
|
|
154
|
+
),
|
|
155
|
+
isFirstRejectionInWindow: count === config.perUserLimit + 1,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
outcome: SubscriberNotificationTestSendRateLimitOutcome.Allowed,
|
|
161
|
+
};
|
|
162
|
+
} catch (err) {
|
|
163
|
+
if (
|
|
164
|
+
SubscriberNotificationTestSendRateLimit.shouldLogCounterUnavailable()
|
|
165
|
+
) {
|
|
166
|
+
logger.warn(
|
|
167
|
+
`SubscriberNotificationTestSendRateLimit: counter failed for user ${data.userKey}`,
|
|
168
|
+
);
|
|
169
|
+
logger.warn(err);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
outcome:
|
|
174
|
+
SubscriberNotificationTestSendRateLimitOutcome.CounterUnavailable,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/*
|
|
180
|
+
* Express middleware. Register after UserMiddleware (the counter is per
|
|
181
|
+
* user) and before the handler, so a flood is refused before it reads a
|
|
182
|
+
* single row.
|
|
183
|
+
*/
|
|
184
|
+
public static getMiddleware(): (
|
|
185
|
+
req: ExpressRequest,
|
|
186
|
+
res: ExpressResponse,
|
|
187
|
+
next: NextFunction,
|
|
188
|
+
) => Promise<void> {
|
|
189
|
+
return async (
|
|
190
|
+
req: ExpressRequest,
|
|
191
|
+
res: ExpressResponse,
|
|
192
|
+
next: NextFunction,
|
|
193
|
+
): Promise<void> => {
|
|
194
|
+
const userKey: string =
|
|
195
|
+
SubscriberNotificationTestSendRateLimit.resolveUserKey(req);
|
|
196
|
+
|
|
197
|
+
const decision: SubscriberNotificationTestSendRateLimitDecision =
|
|
198
|
+
await SubscriberNotificationTestSendRateLimit.consume({
|
|
199
|
+
userKey: userKey,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
if (
|
|
203
|
+
decision.outcome ===
|
|
204
|
+
SubscriberNotificationTestSendRateLimitOutcome.RateLimited
|
|
205
|
+
) {
|
|
206
|
+
if (decision.retryAfterSeconds) {
|
|
207
|
+
SubscriberNotificationTestSendRateLimit.setRetryAfterHeader(
|
|
208
|
+
res,
|
|
209
|
+
decision.retryAfterSeconds,
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (decision.isFirstRejectionInWindow) {
|
|
214
|
+
logger.warn(
|
|
215
|
+
`SubscriberNotificationTestSendRateLimit: rejected test emails from user ${userKey} for the rest of this window`,
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return Response.sendErrorResponse(
|
|
220
|
+
req,
|
|
221
|
+
res,
|
|
222
|
+
new TooManyRequestsException(
|
|
223
|
+
"You have sent yourself too many test emails. Please try again later.",
|
|
224
|
+
),
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (
|
|
229
|
+
decision.outcome ===
|
|
230
|
+
SubscriberNotificationTestSendRateLimitOutcome.CounterUnavailable
|
|
231
|
+
) {
|
|
232
|
+
// Fails closed: see the note at the top of this file.
|
|
233
|
+
if (
|
|
234
|
+
SubscriberNotificationTestSendRateLimit.shouldLogCounterUnavailable()
|
|
235
|
+
) {
|
|
236
|
+
logger.warn(
|
|
237
|
+
"SubscriberNotificationTestSendRateLimit: rate limit counter unavailable, refusing test emails",
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return Response.sendErrorResponse(
|
|
242
|
+
req,
|
|
243
|
+
res,
|
|
244
|
+
new ServiceUnavailableException(
|
|
245
|
+
"Test emails cannot be sent right now. Please try again in a few minutes.",
|
|
246
|
+
),
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return next();
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/*
|
|
255
|
+
* Remaining seconds in the current fixed window, so a refused caller is
|
|
256
|
+
* told to come back when the window actually rolls. The preview limiter
|
|
257
|
+
* (SubscriberNotificationPreviewRateLimit) counts in the same fixed
|
|
258
|
+
* windows, and uses this too.
|
|
259
|
+
*/
|
|
260
|
+
public static getSecondsUntilWindowEnd(windowSeconds: number): number {
|
|
261
|
+
const windowMs: number = windowSeconds * 1000;
|
|
262
|
+
const msIntoWindow: number = Date.now() % windowMs;
|
|
263
|
+
|
|
264
|
+
return Math.max(1, Math.ceil((windowMs - msIntoWindow) / 1000));
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/*
|
|
268
|
+
* A Redis outage means every request takes the unavailable path; one log
|
|
269
|
+
* line per interval makes the condition visible without burying the rest.
|
|
270
|
+
*/
|
|
271
|
+
private static shouldLogCounterUnavailable(): boolean {
|
|
272
|
+
const now: number = Date.now();
|
|
273
|
+
|
|
274
|
+
if (
|
|
275
|
+
now -
|
|
276
|
+
SubscriberNotificationTestSendRateLimit.counterUnavailableLastLoggedAt <
|
|
277
|
+
COUNTER_UNAVAILABLE_LOG_INTERVAL_MS
|
|
278
|
+
) {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
SubscriberNotificationTestSendRateLimit.counterUnavailableLastLoggedAt =
|
|
283
|
+
now;
|
|
284
|
+
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
private static setRetryAfterHeader(
|
|
289
|
+
res: ExpressResponse,
|
|
290
|
+
retryAfterSeconds: number,
|
|
291
|
+
): void {
|
|
292
|
+
const setHeader: unknown = (res as unknown as Record<string, unknown>)[
|
|
293
|
+
"setHeader"
|
|
294
|
+
];
|
|
295
|
+
|
|
296
|
+
if (typeof setHeader === "function") {
|
|
297
|
+
(setHeader as (name: string, value: string) => void).call(
|
|
298
|
+
res,
|
|
299
|
+
"Retry-After",
|
|
300
|
+
String(retryAfterSeconds),
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
@@ -20,7 +20,9 @@ import OnCallDutyPolicyService from "./OnCallDutyPolicyService";
|
|
|
20
20
|
import TeamMemberService from "./TeamMemberService";
|
|
21
21
|
import UserService from "./UserService";
|
|
22
22
|
import URL from "../../Types/API/URL";
|
|
23
|
-
import {
|
|
23
|
+
import LinkedAffectedResources, {
|
|
24
|
+
LinkedAffectedResource,
|
|
25
|
+
} from "../Utils/AffectedResources/LinkedAffectedResources";
|
|
24
26
|
import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
25
27
|
import SortOrder from "../../Types/BaseDatabase/SortOrder";
|
|
26
28
|
import LIMIT_MAX, { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
@@ -73,7 +75,6 @@ import AlertReminderRule from "../../Models/DatabaseModels/AlertReminderRule";
|
|
|
73
75
|
import WorkspaceType from "../../Types/Workspace/WorkspaceType";
|
|
74
76
|
import NotificationRuleWorkspaceChannel from "../../Types/Workspace/NotificationRules/NotificationRuleWorkspaceChannel";
|
|
75
77
|
import AlertWorkspaceMessages from "../Utils/Workspace/WorkspaceMessages/Alert";
|
|
76
|
-
import Monitor from "../../Models/DatabaseModels/Monitor";
|
|
77
78
|
import ServiceLevelObjective from "../../Models/DatabaseModels/ServiceLevelObjective";
|
|
78
79
|
import MonitorService from "./MonitorService";
|
|
79
80
|
import { MessageBlocksByWorkspaceType } from "./WorkspaceNotificationRuleService";
|
|
@@ -1024,19 +1025,6 @@ export class Service extends DatabaseService<Model> {
|
|
|
1024
1025
|
labels: {
|
|
1025
1026
|
name: true,
|
|
1026
1027
|
},
|
|
1027
|
-
monitor: {
|
|
1028
|
-
name: true,
|
|
1029
|
-
_id: true,
|
|
1030
|
-
},
|
|
1031
|
-
/*
|
|
1032
|
-
* This read runs as root, so projectId comes along and the feed
|
|
1033
|
-
* names only this project's SLOs (getSloAffectedResourceMarkdownLines).
|
|
1034
|
-
*/
|
|
1035
|
-
serviceLevelObjectives: {
|
|
1036
|
-
name: true,
|
|
1037
|
-
_id: true,
|
|
1038
|
-
projectId: true,
|
|
1039
|
-
},
|
|
1040
1028
|
},
|
|
1041
1029
|
props: {
|
|
1042
1030
|
isRoot: true,
|
|
@@ -1067,31 +1055,28 @@ ${alert.description || "No description provided."}
|
|
|
1067
1055
|
}
|
|
1068
1056
|
|
|
1069
1057
|
/*
|
|
1070
|
-
*
|
|
1071
|
-
*
|
|
1072
|
-
*
|
|
1073
|
-
*
|
|
1074
|
-
*
|
|
1058
|
+
* Everything the alert's Affected Resources card lists: its monitor,
|
|
1059
|
+
* the hosts, clusters and services it is attached to, then its SLOs. A
|
|
1060
|
+
* burn-rate alert has no monitor, so its SLO is the only resource there
|
|
1061
|
+
* is to name - and the feed's only way back to the objective that
|
|
1062
|
+
* raised it.
|
|
1075
1063
|
*/
|
|
1076
|
-
const
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
})
|
|
1083
|
-
: [];
|
|
1064
|
+
const resources: Array<LinkedAffectedResource> =
|
|
1065
|
+
await LinkedAffectedResources.readForAlert({
|
|
1066
|
+
service: this,
|
|
1067
|
+
projectId: alert.projectId!,
|
|
1068
|
+
alertId: alert.id!,
|
|
1069
|
+
});
|
|
1084
1070
|
|
|
1085
|
-
if (
|
|
1071
|
+
if (resources.length > 0) {
|
|
1086
1072
|
feedInfoInMarkdown += `🌎 **Resources Affected**:\n`;
|
|
1087
1073
|
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
feedInfoInMarkdown += `${sloLine}\n`;
|
|
1074
|
+
for (const resourceLine of LinkedAffectedResources.getMarkdownLines({
|
|
1075
|
+
dashboardUrl: await DatabaseConfig.getDashboardUrl(),
|
|
1076
|
+
projectId: alert.projectId!,
|
|
1077
|
+
resources: resources,
|
|
1078
|
+
})) {
|
|
1079
|
+
feedInfoInMarkdown += `${resourceLine}\n`;
|
|
1095
1080
|
}
|
|
1096
1081
|
|
|
1097
1082
|
feedInfoInMarkdown += `\n\n`;
|
|
@@ -1768,6 +1753,12 @@ ${alertSeverity.name}
|
|
|
1768
1753
|
notifyOwners: boolean;
|
|
1769
1754
|
rootCause: string | undefined;
|
|
1770
1755
|
stateChangeLog: JSONObject | undefined;
|
|
1756
|
+
/*
|
|
1757
|
+
* The user the change is credited to (the alert's feed names them), for
|
|
1758
|
+
* a change a user asked for that is written on their behalf. Unset for
|
|
1759
|
+
* changes the system makes on its own.
|
|
1760
|
+
*/
|
|
1761
|
+
createdByUserId?: ObjectID | undefined;
|
|
1771
1762
|
props: DatabaseCommonInteractionProps | undefined;
|
|
1772
1763
|
}): Promise<void> {
|
|
1773
1764
|
const {
|
|
@@ -1777,6 +1768,7 @@ ${alertSeverity.name}
|
|
|
1777
1768
|
notifyOwners,
|
|
1778
1769
|
rootCause,
|
|
1779
1770
|
stateChangeLog,
|
|
1771
|
+
createdByUserId,
|
|
1780
1772
|
props,
|
|
1781
1773
|
} = data;
|
|
1782
1774
|
|
|
@@ -1822,6 +1814,10 @@ ${alertSeverity.name}
|
|
|
1822
1814
|
statusTimeline.rootCause = rootCause;
|
|
1823
1815
|
}
|
|
1824
1816
|
|
|
1817
|
+
if (createdByUserId) {
|
|
1818
|
+
statusTimeline.createdByUserId = createdByUserId;
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1825
1821
|
await AlertStateTimelineService.create({
|
|
1826
1822
|
data: statusTimeline,
|
|
1827
1823
|
props: props || {},
|
|
@@ -109,6 +109,15 @@ const RULE_CRITERIA_RELATION_OPERATORS: ReadonlySet<RuleCriteriaOperator> =
|
|
|
109
109
|
RuleCriteriaOperator.HasNoneOf,
|
|
110
110
|
]);
|
|
111
111
|
|
|
112
|
+
// A hook-free write to one row by id, ready to run (see buildColumnsByIdUpdateStatement).
|
|
113
|
+
interface ColumnsByIdUpdateStatement {
|
|
114
|
+
tableName: string;
|
|
115
|
+
primaryColumnName: string;
|
|
116
|
+
setSql: string;
|
|
117
|
+
whereSql: string;
|
|
118
|
+
params: Array<unknown>;
|
|
119
|
+
}
|
|
120
|
+
|
|
112
121
|
class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
|
|
113
122
|
public modelType!: { new (): TBaseModel };
|
|
114
123
|
private model!: TBaseModel;
|
|
@@ -3821,6 +3830,78 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
|
|
|
3821
3830
|
*/
|
|
3822
3831
|
skipUpdateDateColumn?: boolean;
|
|
3823
3832
|
}): Promise<void> {
|
|
3833
|
+
const statement: ColumnsByIdUpdateStatement | null =
|
|
3834
|
+
this.buildColumnsByIdUpdateStatement(
|
|
3835
|
+
input,
|
|
3836
|
+
"updateColumnsByIdWithoutHooks",
|
|
3837
|
+
);
|
|
3838
|
+
|
|
3839
|
+
if (!statement) {
|
|
3840
|
+
return;
|
|
3841
|
+
}
|
|
3842
|
+
|
|
3843
|
+
const sql: string = `UPDATE "${statement.tableName}" SET ${statement.setSql} WHERE ${statement.whereSql}`;
|
|
3844
|
+
|
|
3845
|
+
await this.getRepository().manager.query(sql, statement.params);
|
|
3846
|
+
}
|
|
3847
|
+
|
|
3848
|
+
/*
|
|
3849
|
+
* The same single-statement, hook-free, no-version-bump write as
|
|
3850
|
+
* `updateColumnsByIdWithoutHooks` with its `expectedData` guard, which
|
|
3851
|
+
* also says whether it happened: true when the row matched every expected
|
|
3852
|
+
* value and was written, false when another writer had changed it first
|
|
3853
|
+
* (or it no longer exists).
|
|
3854
|
+
*
|
|
3855
|
+
* This is what lets two workers race for one row and have exactly one of
|
|
3856
|
+
* them win - a job claiming a Pending notification by moving it to
|
|
3857
|
+
* InProgress, say, where both would otherwise send it. The check and the
|
|
3858
|
+
* write are one statement, so there is no window between them.
|
|
3859
|
+
*
|
|
3860
|
+
* The UPDATE sits in a CTE so the statement is a SELECT of the rows it
|
|
3861
|
+
* wrote (see updateColumnsByIdIfUnlockedWithoutHooks for why a bare
|
|
3862
|
+
* UPDATE ... RETURNING cannot tell the two cases apart through TypeORM).
|
|
3863
|
+
*/
|
|
3864
|
+
@CaptureSpan()
|
|
3865
|
+
public async compareAndSetColumnsByIdWithoutHooks(input: {
|
|
3866
|
+
id: ObjectID;
|
|
3867
|
+
data: PartialEntity<TBaseModel>;
|
|
3868
|
+
expectedData: PartialEntity<TBaseModel>;
|
|
3869
|
+
skipUpdateDateColumn?: boolean;
|
|
3870
|
+
}): Promise<boolean> {
|
|
3871
|
+
const statement: ColumnsByIdUpdateStatement | null =
|
|
3872
|
+
this.buildColumnsByIdUpdateStatement(
|
|
3873
|
+
input,
|
|
3874
|
+
"compareAndSetColumnsByIdWithoutHooks",
|
|
3875
|
+
);
|
|
3876
|
+
|
|
3877
|
+
if (!statement) {
|
|
3878
|
+
return false;
|
|
3879
|
+
}
|
|
3880
|
+
|
|
3881
|
+
const sql: string = `WITH "updated" AS (UPDATE "${statement.tableName}" SET ${statement.setSql} WHERE ${statement.whereSql} RETURNING "${statement.primaryColumnName}") SELECT "${statement.primaryColumnName}" FROM "updated"`;
|
|
3882
|
+
|
|
3883
|
+
const result: unknown = await this.getRepository().manager.query(
|
|
3884
|
+
sql,
|
|
3885
|
+
statement.params,
|
|
3886
|
+
);
|
|
3887
|
+
|
|
3888
|
+
return Array.isArray(result) && result.length > 0;
|
|
3889
|
+
}
|
|
3890
|
+
|
|
3891
|
+
/*
|
|
3892
|
+
* The SET and WHERE clauses of a hook-free write to one row by id, with
|
|
3893
|
+
* every value bound as a parameter. Null when there is nothing to set.
|
|
3894
|
+
* `methodName` is the public method the errors are reported under.
|
|
3895
|
+
*/
|
|
3896
|
+
private buildColumnsByIdUpdateStatement(
|
|
3897
|
+
input: {
|
|
3898
|
+
id: ObjectID;
|
|
3899
|
+
data: PartialEntity<TBaseModel>;
|
|
3900
|
+
expectedData?: PartialEntity<TBaseModel> | undefined;
|
|
3901
|
+
skipUpdateDateColumn?: boolean | undefined;
|
|
3902
|
+
},
|
|
3903
|
+
methodName: string,
|
|
3904
|
+
): ColumnsByIdUpdateStatement | null {
|
|
3824
3905
|
if (!input.id) {
|
|
3825
3906
|
throw new BadDataException("id is required");
|
|
3826
3907
|
}
|
|
@@ -3846,7 +3927,7 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
|
|
|
3846
3927
|
metadata.findColumnWithPropertyName(propertyName);
|
|
3847
3928
|
if (!column) {
|
|
3848
3929
|
throw new BadDataException(
|
|
3849
|
-
|
|
3930
|
+
`${methodName}: unknown column "${propertyName}" on "${metadata.tableName}"`,
|
|
3850
3931
|
);
|
|
3851
3932
|
}
|
|
3852
3933
|
/*
|
|
@@ -3857,7 +3938,7 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
|
|
|
3857
3938
|
*/
|
|
3858
3939
|
if (typeof value === "function") {
|
|
3859
3940
|
throw new BadDataException(
|
|
3860
|
-
|
|
3941
|
+
`${methodName}: SQL-expression values are not supported (column "${propertyName}"); pass a literal value.`,
|
|
3861
3942
|
);
|
|
3862
3943
|
}
|
|
3863
3944
|
/*
|
|
@@ -3872,7 +3953,7 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
|
|
|
3872
3953
|
}
|
|
3873
3954
|
|
|
3874
3955
|
if (setClauses.length === 0) {
|
|
3875
|
-
return;
|
|
3956
|
+
return null;
|
|
3876
3957
|
}
|
|
3877
3958
|
|
|
3878
3959
|
// The raw path has no entity machinery to touch updateDate — do it here.
|
|
@@ -3898,13 +3979,13 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
|
|
|
3898
3979
|
|
|
3899
3980
|
if (!column) {
|
|
3900
3981
|
throw new BadDataException(
|
|
3901
|
-
|
|
3982
|
+
`${methodName}: unknown expected column "${propertyName}" on "${metadata.tableName}"`,
|
|
3902
3983
|
);
|
|
3903
3984
|
}
|
|
3904
3985
|
|
|
3905
3986
|
if (typeof value === "function") {
|
|
3906
3987
|
throw new BadDataException(
|
|
3907
|
-
|
|
3988
|
+
`${methodName}: SQL-expression expected values are not supported (column "${propertyName}"); pass a literal value.`,
|
|
3908
3989
|
);
|
|
3909
3990
|
}
|
|
3910
3991
|
|
|
@@ -3914,11 +3995,13 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
|
|
|
3914
3995
|
);
|
|
3915
3996
|
}
|
|
3916
3997
|
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3998
|
+
return {
|
|
3999
|
+
tableName: metadata.tableName,
|
|
4000
|
+
primaryColumnName: primaryColumnName,
|
|
4001
|
+
setSql: setClauses.join(", "),
|
|
4002
|
+
whereSql: whereClauses.join(" AND "),
|
|
4003
|
+
params: params,
|
|
4004
|
+
};
|
|
3922
4005
|
}
|
|
3923
4006
|
|
|
3924
4007
|
/*
|