@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
package/Server/Types/Markdown.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Renderer, marked } from "marked";
|
|
2
2
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
3
3
|
import markdownSlugify from "./MarkdownSlugify";
|
|
4
|
+
import SafeHtml from "../../Types/SafeHtml";
|
|
4
5
|
|
|
5
6
|
export type MarkdownRenderer = Renderer;
|
|
6
7
|
|
|
@@ -50,6 +51,26 @@ const HTML_ENTITIES: Record<string, string> = {
|
|
|
50
51
|
nbsp: " ",
|
|
51
52
|
};
|
|
52
53
|
|
|
54
|
+
// The named references getEmailUrl decodes in a link destination.
|
|
55
|
+
const URL_NAMED_CHARACTER_REFERENCES: Record<string, string> = {
|
|
56
|
+
amp: "&",
|
|
57
|
+
lt: "<",
|
|
58
|
+
gt: ">",
|
|
59
|
+
quot: '"',
|
|
60
|
+
apos: "'",
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/*
|
|
64
|
+
* The schemes an email may link to, and load an image from. A destination
|
|
65
|
+
* with no scheme is also allowed (see Markdown.getEmailUrl).
|
|
66
|
+
*/
|
|
67
|
+
export const EMAIL_LINK_SCHEMES: ReadonlyArray<string> = [
|
|
68
|
+
"http",
|
|
69
|
+
"https",
|
|
70
|
+
"mailto",
|
|
71
|
+
];
|
|
72
|
+
export const EMAIL_IMAGE_SCHEMES: ReadonlyArray<string> = ["http", "https"];
|
|
73
|
+
|
|
53
74
|
type HoldFunction = (value: string) => string;
|
|
54
75
|
|
|
55
76
|
interface BacktickRuns {
|
|
@@ -603,12 +624,93 @@ export default class Markdown {
|
|
|
603
624
|
* a second implementation is a second thing to get wrong.
|
|
604
625
|
*/
|
|
605
626
|
public static escapeHtml(text: string): string {
|
|
606
|
-
return text
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
627
|
+
return SafeHtml.escape(text);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* The URL a link or image in an EMAIL may point at, ready to go between
|
|
632
|
+
* the double quotes of an href or src attribute - or null when it may not
|
|
633
|
+
* be emitted at all.
|
|
634
|
+
*
|
|
635
|
+
* An email's Markdown comes from people outside the recipient's control: a
|
|
636
|
+
* public note, an incident description, a root cause built from telemetry.
|
|
637
|
+
* marked emits any destination it is given, so `[Details](javascript:...)`
|
|
638
|
+
* or `(data:text/html;base64,...)` became a live link in a status update
|
|
639
|
+
* the subscriber trusts. Only the schemes listed are kept; a destination
|
|
640
|
+
* with no scheme (a relative link or "#anchor") is kept too, as it was
|
|
641
|
+
* before, and cannot run anything.
|
|
642
|
+
*
|
|
643
|
+
* The scheme is judged on exactly the URL the recipient's mail client will
|
|
644
|
+
* see:
|
|
645
|
+
* - The character references marked leaves in a destination
|
|
646
|
+
* ("javascript:") are decoded first, and the result is percent-
|
|
647
|
+
* encoded the way marked does it (encodeURI), which also encodes every
|
|
648
|
+
* space and control character a browser would strip out of a scheme.
|
|
649
|
+
* - The URL is then HTML-escaped into the attribute, so the client's own
|
|
650
|
+
* decoding of the attribute gives back exactly the string that was
|
|
651
|
+
* checked. A character reference this does not decode (":")
|
|
652
|
+
* therefore reaches the client as literal text, never as a ":".
|
|
653
|
+
*/
|
|
654
|
+
public static getEmailUrl(
|
|
655
|
+
href: string | null | undefined,
|
|
656
|
+
allowedSchemes: ReadonlyArray<string>,
|
|
657
|
+
): string | null {
|
|
658
|
+
if (!href) {
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
let url: string;
|
|
663
|
+
|
|
664
|
+
try {
|
|
665
|
+
url = encodeURI(Markdown.decodeUrlCharacterReferences(href)).replace(
|
|
666
|
+
/%25/g,
|
|
667
|
+
"%",
|
|
668
|
+
);
|
|
669
|
+
} catch {
|
|
670
|
+
// A lone surrogate, which encodeURI refuses: no usable URL.
|
|
671
|
+
return null;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
const scheme: RegExpMatchArray | null = url.match(
|
|
675
|
+
/^([a-zA-Z][a-zA-Z0-9+.-]*):/,
|
|
676
|
+
);
|
|
677
|
+
|
|
678
|
+
if (scheme && !allowedSchemes.includes(scheme[1]!.toLowerCase())) {
|
|
679
|
+
return null;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
return Markdown.escapeHtml(url);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/*
|
|
686
|
+
* Numeric character references, and the named ones for the characters
|
|
687
|
+
* escapeHtml writes. Anything else is left as written, and getEmailUrl's
|
|
688
|
+
* escaping makes it inert.
|
|
689
|
+
*/
|
|
690
|
+
private static decodeUrlCharacterReferences(text: string): string {
|
|
691
|
+
return text.replace(
|
|
692
|
+
/&(#[xX][0-9a-fA-F]+|#[0-9]+|amp|lt|gt|quot|apos);/g,
|
|
693
|
+
(match: string, reference: string): string => {
|
|
694
|
+
if (reference.startsWith("#")) {
|
|
695
|
+
const codePoint: number =
|
|
696
|
+
reference[1] === "x" || reference[1] === "X"
|
|
697
|
+
? parseInt(reference.slice(2), 16)
|
|
698
|
+
: parseInt(reference.slice(1), 10);
|
|
699
|
+
|
|
700
|
+
if (
|
|
701
|
+
!Number.isFinite(codePoint) ||
|
|
702
|
+
codePoint <= 0 ||
|
|
703
|
+
codePoint > 0x10ffff
|
|
704
|
+
) {
|
|
705
|
+
return match;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
return String.fromCodePoint(codePoint);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
return URL_NAMED_CHARACTER_REFERENCES[reference] ?? match;
|
|
712
|
+
},
|
|
713
|
+
);
|
|
612
714
|
}
|
|
613
715
|
|
|
614
716
|
/*
|
|
@@ -743,6 +845,51 @@ export default class Markdown {
|
|
|
743
845
|
);
|
|
744
846
|
};
|
|
745
847
|
|
|
848
|
+
/*
|
|
849
|
+
* Links and images keep only http, https and mailto destinations (http
|
|
850
|
+
* and https for an image), plus relative ones: see getEmailUrl. Any
|
|
851
|
+
* other link renders as its text alone, and any other image as its alt
|
|
852
|
+
* text, so the words the author wrote still read in place.
|
|
853
|
+
*
|
|
854
|
+
* The markup is marked's own. `text` is the link's rendered inline
|
|
855
|
+
* content, and `title` and an image's alt text arrive already escaped by
|
|
856
|
+
* marked's tokenizer, so escaping them again would show "&".
|
|
857
|
+
*/
|
|
858
|
+
renderer.link = function (
|
|
859
|
+
href: string,
|
|
860
|
+
title: string | null | undefined,
|
|
861
|
+
text: string,
|
|
862
|
+
): string {
|
|
863
|
+
const url: string | null = Markdown.getEmailUrl(href, EMAIL_LINK_SCHEMES);
|
|
864
|
+
|
|
865
|
+
if (url === null) {
|
|
866
|
+
return text;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
const titleAttribute: string = title ? ` title="${title}"` : "";
|
|
870
|
+
|
|
871
|
+
return `<a href="${url}"${titleAttribute}>${text}</a>`;
|
|
872
|
+
};
|
|
873
|
+
|
|
874
|
+
renderer.image = function (
|
|
875
|
+
href: string,
|
|
876
|
+
title: string | null,
|
|
877
|
+
text: string,
|
|
878
|
+
): string {
|
|
879
|
+
const url: string | null = Markdown.getEmailUrl(
|
|
880
|
+
href,
|
|
881
|
+
EMAIL_IMAGE_SCHEMES,
|
|
882
|
+
);
|
|
883
|
+
|
|
884
|
+
if (url === null) {
|
|
885
|
+
return text;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
const titleAttribute: string = title ? ` title="${title}"` : "";
|
|
889
|
+
|
|
890
|
+
return `<img src="${url}" alt="${text}"${titleAttribute}>`;
|
|
891
|
+
};
|
|
892
|
+
|
|
746
893
|
this.emailRenderer = renderer;
|
|
747
894
|
|
|
748
895
|
return renderer;
|
|
@@ -6,9 +6,18 @@ import ComponentID from "../../../../Types/Workflow/ComponentID";
|
|
|
6
6
|
import Components from "../../../../Types/Workflow/Components/Email";
|
|
7
7
|
import nodemailer, { Transporter } from "nodemailer";
|
|
8
8
|
import SMTPTransport from "nodemailer/lib/smtp-transport";
|
|
9
|
+
import DataSourceEgressGuard, {
|
|
10
|
+
ResolvedAddress,
|
|
11
|
+
} from "../../../Utils/DataSource/EgressGuard";
|
|
12
|
+
import PinnedSmtpSocket, {
|
|
13
|
+
SmtpSocketCallback,
|
|
14
|
+
} from "../../../Utils/Mail/PinnedSmtpSocket";
|
|
9
15
|
import CaptureSpan from "../../../Utils/Telemetry/CaptureSpan";
|
|
10
16
|
|
|
11
17
|
export default class Email extends ComponentCode {
|
|
18
|
+
// nodemailer's own default connection timeout.
|
|
19
|
+
private static readonly CONNECTION_TIMEOUT_IN_MS: number = 2 * 60 * 1000;
|
|
20
|
+
|
|
12
21
|
public constructor() {
|
|
13
22
|
super();
|
|
14
23
|
|
|
@@ -123,10 +132,60 @@ export default class Email extends ComponentCode {
|
|
|
123
132
|
};
|
|
124
133
|
}
|
|
125
134
|
|
|
135
|
+
const smtpHost: string = args["smtp-host"].toString().trim();
|
|
136
|
+
// "[fd00::25]" is how an IPv6 literal is usually written next to a port.
|
|
137
|
+
const bareSmtpHost: string = smtpHost.replace(/^\[|\]$/g, "");
|
|
138
|
+
const smtpPort: number = args["smtp-port"] as number;
|
|
139
|
+
|
|
126
140
|
try {
|
|
141
|
+
/*
|
|
142
|
+
* The SMTP host is free text typed into the workflow node by any
|
|
143
|
+
* project member who can edit workflows, and nodemailer's failures
|
|
144
|
+
* ("Invalid greeting. response=<banner>", refused vs timed out) come
|
|
145
|
+
* back through the Error port into the workflow log. Unchecked, this
|
|
146
|
+
* step is a port scanner with banner disclosure for whatever network
|
|
147
|
+
* the workflow worker runs in.
|
|
148
|
+
*
|
|
149
|
+
* Same guard and label as a project's own SMTP server in MailService,
|
|
150
|
+
* so the same policy: loopback, link-local and cloud metadata are
|
|
151
|
+
* refused everywhere; private ranges are refused on SaaS and allowed on
|
|
152
|
+
* self-hosted installs unless DATA_SOURCE_BLOCK_PRIVATE_ADDRESSES=true.
|
|
153
|
+
* A refusal is thrown inside this try, so it takes the Error port like
|
|
154
|
+
* any other failure to send, before a socket is opened.
|
|
155
|
+
*/
|
|
156
|
+
const validatedAddresses: Array<ResolvedAddress> =
|
|
157
|
+
await DataSourceEgressGuard.assertHostnameAllowed(bareSmtpHost, {
|
|
158
|
+
targetLabel: "SMTP server",
|
|
159
|
+
});
|
|
160
|
+
|
|
127
161
|
const smtpTransport: SMTPTransport.Options = {
|
|
128
|
-
|
|
129
|
-
|
|
162
|
+
/*
|
|
163
|
+
* nodemailer still needs the name the user typed: it is what TLS
|
|
164
|
+
* sends as SNI and checks the certificate against, on implicit TLS
|
|
165
|
+
* and on the STARTTLS upgrade alike. It is never dialed; see
|
|
166
|
+
* getSocket.
|
|
167
|
+
*/
|
|
168
|
+
host: bareSmtpHost,
|
|
169
|
+
port: smtpPort,
|
|
170
|
+
/*
|
|
171
|
+
* Connect here, to the addresses just validated, and hand nodemailer
|
|
172
|
+
* the open socket. Given the name instead, nodemailer resolves it
|
|
173
|
+
* again on its own (dns.resolve4/6, then a process-wide five-minute
|
|
174
|
+
* cache), so a DNS answer that changed after the check would choose
|
|
175
|
+
* the address actually connected to.
|
|
176
|
+
*/
|
|
177
|
+
getSocket: (
|
|
178
|
+
_options: SMTPTransport.Options,
|
|
179
|
+
callback: SmtpSocketCallback,
|
|
180
|
+
): void => {
|
|
181
|
+
PinnedSmtpSocket.connect({
|
|
182
|
+
host: bareSmtpHost,
|
|
183
|
+
port: smtpPort,
|
|
184
|
+
addresses: validatedAddresses,
|
|
185
|
+
timeoutInMs: Email.CONNECTION_TIMEOUT_IN_MS,
|
|
186
|
+
onDone: callback,
|
|
187
|
+
});
|
|
188
|
+
},
|
|
130
189
|
};
|
|
131
190
|
|
|
132
191
|
if (
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
2
|
+
import TableView from "../../../Models/DatabaseModels/TableView";
|
|
3
|
+
import {
|
|
4
|
+
CustomFieldSavedViewState,
|
|
5
|
+
RenamedCustomFieldSavedViewState,
|
|
6
|
+
renameCustomFieldInSavedView,
|
|
7
|
+
} from "../../../Types/CustomField/CustomFieldSavedViews";
|
|
8
|
+
import LIMIT_MAX from "../../../Types/Database/LimitMax";
|
|
9
|
+
import { JSONObject } from "../../../Types/JSON";
|
|
10
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
11
|
+
import DatabaseService from "../../Services/DatabaseService";
|
|
12
|
+
import TableViewService from "../../Services/TableViewService";
|
|
13
|
+
import QueryHelper from "../../Types/Database/QueryHelper";
|
|
14
|
+
import logger, { LogAttributes } from "../Logger";
|
|
15
|
+
import { ColumnMetadata } from "typeorm/metadata/ColumnMetadata";
|
|
16
|
+
import { EntityManager, EntityMetadata, Repository } from "typeorm";
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
* RENAMING A CUSTOM FIELD.
|
|
20
|
+
*
|
|
21
|
+
* Custom field values live in each record's `customFields` jsonb bag, keyed
|
|
22
|
+
* by the field's display name, so renaming "Impact" to "Business Impact"
|
|
23
|
+
* orphans every stored value unless the key moves with it. This moves it:
|
|
24
|
+
* one UPDATE per table, for the whole project, that takes the value out from
|
|
25
|
+
* under the old key and puts it back under the new one - and does the same
|
|
26
|
+
* to the saved table views that name the field.
|
|
27
|
+
*
|
|
28
|
+
* THE NEW NAME STARTS CLEAN. Deleting a field leaves its values in the
|
|
29
|
+
* records (see the custom fields docs), so a record can hold a value under
|
|
30
|
+
* the new name that belongs to no field: a deleted field's answer. The
|
|
31
|
+
* renamed field must not pick those up - they were never its values, and an
|
|
32
|
+
* incident field marked for subscriber notifications would send them out -
|
|
33
|
+
* so the same UPDATE removes the new name from every record of the project
|
|
34
|
+
* that holds nothing under the old one. After a rename, the values under the
|
|
35
|
+
* new name are exactly the ones that were under the old.
|
|
36
|
+
*
|
|
37
|
+
* WHY NOT DatabaseService.updateBy. It fires the model's "on update" workflow
|
|
38
|
+
* trigger for every changed row, even with ignoreHooks (see _updateBy), and
|
|
39
|
+
* customers' own workflows listen on incident custom fields. A rename is a
|
|
40
|
+
* change of label, not of any incident's answers; it must not start a
|
|
41
|
+
* workflow run per incident. The raw statements here fire no workflow, no
|
|
42
|
+
* realtime event and no audit entry, bump no `version`, and leave `updatedAt`
|
|
43
|
+
* alone, like the other derived-data writes (CustomFieldMappingService).
|
|
44
|
+
*
|
|
45
|
+
* The table and column names come from the entity metadata, never from the
|
|
46
|
+
* caller, and every value is a bound parameter, so the SQL is not an
|
|
47
|
+
* injection surface.
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
export interface MoveCustomFieldValueKeyInput {
|
|
51
|
+
// The service whose table holds values under the field's name.
|
|
52
|
+
service: DatabaseService<any>;
|
|
53
|
+
projectId: ObjectID;
|
|
54
|
+
oldName: string;
|
|
55
|
+
newName: string;
|
|
56
|
+
// The transaction to run the statement in; on its own when not given.
|
|
57
|
+
manager?: EntityManager | undefined;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
type GetColumnNameFunction = (
|
|
61
|
+
metadata: EntityMetadata,
|
|
62
|
+
propertyName: string,
|
|
63
|
+
) => string;
|
|
64
|
+
|
|
65
|
+
const getColumnName: GetColumnNameFunction = (
|
|
66
|
+
metadata: EntityMetadata,
|
|
67
|
+
propertyName: string,
|
|
68
|
+
): string => {
|
|
69
|
+
const column: ColumnMetadata | undefined =
|
|
70
|
+
metadata.findColumnWithPropertyName(propertyName);
|
|
71
|
+
|
|
72
|
+
if (!column) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
`Cannot rename a custom field on ${metadata.tableName}: it has no "${propertyName}" column.`,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return column.databaseName;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export interface MoveCustomFieldValueKeyResult {
|
|
82
|
+
// Records whose value moved from the old name to the new one.
|
|
83
|
+
moved: number;
|
|
84
|
+
// Records that held a value under the new name only, now removed.
|
|
85
|
+
cleared: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Move every value stored under `oldName` to `newName`, on every record of
|
|
90
|
+
* the project in the service's table, and clear what records that hold
|
|
91
|
+
* nothing under `oldName` have under `newName`.
|
|
92
|
+
*
|
|
93
|
+
* Only records whose bag is a JSON object holding one of the two names are
|
|
94
|
+
* written. A value the record already held under `newName` is replaced by
|
|
95
|
+
* the one under `oldName`, or removed when there is none: the renamed
|
|
96
|
+
* field's answer is the only one that counts. One statement, so no reader
|
|
97
|
+
* sees the values half moved.
|
|
98
|
+
*/
|
|
99
|
+
export const moveCustomFieldValueKey: (
|
|
100
|
+
input: MoveCustomFieldValueKeyInput,
|
|
101
|
+
) => Promise<MoveCustomFieldValueKeyResult> = async (
|
|
102
|
+
input: MoveCustomFieldValueKeyInput,
|
|
103
|
+
): Promise<MoveCustomFieldValueKeyResult> => {
|
|
104
|
+
if (!input.oldName || !input.newName || input.oldName === input.newName) {
|
|
105
|
+
return { moved: 0, cleared: 0 };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const repository: Repository<BaseModel> = input.service.getRepository();
|
|
109
|
+
const metadata: EntityMetadata = repository.metadata;
|
|
110
|
+
const customFieldsColumn: string = getColumnName(metadata, "customFields");
|
|
111
|
+
const projectIdColumn: string = getColumnName(metadata, "projectId");
|
|
112
|
+
|
|
113
|
+
/*
|
|
114
|
+
* In a CTE so the statement answers with the rows it wrote: TypeORM hands
|
|
115
|
+
* back a top-level UPDATE as [rows, rowCount] whatever happened. RETURNING
|
|
116
|
+
* reads the row as written, so a record holds the new name afterwards
|
|
117
|
+
* exactly when its value was moved there.
|
|
118
|
+
*
|
|
119
|
+
* jsonb_typeof guards the operators: on a jsonb array `-` and `?` act on
|
|
120
|
+
* the array's string elements, and a bag that is not an object is not a
|
|
121
|
+
* bag of named values to rename.
|
|
122
|
+
*/
|
|
123
|
+
const sql: string = `WITH "renamed" AS (
|
|
124
|
+
UPDATE "${metadata.tableName}"
|
|
125
|
+
SET "${customFieldsColumn}" = CASE
|
|
126
|
+
WHEN jsonb_exists("${customFieldsColumn}", $2::text)
|
|
127
|
+
THEN ("${customFieldsColumn}" - $2::text) || jsonb_build_object($3::text, "${customFieldsColumn}" -> $2::text)
|
|
128
|
+
ELSE "${customFieldsColumn}" - $3::text
|
|
129
|
+
END
|
|
130
|
+
WHERE "${projectIdColumn}" = $1
|
|
131
|
+
AND jsonb_typeof("${customFieldsColumn}") = 'object'
|
|
132
|
+
AND (
|
|
133
|
+
jsonb_exists("${customFieldsColumn}", $2::text)
|
|
134
|
+
OR jsonb_exists("${customFieldsColumn}", $3::text)
|
|
135
|
+
)
|
|
136
|
+
RETURNING jsonb_exists("${customFieldsColumn}", $3::text) AS "moved"
|
|
137
|
+
) SELECT
|
|
138
|
+
(COUNT(*) FILTER (WHERE "moved"))::int AS "moved",
|
|
139
|
+
(COUNT(*) FILTER (WHERE NOT "moved"))::int AS "cleared"
|
|
140
|
+
FROM "renamed"`;
|
|
141
|
+
|
|
142
|
+
const manager: EntityManager = input.manager || repository.manager;
|
|
143
|
+
|
|
144
|
+
const result: unknown = await manager.query(sql, [
|
|
145
|
+
input.projectId.toString(),
|
|
146
|
+
input.oldName,
|
|
147
|
+
input.newName,
|
|
148
|
+
]);
|
|
149
|
+
|
|
150
|
+
const row: JSONObject | undefined = Array.isArray(result)
|
|
151
|
+
? (result[0] as JSONObject | undefined)
|
|
152
|
+
: undefined;
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
moved: Number(row?.["moved"]) || 0,
|
|
156
|
+
cleared: Number(row?.["cleared"]) || 0,
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export interface RenameCustomFieldInTableViewsInput {
|
|
161
|
+
projectId: ObjectID;
|
|
162
|
+
// The saved views to look at, by TableView.tableId.
|
|
163
|
+
tableIds: Array<string>;
|
|
164
|
+
oldName: string;
|
|
165
|
+
newName: string;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Rewrite the saved table views of the project that name the field, so a
|
|
170
|
+
* view keeps its column and its filter chip after the rename. Returns how
|
|
171
|
+
* many views it rewrote.
|
|
172
|
+
*
|
|
173
|
+
* Each view is written with a compare-and-set on the columns it was read
|
|
174
|
+
* with, so a view someone saves at the same moment is left as they saved it
|
|
175
|
+
* rather than half overwritten.
|
|
176
|
+
*/
|
|
177
|
+
export const renameCustomFieldInTableViews: (
|
|
178
|
+
input: RenameCustomFieldInTableViewsInput,
|
|
179
|
+
) => Promise<number> = async (
|
|
180
|
+
input: RenameCustomFieldInTableViewsInput,
|
|
181
|
+
): Promise<number> => {
|
|
182
|
+
if (
|
|
183
|
+
!input.oldName ||
|
|
184
|
+
!input.newName ||
|
|
185
|
+
input.oldName === input.newName ||
|
|
186
|
+
input.tableIds.length === 0
|
|
187
|
+
) {
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const views: Array<TableView> = await TableViewService.findBy({
|
|
192
|
+
query: {
|
|
193
|
+
projectId: input.projectId,
|
|
194
|
+
tableId: QueryHelper.any(input.tableIds),
|
|
195
|
+
},
|
|
196
|
+
select: {
|
|
197
|
+
_id: true,
|
|
198
|
+
query: true,
|
|
199
|
+
facets: true,
|
|
200
|
+
columns: true,
|
|
201
|
+
},
|
|
202
|
+
limit: LIMIT_MAX,
|
|
203
|
+
skip: 0,
|
|
204
|
+
props: {
|
|
205
|
+
isRoot: true,
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
let renamedCount: number = 0;
|
|
210
|
+
|
|
211
|
+
for (const view of views) {
|
|
212
|
+
const current: CustomFieldSavedViewState = {
|
|
213
|
+
query: (view.query as unknown as JSONObject | undefined) ?? null,
|
|
214
|
+
facets: view.facets ?? null,
|
|
215
|
+
columns: view.columns ?? null,
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const renamed: RenamedCustomFieldSavedViewState =
|
|
219
|
+
renameCustomFieldInSavedView({
|
|
220
|
+
view: current,
|
|
221
|
+
oldName: input.oldName,
|
|
222
|
+
newName: input.newName,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
if (!renamed.hasChanged || !view.id) {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const data: Record<string, unknown> = {};
|
|
230
|
+
const expectedData: Record<string, unknown> = {};
|
|
231
|
+
|
|
232
|
+
for (const key of Object.keys(renamed.changes) as Array<
|
|
233
|
+
keyof CustomFieldSavedViewState
|
|
234
|
+
>) {
|
|
235
|
+
data[key] = renamed.changes[key];
|
|
236
|
+
expectedData[key] = current[key];
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
await TableViewService.updateColumnsByIdWithoutHooks({
|
|
240
|
+
id: view.id,
|
|
241
|
+
data: data as never,
|
|
242
|
+
expectedData: expectedData as never,
|
|
243
|
+
skipUpdateDateColumn: true,
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
renamedCount++;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return renamedCount;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
export interface RenameCustomFieldInput {
|
|
253
|
+
projectId: ObjectID;
|
|
254
|
+
oldName: string;
|
|
255
|
+
newName: string;
|
|
256
|
+
// Every service whose table stores values under the field's name.
|
|
257
|
+
valueServices: Array<DatabaseService<any>>;
|
|
258
|
+
// The saved views of tables that show the field.
|
|
259
|
+
tableViewIds: Array<string>;
|
|
260
|
+
// How the field is named in logs, e.g. "incident custom field".
|
|
261
|
+
definitionName: string;
|
|
262
|
+
/*
|
|
263
|
+
* Called when the values could not be moved, and are all still under the
|
|
264
|
+
* old name, before the failure is thrown: the caller gives the field its
|
|
265
|
+
* old name back, so the values stay in view (see renameCustomField).
|
|
266
|
+
*/
|
|
267
|
+
onValuesNotMoved?: (() => Promise<void>) | undefined;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export interface RenameCustomFieldResult {
|
|
271
|
+
movedRecordsByTable: Record<string, number>;
|
|
272
|
+
// Records whose stale value under the new name was removed, by table.
|
|
273
|
+
clearedRecordsByTable: Record<string, number>;
|
|
274
|
+
renamedTableViews: number;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Everything a rename has to move: the stored values in each table, then the
|
|
279
|
+
* saved views.
|
|
280
|
+
*
|
|
281
|
+
* The values move in one transaction across the tables, so either every
|
|
282
|
+
* table holds them under the new name or none does. That matters because
|
|
283
|
+
* the move also clears stale values under the new name: had one table moved
|
|
284
|
+
* and another not, renaming the field back would clear the values the
|
|
285
|
+
* second table still held under the old name. When the transaction fails,
|
|
286
|
+
* onValuesNotMoved runs - the caller puts the field's old name back, so the
|
|
287
|
+
* field and its values agree again - and the failure is thrown. A saved view
|
|
288
|
+
* that could not be rewritten only loses the field's column or filter, and
|
|
289
|
+
* throws too.
|
|
290
|
+
*/
|
|
291
|
+
export const renameCustomField: (
|
|
292
|
+
input: RenameCustomFieldInput,
|
|
293
|
+
) => Promise<RenameCustomFieldResult> = async (
|
|
294
|
+
input: RenameCustomFieldInput,
|
|
295
|
+
): Promise<RenameCustomFieldResult> => {
|
|
296
|
+
const result: RenameCustomFieldResult = {
|
|
297
|
+
movedRecordsByTable: {},
|
|
298
|
+
clearedRecordsByTable: {},
|
|
299
|
+
renamedTableViews: 0,
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
if (!input.oldName || !input.newName || input.oldName === input.newName) {
|
|
303
|
+
return result;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const firstService: DatabaseService<any> | undefined = input.valueServices[0];
|
|
307
|
+
|
|
308
|
+
if (firstService) {
|
|
309
|
+
try {
|
|
310
|
+
await firstService
|
|
311
|
+
.getRepository()
|
|
312
|
+
.manager.transaction(async (manager: EntityManager): Promise<void> => {
|
|
313
|
+
for (const service of input.valueServices) {
|
|
314
|
+
const tableName: string =
|
|
315
|
+
service.getModel().tableName ||
|
|
316
|
+
service.getRepository().metadata.name;
|
|
317
|
+
|
|
318
|
+
const moved: MoveCustomFieldValueKeyResult =
|
|
319
|
+
await moveCustomFieldValueKey({
|
|
320
|
+
service: service,
|
|
321
|
+
projectId: input.projectId,
|
|
322
|
+
oldName: input.oldName,
|
|
323
|
+
newName: input.newName,
|
|
324
|
+
manager: manager,
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
result.movedRecordsByTable[tableName] = moved.moved;
|
|
328
|
+
result.clearedRecordsByTable[tableName] = moved.cleared;
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
} catch (err) {
|
|
332
|
+
logger.error(
|
|
333
|
+
`Could not move ${input.definitionName} values from ${JSON.stringify(
|
|
334
|
+
input.oldName,
|
|
335
|
+
)} to ${JSON.stringify(input.newName)}; none were moved.`,
|
|
336
|
+
{
|
|
337
|
+
projectId: input.projectId.toString(),
|
|
338
|
+
} as LogAttributes,
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
if (input.onValuesNotMoved) {
|
|
342
|
+
try {
|
|
343
|
+
await input.onValuesNotMoved();
|
|
344
|
+
} catch (restoreError) {
|
|
345
|
+
logger.error(restoreError, {
|
|
346
|
+
projectId: input.projectId.toString(),
|
|
347
|
+
} as LogAttributes);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
throw err;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
result.renamedTableViews = await renameCustomFieldInTableViews({
|
|
356
|
+
projectId: input.projectId,
|
|
357
|
+
tableIds: input.tableViewIds,
|
|
358
|
+
oldName: input.oldName,
|
|
359
|
+
newName: input.newName,
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
logger.info(
|
|
363
|
+
`Renamed ${input.definitionName} values from ${JSON.stringify(
|
|
364
|
+
input.oldName,
|
|
365
|
+
)} to ${JSON.stringify(input.newName)}: ${JSON.stringify(
|
|
366
|
+
result.movedRecordsByTable,
|
|
367
|
+
)} records moved, ${JSON.stringify(
|
|
368
|
+
result.clearedRecordsByTable,
|
|
369
|
+
)} stale values under the new name cleared, ${
|
|
370
|
+
result.renamedTableViews
|
|
371
|
+
} saved views.`,
|
|
372
|
+
{
|
|
373
|
+
projectId: input.projectId.toString(),
|
|
374
|
+
} as LogAttributes,
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
return result;
|
|
378
|
+
};
|