@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
|
@@ -0,0 +1,586 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MoveCustomFieldValueKeyResult,
|
|
3
|
+
moveCustomFieldValueKey,
|
|
4
|
+
renameCustomFieldInTableViews,
|
|
5
|
+
} from "../../../../Server/Utils/CustomField/CustomFieldRename";
|
|
6
|
+
import DatabaseService from "../../../../Server/Services/DatabaseService";
|
|
7
|
+
import TableViewService from "../../../../Server/Services/TableViewService";
|
|
8
|
+
import TableView from "../../../../Models/DatabaseModels/TableView";
|
|
9
|
+
import ObjectID from "../../../../Types/ObjectID";
|
|
10
|
+
import { JSONObject } from "../../../../Types/JSON";
|
|
11
|
+
import getJestMockFunction, { MockFunction } from "../../../MockType";
|
|
12
|
+
import {
|
|
13
|
+
afterEach,
|
|
14
|
+
beforeEach,
|
|
15
|
+
describe,
|
|
16
|
+
expect,
|
|
17
|
+
jest,
|
|
18
|
+
test,
|
|
19
|
+
} from "@jest/globals";
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* Renaming a custom field.
|
|
23
|
+
*
|
|
24
|
+
* A custom field's values are stored in each record's `customFields` bag under
|
|
25
|
+
* the field's display name, so a rename has to move the key or every stored
|
|
26
|
+
* answer is orphaned. This does it with one raw UPDATE per table rather than
|
|
27
|
+
* through DatabaseService, deliberately: updateBy fires the model's "on
|
|
28
|
+
* update" workflow trigger per row, and customers run workflows on incident
|
|
29
|
+
* custom fields. A rename is a change of label, not of anyone's answers.
|
|
30
|
+
*
|
|
31
|
+
* NOT the only cover this has, and deliberately not the same cover.
|
|
32
|
+
* Tests/Server/Services/IncidentCustomFieldRenamePostgres.test.ts drives a real
|
|
33
|
+
* rename through IncidentCustomFieldService against a migrated Postgres and
|
|
34
|
+
* pins the outcome: values moved in Incident and IncidentTemplate, saved views
|
|
35
|
+
* rewritten, other projects untouched, no workflow fired. That is the stronger
|
|
36
|
+
* test of the two and it is where the behaviour lives. But it is opt-in
|
|
37
|
+
* (RUN_POSTGRES_INCIDENT_CUSTOM_FIELD_TESTS) and runs only in the
|
|
38
|
+
* postgres-schema-drift workflow, after that job has a migrated database to
|
|
39
|
+
* work with; it does not run in Common Test, so on an ordinary change to this
|
|
40
|
+
* file nothing here goes red. These tests do, and they cover the statement
|
|
41
|
+
* itself rather than its effect.
|
|
42
|
+
*
|
|
43
|
+
* Two things make that worth doing without a database. The statement is
|
|
44
|
+
* assembled from entity metadata, and the claim that it is not an injection
|
|
45
|
+
* surface rests on the names coming from metadata and every value being bound
|
|
46
|
+
* -- assertable exactly here. And its second job is destructive: it *removes*
|
|
47
|
+
* what a record holds under the new name, because a deleted field leaves its
|
|
48
|
+
* values behind and the renamed field must not adopt them. A record picking up
|
|
49
|
+
* a stranger's value is the bug this guards, and on an incident field marked
|
|
50
|
+
* for subscriber notifications it would be sent out.
|
|
51
|
+
*
|
|
52
|
+
* So the query is captured rather than run. What Postgres does with the
|
|
53
|
+
* statement is not in scope here; what is in scope is that the right statement,
|
|
54
|
+
* with the right bound values, is what gets sent -- and that the early returns
|
|
55
|
+
* send nothing at all.
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
const PROJECT_ID: ObjectID = new ObjectID(
|
|
59
|
+
"a0000000-0000-4000-8000-000000000001",
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
interface CapturedQuery {
|
|
63
|
+
sql: string;
|
|
64
|
+
parameters: Array<unknown>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let queries: Array<CapturedQuery> = [];
|
|
68
|
+
let queryResult: unknown = [{ moved: 0, cleared: 0 }];
|
|
69
|
+
|
|
70
|
+
// Stands in for the service's repository: the metadata the SQL is built from.
|
|
71
|
+
function serviceFor(data: {
|
|
72
|
+
tableName: string;
|
|
73
|
+
columns: Record<string, string>;
|
|
74
|
+
}): DatabaseService<any> {
|
|
75
|
+
const query: MockFunction = getJestMockFunction();
|
|
76
|
+
query.mockImplementation(
|
|
77
|
+
(sql: string, parameters: Array<unknown>): Promise<unknown> => {
|
|
78
|
+
queries.push({ sql: sql, parameters: parameters });
|
|
79
|
+
return Promise.resolve(queryResult);
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
getRepository: (): unknown => {
|
|
85
|
+
return {
|
|
86
|
+
metadata: {
|
|
87
|
+
tableName: data.tableName,
|
|
88
|
+
findColumnWithPropertyName: (
|
|
89
|
+
propertyName: string,
|
|
90
|
+
): { databaseName: string } | undefined => {
|
|
91
|
+
const databaseName: string | undefined = data.columns[propertyName];
|
|
92
|
+
return databaseName ? { databaseName: databaseName } : undefined;
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
manager: { query: query },
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
} as unknown as DatabaseService<any>;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function incidentService(): DatabaseService<any> {
|
|
102
|
+
return serviceFor({
|
|
103
|
+
tableName: "Incident",
|
|
104
|
+
columns: { customFields: "customFields", projectId: "projectId" },
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
beforeEach(() => {
|
|
109
|
+
queries = [];
|
|
110
|
+
queryResult = [{ moved: 0, cleared: 0 }];
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
afterEach(() => {
|
|
114
|
+
jest.restoreAllMocks();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe("moveCustomFieldValueKey", () => {
|
|
118
|
+
describe("what it refuses to run at all", () => {
|
|
119
|
+
/*
|
|
120
|
+
* Each of these would be a destructive no-op if it reached the database:
|
|
121
|
+
* with the two names equal the statement's ELSE branch deletes the very
|
|
122
|
+
* key it was asked to keep, and a blank name matches no field.
|
|
123
|
+
*/
|
|
124
|
+
test.each([
|
|
125
|
+
["the names are the same", "Impact", "Impact"],
|
|
126
|
+
["the old name is blank", "", "Business Impact"],
|
|
127
|
+
["the new name is blank", "Impact", ""],
|
|
128
|
+
])(
|
|
129
|
+
"sends no statement when %s",
|
|
130
|
+
async (_case: string, oldName: string, newName: string) => {
|
|
131
|
+
const result: MoveCustomFieldValueKeyResult =
|
|
132
|
+
await moveCustomFieldValueKey({
|
|
133
|
+
service: incidentService(),
|
|
134
|
+
projectId: PROJECT_ID,
|
|
135
|
+
oldName: oldName,
|
|
136
|
+
newName: newName,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
expect(queries).toHaveLength(0);
|
|
140
|
+
expect(result).toEqual({ moved: 0, cleared: 0 });
|
|
141
|
+
},
|
|
142
|
+
);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe("the statement it sends", () => {
|
|
146
|
+
beforeEach(async () => {
|
|
147
|
+
await moveCustomFieldValueKey({
|
|
148
|
+
service: incidentService(),
|
|
149
|
+
projectId: PROJECT_ID,
|
|
150
|
+
oldName: "Impact",
|
|
151
|
+
newName: "Business Impact",
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("runs exactly one statement", () => {
|
|
156
|
+
expect(queries).toHaveLength(1);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
/*
|
|
160
|
+
* The injection claim, stated as a test: the only things interpolated are
|
|
161
|
+
* the table and column names read from the entity metadata. Neither name
|
|
162
|
+
* the caller passed appears in the SQL text.
|
|
163
|
+
*/
|
|
164
|
+
test("interpolates only names taken from the entity metadata", () => {
|
|
165
|
+
expect(queries[0]!.sql).toContain('UPDATE "Incident"');
|
|
166
|
+
expect(queries[0]!.sql).toContain('"customFields"');
|
|
167
|
+
expect(queries[0]!.sql).toContain('"projectId" = $1');
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test("carries both field names as bound parameters, never as SQL text", () => {
|
|
171
|
+
expect(queries[0]!.parameters).toEqual([
|
|
172
|
+
PROJECT_ID.toString(),
|
|
173
|
+
"Impact",
|
|
174
|
+
"Business Impact",
|
|
175
|
+
]);
|
|
176
|
+
expect(queries[0]!.sql).not.toContain("Impact");
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Without this the rename would run across every project on the instance.
|
|
180
|
+
test("is scoped to the project", () => {
|
|
181
|
+
expect(queries[0]!.sql).toContain('WHERE "projectId" = $1');
|
|
182
|
+
expect(queries[0]!.parameters[0]).toBe(PROJECT_ID.toString());
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
/*
|
|
186
|
+
* The clean-start rule: a record with nothing under the old name has the
|
|
187
|
+
* new name removed, so a deleted field's leftover answer is not adopted by
|
|
188
|
+
* the renamed field.
|
|
189
|
+
*/
|
|
190
|
+
test("clears the new name from records that hold nothing under the old one", () => {
|
|
191
|
+
expect(queries[0]!.sql).toContain('ELSE "customFields" - $3::text');
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test("moves the value out from under the old name and back under the new one", () => {
|
|
195
|
+
expect(queries[0]!.sql).toContain(
|
|
196
|
+
'("customFields" - $2::text) || jsonb_build_object($3::text, "customFields" -> $2::text)',
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
/*
|
|
201
|
+
* `-` and `?` act on a jsonb array's elements rather than on object keys,
|
|
202
|
+
* so a bag that is not an object is not a bag of named values.
|
|
203
|
+
*/
|
|
204
|
+
test("only touches rows whose bag is a JSON object", () => {
|
|
205
|
+
expect(queries[0]!.sql).toContain(
|
|
206
|
+
`jsonb_typeof("customFields") = 'object'`,
|
|
207
|
+
);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test("only touches rows that hold one of the two names", () => {
|
|
211
|
+
expect(queries[0]!.sql).toContain(
|
|
212
|
+
'jsonb_exists("customFields", $2::text)',
|
|
213
|
+
);
|
|
214
|
+
expect(queries[0]!.sql).toContain(
|
|
215
|
+
'jsonb_exists("customFields", $3::text)',
|
|
216
|
+
);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
describe("the counts it reports", () => {
|
|
221
|
+
async function moveWithResult(
|
|
222
|
+
result: unknown,
|
|
223
|
+
): Promise<MoveCustomFieldValueKeyResult> {
|
|
224
|
+
queryResult = result;
|
|
225
|
+
|
|
226
|
+
return moveCustomFieldValueKey({
|
|
227
|
+
service: incidentService(),
|
|
228
|
+
projectId: PROJECT_ID,
|
|
229
|
+
oldName: "Impact",
|
|
230
|
+
newName: "Business Impact",
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
test("reports what the statement returned", async () => {
|
|
235
|
+
await expect(moveWithResult([{ moved: 3, cleared: 2 }])).resolves.toEqual(
|
|
236
|
+
{ moved: 3, cleared: 2 },
|
|
237
|
+
);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
/*
|
|
241
|
+
* Postgres hands back bigint-ish counts as strings through some drivers,
|
|
242
|
+
* and a count that arrived as "3" must not be reported as 0.
|
|
243
|
+
*/
|
|
244
|
+
test("reads counts that arrived as strings", async () => {
|
|
245
|
+
await expect(
|
|
246
|
+
moveWithResult([{ moved: "3", cleared: "2" }]),
|
|
247
|
+
).resolves.toEqual({ moved: 3, cleared: 2 });
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
test.each([
|
|
251
|
+
["no rows came back", []],
|
|
252
|
+
["the answer was not a list", { moved: 1 }],
|
|
253
|
+
["the row is missing the counts", [{}]],
|
|
254
|
+
["a count is null", [{ moved: null, cleared: null }]],
|
|
255
|
+
["a count is not a number", [{ moved: "many", cleared: "some" }]],
|
|
256
|
+
])("reports zero when %s", async (_case: string, result: unknown) => {
|
|
257
|
+
await expect(moveWithResult(result)).resolves.toEqual({
|
|
258
|
+
moved: 0,
|
|
259
|
+
cleared: 0,
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
describe("where it runs", () => {
|
|
265
|
+
test("uses the transaction it was given, so the rename is one unit of work", async () => {
|
|
266
|
+
const transactionQuery: MockFunction = getJestMockFunction();
|
|
267
|
+
transactionQuery.mockImplementation((): Promise<unknown> => {
|
|
268
|
+
return Promise.resolve([{ moved: 1, cleared: 0 }]);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const service: DatabaseService<any> = incidentService();
|
|
272
|
+
|
|
273
|
+
await moveCustomFieldValueKey({
|
|
274
|
+
service: service,
|
|
275
|
+
projectId: PROJECT_ID,
|
|
276
|
+
oldName: "Impact",
|
|
277
|
+
newName: "Business Impact",
|
|
278
|
+
manager: { query: transactionQuery } as never,
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
expect(transactionQuery).toHaveBeenCalledTimes(1);
|
|
282
|
+
// Nothing went to the repository's own manager, outside the transaction.
|
|
283
|
+
expect(queries).toHaveLength(0);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
test("falls back to the repository's manager when there is no transaction", async () => {
|
|
287
|
+
await moveCustomFieldValueKey({
|
|
288
|
+
service: incidentService(),
|
|
289
|
+
projectId: PROJECT_ID,
|
|
290
|
+
oldName: "Impact",
|
|
291
|
+
newName: "Business Impact",
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
expect(queries).toHaveLength(1);
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
describe("a table it cannot rename on", () => {
|
|
299
|
+
/*
|
|
300
|
+
* Better to fail than to build a statement against a guessed column name:
|
|
301
|
+
* the model would be one that has no custom fields at all.
|
|
302
|
+
*/
|
|
303
|
+
test("refuses a table with no customFields column, and names it", async () => {
|
|
304
|
+
const service: DatabaseService<any> = serviceFor({
|
|
305
|
+
tableName: "Label",
|
|
306
|
+
columns: { projectId: "projectId" },
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
await expect(
|
|
310
|
+
moveCustomFieldValueKey({
|
|
311
|
+
service: service,
|
|
312
|
+
projectId: PROJECT_ID,
|
|
313
|
+
oldName: "Impact",
|
|
314
|
+
newName: "Business Impact",
|
|
315
|
+
}),
|
|
316
|
+
).rejects.toThrow(
|
|
317
|
+
'Cannot rename a custom field on Label: it has no "customFields" column.',
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
expect(queries).toHaveLength(0);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
test("refuses a table with no projectId column", async () => {
|
|
324
|
+
const service: DatabaseService<any> = serviceFor({
|
|
325
|
+
tableName: "GlobalConfig",
|
|
326
|
+
columns: { customFields: "customFields" },
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
await expect(
|
|
330
|
+
moveCustomFieldValueKey({
|
|
331
|
+
service: service,
|
|
332
|
+
projectId: PROJECT_ID,
|
|
333
|
+
oldName: "Impact",
|
|
334
|
+
newName: "Business Impact",
|
|
335
|
+
}),
|
|
336
|
+
).rejects.toThrow('it has no "projectId" column');
|
|
337
|
+
|
|
338
|
+
expect(queries).toHaveLength(0);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
/*
|
|
342
|
+
* The column the statement writes is the database name, which is not
|
|
343
|
+
* always the property name.
|
|
344
|
+
*/
|
|
345
|
+
test("writes the database column name, not the property name", async () => {
|
|
346
|
+
const service: DatabaseService<any> = serviceFor({
|
|
347
|
+
tableName: "Incident",
|
|
348
|
+
columns: { customFields: "custom_fields", projectId: "project_id" },
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
await moveCustomFieldValueKey({
|
|
352
|
+
service: service,
|
|
353
|
+
projectId: PROJECT_ID,
|
|
354
|
+
oldName: "Impact",
|
|
355
|
+
newName: "Business Impact",
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
expect(queries[0]!.sql).toContain('"custom_fields"');
|
|
359
|
+
expect(queries[0]!.sql).toContain('"project_id" = $1');
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
describe("renameCustomFieldInTableViews", () => {
|
|
365
|
+
let findBy: MockFunction;
|
|
366
|
+
let updateColumns: MockFunction;
|
|
367
|
+
|
|
368
|
+
function viewNaming(data: {
|
|
369
|
+
id: string;
|
|
370
|
+
columns?: JSONObject | undefined;
|
|
371
|
+
facets?: JSONObject | undefined;
|
|
372
|
+
query?: JSONObject | undefined;
|
|
373
|
+
}): TableView {
|
|
374
|
+
const view: TableView = new TableView();
|
|
375
|
+
view._id = data.id;
|
|
376
|
+
view.columns = data.columns as never;
|
|
377
|
+
view.facets = data.facets as never;
|
|
378
|
+
view.query = data.query as never;
|
|
379
|
+
return view;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
beforeEach(() => {
|
|
383
|
+
findBy = getJestMockFunction();
|
|
384
|
+
findBy.mockImplementation((): Promise<Array<TableView>> => {
|
|
385
|
+
return Promise.resolve([]);
|
|
386
|
+
});
|
|
387
|
+
jest.spyOn(TableViewService, "findBy").mockImplementation(findBy as never);
|
|
388
|
+
|
|
389
|
+
updateColumns = getJestMockFunction();
|
|
390
|
+
updateColumns.mockImplementation((): Promise<void> => {
|
|
391
|
+
return Promise.resolve();
|
|
392
|
+
});
|
|
393
|
+
jest
|
|
394
|
+
.spyOn(TableViewService, "updateColumnsByIdWithoutHooks")
|
|
395
|
+
.mockImplementation(updateColumns as never);
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
test.each([
|
|
399
|
+
["the names are the same", "Impact", "Impact", ["all-incidents-table"]],
|
|
400
|
+
["the old name is blank", "", "Business Impact", ["all-incidents-table"]],
|
|
401
|
+
["the new name is blank", "Impact", "", ["all-incidents-table"]],
|
|
402
|
+
["no table has saved views", "Impact", "Business Impact", []],
|
|
403
|
+
])(
|
|
404
|
+
"reads nothing when %s",
|
|
405
|
+
async (
|
|
406
|
+
_case: string,
|
|
407
|
+
oldName: string,
|
|
408
|
+
newName: string,
|
|
409
|
+
tableIds: Array<string>,
|
|
410
|
+
) => {
|
|
411
|
+
await expect(
|
|
412
|
+
renameCustomFieldInTableViews({
|
|
413
|
+
projectId: PROJECT_ID,
|
|
414
|
+
tableIds: tableIds,
|
|
415
|
+
oldName: oldName,
|
|
416
|
+
newName: newName,
|
|
417
|
+
}),
|
|
418
|
+
).resolves.toBe(0);
|
|
419
|
+
|
|
420
|
+
expect(findBy).not.toHaveBeenCalled();
|
|
421
|
+
},
|
|
422
|
+
);
|
|
423
|
+
|
|
424
|
+
test("rewrites the column id a view remembers the field by", async () => {
|
|
425
|
+
findBy.mockImplementation((): Promise<Array<TableView>> => {
|
|
426
|
+
return Promise.resolve([
|
|
427
|
+
viewNaming({
|
|
428
|
+
id: "b0000000-0000-4000-8000-00000000000a",
|
|
429
|
+
columns: {
|
|
430
|
+
order: ["name", "customFields.Impact"],
|
|
431
|
+
hidden: ["customFields.Impact"],
|
|
432
|
+
},
|
|
433
|
+
}),
|
|
434
|
+
]);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
await expect(
|
|
438
|
+
renameCustomFieldInTableViews({
|
|
439
|
+
projectId: PROJECT_ID,
|
|
440
|
+
tableIds: ["all-incidents-table"],
|
|
441
|
+
oldName: "Impact",
|
|
442
|
+
newName: "Business Impact",
|
|
443
|
+
}),
|
|
444
|
+
).resolves.toBe(1);
|
|
445
|
+
|
|
446
|
+
const call: JSONObject = updateColumns.mock.calls[0]![0] as JSONObject;
|
|
447
|
+
|
|
448
|
+
expect(call["data"]).toEqual({
|
|
449
|
+
columns: {
|
|
450
|
+
order: ["name", "customFields.Business Impact"],
|
|
451
|
+
hidden: ["customFields.Business Impact"],
|
|
452
|
+
},
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
/*
|
|
457
|
+
* The write is a compare-and-set against what was read, so a view someone
|
|
458
|
+
* saves between the read and the write is left as they saved it rather than
|
|
459
|
+
* half overwritten with a stale copy.
|
|
460
|
+
*/
|
|
461
|
+
test("writes each view against the value it was read with", async () => {
|
|
462
|
+
const columns: JSONObject = { order: ["customFields.Impact"] };
|
|
463
|
+
|
|
464
|
+
findBy.mockImplementation((): Promise<Array<TableView>> => {
|
|
465
|
+
return Promise.resolve([
|
|
466
|
+
viewNaming({
|
|
467
|
+
id: "b0000000-0000-4000-8000-00000000000a",
|
|
468
|
+
columns: columns,
|
|
469
|
+
}),
|
|
470
|
+
]);
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
await renameCustomFieldInTableViews({
|
|
474
|
+
projectId: PROJECT_ID,
|
|
475
|
+
tableIds: ["all-incidents-table"],
|
|
476
|
+
oldName: "Impact",
|
|
477
|
+
newName: "Business Impact",
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
const call: JSONObject = updateColumns.mock.calls[0]![0] as JSONObject;
|
|
481
|
+
|
|
482
|
+
expect(call["expectedData"]).toEqual({ columns: columns });
|
|
483
|
+
// A relabelled column is not a change anyone made to the view.
|
|
484
|
+
expect(call["skipUpdateDateColumn"]).toBe(true);
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
test("leaves a view that never mentioned the field alone", async () => {
|
|
488
|
+
findBy.mockImplementation((): Promise<Array<TableView>> => {
|
|
489
|
+
return Promise.resolve([
|
|
490
|
+
viewNaming({
|
|
491
|
+
id: "b0000000-0000-4000-8000-00000000000a",
|
|
492
|
+
columns: { order: ["name", "customFields.Severity"] },
|
|
493
|
+
}),
|
|
494
|
+
]);
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
await expect(
|
|
498
|
+
renameCustomFieldInTableViews({
|
|
499
|
+
projectId: PROJECT_ID,
|
|
500
|
+
tableIds: ["all-incidents-table"],
|
|
501
|
+
oldName: "Impact",
|
|
502
|
+
newName: "Business Impact",
|
|
503
|
+
}),
|
|
504
|
+
).resolves.toBe(0);
|
|
505
|
+
|
|
506
|
+
expect(updateColumns).not.toHaveBeenCalled();
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
test("counts only the views it rewrote", async () => {
|
|
510
|
+
findBy.mockImplementation((): Promise<Array<TableView>> => {
|
|
511
|
+
return Promise.resolve([
|
|
512
|
+
viewNaming({
|
|
513
|
+
id: "b0000000-0000-4000-8000-00000000000a",
|
|
514
|
+
columns: { order: ["customFields.Impact"] },
|
|
515
|
+
}),
|
|
516
|
+
viewNaming({
|
|
517
|
+
id: "b0000000-0000-4000-8000-00000000000b",
|
|
518
|
+
columns: { order: ["name"] },
|
|
519
|
+
}),
|
|
520
|
+
viewNaming({
|
|
521
|
+
id: "b0000000-0000-4000-8000-00000000000c",
|
|
522
|
+
facets: {
|
|
523
|
+
facetSelections: { "customField:Impact": ["High"] },
|
|
524
|
+
},
|
|
525
|
+
}),
|
|
526
|
+
]);
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
await expect(
|
|
530
|
+
renameCustomFieldInTableViews({
|
|
531
|
+
projectId: PROJECT_ID,
|
|
532
|
+
tableIds: ["all-incidents-table"],
|
|
533
|
+
oldName: "Impact",
|
|
534
|
+
newName: "Business Impact",
|
|
535
|
+
}),
|
|
536
|
+
).resolves.toBe(2);
|
|
537
|
+
|
|
538
|
+
expect(updateColumns).toHaveBeenCalledTimes(2);
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
test("rewrites the facet chip a view filters by", async () => {
|
|
542
|
+
findBy.mockImplementation((): Promise<Array<TableView>> => {
|
|
543
|
+
return Promise.resolve([
|
|
544
|
+
viewNaming({
|
|
545
|
+
id: "b0000000-0000-4000-8000-00000000000a",
|
|
546
|
+
facets: {
|
|
547
|
+
facetSelections: { "customField:Impact": ["High"] },
|
|
548
|
+
facetOperators: { "customField:Impact": "EqualTo" },
|
|
549
|
+
},
|
|
550
|
+
}),
|
|
551
|
+
]);
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
await renameCustomFieldInTableViews({
|
|
555
|
+
projectId: PROJECT_ID,
|
|
556
|
+
tableIds: ["all-incidents-table"],
|
|
557
|
+
oldName: "Impact",
|
|
558
|
+
newName: "Business Impact",
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
const call: JSONObject = updateColumns.mock.calls[0]![0] as JSONObject;
|
|
562
|
+
|
|
563
|
+
expect(call["data"]).toEqual({
|
|
564
|
+
facets: {
|
|
565
|
+
facetSelections: { "customField:Business Impact": ["High"] },
|
|
566
|
+
facetOperators: { "customField:Business Impact": "EqualTo" },
|
|
567
|
+
},
|
|
568
|
+
});
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
// Only the project's own views, and only the tables that have any.
|
|
572
|
+
test("reads only this project's views, for the tables asked about", async () => {
|
|
573
|
+
await renameCustomFieldInTableViews({
|
|
574
|
+
projectId: PROJECT_ID,
|
|
575
|
+
tableIds: ["all-incidents-table"],
|
|
576
|
+
oldName: "Impact",
|
|
577
|
+
newName: "Business Impact",
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
const query: JSONObject = (findBy.mock.calls[0]![0] as JSONObject)[
|
|
581
|
+
"query"
|
|
582
|
+
] as JSONObject;
|
|
583
|
+
|
|
584
|
+
expect(query["projectId"]).toBe(PROJECT_ID);
|
|
585
|
+
});
|
|
586
|
+
});
|