@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
|
@@ -2,21 +2,256 @@ import DatabaseService from "./DatabaseService";
|
|
|
2
2
|
import Model from "../../Models/DatabaseModels/StatusPageSubscriberNotificationTemplate";
|
|
3
3
|
import StatusPageSubscriberNotificationTemplateStatusPage from "../../Models/DatabaseModels/StatusPageSubscriberNotificationTemplateStatusPage";
|
|
4
4
|
import ObjectID from "../../Types/ObjectID";
|
|
5
|
+
import LIMIT_MAX, { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
6
|
+
import CreateBy from "../Types/Database/CreateBy";
|
|
7
|
+
import { OnCreate, OnUpdate } from "../Types/Database/Hooks";
|
|
8
|
+
import Query from "../Types/Database/Query";
|
|
9
|
+
import QueryHelper from "../Types/Database/QueryHelper";
|
|
10
|
+
import UpdateBy from "../Types/Database/UpdateBy";
|
|
11
|
+
import SubscriberTemplateIncidentRecordAccess from "../Utils/StatusPage/SubscriberTemplateIncidentRecordAccess";
|
|
12
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
5
13
|
import StatusPageSubscriberNotificationEventType from "../../Types/StatusPage/StatusPageSubscriberNotificationEventType";
|
|
6
14
|
import StatusPageSubscriberNotificationMethod from "../../Types/StatusPage/StatusPageSubscriberNotificationMethod";
|
|
7
15
|
import StatusPageSubscriberNotificationTemplateStatusPageService from "./StatusPageSubscriberNotificationTemplateStatusPageService";
|
|
8
16
|
import SubscriberNotificationTemplateVariables, {
|
|
9
17
|
SubscriberNotificationTemplateVariable,
|
|
10
18
|
} from "../../Types/StatusPage/SubscriberNotificationTemplateVariables";
|
|
19
|
+
import SubscriberNotificationTemplateCompiler, {
|
|
20
|
+
SubscriberNotificationEmailBodyTemplateVariables,
|
|
21
|
+
SubscriberNotificationTextTemplateVariables,
|
|
22
|
+
} from "../../Types/StatusPage/SubscriberNotificationTemplateCompiler";
|
|
23
|
+
|
|
24
|
+
export type {
|
|
25
|
+
SubscriberNotificationEmailBodyTemplateVariables,
|
|
26
|
+
SubscriberNotificationTextTemplateVariables,
|
|
27
|
+
};
|
|
11
28
|
|
|
12
29
|
export class Service extends DatabaseService<Model> {
|
|
13
30
|
public constructor() {
|
|
14
31
|
super(Model);
|
|
15
32
|
}
|
|
16
33
|
|
|
34
|
+
/*
|
|
35
|
+
* A template's body and subject may place values from the team's incident
|
|
36
|
+
* records - {{incidentLabels}} and {{customFields.<key>}} - only when
|
|
37
|
+
* whoever writes them may read those records: the status page roles that
|
|
38
|
+
* may write templates may not (SubscriberTemplateIncidentRecordAccess).
|
|
39
|
+
*/
|
|
40
|
+
@CaptureSpan()
|
|
41
|
+
protected override async onBeforeCreate(
|
|
42
|
+
createBy: CreateBy<Model>,
|
|
43
|
+
): Promise<OnCreate<Model>> {
|
|
44
|
+
SubscriberTemplateIncidentRecordAccess.assertCanPlace({
|
|
45
|
+
placeholders:
|
|
46
|
+
SubscriberNotificationTemplateVariables.getIncidentRecordPlaceholders([
|
|
47
|
+
createBy.data.templateBody,
|
|
48
|
+
createBy.data.emailSubject,
|
|
49
|
+
]),
|
|
50
|
+
props: createBy.props,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return { createBy, carryForward: null };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/*
|
|
57
|
+
* On an update, only what the write adds is checked: a placeholder the
|
|
58
|
+
* template already holds was allowed when it was written, so someone
|
|
59
|
+
* without incident access can still fix a typo, rename the template or
|
|
60
|
+
* move a placeholder from the subject to the body - but not add one.
|
|
61
|
+
*
|
|
62
|
+
* Pointing a template somewhere else counts as placing everything it
|
|
63
|
+
* holds: changing its channel or event type makes an admin's template
|
|
64
|
+
* send its incident records to wherever the new channel goes, and a
|
|
65
|
+
* status page role can add a Slack, Teams or webhook subscriber of its
|
|
66
|
+
* own. (Linking it to another status page is checked by
|
|
67
|
+
* StatusPageSubscriberNotificationTemplateStatusPageService.)
|
|
68
|
+
*/
|
|
69
|
+
@CaptureSpan()
|
|
70
|
+
protected override async onBeforeUpdate(
|
|
71
|
+
updateBy: UpdateBy<Model>,
|
|
72
|
+
): Promise<OnUpdate<Model>> {
|
|
73
|
+
SubscriberTemplateIncidentRecordAccess.assertCanPlace({
|
|
74
|
+
placeholders: await this.getIncidentRecordPlaceholdersToCheck(updateBy),
|
|
75
|
+
props: updateBy.props,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return { updateBy, carryForward: null };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/*
|
|
82
|
+
* The incident record placeholders this update must be allowed to place,
|
|
83
|
+
* across every template it would change: those it writes into a body or
|
|
84
|
+
* subject that the template did not hold before, and, when it changes
|
|
85
|
+
* where the template is sent (its channel or event type), every one the
|
|
86
|
+
* template will hold once written. The templates are read as root and
|
|
87
|
+
* limited to the caller's project, like other update hooks: the update's
|
|
88
|
+
* own permission check has not run yet, and only narrows the rows further.
|
|
89
|
+
*/
|
|
90
|
+
private async getIncidentRecordPlaceholdersToCheck(
|
|
91
|
+
updateBy: UpdateBy<Model>,
|
|
92
|
+
): Promise<Array<string>> {
|
|
93
|
+
if (updateBy.props.isRoot || updateBy.props.isMasterAdmin) {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const data: {
|
|
98
|
+
templateBody?: unknown;
|
|
99
|
+
emailSubject?: unknown;
|
|
100
|
+
eventType?: unknown;
|
|
101
|
+
notificationMethod?: unknown;
|
|
102
|
+
} = updateBy.data as unknown as {
|
|
103
|
+
templateBody?: unknown;
|
|
104
|
+
emailSubject?: unknown;
|
|
105
|
+
eventType?: unknown;
|
|
106
|
+
notificationMethod?: unknown;
|
|
107
|
+
};
|
|
108
|
+
const writesBody: boolean = data.templateBody !== undefined;
|
|
109
|
+
const writesSubject: boolean = data.emailSubject !== undefined;
|
|
110
|
+
const writesTarget: boolean =
|
|
111
|
+
data.eventType !== undefined || data.notificationMethod !== undefined;
|
|
112
|
+
|
|
113
|
+
if (!writesBody && !writesSubject && !writesTarget) {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Anything but text places nothing: the column check refuses it anyway.
|
|
118
|
+
const writtenBody: string | null =
|
|
119
|
+
writesBody && typeof data.templateBody === "string"
|
|
120
|
+
? data.templateBody
|
|
121
|
+
: null;
|
|
122
|
+
const writtenSubject: string | null =
|
|
123
|
+
writesSubject && typeof data.emailSubject === "string"
|
|
124
|
+
? data.emailSubject
|
|
125
|
+
: null;
|
|
126
|
+
|
|
127
|
+
const written: Array<string> =
|
|
128
|
+
SubscriberNotificationTemplateVariables.getIncidentRecordPlaceholders([
|
|
129
|
+
writtenBody,
|
|
130
|
+
writtenSubject,
|
|
131
|
+
]);
|
|
132
|
+
|
|
133
|
+
if (written.length === 0 && !writesTarget) {
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const query: Query<Model> = updateBy.props.tenantId
|
|
138
|
+
? { ...updateBy.query, projectId: updateBy.props.tenantId }
|
|
139
|
+
: updateBy.query;
|
|
140
|
+
|
|
141
|
+
const templates: Array<Model> = await this.findBy({
|
|
142
|
+
query: query,
|
|
143
|
+
select: {
|
|
144
|
+
templateBody: true,
|
|
145
|
+
emailSubject: true,
|
|
146
|
+
eventType: true,
|
|
147
|
+
notificationMethod: true,
|
|
148
|
+
},
|
|
149
|
+
limit: LIMIT_MAX,
|
|
150
|
+
skip: 0,
|
|
151
|
+
props: {
|
|
152
|
+
isRoot: true,
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
const added: Set<string> = new Set<string>();
|
|
157
|
+
|
|
158
|
+
for (const template of templates) {
|
|
159
|
+
const held: Array<string> =
|
|
160
|
+
SubscriberNotificationTemplateVariables.getIncidentRecordPlaceholders([
|
|
161
|
+
template.templateBody,
|
|
162
|
+
template.emailSubject,
|
|
163
|
+
]);
|
|
164
|
+
|
|
165
|
+
/*
|
|
166
|
+
* Only a real change: the edit form sends the channel and event type
|
|
167
|
+
* back as they were, and a typo fix must still go through.
|
|
168
|
+
*/
|
|
169
|
+
const changesTarget: boolean =
|
|
170
|
+
writesTarget &&
|
|
171
|
+
((data.eventType !== undefined &&
|
|
172
|
+
data.eventType !== template.eventType) ||
|
|
173
|
+
(data.notificationMethod !== undefined &&
|
|
174
|
+
data.notificationMethod !== template.notificationMethod));
|
|
175
|
+
|
|
176
|
+
if (changesTarget) {
|
|
177
|
+
// Everything the template will hold goes to the new target.
|
|
178
|
+
for (const name of SubscriberNotificationTemplateVariables.getIncidentRecordPlaceholders(
|
|
179
|
+
[
|
|
180
|
+
writesBody ? writtenBody : template.templateBody,
|
|
181
|
+
writesSubject ? writtenSubject : template.emailSubject,
|
|
182
|
+
],
|
|
183
|
+
)) {
|
|
184
|
+
added.add(name);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
for (const name of written) {
|
|
191
|
+
if (!held.includes(name)) {
|
|
192
|
+
added.add(name);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return Array.from(added).sort();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/*
|
|
201
|
+
* The incident record placeholders the given templates hold, in the
|
|
202
|
+
* caller's project: what linking them to a status page places there
|
|
203
|
+
* (StatusPageSubscriberNotificationTemplateStatusPageService). Read as
|
|
204
|
+
* root, like the update hook above.
|
|
205
|
+
*/
|
|
206
|
+
public async getIncidentRecordPlaceholdersHeld(data: {
|
|
207
|
+
templateIds: Array<ObjectID>;
|
|
208
|
+
projectId?: ObjectID | undefined;
|
|
209
|
+
}): Promise<Array<string>> {
|
|
210
|
+
if (data.templateIds.length === 0) {
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const templates: Array<Model> = await this.findBy({
|
|
215
|
+
query: {
|
|
216
|
+
_id: QueryHelper.any(data.templateIds),
|
|
217
|
+
...(data.projectId ? { projectId: data.projectId } : {}),
|
|
218
|
+
},
|
|
219
|
+
select: {
|
|
220
|
+
templateBody: true,
|
|
221
|
+
emailSubject: true,
|
|
222
|
+
},
|
|
223
|
+
limit: LIMIT_MAX,
|
|
224
|
+
skip: 0,
|
|
225
|
+
props: {
|
|
226
|
+
isRoot: true,
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const held: Set<string> = new Set<string>();
|
|
231
|
+
|
|
232
|
+
for (const template of templates) {
|
|
233
|
+
for (const name of SubscriberNotificationTemplateVariables.getIncidentRecordPlaceholders(
|
|
234
|
+
[template.templateBody, template.emailSubject],
|
|
235
|
+
)) {
|
|
236
|
+
held.add(name);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return Array.from(held).sort();
|
|
241
|
+
}
|
|
242
|
+
|
|
17
243
|
/**
|
|
18
244
|
* Get template for a specific status page, event type, and notification method.
|
|
19
245
|
* Returns null if no custom template is found (caller should use default template).
|
|
246
|
+
*
|
|
247
|
+
* Workers call this as root, so nothing but the query below keeps one
|
|
248
|
+
* project's page from reading another project's templates. The template
|
|
249
|
+
* query is therefore narrowed to the ids this page links to AND to the
|
|
250
|
+
* page's own project. It used to ask for every template of this event type
|
|
251
|
+
* and channel across all projects, 100 at a time, and look for the linked
|
|
252
|
+
* id in memory: once more than 100 such templates existed on a shared
|
|
253
|
+
* server, the linked one could fall outside those 100 and the page's
|
|
254
|
+
* subscribers silently got the default template instead of the branded one.
|
|
20
255
|
*/
|
|
21
256
|
public async getTemplateForStatusPage(data: {
|
|
22
257
|
statusPageId: ObjectID;
|
|
@@ -25,7 +260,11 @@ export class Service extends DatabaseService<Model> {
|
|
|
25
260
|
}): Promise<Model | null> {
|
|
26
261
|
const { statusPageId, eventType, notificationMethod } = data;
|
|
27
262
|
|
|
28
|
-
|
|
263
|
+
/*
|
|
264
|
+
* First find the template links for this status page. There is one per
|
|
265
|
+
* linked template, so a page has only a handful, but nothing enforces a
|
|
266
|
+
* cap - so read them all rather than risk the same truncation as above.
|
|
267
|
+
*/
|
|
29
268
|
const templateLinks: Array<StatusPageSubscriberNotificationTemplateStatusPage> =
|
|
30
269
|
await StatusPageSubscriberNotificationTemplateStatusPageService.findBy({
|
|
31
270
|
query: {
|
|
@@ -33,9 +272,13 @@ export class Service extends DatabaseService<Model> {
|
|
|
33
272
|
},
|
|
34
273
|
select: {
|
|
35
274
|
statusPageSubscriberNotificationTemplateId: true,
|
|
275
|
+
projectId: true,
|
|
276
|
+
statusPage: {
|
|
277
|
+
projectId: true,
|
|
278
|
+
},
|
|
36
279
|
},
|
|
37
280
|
skip: 0,
|
|
38
|
-
limit:
|
|
281
|
+
limit: LIMIT_PER_PROJECT,
|
|
39
282
|
props: {
|
|
40
283
|
isRoot: true,
|
|
41
284
|
},
|
|
@@ -45,27 +288,52 @@ export class Service extends DatabaseService<Model> {
|
|
|
45
288
|
return null;
|
|
46
289
|
}
|
|
47
290
|
|
|
48
|
-
|
|
291
|
+
const statusPageProjectId: ObjectID | undefined =
|
|
292
|
+
templateLinks.find(
|
|
293
|
+
(link: StatusPageSubscriberNotificationTemplateStatusPage) => {
|
|
294
|
+
return Boolean(link.statusPage?.projectId);
|
|
295
|
+
},
|
|
296
|
+
)?.statusPage?.projectId || undefined;
|
|
297
|
+
|
|
298
|
+
if (!statusPageProjectId) {
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/*
|
|
303
|
+
* Only links the page's own project made count: a link row stamped with
|
|
304
|
+
* another project cannot pull that project's template onto this page.
|
|
305
|
+
*/
|
|
49
306
|
const templateIds: Array<ObjectID> = templateLinks
|
|
307
|
+
.filter((link: StatusPageSubscriberNotificationTemplateStatusPage) => {
|
|
308
|
+
return link.projectId?.toString() === statusPageProjectId.toString();
|
|
309
|
+
})
|
|
50
310
|
.map((link: StatusPageSubscriberNotificationTemplateStatusPage) => {
|
|
51
311
|
return link.statusPageSubscriberNotificationTemplateId;
|
|
52
312
|
})
|
|
53
313
|
.filter((id: ObjectID | undefined): id is ObjectID => {
|
|
54
|
-
return id !== undefined;
|
|
314
|
+
return id !== undefined && id !== null;
|
|
55
315
|
});
|
|
56
316
|
|
|
57
317
|
if (templateIds.length === 0) {
|
|
58
318
|
return null;
|
|
59
319
|
}
|
|
60
320
|
|
|
61
|
-
|
|
321
|
+
/*
|
|
322
|
+
* Find the linked template for this event type and notification method.
|
|
323
|
+
* Several linked templates can match (nothing stops a page linking two
|
|
324
|
+
* for the same event and channel); the default sort returns the newest
|
|
325
|
+
* first, which is the one this method has always picked.
|
|
326
|
+
*/
|
|
62
327
|
const templates: Array<Model> = await this.findBy({
|
|
63
328
|
query: {
|
|
329
|
+
_id: QueryHelper.any(templateIds),
|
|
330
|
+
projectId: statusPageProjectId,
|
|
64
331
|
eventType: eventType,
|
|
65
332
|
notificationMethod: notificationMethod,
|
|
66
333
|
},
|
|
67
334
|
select: {
|
|
68
335
|
_id: true,
|
|
336
|
+
projectId: true,
|
|
69
337
|
templateName: true,
|
|
70
338
|
templateBody: true,
|
|
71
339
|
emailSubject: true,
|
|
@@ -73,24 +341,13 @@ export class Service extends DatabaseService<Model> {
|
|
|
73
341
|
notificationMethod: true,
|
|
74
342
|
},
|
|
75
343
|
skip: 0,
|
|
76
|
-
limit:
|
|
344
|
+
limit: 1,
|
|
77
345
|
props: {
|
|
78
346
|
isRoot: true,
|
|
79
347
|
},
|
|
80
348
|
});
|
|
81
349
|
|
|
82
|
-
|
|
83
|
-
for (const template of templates) {
|
|
84
|
-
if (
|
|
85
|
-
templateIds.some((id: ObjectID) => {
|
|
86
|
-
return id.toString() === template._id?.toString();
|
|
87
|
-
})
|
|
88
|
-
) {
|
|
89
|
-
return template;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return null;
|
|
350
|
+
return templates[0] || null;
|
|
94
351
|
}
|
|
95
352
|
|
|
96
353
|
/**
|
|
@@ -108,31 +365,36 @@ export class Service extends DatabaseService<Model> {
|
|
|
108
365
|
}
|
|
109
366
|
|
|
110
367
|
/**
|
|
111
|
-
* Compile a template
|
|
112
|
-
*
|
|
368
|
+
* Compile a template for a channel that does not render HTML - an email
|
|
369
|
+
* subject, SMS, Slack or Microsoft Teams - replacing {{variableName}} with
|
|
370
|
+
* each value exactly as written.
|
|
113
371
|
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* meaning, so a note mentioning "$$5" or a resource named "Store $&" was
|
|
117
|
-
* rewritten on its way to subscribers.
|
|
118
|
-
* - Replacing one variable at a time also expanded placeholders that
|
|
119
|
-
* appeared inside an earlier value, so a note containing
|
|
120
|
-
* "{{unsubscribeUrl}}" came out as a link.
|
|
121
|
-
* A placeholder with no variable is left as written.
|
|
372
|
+
* Never use it for the body of an email template, which is HTML: use
|
|
373
|
+
* compileEmailBodyTemplate. See SubscriberNotificationTemplateCompiler.
|
|
122
374
|
*/
|
|
123
375
|
public static compileTemplate(
|
|
124
376
|
template: string,
|
|
125
|
-
variables:
|
|
377
|
+
variables: SubscriberNotificationTextTemplateVariables,
|
|
126
378
|
): string {
|
|
127
|
-
return
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
379
|
+
return SubscriberNotificationTemplateCompiler.compileTemplate(
|
|
380
|
+
template,
|
|
381
|
+
variables,
|
|
382
|
+
);
|
|
383
|
+
}
|
|
133
384
|
|
|
134
|
-
|
|
135
|
-
|
|
385
|
+
/**
|
|
386
|
+
* Compile the body of an EMAIL template, which is sent as HTML. Plain
|
|
387
|
+
* values are HTML-escaped; only a SafeHtml value (rendered Markdown, the
|
|
388
|
+
* date helper's HTML, the escaped resource list) is inserted as it is. See
|
|
389
|
+
* SubscriberNotificationTemplateCompiler.
|
|
390
|
+
*/
|
|
391
|
+
public static compileEmailBodyTemplate(
|
|
392
|
+
template: string,
|
|
393
|
+
variables: SubscriberNotificationEmailBodyTemplateVariables,
|
|
394
|
+
): string {
|
|
395
|
+
return SubscriberNotificationTemplateCompiler.compileEmailBodyTemplate(
|
|
396
|
+
template,
|
|
397
|
+
variables,
|
|
136
398
|
);
|
|
137
399
|
}
|
|
138
400
|
}
|
|
@@ -1,10 +1,139 @@
|
|
|
1
1
|
import DatabaseService from "./DatabaseService";
|
|
2
|
+
import StatusPageSubscriberNotificationTemplateService from "./StatusPageSubscriberNotificationTemplateService";
|
|
2
3
|
import Model from "../../Models/DatabaseModels/StatusPageSubscriberNotificationTemplateStatusPage";
|
|
4
|
+
import LIMIT_MAX from "../../Types/Database/LimitMax";
|
|
5
|
+
import ObjectID from "../../Types/ObjectID";
|
|
6
|
+
import CreateBy from "../Types/Database/CreateBy";
|
|
7
|
+
import { OnCreate, OnUpdate } from "../Types/Database/Hooks";
|
|
8
|
+
import Query from "../Types/Database/Query";
|
|
9
|
+
import UpdateBy from "../Types/Database/UpdateBy";
|
|
10
|
+
import SubscriberTemplateIncidentRecordAccess from "../Utils/StatusPage/SubscriberTemplateIncidentRecordAccess";
|
|
11
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
3
12
|
|
|
13
|
+
/*
|
|
14
|
+
* Linking a custom subscriber notification template to a status page sends
|
|
15
|
+
* that page's subscribers whatever the template places. A template may place
|
|
16
|
+
* values from the team's incident records ({{incidentLabels}},
|
|
17
|
+
* {{customFields.<key>}}), which only someone who may read them may put in a
|
|
18
|
+
* template (SubscriberTemplateIncidentRecordAccess) - and the status page
|
|
19
|
+
* roles that may link templates may also add a Slack, Teams or webhook
|
|
20
|
+
* subscriber of their own to a page. So linking such a template, or moving a
|
|
21
|
+
* link to another template or page, is checked as placing everything the
|
|
22
|
+
* template holds. Root and master admin writes are not checked.
|
|
23
|
+
*/
|
|
4
24
|
export class Service extends DatabaseService<Model> {
|
|
5
25
|
public constructor() {
|
|
6
26
|
super(Model);
|
|
7
27
|
}
|
|
28
|
+
|
|
29
|
+
@CaptureSpan()
|
|
30
|
+
protected override async onBeforeCreate(
|
|
31
|
+
createBy: CreateBy<Model>,
|
|
32
|
+
): Promise<OnCreate<Model>> {
|
|
33
|
+
if (!createBy.props.isRoot && !createBy.props.isMasterAdmin) {
|
|
34
|
+
const templateId: ObjectID | undefined =
|
|
35
|
+
createBy.data.statusPageSubscriberNotificationTemplateId ||
|
|
36
|
+
createBy.data.statusPageSubscriberNotificationTemplate?.id ||
|
|
37
|
+
undefined;
|
|
38
|
+
|
|
39
|
+
await this.assertCanLink({
|
|
40
|
+
templateIds: templateId ? [templateId] : [],
|
|
41
|
+
createBy: createBy,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return { createBy, carryForward: null };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@CaptureSpan()
|
|
49
|
+
protected override async onBeforeUpdate(
|
|
50
|
+
updateBy: UpdateBy<Model>,
|
|
51
|
+
): Promise<OnUpdate<Model>> {
|
|
52
|
+
if (updateBy.props.isRoot || updateBy.props.isMasterAdmin) {
|
|
53
|
+
return { updateBy, carryForward: null };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const data: {
|
|
57
|
+
statusPageSubscriberNotificationTemplateId?: unknown;
|
|
58
|
+
statusPageId?: unknown;
|
|
59
|
+
} = updateBy.data as unknown as {
|
|
60
|
+
statusPageSubscriberNotificationTemplateId?: unknown;
|
|
61
|
+
statusPageId?: unknown;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const writesTemplate: boolean =
|
|
65
|
+
data.statusPageSubscriberNotificationTemplateId !== undefined &&
|
|
66
|
+
data.statusPageSubscriberNotificationTemplateId !== null;
|
|
67
|
+
const writesStatusPage: boolean = data.statusPageId !== undefined;
|
|
68
|
+
|
|
69
|
+
if (!writesTemplate && !writesStatusPage) {
|
|
70
|
+
return { updateBy, carryForward: null };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let templateIds: Array<ObjectID> = [];
|
|
74
|
+
|
|
75
|
+
if (writesTemplate) {
|
|
76
|
+
templateIds = [
|
|
77
|
+
new ObjectID(String(data.statusPageSubscriberNotificationTemplateId)),
|
|
78
|
+
];
|
|
79
|
+
} else {
|
|
80
|
+
// Moved to another page: the templates the links already point at.
|
|
81
|
+
const query: Query<Model> = updateBy.props.tenantId
|
|
82
|
+
? { ...updateBy.query, projectId: updateBy.props.tenantId }
|
|
83
|
+
: updateBy.query;
|
|
84
|
+
|
|
85
|
+
const links: Array<Model> = await this.findBy({
|
|
86
|
+
query: query,
|
|
87
|
+
select: {
|
|
88
|
+
statusPageSubscriberNotificationTemplateId: true,
|
|
89
|
+
},
|
|
90
|
+
limit: LIMIT_MAX,
|
|
91
|
+
skip: 0,
|
|
92
|
+
props: {
|
|
93
|
+
isRoot: true,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
templateIds = links
|
|
98
|
+
.map((link: Model): ObjectID | undefined => {
|
|
99
|
+
return link.statusPageSubscriberNotificationTemplateId;
|
|
100
|
+
})
|
|
101
|
+
.filter((id: ObjectID | undefined): id is ObjectID => {
|
|
102
|
+
return Boolean(id);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
SubscriberTemplateIncidentRecordAccess.assertCanPlace({
|
|
107
|
+
placeholders:
|
|
108
|
+
await StatusPageSubscriberNotificationTemplateService.getIncidentRecordPlaceholdersHeld(
|
|
109
|
+
{
|
|
110
|
+
templateIds: templateIds,
|
|
111
|
+
projectId: updateBy.props.tenantId as ObjectID | undefined,
|
|
112
|
+
},
|
|
113
|
+
),
|
|
114
|
+
props: updateBy.props,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return { updateBy, carryForward: null };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private async assertCanLink(data: {
|
|
121
|
+
templateIds: Array<ObjectID>;
|
|
122
|
+
createBy: CreateBy<Model>;
|
|
123
|
+
}): Promise<void> {
|
|
124
|
+
SubscriberTemplateIncidentRecordAccess.assertCanPlace({
|
|
125
|
+
placeholders:
|
|
126
|
+
await StatusPageSubscriberNotificationTemplateService.getIncidentRecordPlaceholdersHeld(
|
|
127
|
+
{
|
|
128
|
+
templateIds: data.templateIds,
|
|
129
|
+
projectId:
|
|
130
|
+
(data.createBy.props.tenantId as ObjectID | undefined) ||
|
|
131
|
+
data.createBy.data.projectId,
|
|
132
|
+
},
|
|
133
|
+
),
|
|
134
|
+
props: data.createBy.props,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
8
137
|
}
|
|
9
138
|
|
|
10
139
|
export default new Service();
|