@oneuptime/common 14.0.7 → 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/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/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 +14 -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/DatabaseService.ts +93 -10
- 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 +1535 -65
- package/Server/Services/IncidentStateTimelineService.ts +13 -0
- package/Server/Services/IncidentTemplateService.ts +109 -0
- package/Server/Services/ScheduledMaintenancePublicNoteService.ts +30 -1
- package/Server/Services/ScheduledMaintenanceService.ts +68 -18
- 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/Types/Markdown.ts +153 -6
- package/Server/Types/Workflow/Components/Email.ts +61 -2
- package/Server/Utils/CustomField/CustomFieldRename.ts +378 -0
- package/Server/Utils/DataSource/EgressGuard.ts +66 -21
- package/Server/Utils/Mail/PinnedSmtpSocket.ts +130 -0
- package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +10 -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/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/CustomFieldsSettingsIncidentOptions.test.tsx +357 -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 +242 -5
- package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +91 -1
- 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/PublicNotePagesNotifyDefault.test.tsx +113 -1
- 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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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 +14 -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/DatabaseService.js +56 -7
- package/build/dist/Server/Services/DatabaseService.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 +1052 -0
- 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/ScheduledMaintenancePublicNoteService.js +26 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +47 -17
- 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/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/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/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/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/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/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/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/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
|
@@ -131,6 +131,14 @@ import StatusPageSubscriberNotificationTemplateService, {
|
|
|
131
131
|
Service as StatusPageSubscriberNotificationTemplateServiceClass,
|
|
132
132
|
} from "../Services/StatusPageSubscriberNotificationTemplateService";
|
|
133
133
|
import { canServeStatusPageCustomizations } from "../Utils/StatusPageCustomizationAccess";
|
|
134
|
+
import IncidentStatusPageScope, {
|
|
135
|
+
INCIDENT_SCOPE_SELECT,
|
|
136
|
+
} from "../Utils/StatusPage/IncidentStatusPageScope";
|
|
137
|
+
import { StatusPageSubscriberUnsubscribeSource } from "../Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice";
|
|
138
|
+
import StatusPageSubscriberUnsubscribe, {
|
|
139
|
+
StatusPageSubscriberUnsubscribeDetails,
|
|
140
|
+
StatusPageSubscriberUnsubscribeState,
|
|
141
|
+
} from "../../Types/StatusPage/StatusPageSubscriberUnsubscribe";
|
|
134
142
|
|
|
135
143
|
/*
|
|
136
144
|
* A manage-subscription request is unauthenticated, and one Slack or Microsoft
|
|
@@ -765,6 +773,80 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
765
773
|
},
|
|
766
774
|
);
|
|
767
775
|
|
|
776
|
+
/*
|
|
777
|
+
* The unsubscribe link in every subscriber notification opens the status
|
|
778
|
+
* page's unsubscribe page ({statusPageUrl}/unsubscribe/{id}-{token}, see
|
|
779
|
+
* Common/Types/StatusPage/StatusPageSubscriberUnsubscribe), which reads
|
|
780
|
+
* what the link belongs to with GET and cancels it with POST.
|
|
781
|
+
*
|
|
782
|
+
* - GET changes nothing. Mail scanners and link previewers fetch every
|
|
783
|
+
* link in a message; they must not unsubscribe anybody.
|
|
784
|
+
* - POST unsubscribes, and is idempotent. It answers whatever its body is
|
|
785
|
+
* - the page sends none, and an RFC 8058 one-click request sends
|
|
786
|
+
* "List-Unsubscribe=One-Click" - because holding the token is the whole
|
|
787
|
+
* authorisation.
|
|
788
|
+
*
|
|
789
|
+
* Deliberately no read-access check: a private status page's subscribers
|
|
790
|
+
* are exactly the people who may not be able to sign in to it, and the
|
|
791
|
+
* token proves the request came from the subscription's own inbox (or
|
|
792
|
+
* phone, or channel). Nothing but the subscription's own contact is ever
|
|
793
|
+
* returned - no page content - so a private page stays private.
|
|
794
|
+
*
|
|
795
|
+
* Every bad link answers the same Invalid, so the endpoint cannot be used
|
|
796
|
+
* to learn which subscriptions exist; see
|
|
797
|
+
* StatusPageSubscriberService.getUnsubscribeLinkDetails.
|
|
798
|
+
*/
|
|
799
|
+
const unsubscribeApiPath: string = `${new this.entityType()
|
|
800
|
+
.getCrudApiPath()
|
|
801
|
+
?.toString()}/unsubscribe/:statusPageId/:subscriberId/:token`;
|
|
802
|
+
|
|
803
|
+
this.router.get(
|
|
804
|
+
unsubscribeApiPath,
|
|
805
|
+
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
|
806
|
+
try {
|
|
807
|
+
const details: StatusPageSubscriberUnsubscribeDetails =
|
|
808
|
+
await StatusPageSubscriberService.getUnsubscribeLinkDetails({
|
|
809
|
+
statusPageId: req.params["statusPageId"] as string,
|
|
810
|
+
subscriberId: req.params["subscriberId"] as string,
|
|
811
|
+
token: req.params["token"] as string,
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
// A token-bearing answer: never let a shared cache keep it.
|
|
815
|
+
Response.setNoCacheHeaders(res);
|
|
816
|
+
|
|
817
|
+
return Response.sendJsonObjectResponse(
|
|
818
|
+
req,
|
|
819
|
+
res,
|
|
820
|
+
details as unknown as JSONObject,
|
|
821
|
+
);
|
|
822
|
+
} catch (err) {
|
|
823
|
+
next(err);
|
|
824
|
+
}
|
|
825
|
+
},
|
|
826
|
+
);
|
|
827
|
+
|
|
828
|
+
this.router.post(
|
|
829
|
+
unsubscribeApiPath,
|
|
830
|
+
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
|
831
|
+
try {
|
|
832
|
+
const state: StatusPageSubscriberUnsubscribeState =
|
|
833
|
+
await StatusPageSubscriberService.unsubscribeWithLink({
|
|
834
|
+
statusPageId: req.params["statusPageId"] as string,
|
|
835
|
+
subscriberId: req.params["subscriberId"] as string,
|
|
836
|
+
token: req.params["token"] as string,
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
Response.setNoCacheHeaders(res);
|
|
840
|
+
|
|
841
|
+
return Response.sendJsonObjectResponse(req, res, {
|
|
842
|
+
state: state,
|
|
843
|
+
});
|
|
844
|
+
} catch (err) {
|
|
845
|
+
next(err);
|
|
846
|
+
}
|
|
847
|
+
},
|
|
848
|
+
);
|
|
849
|
+
|
|
768
850
|
// CNAME verification api
|
|
769
851
|
this.router.get(
|
|
770
852
|
`${new this.entityType()
|
|
@@ -2912,20 +2994,40 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2912
2994
|
let lookupQuery: Query<StatusPageSubscriber>;
|
|
2913
2995
|
let lookupSelect: Select<StatusPageSubscriber>;
|
|
2914
2996
|
|
|
2997
|
+
/*
|
|
2998
|
+
* The unsubscribe token is read too: the message carries the
|
|
2999
|
+
* subscription's unsubscribe link as well as its manage link.
|
|
3000
|
+
*/
|
|
2915
3001
|
if (email) {
|
|
2916
3002
|
lookupQuery = { subscriberEmail: email };
|
|
2917
|
-
lookupSelect = {
|
|
3003
|
+
lookupSelect = {
|
|
3004
|
+
_id: true,
|
|
3005
|
+
subscriberEmail: true,
|
|
3006
|
+
unsubscribeToken: true,
|
|
3007
|
+
};
|
|
2918
3008
|
} else if (phone) {
|
|
2919
3009
|
lookupQuery = { subscriberPhone: phone };
|
|
2920
|
-
lookupSelect = {
|
|
3010
|
+
lookupSelect = {
|
|
3011
|
+
_id: true,
|
|
3012
|
+
subscriberPhone: true,
|
|
3013
|
+
unsubscribeToken: true,
|
|
3014
|
+
};
|
|
2921
3015
|
} else if (slackWorkspaceName) {
|
|
2922
3016
|
lookupQuery = { slackWorkspaceName: slackWorkspaceName };
|
|
2923
|
-
lookupSelect = {
|
|
3017
|
+
lookupSelect = {
|
|
3018
|
+
_id: true,
|
|
3019
|
+
slackIncomingWebhookUrl: true,
|
|
3020
|
+
unsubscribeToken: true,
|
|
3021
|
+
};
|
|
2924
3022
|
} else {
|
|
2925
3023
|
lookupQuery = {
|
|
2926
3024
|
microsoftTeamsWorkspaceName: microsoftTeamsWorkspaceName!,
|
|
2927
3025
|
};
|
|
2928
|
-
lookupSelect = {
|
|
3026
|
+
lookupSelect = {
|
|
3027
|
+
_id: true,
|
|
3028
|
+
microsoftTeamsIncomingWebhookUrl: true,
|
|
3029
|
+
unsubscribeToken: true,
|
|
3030
|
+
};
|
|
2929
3031
|
}
|
|
2930
3032
|
|
|
2931
3033
|
logger.debug(
|
|
@@ -2990,6 +3092,13 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2990
3092
|
}): Promise<void> {
|
|
2991
3093
|
const { statusPageId, subscribers, req } = data;
|
|
2992
3094
|
|
|
3095
|
+
/*
|
|
3096
|
+
* Their unsubscribe links need their tokens, as every other sender's do:
|
|
3097
|
+
* a subscriber the backfill has not reached yet is given one first,
|
|
3098
|
+
* rather than sent a link to the "out of date" page.
|
|
3099
|
+
*/
|
|
3100
|
+
await StatusPageSubscriberService.ensureUnsubscribeTokens(subscribers);
|
|
3101
|
+
|
|
2993
3102
|
const statusPageURL: string =
|
|
2994
3103
|
await StatusPageService.getStatusPageURL(statusPageId);
|
|
2995
3104
|
|
|
@@ -3060,20 +3169,28 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
3060
3169
|
statusPageSubscriber.microsoftTeamsIncomingWebhookUrl;
|
|
3061
3170
|
|
|
3062
3171
|
const manageUrlink: string =
|
|
3063
|
-
StatusPageSubscriberService.
|
|
3172
|
+
StatusPageSubscriberService.getManageSubscriptionLink(
|
|
3064
3173
|
URL.fromString(statusPageURL),
|
|
3065
3174
|
statusPageSubscriber.id!,
|
|
3066
3175
|
).toString();
|
|
3067
3176
|
|
|
3068
3177
|
/*
|
|
3069
|
-
* The
|
|
3070
|
-
*
|
|
3071
|
-
*
|
|
3178
|
+
* The visitor asked to manage their subscription, so the message
|
|
3179
|
+
* links to its Update Subscription page. It also hands templates the
|
|
3180
|
+
* unsubscribe link every other sender passes as unsubscribeUrl: that
|
|
3181
|
+
* one works without signing in, which the manage page on a private
|
|
3182
|
+
* status page does not.
|
|
3072
3183
|
*/
|
|
3184
|
+
const unsubscribeUrl: string =
|
|
3185
|
+
StatusPageSubscriberService.getUnsubscribeLink(
|
|
3186
|
+
URL.fromString(statusPageURL),
|
|
3187
|
+
statusPageSubscriber,
|
|
3188
|
+
).toString();
|
|
3189
|
+
|
|
3073
3190
|
const manageTemplateVariables: Record<string, string> = {
|
|
3074
3191
|
statusPageName: statusPageNameStr,
|
|
3075
3192
|
statusPageUrl: statusPageURL,
|
|
3076
|
-
unsubscribeUrl:
|
|
3193
|
+
unsubscribeUrl: unsubscribeUrl,
|
|
3077
3194
|
manageSubscriptionUrl: manageUrlink,
|
|
3078
3195
|
};
|
|
3079
3196
|
|
|
@@ -3086,8 +3203,9 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
3086
3203
|
statusPage.id?.toString() || statusPage._id?.toString() || null;
|
|
3087
3204
|
|
|
3088
3205
|
if (manageEmailTemplate?.templateBody && statusPage.smtpConfig) {
|
|
3206
|
+
// The body is HTML, so the (plain-text) values are escaped into it.
|
|
3089
3207
|
const compiledBody: string =
|
|
3090
|
-
StatusPageSubscriberNotificationTemplateServiceClass.
|
|
3208
|
+
StatusPageSubscriberNotificationTemplateServiceClass.compileEmailBodyTemplate(
|
|
3091
3209
|
manageEmailTemplate.templateBody,
|
|
3092
3210
|
manageTemplateVariables,
|
|
3093
3211
|
);
|
|
@@ -3159,10 +3277,24 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
3159
3277
|
if (subscriberPhone) {
|
|
3160
3278
|
let smsMessage: string;
|
|
3161
3279
|
if (manageSmsTemplate?.templateBody && statusPage.callSmsConfig) {
|
|
3280
|
+
/*
|
|
3281
|
+
* On a public status page an SMS carries the shorter manage link
|
|
3282
|
+
* where other messages carry the unsubscribe link: an SMS is
|
|
3283
|
+
* billed by the segment (see
|
|
3284
|
+
* StatusPageSubscriberUnsubscribe.buildSmsLink).
|
|
3285
|
+
*/
|
|
3162
3286
|
smsMessage =
|
|
3163
3287
|
StatusPageSubscriberNotificationTemplateServiceClass.compileTemplate(
|
|
3164
3288
|
manageSmsTemplate.templateBody,
|
|
3165
|
-
|
|
3289
|
+
{
|
|
3290
|
+
...manageTemplateVariables,
|
|
3291
|
+
unsubscribeUrl: StatusPageSubscriberUnsubscribe.buildSmsLink({
|
|
3292
|
+
isPublicStatusPage: statusPage.isPublicStatusPage,
|
|
3293
|
+
statusPageUrl: statusPageURL,
|
|
3294
|
+
subscriberId: statusPageSubscriber.id!,
|
|
3295
|
+
unsubscribeUrl: unsubscribeUrl,
|
|
3296
|
+
}),
|
|
3297
|
+
},
|
|
3166
3298
|
);
|
|
3167
3299
|
} else {
|
|
3168
3300
|
smsMessage = defaultChatMessage;
|
|
@@ -3588,12 +3720,12 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
3588
3720
|
}
|
|
3589
3721
|
|
|
3590
3722
|
if (isUpdate) {
|
|
3591
|
-
// check isUnsubscribed is set to false.
|
|
3592
3723
|
logger.debug(
|
|
3593
3724
|
`Updating subscriber with ID: ${statusPageSubscriber.id}`,
|
|
3594
3725
|
getLogAttributesFromRequest(req as any),
|
|
3595
3726
|
);
|
|
3596
|
-
|
|
3727
|
+
|
|
3728
|
+
const wantsToUnsubscribe: boolean = Boolean(
|
|
3597
3729
|
req.body.data["isUnsubscribed"],
|
|
3598
3730
|
);
|
|
3599
3731
|
|
|
@@ -3606,23 +3738,34 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
3606
3738
|
statusPageEventTypes: statusPageSubscriber.statusPageEventTypes!,
|
|
3607
3739
|
isSubscribedToAllEventTypes:
|
|
3608
3740
|
statusPageSubscriber.isSubscribedToAllEventTypes!,
|
|
3609
|
-
|
|
3741
|
+
/*
|
|
3742
|
+
* Cancelling goes through unsubscribe() below, like the unsubscribe
|
|
3743
|
+
* link: it records when, once, and tells the team about a
|
|
3744
|
+
* subscriber it added. Only turning the subscription back on is
|
|
3745
|
+
* written here (which clears Unsubscribed At).
|
|
3746
|
+
*/
|
|
3747
|
+
...(wantsToUnsubscribe ? {} : { isUnsubscribed: false }),
|
|
3610
3748
|
} as any,
|
|
3611
3749
|
props: {
|
|
3612
3750
|
isRoot: true,
|
|
3613
3751
|
},
|
|
3614
3752
|
});
|
|
3753
|
+
|
|
3754
|
+
if (wantsToUnsubscribe) {
|
|
3755
|
+
await StatusPageSubscriberService.unsubscribe({
|
|
3756
|
+
subscriberId: statusPageSubscriber.id!,
|
|
3757
|
+
source: StatusPageSubscriberUnsubscribeSource.ManageSubscriptionPage,
|
|
3758
|
+
});
|
|
3759
|
+
}
|
|
3615
3760
|
} else {
|
|
3616
3761
|
logger.debug(
|
|
3617
3762
|
`Creating new subscriber: ${JSON.stringify(statusPageSubscriber)}`,
|
|
3618
3763
|
getLogAttributesFromRequest(req as any),
|
|
3619
3764
|
);
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
},
|
|
3625
|
-
});
|
|
3765
|
+
// A sign-up, not a subscriber the team added (Is Added By Team stays off).
|
|
3766
|
+
await StatusPageSubscriberService.createFromStatusPageSignUp(
|
|
3767
|
+
statusPageSubscriber,
|
|
3768
|
+
);
|
|
3626
3769
|
}
|
|
3627
3770
|
|
|
3628
3771
|
logger.debug(
|
|
@@ -3694,6 +3837,12 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
3694
3837
|
return statusPageSubscriber;
|
|
3695
3838
|
}
|
|
3696
3839
|
|
|
3840
|
+
/*
|
|
3841
|
+
* Every incident a public status page is sent goes through here - the
|
|
3842
|
+
* overview's active and timeline incidents, and the incident list and
|
|
3843
|
+
* detail - so it is where the page's JSON, and the overview cache, are made
|
|
3844
|
+
* safe to serve.
|
|
3845
|
+
*/
|
|
3697
3846
|
private serializeIncidentsForStatusPage(
|
|
3698
3847
|
incidents: Array<Incident>,
|
|
3699
3848
|
): JSONArray {
|
|
@@ -3707,10 +3856,41 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
3707
3856
|
delete incidentJson["postmortemAttachments"];
|
|
3708
3857
|
}
|
|
3709
3858
|
|
|
3859
|
+
/*
|
|
3860
|
+
* Which status pages an incident is limited to names the other
|
|
3861
|
+
* audiences it is shown to. The display queries never select these
|
|
3862
|
+
* columns (IncidentStatusPageScope), so this is a second line of
|
|
3863
|
+
* defence against a select that one day does.
|
|
3864
|
+
*/
|
|
3865
|
+
IncidentStatusPageScope.removeScopeColumns(incidentJson);
|
|
3866
|
+
|
|
3710
3867
|
return incidentJson;
|
|
3711
3868
|
});
|
|
3712
3869
|
}
|
|
3713
3870
|
|
|
3871
|
+
/*
|
|
3872
|
+
* An episode's member incidents, read by id to work out which of the
|
|
3873
|
+
* page's monitors the episode affects, keeping only those this page shows
|
|
3874
|
+
* as far as scope goes. The read selects the scope columns for that
|
|
3875
|
+
* (INCIDENT_SCOPE_SELECT); they are removed again before the incidents are
|
|
3876
|
+
* used, so they cannot reach the page's JSON.
|
|
3877
|
+
*/
|
|
3878
|
+
private keepMemberIncidentsInScope(data: {
|
|
3879
|
+
incidents: Array<Incident>;
|
|
3880
|
+
statusPage: StatusPage;
|
|
3881
|
+
}): Array<Incident> {
|
|
3882
|
+
return data.incidents
|
|
3883
|
+
.filter((incident: Incident): boolean => {
|
|
3884
|
+
return IncidentStatusPageScope.isIncidentInScope(
|
|
3885
|
+
incident,
|
|
3886
|
+
data.statusPage,
|
|
3887
|
+
);
|
|
3888
|
+
})
|
|
3889
|
+
.map((incident: Incident): Incident => {
|
|
3890
|
+
return IncidentStatusPageScope.removeScopeColumns(incident);
|
|
3891
|
+
});
|
|
3892
|
+
}
|
|
3893
|
+
|
|
3714
3894
|
@CaptureSpan()
|
|
3715
3895
|
public async getIncidents(
|
|
3716
3896
|
statusPageId: ObjectID,
|
|
@@ -3732,6 +3912,8 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
3732
3912
|
showIncidentHistoryInDays: true,
|
|
3733
3913
|
showIncidentLabelsOnStatusPage: true,
|
|
3734
3914
|
showIncidentsOnStatusPage: true,
|
|
3915
|
+
// Read by IncidentStatusPageScope to decide which incidents it shows.
|
|
3916
|
+
onlyShowScopedIncidents: true,
|
|
3735
3917
|
},
|
|
3736
3918
|
props: {
|
|
3737
3919
|
isRoot: true,
|
|
@@ -3826,7 +4008,15 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
3826
4008
|
}
|
|
3827
4009
|
|
|
3828
4010
|
if (monitorsOnStatusPage.length > 0) {
|
|
3829
|
-
|
|
4011
|
+
/*
|
|
4012
|
+
* Through IncidentStatusPageScope, like every incident read here that
|
|
4013
|
+
* decides what the page shows: an incident limited to other status
|
|
4014
|
+
* pages is left out, and so is an unlimited one when this page only
|
|
4015
|
+
* shows incidents limited to it. The scope is applied in SQL, before
|
|
4016
|
+
* LIMIT_PER_PROJECT cuts the list, not filtered out afterwards.
|
|
4017
|
+
*/
|
|
4018
|
+
incidents = await IncidentStatusPageScope.findIncidentsForStatusPage({
|
|
4019
|
+
statusPage: statusPage,
|
|
3830
4020
|
query: incidentQuery,
|
|
3831
4021
|
select: selectIncidents,
|
|
3832
4022
|
sort: {
|
|
@@ -3857,27 +4047,29 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
3857
4047
|
|
|
3858
4048
|
// If there is no particular incident id to fetch then fetch active incidents.
|
|
3859
4049
|
if (!incidentId) {
|
|
3860
|
-
activeIncidents =
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
4050
|
+
activeIncidents =
|
|
4051
|
+
await IncidentStatusPageScope.findIncidentsForStatusPage({
|
|
4052
|
+
statusPage: statusPage,
|
|
4053
|
+
query: {
|
|
4054
|
+
monitors: monitorsOnStatusPage as any,
|
|
4055
|
+
isVisibleOnStatusPage: true,
|
|
4056
|
+
currentIncidentStateId: QueryHelper.any(
|
|
4057
|
+
unresolvbedIncidentStateIds,
|
|
4058
|
+
),
|
|
4059
|
+
projectId: statusPage.projectId!,
|
|
4060
|
+
},
|
|
4061
|
+
select: selectIncidents,
|
|
4062
|
+
sort: {
|
|
4063
|
+
declaredAt: SortOrder.Descending,
|
|
4064
|
+
createdAt: SortOrder.Descending,
|
|
4065
|
+
},
|
|
3874
4066
|
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
4067
|
+
skip: 0,
|
|
4068
|
+
limit: LIMIT_PER_PROJECT,
|
|
4069
|
+
props: {
|
|
4070
|
+
isRoot: true,
|
|
4071
|
+
},
|
|
4072
|
+
});
|
|
3881
4073
|
}
|
|
3882
4074
|
|
|
3883
4075
|
incidents = [...activeIncidents, ...incidents];
|
|
@@ -4010,6 +4202,8 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
4010
4202
|
showEpisodeHistoryInDays: true,
|
|
4011
4203
|
showEpisodesOnStatusPage: true,
|
|
4012
4204
|
showEpisodeLabelsOnStatusPage: true,
|
|
4205
|
+
// Read by IncidentStatusPageScope to decide which incidents it shows.
|
|
4206
|
+
onlyShowScopedIncidents: true,
|
|
4013
4207
|
},
|
|
4014
4208
|
props: {
|
|
4015
4209
|
isRoot: true,
|
|
@@ -4061,11 +4255,22 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
4061
4255
|
let incidents: Array<Incident> = [];
|
|
4062
4256
|
|
|
4063
4257
|
if (monitorsOnStatusPage.length > 0) {
|
|
4064
|
-
|
|
4258
|
+
/*
|
|
4259
|
+
* An episode is listed through the incidents in it that this page
|
|
4260
|
+
* shows, so an incident limited to other status pages (or an unlimited
|
|
4261
|
+
* one, on a page that only shows incidents limited to it) does not
|
|
4262
|
+
* bring its episode here. Newest first, so that when LIMIT_PER_PROJECT
|
|
4263
|
+
* cuts the list it keeps the recent episodes.
|
|
4264
|
+
*/
|
|
4265
|
+
incidents = await IncidentStatusPageScope.findIncidentsForStatusPage({
|
|
4266
|
+
statusPage: statusPage,
|
|
4065
4267
|
query: incidentQuery,
|
|
4066
4268
|
select: {
|
|
4067
4269
|
_id: true,
|
|
4068
4270
|
},
|
|
4271
|
+
sort: {
|
|
4272
|
+
createdAt: SortOrder.Descending,
|
|
4273
|
+
},
|
|
4069
4274
|
skip: 0,
|
|
4070
4275
|
limit: LIMIT_PER_PROJECT,
|
|
4071
4276
|
props: {
|
|
@@ -4142,6 +4347,47 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
4142
4347
|
},
|
|
4143
4348
|
});
|
|
4144
4349
|
|
|
4350
|
+
/*
|
|
4351
|
+
* An episode is this page's to show only through an incident in it
|
|
4352
|
+
* that the page shows: one on a monitor the page lists, and in scope
|
|
4353
|
+
* for the page. Without this check any visible episode of the project
|
|
4354
|
+
* could be read from any of its status pages by id - including an
|
|
4355
|
+
* episode whose incidents are all limited to other status pages. Like
|
|
4356
|
+
* the list, it does not ask whether the incidents themselves are
|
|
4357
|
+
* visible on status pages, and unlike the list, it has no history
|
|
4358
|
+
* window: a link to an older episode keeps working.
|
|
4359
|
+
*/
|
|
4360
|
+
const episodeMemberIncidentIds: Array<ObjectID> =
|
|
4361
|
+
episodeMembersForSpecificEpisode
|
|
4362
|
+
.map((member: IncidentEpisodeMember) => {
|
|
4363
|
+
return member.incidentId;
|
|
4364
|
+
})
|
|
4365
|
+
.filter((id: ObjectID | undefined): id is ObjectID => {
|
|
4366
|
+
return Boolean(id);
|
|
4367
|
+
});
|
|
4368
|
+
|
|
4369
|
+
const incidentShownOnStatusPage: Incident | null =
|
|
4370
|
+
monitorsOnStatusPage.length > 0 && episodeMemberIncidentIds.length > 0
|
|
4371
|
+
? await IncidentStatusPageScope.findOneIncidentForStatusPage({
|
|
4372
|
+
statusPage: statusPage,
|
|
4373
|
+
query: {
|
|
4374
|
+
_id: QueryHelper.any(episodeMemberIncidentIds),
|
|
4375
|
+
monitors: monitorsOnStatusPage as any,
|
|
4376
|
+
projectId: statusPage.projectId!,
|
|
4377
|
+
},
|
|
4378
|
+
select: {
|
|
4379
|
+
_id: true,
|
|
4380
|
+
},
|
|
4381
|
+
props: {
|
|
4382
|
+
isRoot: true,
|
|
4383
|
+
},
|
|
4384
|
+
})
|
|
4385
|
+
: null;
|
|
4386
|
+
|
|
4387
|
+
if (!incidentShownOnStatusPage) {
|
|
4388
|
+
throw new NotFoundException("Episode not found");
|
|
4389
|
+
}
|
|
4390
|
+
|
|
4145
4391
|
// Merge with existing episode members
|
|
4146
4392
|
for (const member of episodeMembersForSpecificEpisode) {
|
|
4147
4393
|
if (
|
|
@@ -4276,25 +4522,34 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
4276
4522
|
}
|
|
4277
4523
|
}
|
|
4278
4524
|
|
|
4279
|
-
|
|
4525
|
+
/*
|
|
4526
|
+
* Fetch incidents with their monitors. Read by id, so the scope is
|
|
4527
|
+
* applied here, in memory: a member incident limited to other status
|
|
4528
|
+
* pages does not tell this page which of its monitors the episode
|
|
4529
|
+
* affects. (An episode viewed by id brings all of its members.)
|
|
4530
|
+
*/
|
|
4280
4531
|
let memberIncidents: Array<Incident> = [];
|
|
4281
4532
|
if (memberIncidentIds.length > 0) {
|
|
4282
|
-
memberIncidents =
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
monitors: {
|
|
4533
|
+
memberIncidents = this.keepMemberIncidentsInScope({
|
|
4534
|
+
incidents: await IncidentService.findBy({
|
|
4535
|
+
query: {
|
|
4536
|
+
_id: QueryHelper.any(memberIncidentIds),
|
|
4537
|
+
projectId: statusPage.projectId!,
|
|
4538
|
+
},
|
|
4539
|
+
select: {
|
|
4290
4540
|
_id: true,
|
|
4541
|
+
monitors: {
|
|
4542
|
+
_id: true,
|
|
4543
|
+
},
|
|
4544
|
+
...INCIDENT_SCOPE_SELECT,
|
|
4291
4545
|
},
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
},
|
|
4546
|
+
skip: 0,
|
|
4547
|
+
limit: LIMIT_PER_PROJECT,
|
|
4548
|
+
props: {
|
|
4549
|
+
isRoot: true,
|
|
4550
|
+
},
|
|
4551
|
+
}),
|
|
4552
|
+
statusPage: statusPage,
|
|
4298
4553
|
});
|
|
4299
4554
|
}
|
|
4300
4555
|
|
|
@@ -4507,6 +4762,11 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
4507
4762
|
showEpisodesOnStatusPage: true,
|
|
4508
4763
|
showScheduledMaintenanceEventsOnStatusPage: true,
|
|
4509
4764
|
showUptimeHistoryInDays: true,
|
|
4765
|
+
/*
|
|
4766
|
+
* Read by IncidentStatusPageScope to decide which incidents the
|
|
4767
|
+
* overview shows. Not public: the overview removes it again.
|
|
4768
|
+
*/
|
|
4769
|
+
onlyShowScopedIncidents: true,
|
|
4510
4770
|
},
|
|
4511
4771
|
props: {
|
|
4512
4772
|
isRoot: true,
|
|
@@ -4956,25 +5216,30 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
4956
5216
|
});
|
|
4957
5217
|
|
|
4958
5218
|
if (statusPage.showIncidentsOnStatusPage) {
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
5219
|
+
// Only the incidents in scope for this page; see getIncidents.
|
|
5220
|
+
activeIncidents =
|
|
5221
|
+
await IncidentStatusPageScope.findIncidentsForStatusPage({
|
|
5222
|
+
statusPage: statusPage,
|
|
5223
|
+
query: {
|
|
5224
|
+
monitors: monitorsOnStatusPage as any,
|
|
5225
|
+
currentIncidentStateId: QueryHelper.any(
|
|
5226
|
+
unresolvedIncidentStateIds,
|
|
5227
|
+
),
|
|
5228
|
+
isVisibleOnStatusPage: true,
|
|
5229
|
+
projectId: statusPage.projectId!,
|
|
5230
|
+
},
|
|
5231
|
+
select: select,
|
|
5232
|
+
sort: {
|
|
5233
|
+
declaredAt: SortOrder.Descending,
|
|
5234
|
+
createdAt: SortOrder.Descending,
|
|
5235
|
+
},
|
|
4971
5236
|
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
5237
|
+
skip: 0,
|
|
5238
|
+
limit: LIMIT_PER_PROJECT,
|
|
5239
|
+
props: {
|
|
5240
|
+
isRoot: true,
|
|
5241
|
+
},
|
|
5242
|
+
});
|
|
4978
5243
|
}
|
|
4979
5244
|
}
|
|
4980
5245
|
|
|
@@ -5098,9 +5363,16 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
5098
5363
|
}
|
|
5099
5364
|
|
|
5100
5365
|
if (hasActiveEpisodes) {
|
|
5101
|
-
|
|
5366
|
+
/*
|
|
5367
|
+
* First, get incidents that have monitors on status page, and are in
|
|
5368
|
+
* scope for it: an episode is shown through the incidents in it that
|
|
5369
|
+
* the page shows (see getEpisodes). Newest first, so that when
|
|
5370
|
+
* LIMIT_PER_PROJECT cuts the list it keeps the incidents most likely
|
|
5371
|
+
* to be in an active episode.
|
|
5372
|
+
*/
|
|
5102
5373
|
const incidentsForEpisodes: Array<Incident> =
|
|
5103
|
-
await
|
|
5374
|
+
await IncidentStatusPageScope.findIncidentsForStatusPage({
|
|
5375
|
+
statusPage: statusPage,
|
|
5104
5376
|
query: {
|
|
5105
5377
|
monitors: monitorsOnStatusPage as any,
|
|
5106
5378
|
isVisibleOnStatusPage: true,
|
|
@@ -5109,6 +5381,9 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
5109
5381
|
select: {
|
|
5110
5382
|
_id: true,
|
|
5111
5383
|
},
|
|
5384
|
+
sort: {
|
|
5385
|
+
createdAt: SortOrder.Descending,
|
|
5386
|
+
},
|
|
5112
5387
|
skip: 0,
|
|
5113
5388
|
limit: LIMIT_PER_PROJECT,
|
|
5114
5389
|
props: {
|
|
@@ -5233,26 +5508,35 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
5233
5508
|
}
|
|
5234
5509
|
}
|
|
5235
5510
|
|
|
5236
|
-
|
|
5511
|
+
/*
|
|
5512
|
+
* Fetch incidents with monitors. Read by id, so the scope is
|
|
5513
|
+
* applied in memory, as in getEpisodes - these members came from
|
|
5514
|
+
* incidents in scope, and this keeps it that way should that
|
|
5515
|
+
* change.
|
|
5516
|
+
*/
|
|
5237
5517
|
let memberIncidents: Array<Incident> = [];
|
|
5238
5518
|
if (memberIncidentIds.length > 0) {
|
|
5239
|
-
memberIncidents =
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
monitors: {
|
|
5519
|
+
memberIncidents = this.keepMemberIncidentsInScope({
|
|
5520
|
+
incidents: await IncidentService.findBy({
|
|
5521
|
+
query: {
|
|
5522
|
+
_id: QueryHelper.any(memberIncidentIds),
|
|
5523
|
+
isVisibleOnStatusPage: true,
|
|
5524
|
+
projectId: statusPage.projectId!,
|
|
5525
|
+
},
|
|
5526
|
+
select: {
|
|
5248
5527
|
_id: true,
|
|
5528
|
+
monitors: {
|
|
5529
|
+
_id: true,
|
|
5530
|
+
},
|
|
5531
|
+
...INCIDENT_SCOPE_SELECT,
|
|
5249
5532
|
},
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
},
|
|
5533
|
+
skip: 0,
|
|
5534
|
+
limit: LIMIT_PER_PROJECT,
|
|
5535
|
+
props: {
|
|
5536
|
+
isRoot: true,
|
|
5537
|
+
},
|
|
5538
|
+
}),
|
|
5539
|
+
statusPage: statusPage,
|
|
5256
5540
|
});
|
|
5257
5541
|
}
|
|
5258
5542
|
|
|
@@ -5608,39 +5892,47 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
5608
5892
|
monitorsOnStatusPage.length > 0 &&
|
|
5609
5893
|
statusPage.showIncidentsOnStatusPage
|
|
5610
5894
|
) {
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5895
|
+
/*
|
|
5896
|
+
* Only the incidents in scope for this page; see getIncidents. The
|
|
5897
|
+
* uptime bars stay as they are - a monitor's status is shared by every
|
|
5898
|
+
* page that lists it - but an incident limited to other pages is not
|
|
5899
|
+
* named in their tooltips.
|
|
5900
|
+
*/
|
|
5901
|
+
timelineIncidents =
|
|
5902
|
+
await IncidentStatusPageScope.findIncidentsForStatusPage({
|
|
5903
|
+
statusPage: statusPage,
|
|
5904
|
+
query: {
|
|
5905
|
+
monitors: monitorsOnStatusPage as any,
|
|
5906
|
+
declaredAt: QueryHelper.inBetween(startDate, endDate),
|
|
5907
|
+
isVisibleOnStatusPage: true,
|
|
5908
|
+
projectId: statusPage.projectId!,
|
|
5625
5909
|
},
|
|
5626
|
-
|
|
5910
|
+
select: {
|
|
5627
5911
|
_id: true,
|
|
5628
|
-
|
|
5629
|
-
|
|
5912
|
+
title: true,
|
|
5913
|
+
declaredAt: true,
|
|
5914
|
+
incidentSeverity: {
|
|
5915
|
+
name: true,
|
|
5916
|
+
color: true,
|
|
5917
|
+
},
|
|
5918
|
+
currentIncidentState: {
|
|
5919
|
+
_id: true,
|
|
5920
|
+
name: true,
|
|
5921
|
+
color: true,
|
|
5922
|
+
},
|
|
5923
|
+
monitors: {
|
|
5924
|
+
_id: true,
|
|
5925
|
+
},
|
|
5630
5926
|
},
|
|
5631
|
-
|
|
5632
|
-
|
|
5927
|
+
sort: {
|
|
5928
|
+
declaredAt: SortOrder.Descending,
|
|
5633
5929
|
},
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
props: {
|
|
5641
|
-
isRoot: true,
|
|
5642
|
-
},
|
|
5643
|
-
});
|
|
5930
|
+
skip: 0,
|
|
5931
|
+
limit: LIMIT_PER_PROJECT,
|
|
5932
|
+
props: {
|
|
5933
|
+
isRoot: true,
|
|
5934
|
+
},
|
|
5935
|
+
});
|
|
5644
5936
|
}
|
|
5645
5937
|
|
|
5646
5938
|
const overallStatus: MonitorStatus | null =
|
|
@@ -5713,6 +6005,11 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
5713
6005
|
StatusPage,
|
|
5714
6006
|
);
|
|
5715
6007
|
delete statusPageJson["projectId"];
|
|
6008
|
+
/*
|
|
6009
|
+
* Read only to decide which incidents the overview shows; the page
|
|
6010
|
+
* itself has no use for it.
|
|
6011
|
+
*/
|
|
6012
|
+
delete statusPageJson["onlyShowScopedIncidents"];
|
|
5716
6013
|
return statusPageJson;
|
|
5717
6014
|
})(),
|
|
5718
6015
|
scheduledMaintenanceStateTimelines: BaseModel.toJSONArray(
|
|
@@ -5724,7 +6021,8 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
5724
6021
|
monitorGroupCurrentStatuses,
|
|
5725
6022
|
),
|
|
5726
6023
|
monitorsInGroup: JSONFunctions.serialize(monitorsInGroup),
|
|
5727
|
-
timelineIncidents:
|
|
6024
|
+
timelineIncidents:
|
|
6025
|
+
this.serializeIncidentsForStatusPage(timelineIncidents),
|
|
5728
6026
|
};
|
|
5729
6027
|
|
|
5730
6028
|
return response;
|
|
@@ -5984,6 +6282,8 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
5984
6282
|
_id: true,
|
|
5985
6283
|
projectId: true,
|
|
5986
6284
|
showIncidentsOnStatusPage: true,
|
|
6285
|
+
// Read by IncidentStatusPageScope to decide which incidents it shows.
|
|
6286
|
+
onlyShowScopedIncidents: true,
|
|
5987
6287
|
},
|
|
5988
6288
|
props: {
|
|
5989
6289
|
isRoot: true,
|
|
@@ -6007,26 +6307,29 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
6007
6307
|
throw new NotFoundException("Attachment not found");
|
|
6008
6308
|
}
|
|
6009
6309
|
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
_id: true,
|
|
6021
|
-
file: true,
|
|
6022
|
-
fileType: true,
|
|
6023
|
-
name: true,
|
|
6310
|
+
// Only an incident this page shows: on its monitors and in its scope.
|
|
6311
|
+
const incident: Incident | null =
|
|
6312
|
+
await IncidentStatusPageScope.findOneIncidentForStatusPage({
|
|
6313
|
+
statusPage: statusPage,
|
|
6314
|
+
query: {
|
|
6315
|
+
_id: incidentId.toString(),
|
|
6316
|
+
projectId: statusPage.projectId!,
|
|
6317
|
+
isVisibleOnStatusPage: true,
|
|
6318
|
+
showPostmortemOnStatusPage: true,
|
|
6319
|
+
monitors: monitorsOnStatusPage as any,
|
|
6024
6320
|
},
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6321
|
+
select: {
|
|
6322
|
+
postmortemAttachments: {
|
|
6323
|
+
_id: true,
|
|
6324
|
+
file: true,
|
|
6325
|
+
fileType: true,
|
|
6326
|
+
name: true,
|
|
6327
|
+
},
|
|
6328
|
+
},
|
|
6329
|
+
props: {
|
|
6330
|
+
isRoot: true,
|
|
6331
|
+
},
|
|
6332
|
+
});
|
|
6030
6333
|
|
|
6031
6334
|
if (!incident) {
|
|
6032
6335
|
throw new NotFoundException("Attachment not found");
|
|
@@ -6096,6 +6399,8 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
6096
6399
|
_id: true,
|
|
6097
6400
|
projectId: true,
|
|
6098
6401
|
showIncidentsOnStatusPage: true,
|
|
6402
|
+
// Read by IncidentStatusPageScope to decide which incidents it shows.
|
|
6403
|
+
onlyShowScopedIncidents: true,
|
|
6099
6404
|
},
|
|
6100
6405
|
props: {
|
|
6101
6406
|
isRoot: true,
|
|
@@ -6119,20 +6424,23 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
6119
6424
|
throw new NotFoundException("Attachment not found");
|
|
6120
6425
|
}
|
|
6121
6426
|
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
|
|
6427
|
+
// Only an incident this page shows: on its monitors and in its scope.
|
|
6428
|
+
const incident: Incident | null =
|
|
6429
|
+
await IncidentStatusPageScope.findOneIncidentForStatusPage({
|
|
6430
|
+
statusPage: statusPage,
|
|
6431
|
+
query: {
|
|
6432
|
+
_id: incidentId.toString(),
|
|
6433
|
+
projectId: statusPage.projectId!,
|
|
6434
|
+
isVisibleOnStatusPage: true,
|
|
6435
|
+
monitors: monitorsOnStatusPage as any,
|
|
6436
|
+
},
|
|
6437
|
+
select: {
|
|
6438
|
+
_id: true,
|
|
6439
|
+
},
|
|
6440
|
+
props: {
|
|
6441
|
+
isRoot: true,
|
|
6442
|
+
},
|
|
6443
|
+
});
|
|
6136
6444
|
|
|
6137
6445
|
if (!incident) {
|
|
6138
6446
|
throw new NotFoundException("Attachment not found");
|
|
@@ -6221,6 +6529,8 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
6221
6529
|
_id: true,
|
|
6222
6530
|
projectId: true,
|
|
6223
6531
|
showEpisodesOnStatusPage: true,
|
|
6532
|
+
// Read by IncidentStatusPageScope to decide which incidents it shows.
|
|
6533
|
+
onlyShowScopedIncidents: true,
|
|
6224
6534
|
},
|
|
6225
6535
|
props: {
|
|
6226
6536
|
isRoot: true,
|
|
@@ -6273,21 +6583,27 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
6273
6583
|
return Boolean(id);
|
|
6274
6584
|
});
|
|
6275
6585
|
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
|
|
6586
|
+
/*
|
|
6587
|
+
* Check if any of the incidents are linked to monitors on the status
|
|
6588
|
+
* page, and in scope for it: an episode whose incidents are all limited
|
|
6589
|
+
* to other status pages is not this page's to serve.
|
|
6590
|
+
*/
|
|
6591
|
+
const incident: Incident | null =
|
|
6592
|
+
await IncidentStatusPageScope.findOneIncidentForStatusPage({
|
|
6593
|
+
statusPage: statusPage,
|
|
6594
|
+
query: {
|
|
6595
|
+
_id: QueryHelper.any(incidentIds),
|
|
6596
|
+
projectId: statusPage.projectId!,
|
|
6597
|
+
isVisibleOnStatusPage: true,
|
|
6598
|
+
monitors: monitorsOnStatusPage as any,
|
|
6599
|
+
},
|
|
6600
|
+
select: {
|
|
6601
|
+
_id: true,
|
|
6602
|
+
},
|
|
6603
|
+
props: {
|
|
6604
|
+
isRoot: true,
|
|
6605
|
+
},
|
|
6606
|
+
});
|
|
6291
6607
|
|
|
6292
6608
|
if (!incident) {
|
|
6293
6609
|
throw new NotFoundException("Attachment not found");
|