@oneuptime/common 12.0.18 → 12.0.20
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/EnterpriseLicense.ts +23 -0
- package/Models/DatabaseModels/Index.ts +4 -2
- package/Models/DatabaseModels/Monitor.ts +39 -9
- package/Models/DatabaseModels/UserMicrosoftTeams.ts +344 -0
- package/Models/DatabaseModels/UserNotificationRule.ts +144 -8
- package/Models/DatabaseModels/UserNotificationSetting.ts +34 -0
- package/Models/DatabaseModels/UserOnCallLogTimeline.ts +95 -0
- package/Models/DatabaseModels/UserSlack.ts +341 -0
- package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +9 -0
- package/Server/API/EnterpriseLicenseAPI.ts +94 -19
- package/Server/API/UserMicrosoftTeamsAPI.ts +127 -0
- package/Server/API/UserSlackAPI.ts +125 -0
- package/Server/EnvironmentConfig.ts +29 -107
- package/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.ts +51 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.ts +117 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.ts +197 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
- package/Server/Infrastructure/Queue.ts +7 -0
- package/Server/Services/EnterpriseLicenseService.ts +60 -0
- package/Server/Services/Index.ts +6 -2
- package/Server/Services/LlmLogService.ts +25 -9
- package/Server/Services/OnCallReadinessService.ts +86 -2
- package/Server/Services/ProjectService.ts +171 -0
- package/Server/Services/UserMicrosoftTeamsService.ts +208 -0
- package/Server/Services/UserNotificationMethodAdminService.ts +167 -5
- package/Server/Services/UserNotificationRuleAdminService.ts +40 -6
- package/Server/Services/UserNotificationRuleService.ts +589 -11
- package/Server/Services/UserNotificationSettingService.ts +138 -0
- package/Server/Services/UserService.ts +28 -0
- package/Server/Services/UserSlackService.ts +218 -0
- package/Server/Services/WorkspaceProjectAuthTokenService.ts +67 -1
- package/Server/Services/WorkspaceUserAuthTokenService.ts +73 -0
- package/Server/Services/WorkspaceUserNotificationService.ts +190 -0
- package/Server/Utils/Marketing/MarketingEventUtil.ts +145 -0
- package/Server/Utils/Marketing/MarketingEventWebhook.ts +114 -0
- package/Server/Utils/Monitor/MonitorLogUtil.ts +14 -1
- package/Server/Utils/Monitor/MonitorPayloadRedaction.ts +321 -0
- package/Server/Utils/Response.ts +2 -2
- package/Server/Utils/StartServer.ts +2 -2
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +191 -4
- package/Server/Views/Partials/AnalyticsConsent.ejs +533 -0
- package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +22 -14
- package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +22 -11
- package/Tests/App/Dashboard/AlertEpisodeViewFields.test.tsx +465 -0
- package/Tests/App/Dashboard/DashboardChartWidgetZoom.test.tsx +302 -0
- package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +408 -0
- package/Tests/App/Dashboard/IncidentEpisodeViewFields.test.tsx +474 -0
- package/Tests/App/Dashboard/MetricSeriesInvestigateMenu.test.tsx +368 -0
- package/Tests/App/Dashboard/OnCallPreventionGuards.test.tsx +37 -1
- package/Tests/App/Dashboard/OnCallRulesTable.test.tsx +18 -10
- package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +27 -1
- package/Tests/Models/DatabaseModels/MonitorSecretKeyColumnAccessControl.test.ts +214 -0
- package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +763 -0
- package/Tests/Server/API/OnCallReadinessAPI.test.ts +145 -26
- package/Tests/Server/API/UserNotificationMethodAdminAPI.test.ts +2 -2
- package/Tests/Server/Services/AIServiceDailyBudget.test.ts +11 -1
- package/Tests/Server/Services/AdminRuleEditGuards.test.ts +22 -8
- package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +18 -2
- package/Tests/Server/Services/EpisodeRuleSeverityRepair.test.ts +5 -1
- package/Tests/Server/Services/LlmLogServiceTokenAggregateParams.test.ts +640 -0
- package/Tests/Server/Services/NotificationChannelEventCoverage.test.ts +246 -22
- package/Tests/Server/Services/NotificationDeletionImpact.test.ts +136 -8
- package/Tests/Server/Services/OnCallNotificationFallback.test.ts +191 -8
- package/Tests/Server/Services/OnCallReadinessService.test.ts +343 -18
- package/Tests/Server/Services/ProjectServiceChangePlan.test.ts +138 -0
- package/Tests/Server/Services/ProjectServiceCreateSubscriptionStarted.test.ts +516 -0
- package/Tests/Server/Services/SeverityRuleBackfill.test.ts +5 -1
- package/Tests/Server/Services/UserMicrosoftTeamsService.test.ts +343 -0
- package/Tests/Server/Services/UserNotificationMethodAdminService.test.ts +209 -8
- package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +22 -6
- package/Tests/Server/Services/UserNotificationRuleDefaultCreation.test.ts +12 -6
- package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +37 -3
- package/Tests/Server/Services/UserNotificationRuleWorkspaceDelivery.test.ts +669 -0
- package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +410 -0
- package/Tests/Server/Services/UserSlackService.test.ts +407 -0
- package/Tests/Server/Services/WorkspaceProjectAuthTokenDisconnectCascade.test.ts +224 -0
- package/Tests/Server/Services/WorkspaceUserAuthTokenNotificationMethodCascade.test.ts +189 -0
- package/Tests/Server/Services/WorkspaceUserNotificationService.test.ts +496 -0
- package/Tests/Server/Types/Database/Permissions/AdminNotificationRuleAccess.test.ts +30 -17
- package/Tests/Server/Types/Database/Permissions/CreateOwnershipScoping.test.ts +8 -3
- package/Tests/Server/Types/Database/Permissions/OwnerOnlyColumns.test.ts +72 -3
- package/Tests/Server/Types/Database/Permissions/UserNotificationRuleScoping.test.ts +22 -18
- package/Tests/Server/Types/Database/Permissions/WorkspaceMethodStampedColumnCreate.test.ts +178 -0
- package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +259 -0
- package/Tests/Server/Utils/Marketing/MarketingEventWebhook.test.ts +257 -0
- package/Tests/Server/Utils/Monitor/MonitorLogUtilRedaction.test.ts +300 -0
- package/Tests/Server/Utils/Monitor/MonitorPayloadRedaction.test.ts +381 -0
- package/Tests/Server/Utils/ResponseRenderAnalytics.test.ts +53 -0
- package/Tests/Server/Utils/Runbook/RunbookExecutePermission.test.ts +228 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayErasureTombstone.test.ts +189 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayUsage.test.ts +205 -0
- package/Tests/Server/Utils/Telemetry/AppMetrics.test.ts +275 -0
- package/Tests/Server/Utils/Telemetry/TelemetryContext.test.ts +279 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsDirectMessage.test.ts +454 -0
- package/Tests/Server/Views/AnalyticsConsentPartial.test.ts +241 -0
- package/Tests/UI/Components/Charts/ChartTooltipSorted.test.tsx +129 -0
- package/Tests/UI/Components/Charts/TooltipEntries.test.ts +155 -0
- package/Tests/UI/Components/Detail/DetailFieldErrors.test.tsx +347 -0
- package/Tests/UI/Components/Forms/BasicFormStepValidation.test.tsx +392 -0
- package/Tests/UI/Components/Forms/ValidationFormSteps.test.ts +549 -0
- package/Tests/UI/Utils/NotificationMethodUtil.test.ts +137 -9
- package/Tests/UI/Utils/PermissionGate.test.ts +105 -0
- package/Tests/Utils/EnterpriseLicenseSync.test.ts +562 -0
- package/Types/Analytics/RevenueEvent.ts +1 -0
- package/Types/Marketing/MarketingEvent.ts +140 -0
- package/UI/Components/Charts/Area/AreaChart.tsx +8 -1
- package/UI/Components/Charts/Bar/BarChart.tsx +8 -1
- package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +19 -4
- package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +20 -2
- package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +19 -4
- package/UI/Components/Charts/ChartLibrary/Utils/TooltipEntries.ts +105 -0
- package/UI/Components/Charts/Line/LineChart.tsx +8 -1
- package/UI/Components/Detail/Detail.tsx +18 -1
- package/UI/Utils/NotificationMethodUtil.ts +41 -1
- package/UI/Utils/PermissionGate.ts +56 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +244 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +24 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +4 -2
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +39 -9
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserMicrosoftTeams.js +363 -0
- package/build/dist/Models/DatabaseModels/UserMicrosoftTeams.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserNotificationRule.js +145 -8
- package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserNotificationSetting.js +38 -0
- package/build/dist/Models/DatabaseModels/UserNotificationSetting.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +96 -0
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserSlack.js +361 -0
- package/build/dist/Models/DatabaseModels/UserSlack.js.map +1 -0
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
- package/build/dist/Server/API/EnterpriseLicenseAPI.js +66 -12
- package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
- package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +82 -0
- package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -0
- package/build/dist/Server/API/UserSlackAPI.js +81 -0
- package/build/dist/Server/API/UserSlackAPI.js.map +1 -0
- package/build/dist/Server/EnvironmentConfig.js +25 -70
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.js +37 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js +106 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js +78 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Queue.js +7 -0
- package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
- package/build/dist/Server/Services/EnterpriseLicenseService.js +65 -0
- package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +6 -2
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/LlmLogService.js +25 -9
- package/build/dist/Server/Services/LlmLogService.js.map +1 -1
- package/build/dist/Server/Services/OnCallReadinessService.js +74 -2
- package/build/dist/Server/Services/OnCallReadinessService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +144 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/UserMicrosoftTeamsService.js +183 -0
- package/build/dist/Server/Services/UserMicrosoftTeamsService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationMethodAdminService.js +138 -2
- package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleAdminService.js +32 -4
- package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +499 -67
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js +118 -0
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +26 -1
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Services/UserSlackService.js +195 -0
- package/build/dist/Server/Services/UserSlackService.js.map +1 -0
- package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +64 -1
- package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js +70 -0
- package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceUserNotificationService.js +129 -0
- package/build/dist/Server/Services/WorkspaceUserNotificationService.js.map +1 -0
- package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +94 -0
- package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -0
- package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js +93 -0
- package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js +12 -1
- package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js +233 -0
- package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js.map +1 -0
- package/build/dist/Server/Utils/Response.js +2 -2
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +2 -2
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +141 -4
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Types/Analytics/RevenueEvent.js +1 -0
- package/build/dist/Types/Analytics/RevenueEvent.js.map +1 -1
- package/build/dist/Types/Marketing/MarketingEvent.js +82 -0
- package/build/dist/Types/Marketing/MarketingEvent.js.map +1 -0
- package/build/dist/UI/Components/Charts/Area/AreaChart.js +9 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js +9 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +22 -13
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +27 -15
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +27 -18
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/TooltipEntries.js +71 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/TooltipEntries.js.map +1 -0
- package/build/dist/UI/Components/Charts/Line/LineChart.js +9 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Detail/Detail.js +17 -1
- package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
- package/build/dist/UI/Utils/NotificationMethodUtil.js +33 -1
- package/build/dist/UI/Utils/NotificationMethodUtil.js.map +1 -1
- package/build/dist/UI/Utils/PermissionGate.js +32 -0
- package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +174 -0
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +1 -0
- package/package.json +1 -1
- package/Models/DatabaseModels/MarketingConversion.ts +0 -410
- package/Server/Services/MarketingConversionService.ts +0 -10
- package/Server/Utils/Marketing/ConversionUploadProvider.ts +0 -215
- package/Server/Utils/Marketing/ConversionUploadProviders.ts +0 -22
- package/Server/Utils/Marketing/Providers/GoogleAds.ts +0 -333
- package/Server/Utils/Marketing/Providers/LinkedIn.ts +0 -185
- package/Server/Utils/Marketing/Providers/Meta.ts +0 -182
- package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +0 -223
- package/Server/Utils/Marketing/Providers/Reddit.ts +0 -208
- package/Tests/Server/Utils/Marketing/AdUploadableConversionTypes.test.ts +0 -315
- package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +0 -300
- package/Tests/Server/Utils/Marketing/GoogleAds.test.ts +0 -592
- package/Tests/Server/Utils/Marketing/LinkedIn.test.ts +0 -282
- package/Tests/Server/Utils/Marketing/Meta.test.ts +0 -304
- package/Tests/Server/Utils/Marketing/MicrosoftAds.test.ts +0 -263
- package/Tests/Server/Utils/Marketing/Reddit.test.ts +0 -259
- package/Types/Marketing/MarketingConversion.ts +0 -53
- package/build/dist/Models/DatabaseModels/MarketingConversion.js +0 -445
- package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +0 -1
- package/build/dist/Server/Services/MarketingConversionService.js +0 -9
- package/build/dist/Server/Services/MarketingConversionService.js.map +0 -1
- package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +0 -93
- package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +0 -1
- package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js +0 -20
- package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js.map +0 -1
- package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +0 -221
- package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +0 -1
- package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +0 -137
- package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +0 -1
- package/build/dist/Server/Utils/Marketing/Providers/Meta.js +0 -133
- package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +0 -1
- package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +0 -143
- package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +0 -1
- package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +0 -145
- package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +0 -1
- package/build/dist/Types/Marketing/MarketingConversion.js +0 -52
- package/build/dist/Types/Marketing/MarketingConversion.js.map +0 -1
|
@@ -15,12 +15,14 @@ import ProjectService from "../../../Server/Services/ProjectService";
|
|
|
15
15
|
import TeamMemberService from "../../../Server/Services/TeamMemberService";
|
|
16
16
|
import UserCallService from "../../../Server/Services/UserCallService";
|
|
17
17
|
import UserEmailService from "../../../Server/Services/UserEmailService";
|
|
18
|
+
import UserMicrosoftTeamsService from "../../../Server/Services/UserMicrosoftTeamsService";
|
|
18
19
|
import UserNotificationRuleService, {
|
|
19
20
|
CoverageLossCell,
|
|
20
21
|
NotificationDeletionImpact,
|
|
21
22
|
PostDeletionReachability,
|
|
22
23
|
} from "../../../Server/Services/UserNotificationRuleService";
|
|
23
24
|
import UserPushService from "../../../Server/Services/UserPushService";
|
|
25
|
+
import UserSlackService from "../../../Server/Services/UserSlackService";
|
|
24
26
|
import UserSmsService from "../../../Server/Services/UserSmsService";
|
|
25
27
|
import UserTelegramService from "../../../Server/Services/UserTelegramService";
|
|
26
28
|
import UserWebhookService from "../../../Server/Services/UserWebhookService";
|
|
@@ -31,8 +33,10 @@ import IncidentSeverity from "../../../Models/DatabaseModels/IncidentSeverity";
|
|
|
31
33
|
import Project from "../../../Models/DatabaseModels/Project";
|
|
32
34
|
import UserCall from "../../../Models/DatabaseModels/UserCall";
|
|
33
35
|
import UserEmail from "../../../Models/DatabaseModels/UserEmail";
|
|
36
|
+
import UserMicrosoftTeams from "../../../Models/DatabaseModels/UserMicrosoftTeams";
|
|
34
37
|
import UserNotificationRule from "../../../Models/DatabaseModels/UserNotificationRule";
|
|
35
38
|
import UserPush from "../../../Models/DatabaseModels/UserPush";
|
|
39
|
+
import UserSlack from "../../../Models/DatabaseModels/UserSlack";
|
|
36
40
|
import UserSMS from "../../../Models/DatabaseModels/UserSMS";
|
|
37
41
|
import UserTelegram from "../../../Models/DatabaseModels/UserTelegram";
|
|
38
42
|
import UserWebhook from "../../../Models/DatabaseModels/UserWebhook";
|
|
@@ -57,7 +61,7 @@ import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
|
|
|
57
61
|
* is the only thing left for Sev1 incidents" is written nowhere.
|
|
58
62
|
*
|
|
59
63
|
* (b) Deleting a METHOD, which CASCADES. Every method foreign key on
|
|
60
|
-
* UserNotificationRule is onDelete: "CASCADE" - and
|
|
64
|
+
* UserNotificationRule is onDelete: "CASCADE" - and eight of the nine
|
|
61
65
|
* method services delete the rows themselves in onBeforeDelete besides -
|
|
62
66
|
* so removing one phone number destroys every rule that pointed at it.
|
|
63
67
|
* The delete dialog for a phone number mentions notification rules
|
|
@@ -90,8 +94,9 @@ import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
|
|
|
90
94
|
* A rule read through the wrong column matches no page at runtime, so
|
|
91
95
|
* counting it as coverage would certify a gap as covered.
|
|
92
96
|
*
|
|
93
|
-
* CERTAINTY ABOUT REACHABILITY. Push, Email
|
|
94
|
-
* switch, which is what makes "a verified one of
|
|
97
|
+
* CERTAINTY ABOUT REACHABILITY. Push, Email, Slack, Microsoft Teams and
|
|
98
|
+
* Webhook have no project switch, which is what makes "a verified one of
|
|
99
|
+
* those survives" a certain
|
|
95
100
|
* answer and "only paid channels survive" an honest "depends". Inventing a
|
|
96
101
|
* green in the second case is the exact false reassurance this whole feature
|
|
97
102
|
* exists to prevent.
|
|
@@ -191,6 +196,8 @@ let callFindOneBy: jest.SpyInstance;
|
|
|
191
196
|
let pushFindOneBy: jest.SpyInstance;
|
|
192
197
|
let whatsAppFindOneBy: jest.SpyInstance;
|
|
193
198
|
let telegramFindOneBy: jest.SpyInstance;
|
|
199
|
+
let slackFindOneBy: jest.SpyInstance;
|
|
200
|
+
let microsoftTeamsFindOneBy: jest.SpyInstance;
|
|
194
201
|
let webhookFindOneBy: jest.SpyInstance;
|
|
195
202
|
let escalationUserFindBy: jest.SpyInstance;
|
|
196
203
|
let escalationTeamFindBy: jest.SpyInstance;
|
|
@@ -211,6 +218,8 @@ function rule(data: {
|
|
|
211
218
|
userPushId?: ObjectID | undefined;
|
|
212
219
|
userWhatsAppId?: ObjectID | undefined;
|
|
213
220
|
userTelegramId?: ObjectID | undefined;
|
|
221
|
+
userSlackId?: ObjectID | undefined;
|
|
222
|
+
userMicrosoftTeamsId?: ObjectID | undefined;
|
|
214
223
|
userWebhookId?: ObjectID | undefined;
|
|
215
224
|
}): UserNotificationRule {
|
|
216
225
|
const model: UserNotificationRule = new UserNotificationRule();
|
|
@@ -258,6 +267,14 @@ function rule(data: {
|
|
|
258
267
|
model.userTelegramId = data.userTelegramId;
|
|
259
268
|
}
|
|
260
269
|
|
|
270
|
+
if (data.userSlackId) {
|
|
271
|
+
model.userSlackId = data.userSlackId;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (data.userMicrosoftTeamsId) {
|
|
275
|
+
model.userMicrosoftTeamsId = data.userMicrosoftTeamsId;
|
|
276
|
+
}
|
|
277
|
+
|
|
261
278
|
if (data.userWebhookId) {
|
|
262
279
|
model.userWebhookId = data.userWebhookId;
|
|
263
280
|
}
|
|
@@ -500,6 +517,20 @@ beforeEach(() => {
|
|
|
500
517
|
telegramRow.userId = USER_ID;
|
|
501
518
|
telegramRow.isVerified = true;
|
|
502
519
|
|
|
520
|
+
/*
|
|
521
|
+
* Born verified: a UserSlack / UserMicrosoftTeams row is a pointer at the
|
|
522
|
+
* owner's own OAuth workspace link, so creation is verification.
|
|
523
|
+
*/
|
|
524
|
+
const slackRow: UserSlack = new UserSlack();
|
|
525
|
+
slackRow.id = SMS_METHOD_ID;
|
|
526
|
+
slackRow.userId = USER_ID;
|
|
527
|
+
slackRow.isVerified = true;
|
|
528
|
+
|
|
529
|
+
const microsoftTeamsRow: UserMicrosoftTeams = new UserMicrosoftTeams();
|
|
530
|
+
microsoftTeamsRow.id = SMS_METHOD_ID;
|
|
531
|
+
microsoftTeamsRow.userId = USER_ID;
|
|
532
|
+
microsoftTeamsRow.isVerified = true;
|
|
533
|
+
|
|
503
534
|
/*
|
|
504
535
|
* Deliberately carries NO isVerified. UserWebhook has no such column at all,
|
|
505
536
|
* and the service has to treat presence as the whole test - a fixture that
|
|
@@ -527,6 +558,12 @@ beforeEach(() => {
|
|
|
527
558
|
telegramFindOneBy = jest
|
|
528
559
|
.spyOn(UserTelegramService, "findOneBy")
|
|
529
560
|
.mockResolvedValue(telegramRow as never);
|
|
561
|
+
slackFindOneBy = jest
|
|
562
|
+
.spyOn(UserSlackService, "findOneBy")
|
|
563
|
+
.mockResolvedValue(slackRow as never);
|
|
564
|
+
microsoftTeamsFindOneBy = jest
|
|
565
|
+
.spyOn(UserMicrosoftTeamsService, "findOneBy")
|
|
566
|
+
.mockResolvedValue(microsoftTeamsRow as never);
|
|
530
567
|
webhookFindOneBy = jest
|
|
531
568
|
.spyOn(UserWebhookService, "findOneBy")
|
|
532
569
|
.mockResolvedValue(webhookRow as never);
|
|
@@ -1117,7 +1154,7 @@ describe("deleting a notification method: the cascade", () => {
|
|
|
1117
1154
|
expect(impact.coverageLost).toHaveLength(0);
|
|
1118
1155
|
});
|
|
1119
1156
|
|
|
1120
|
-
test("each of the
|
|
1157
|
+
test("each of the nine channels reads its own foreign key", async () => {
|
|
1121
1158
|
const cases: Array<{
|
|
1122
1159
|
methodType: ReadinessMethodType;
|
|
1123
1160
|
makeRule: () => UserNotificationRule;
|
|
@@ -1188,6 +1225,28 @@ describe("deleting a notification method: the cascade", () => {
|
|
|
1188
1225
|
});
|
|
1189
1226
|
},
|
|
1190
1227
|
},
|
|
1228
|
+
{
|
|
1229
|
+
methodType: ReadinessMethodType.Slack,
|
|
1230
|
+
makeRule: (): UserNotificationRule => {
|
|
1231
|
+
return rule({
|
|
1232
|
+
id: RULE_1_ID,
|
|
1233
|
+
ruleType: NotificationRuleType.ON_CALL_EXECUTED_INCIDENT,
|
|
1234
|
+
incidentSeverityId: SEV1_ID,
|
|
1235
|
+
userSlackId: SMS_METHOD_ID,
|
|
1236
|
+
});
|
|
1237
|
+
},
|
|
1238
|
+
},
|
|
1239
|
+
{
|
|
1240
|
+
methodType: ReadinessMethodType.MicrosoftTeams,
|
|
1241
|
+
makeRule: (): UserNotificationRule => {
|
|
1242
|
+
return rule({
|
|
1243
|
+
id: RULE_1_ID,
|
|
1244
|
+
ruleType: NotificationRuleType.ON_CALL_EXECUTED_INCIDENT,
|
|
1245
|
+
incidentSeverityId: SEV1_ID,
|
|
1246
|
+
userMicrosoftTeamsId: SMS_METHOD_ID,
|
|
1247
|
+
});
|
|
1248
|
+
},
|
|
1249
|
+
},
|
|
1191
1250
|
{
|
|
1192
1251
|
methodType: ReadinessMethodType.Webhook,
|
|
1193
1252
|
makeRule: (): UserNotificationRule => {
|
|
@@ -1315,8 +1374,9 @@ describe("deleting a notification method: the cascade", () => {
|
|
|
1315
1374
|
* (F) Reachability after the deletion.
|
|
1316
1375
|
*
|
|
1317
1376
|
* Two of the four answers are certain and two are not, and the split is
|
|
1318
|
-
* structural: a method must be VERIFIED to be used at all, and Push, Email
|
|
1319
|
-
* Webhook have no project switch that can turn
|
|
1377
|
+
* structural: a method must be VERIFIED to be used at all, and Push, Email,
|
|
1378
|
+
* Slack, Microsoft Teams and Webhook have no project switch that can turn
|
|
1379
|
+
* them off. Anything that turns
|
|
1320
1380
|
* the honest "depends" into a green is a false reassurance in the one dialog
|
|
1321
1381
|
* where it costs a page.
|
|
1322
1382
|
* ---------------------------------------------------------------------------
|
|
@@ -1380,6 +1440,42 @@ describe("reachability after the deletion", () => {
|
|
|
1380
1440
|
expect(impact.reachability).toBe(PostDeletionReachability.Reachable);
|
|
1381
1441
|
});
|
|
1382
1442
|
|
|
1443
|
+
test("a surviving verified Slack account is equally certain - no project switch exists for it", async () => {
|
|
1444
|
+
readinessRows = [
|
|
1445
|
+
readiness({
|
|
1446
|
+
methods: [
|
|
1447
|
+
method(ReadinessMethodType.SMS),
|
|
1448
|
+
method(ReadinessMethodType.Slack),
|
|
1449
|
+
],
|
|
1450
|
+
}),
|
|
1451
|
+
];
|
|
1452
|
+
|
|
1453
|
+
const impact: NotificationDeletionImpact = await methodDeletionImpact(
|
|
1454
|
+
ReadinessMethodType.SMS,
|
|
1455
|
+
SMS_METHOD_ID,
|
|
1456
|
+
);
|
|
1457
|
+
|
|
1458
|
+
expect(impact.reachability).toBe(PostDeletionReachability.Reachable);
|
|
1459
|
+
});
|
|
1460
|
+
|
|
1461
|
+
test("a surviving verified Microsoft Teams account is equally certain", async () => {
|
|
1462
|
+
readinessRows = [
|
|
1463
|
+
readiness({
|
|
1464
|
+
methods: [
|
|
1465
|
+
method(ReadinessMethodType.SMS),
|
|
1466
|
+
method(ReadinessMethodType.MicrosoftTeams),
|
|
1467
|
+
],
|
|
1468
|
+
}),
|
|
1469
|
+
];
|
|
1470
|
+
|
|
1471
|
+
const impact: NotificationDeletionImpact = await methodDeletionImpact(
|
|
1472
|
+
ReadinessMethodType.SMS,
|
|
1473
|
+
SMS_METHOD_ID,
|
|
1474
|
+
);
|
|
1475
|
+
|
|
1476
|
+
expect(impact.reachability).toBe(PostDeletionReachability.Reachable);
|
|
1477
|
+
});
|
|
1478
|
+
|
|
1383
1479
|
test("a surviving Webhook counts, because a webhook has no verification concept", async () => {
|
|
1384
1480
|
readinessRows = [
|
|
1385
1481
|
readiness({
|
|
@@ -2055,7 +2151,7 @@ describe("paging the rule read", () => {
|
|
|
2055
2151
|
* ---------------------------------------------------------------------------
|
|
2056
2152
|
* (L) The per-method-service entry points.
|
|
2057
2153
|
*
|
|
2058
|
-
* Each of the
|
|
2154
|
+
* Each of the nine notification-method services can answer for its own row,
|
|
2059
2155
|
* which is where the delete is actually initiated from. Each must name its own
|
|
2060
2156
|
* channel: a service that passed the wrong one would preview the cascade of a
|
|
2061
2157
|
* method the user is not deleting.
|
|
@@ -2159,6 +2255,36 @@ describe("the per-method-service entry points", () => {
|
|
|
2159
2255
|
userTelegramId: SMS_METHOD_ID,
|
|
2160
2256
|
}),
|
|
2161
2257
|
},
|
|
2258
|
+
{
|
|
2259
|
+
name: "UserSlackService",
|
|
2260
|
+
call: (): Promise<NotificationDeletionImpact> => {
|
|
2261
|
+
return UserSlackService.getDeletionImpact({
|
|
2262
|
+
itemId: SMS_METHOD_ID,
|
|
2263
|
+
projectId: PROJECT_ID,
|
|
2264
|
+
});
|
|
2265
|
+
},
|
|
2266
|
+
ruleWithThisMethod: rule({
|
|
2267
|
+
id: RULE_1_ID,
|
|
2268
|
+
ruleType: NotificationRuleType.ON_CALL_EXECUTED_INCIDENT,
|
|
2269
|
+
incidentSeverityId: SEV1_ID,
|
|
2270
|
+
userSlackId: SMS_METHOD_ID,
|
|
2271
|
+
}),
|
|
2272
|
+
},
|
|
2273
|
+
{
|
|
2274
|
+
name: "UserMicrosoftTeamsService",
|
|
2275
|
+
call: (): Promise<NotificationDeletionImpact> => {
|
|
2276
|
+
return UserMicrosoftTeamsService.getDeletionImpact({
|
|
2277
|
+
itemId: SMS_METHOD_ID,
|
|
2278
|
+
projectId: PROJECT_ID,
|
|
2279
|
+
});
|
|
2280
|
+
},
|
|
2281
|
+
ruleWithThisMethod: rule({
|
|
2282
|
+
id: RULE_1_ID,
|
|
2283
|
+
ruleType: NotificationRuleType.ON_CALL_EXECUTED_INCIDENT,
|
|
2284
|
+
incidentSeverityId: SEV1_ID,
|
|
2285
|
+
userMicrosoftTeamsId: SMS_METHOD_ID,
|
|
2286
|
+
}),
|
|
2287
|
+
},
|
|
2162
2288
|
{
|
|
2163
2289
|
name: "UserWebhookService",
|
|
2164
2290
|
call: (): Promise<NotificationDeletionImpact> => {
|
|
@@ -2229,7 +2355,7 @@ describe("the per-method-service entry points", () => {
|
|
|
2229
2355
|
expect(impact.reachability).toBe(PostDeletionReachability.NotReachable);
|
|
2230
2356
|
});
|
|
2231
2357
|
|
|
2232
|
-
test("the
|
|
2358
|
+
test("the nine services do not read each other's tables", async () => {
|
|
2233
2359
|
ruleRows = [];
|
|
2234
2360
|
|
|
2235
2361
|
await UserTelegramService.getDeletionImpact({
|
|
@@ -2243,6 +2369,8 @@ describe("the per-method-service entry points", () => {
|
|
|
2243
2369
|
expect(callFindOneBy).not.toHaveBeenCalled();
|
|
2244
2370
|
expect(pushFindOneBy).not.toHaveBeenCalled();
|
|
2245
2371
|
expect(whatsAppFindOneBy).not.toHaveBeenCalled();
|
|
2372
|
+
expect(slackFindOneBy).not.toHaveBeenCalled();
|
|
2373
|
+
expect(microsoftTeamsFindOneBy).not.toHaveBeenCalled();
|
|
2246
2374
|
expect(webhookFindOneBy).not.toHaveBeenCalled();
|
|
2247
2375
|
});
|
|
2248
2376
|
});
|
|
@@ -3,6 +3,7 @@ import OnCallNotificationAlertingService from "../../../Server/Services/OnCallNo
|
|
|
3
3
|
import ProjectService from "../../../Server/Services/ProjectService";
|
|
4
4
|
import UserCallService from "../../../Server/Services/UserCallService";
|
|
5
5
|
import UserEmailService from "../../../Server/Services/UserEmailService";
|
|
6
|
+
import UserMicrosoftTeamsService from "../../../Server/Services/UserMicrosoftTeamsService";
|
|
6
7
|
import UserNotificationRuleService, {
|
|
7
8
|
ExecuteFallbackNotificationOptions,
|
|
8
9
|
ExecuteNotificationRuleOptions,
|
|
@@ -15,6 +16,7 @@ import UserOnCallLogService, {
|
|
|
15
16
|
} from "../../../Server/Services/UserOnCallLogService";
|
|
16
17
|
import UserPushService from "../../../Server/Services/UserPushService";
|
|
17
18
|
import UserService from "../../../Server/Services/UserService";
|
|
19
|
+
import UserSlackService from "../../../Server/Services/UserSlackService";
|
|
18
20
|
import UserSmsService from "../../../Server/Services/UserSmsService";
|
|
19
21
|
import UserTelegramService from "../../../Server/Services/UserTelegramService";
|
|
20
22
|
import UserWebhookService from "../../../Server/Services/UserWebhookService";
|
|
@@ -43,10 +45,12 @@ import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
|
|
|
43
45
|
* verified. This file pins the four things about it that are easy to get subtly,
|
|
44
46
|
* silently wrong:
|
|
45
47
|
*
|
|
46
|
-
* 1. WHICH CHANNELS. Zero-cost first: a responder with a verified push
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
48
|
+
* 1. WHICH CHANNELS. Zero-cost first: a responder with any of a verified push
|
|
49
|
+
* device, a verified email, a linked Slack account or a linked Microsoft
|
|
50
|
+
* Teams account gets ALL of those they have, because there is no reason to
|
|
51
|
+
* choose and none of them costs the project anything. Only a responder
|
|
52
|
+
* with none of the four is worth spending money on, and then exactly once,
|
|
53
|
+
* down the ladder
|
|
50
54
|
* SMS -> Call -> WhatsApp -> Telegram -> Webhook - and only through
|
|
51
55
|
* channels the PROJECT still has switched on. That last clause is the one
|
|
52
56
|
* with a bill attached: SmsService and CallService check their project flag
|
|
@@ -83,7 +87,7 @@ import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
|
|
|
83
87
|
*
|
|
84
88
|
* Nothing here touches a database or a sender: deliverNotificationForRule is
|
|
85
89
|
* stubbed at the service boundary (it fans out into template generation, short
|
|
86
|
-
* links,
|
|
90
|
+
* links, nine providers and the timeline writer), and every lookup is a
|
|
87
91
|
* jest.spyOn. What is under test is the fallback's own decision-making.
|
|
88
92
|
*/
|
|
89
93
|
|
|
@@ -126,6 +130,12 @@ const TELEGRAM_METHOD_ID: ObjectID = new ObjectID(
|
|
|
126
130
|
const WEBHOOK_METHOD_ID: ObjectID = new ObjectID(
|
|
127
131
|
"a7a7a7a7-a7a7-4a7a-8a7a-a7a7a7a7a7a7",
|
|
128
132
|
);
|
|
133
|
+
const SLACK_METHOD_ID: ObjectID = new ObjectID(
|
|
134
|
+
"a8a8a8a8-a8a8-4a8a-8a8a-a8a8a8a8a8a8",
|
|
135
|
+
);
|
|
136
|
+
const MICROSOFT_TEAMS_METHOD_ID: ObjectID = new ObjectID(
|
|
137
|
+
"a9a9a9a9-a9a9-4a9a-8a9a-a9a9a9a9a9a9",
|
|
138
|
+
);
|
|
129
139
|
|
|
130
140
|
const RESPONDER_EMAIL: string = "responder@company.com";
|
|
131
141
|
const SEVERITY_NAME: string = "Sev4";
|
|
@@ -179,6 +189,31 @@ function makeVerifiedEmail(): Record<string, unknown> {
|
|
|
179
189
|
};
|
|
180
190
|
}
|
|
181
191
|
|
|
192
|
+
/*
|
|
193
|
+
* Slack and Microsoft Teams rows are born verified - they come from the user's
|
|
194
|
+
* own OAuth workspace link, not a verification-code flow - but the fallback
|
|
195
|
+
* still queries on isVerified, so the fixtures carry it.
|
|
196
|
+
*/
|
|
197
|
+
function makeVerifiedSlack(): Record<string, unknown> {
|
|
198
|
+
return {
|
|
199
|
+
id: SLACK_METHOD_ID,
|
|
200
|
+
_id: SLACK_METHOD_ID.toString(),
|
|
201
|
+
slackUserId: "U0123456789",
|
|
202
|
+
slackUserName: "responder",
|
|
203
|
+
isVerified: true,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function makeVerifiedMicrosoftTeams(): Record<string, unknown> {
|
|
208
|
+
return {
|
|
209
|
+
id: MICROSOFT_TEAMS_METHOD_ID,
|
|
210
|
+
_id: MICROSOFT_TEAMS_METHOD_ID.toString(),
|
|
211
|
+
microsoftTeamsUserId: "teams-user-1",
|
|
212
|
+
microsoftTeamsUserName: RESPONDER_NAME,
|
|
213
|
+
isVerified: true,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
182
217
|
function makeVerifiedSms(): Record<string, unknown> {
|
|
183
218
|
return {
|
|
184
219
|
id: SMS_METHOD_ID,
|
|
@@ -308,6 +343,8 @@ describe("UserNotificationRuleService.executeFallbackNotification", () => {
|
|
|
308
343
|
let ruleCreateSpy: jest.SpyInstance;
|
|
309
344
|
let pushFindSpy: jest.SpyInstance;
|
|
310
345
|
let emailFindSpy: jest.SpyInstance;
|
|
346
|
+
let slackFindSpy: jest.SpyInstance;
|
|
347
|
+
let microsoftTeamsFindSpy: jest.SpyInstance;
|
|
311
348
|
let smsFindSpy: jest.SpyInstance;
|
|
312
349
|
let callFindSpy: jest.SpyInstance;
|
|
313
350
|
let whatsAppFindSpy: jest.SpyInstance;
|
|
@@ -329,7 +366,7 @@ describe("UserNotificationRuleService.executeFallbackNotification", () => {
|
|
|
329
366
|
|
|
330
367
|
/*
|
|
331
368
|
* Stubbed at the service boundary. The real method fans out into template
|
|
332
|
-
* generation, short-link creation,
|
|
369
|
+
* generation, short-link creation, nine providers and the timeline writer;
|
|
333
370
|
* its return value ("was a page actually handed to a sender") is the only
|
|
334
371
|
* part of it the fallback reasons about.
|
|
335
372
|
*/
|
|
@@ -348,6 +385,12 @@ describe("UserNotificationRuleService.executeFallbackNotification", () => {
|
|
|
348
385
|
emailFindSpy = jest
|
|
349
386
|
.spyOn(UserEmailService, "findOneBy")
|
|
350
387
|
.mockResolvedValue(null as never);
|
|
388
|
+
slackFindSpy = jest
|
|
389
|
+
.spyOn(UserSlackService, "findOneBy")
|
|
390
|
+
.mockResolvedValue(null as never);
|
|
391
|
+
microsoftTeamsFindSpy = jest
|
|
392
|
+
.spyOn(UserMicrosoftTeamsService, "findOneBy")
|
|
393
|
+
.mockResolvedValue(null as never);
|
|
351
394
|
smsFindSpy = jest
|
|
352
395
|
.spyOn(UserSmsService, "findOneBy")
|
|
353
396
|
.mockResolvedValue(null as never);
|
|
@@ -426,7 +469,7 @@ describe("UserNotificationRuleService.executeFallbackNotification", () => {
|
|
|
426
469
|
* -----------------------------------------------------------------------
|
|
427
470
|
*/
|
|
428
471
|
|
|
429
|
-
describe("channel selection: the zero-cost
|
|
472
|
+
describe("channel selection: the zero-cost tier", () => {
|
|
430
473
|
test("a responder with a verified push device AND a verified email gets BOTH", async () => {
|
|
431
474
|
pushFindSpy.mockResolvedValue(makeVerifiedPush() as never);
|
|
432
475
|
emailFindSpy.mockResolvedValue(makeVerifiedEmail() as never);
|
|
@@ -466,6 +509,86 @@ describe("UserNotificationRuleService.executeFallbackNotification", () => {
|
|
|
466
509
|
}
|
|
467
510
|
});
|
|
468
511
|
|
|
512
|
+
test('a verified Slack account alone is chosen, as "Slack", with the relation AND the FK', async () => {
|
|
513
|
+
const slack: Record<string, unknown> = makeVerifiedSlack();
|
|
514
|
+
slackFindSpy.mockResolvedValue(slack as never);
|
|
515
|
+
|
|
516
|
+
const result: FallbackNotificationResult = await runFallback();
|
|
517
|
+
|
|
518
|
+
expect(result.channelsUsed).toEqual(["Slack"]);
|
|
519
|
+
expect(result.notified).toBe(true);
|
|
520
|
+
expect(result.outcome).toBe(FallbackNotificationOutcome.Delivered);
|
|
521
|
+
|
|
522
|
+
/*
|
|
523
|
+
* The relation, not merely the FK: the Slack channel block reads
|
|
524
|
+
* `userSlack?.slackUserId && userSlack?.isVerified` off the loaded
|
|
525
|
+
* relation and never dereferences the id, so a rule carrying only
|
|
526
|
+
* userSlackId would sail through delivery sending nothing at all.
|
|
527
|
+
*/
|
|
528
|
+
const rule: UserNotificationRule = deliveredRules()[0]!;
|
|
529
|
+
expect(rule.userSlack).toBe(slack);
|
|
530
|
+
expect(rule.userSlackId!.toString()).toBe(SLACK_METHOD_ID.toString());
|
|
531
|
+
|
|
532
|
+
for (const spy of everyPaidChannelFindSpy()) {
|
|
533
|
+
expect(spy).not.toHaveBeenCalled();
|
|
534
|
+
}
|
|
535
|
+
expect(webhookFindSpy).not.toHaveBeenCalled();
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
test('a verified Microsoft Teams account alone is chosen, as "Microsoft Teams", with the relation AND the FK', async () => {
|
|
539
|
+
const microsoftTeams: Record<string, unknown> =
|
|
540
|
+
makeVerifiedMicrosoftTeams();
|
|
541
|
+
microsoftTeamsFindSpy.mockResolvedValue(microsoftTeams as never);
|
|
542
|
+
|
|
543
|
+
const result: FallbackNotificationResult = await runFallback();
|
|
544
|
+
|
|
545
|
+
expect(result.channelsUsed).toEqual(["Microsoft Teams"]);
|
|
546
|
+
expect(result.notified).toBe(true);
|
|
547
|
+
expect(result.outcome).toBe(FallbackNotificationOutcome.Delivered);
|
|
548
|
+
|
|
549
|
+
const rule: UserNotificationRule = deliveredRules()[0]!;
|
|
550
|
+
expect(rule.userMicrosoftTeams).toBe(microsoftTeams);
|
|
551
|
+
expect(rule.userMicrosoftTeamsId!.toString()).toBe(
|
|
552
|
+
MICROSOFT_TEAMS_METHOD_ID.toString(),
|
|
553
|
+
);
|
|
554
|
+
|
|
555
|
+
for (const spy of everyPaidChannelFindSpy()) {
|
|
556
|
+
expect(spy).not.toHaveBeenCalled();
|
|
557
|
+
}
|
|
558
|
+
expect(webhookFindSpy).not.toHaveBeenCalled();
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
test("a responder with push, email, Slack AND Microsoft Teams gets ALL FOUR, in this order", async () => {
|
|
562
|
+
pushFindSpy.mockResolvedValue(makeVerifiedPush() as never);
|
|
563
|
+
emailFindSpy.mockResolvedValue(makeVerifiedEmail() as never);
|
|
564
|
+
slackFindSpy.mockResolvedValue(makeVerifiedSlack() as never);
|
|
565
|
+
microsoftTeamsFindSpy.mockResolvedValue(
|
|
566
|
+
makeVerifiedMicrosoftTeams() as never,
|
|
567
|
+
);
|
|
568
|
+
|
|
569
|
+
const result: FallbackNotificationResult = await runFallback();
|
|
570
|
+
|
|
571
|
+
/*
|
|
572
|
+
* The zero-cost tier takes everything present, never a subset: none of
|
|
573
|
+
* the four costs the project anything, so there is no reason to pick
|
|
574
|
+
* between them and every reason to maximise the chance of reaching a
|
|
575
|
+
* human wherever they happen to be looking.
|
|
576
|
+
*/
|
|
577
|
+
expect(result.channelsUsed).toEqual([
|
|
578
|
+
"Push",
|
|
579
|
+
"Email",
|
|
580
|
+
"Slack",
|
|
581
|
+
"Microsoft Teams",
|
|
582
|
+
]);
|
|
583
|
+
expect(result.notified).toBe(true);
|
|
584
|
+
expect(result.outcome).toBe(FallbackNotificationOutcome.Delivered);
|
|
585
|
+
// Four channels, four delivery calls, each with its own rule.
|
|
586
|
+
expect(deliverSpy).toHaveBeenCalledTimes(4);
|
|
587
|
+
for (const spy of everyPaidChannelFindSpy()) {
|
|
588
|
+
expect(spy).not.toHaveBeenCalled();
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
|
|
469
592
|
test("with a zero-cost channel available the project settings are never even read", async () => {
|
|
470
593
|
emailFindSpy.mockResolvedValue(makeVerifiedEmail() as never);
|
|
471
594
|
|
|
@@ -509,6 +632,34 @@ describe("UserNotificationRuleService.executeFallbackNotification", () => {
|
|
|
509
632
|
expect((query["userId"] as ObjectID).toString()).toBe(USER_ID.toString());
|
|
510
633
|
expect(query["isVerified"]).toBe(true);
|
|
511
634
|
});
|
|
635
|
+
|
|
636
|
+
test("the Slack lookup is scoped to this project, this user, and verified accounts only", async () => {
|
|
637
|
+
slackFindSpy.mockResolvedValue(makeVerifiedSlack() as never);
|
|
638
|
+
|
|
639
|
+
await runFallback();
|
|
640
|
+
|
|
641
|
+
const query: Record<string, unknown> = queryOf(slackFindSpy);
|
|
642
|
+
expect((query["projectId"] as ObjectID).toString()).toBe(
|
|
643
|
+
PROJECT_ID.toString(),
|
|
644
|
+
);
|
|
645
|
+
expect((query["userId"] as ObjectID).toString()).toBe(USER_ID.toString());
|
|
646
|
+
expect(query["isVerified"]).toBe(true);
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
test("the Microsoft Teams lookup is scoped to this project, this user, and verified accounts only", async () => {
|
|
650
|
+
microsoftTeamsFindSpy.mockResolvedValue(
|
|
651
|
+
makeVerifiedMicrosoftTeams() as never,
|
|
652
|
+
);
|
|
653
|
+
|
|
654
|
+
await runFallback();
|
|
655
|
+
|
|
656
|
+
const query: Record<string, unknown> = queryOf(microsoftTeamsFindSpy);
|
|
657
|
+
expect((query["projectId"] as ObjectID).toString()).toBe(
|
|
658
|
+
PROJECT_ID.toString(),
|
|
659
|
+
);
|
|
660
|
+
expect((query["userId"] as ObjectID).toString()).toBe(USER_ID.toString());
|
|
661
|
+
expect(query["isVerified"]).toBe(true);
|
|
662
|
+
});
|
|
512
663
|
});
|
|
513
664
|
|
|
514
665
|
/*
|
|
@@ -659,7 +810,7 @@ describe("UserNotificationRuleService.executeFallbackNotification", () => {
|
|
|
659
810
|
},
|
|
660
811
|
);
|
|
661
812
|
|
|
662
|
-
test("the paid ladder is only reached when
|
|
813
|
+
test("the paid ladder is only reached when ALL FOUR zero-cost channels are missing", async () => {
|
|
663
814
|
pushFindSpy.mockResolvedValue(makeVerifiedPush() as never);
|
|
664
815
|
giveResponderEveryPaidMethod();
|
|
665
816
|
projectFindSpy.mockResolvedValue(
|
|
@@ -671,6 +822,36 @@ describe("UserNotificationRuleService.executeFallbackNotification", () => {
|
|
|
671
822
|
expect(result.channelsUsed).toEqual(["Push"]);
|
|
672
823
|
expect(smsFindSpy).not.toHaveBeenCalled();
|
|
673
824
|
});
|
|
825
|
+
|
|
826
|
+
test("a Slack account alone keeps the paid ladder shut - the project row is never even read", async () => {
|
|
827
|
+
slackFindSpy.mockResolvedValue(makeVerifiedSlack() as never);
|
|
828
|
+
giveResponderEveryPaidMethod();
|
|
829
|
+
projectFindSpy.mockResolvedValue(
|
|
830
|
+
makeProject({ [SMS_FLAG]: true }) as never,
|
|
831
|
+
);
|
|
832
|
+
|
|
833
|
+
const result: FallbackNotificationResult = await runFallback();
|
|
834
|
+
|
|
835
|
+
expect(result.channelsUsed).toEqual(["Slack"]);
|
|
836
|
+
expect(projectFindSpy).not.toHaveBeenCalled();
|
|
837
|
+
expect(smsFindSpy).not.toHaveBeenCalled();
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
test("a Microsoft Teams account alone keeps the paid ladder shut too", async () => {
|
|
841
|
+
microsoftTeamsFindSpy.mockResolvedValue(
|
|
842
|
+
makeVerifiedMicrosoftTeams() as never,
|
|
843
|
+
);
|
|
844
|
+
giveResponderEveryPaidMethod();
|
|
845
|
+
projectFindSpy.mockResolvedValue(
|
|
846
|
+
makeProject({ [SMS_FLAG]: true }) as never,
|
|
847
|
+
);
|
|
848
|
+
|
|
849
|
+
const result: FallbackNotificationResult = await runFallback();
|
|
850
|
+
|
|
851
|
+
expect(result.channelsUsed).toEqual(["Microsoft Teams"]);
|
|
852
|
+
expect(projectFindSpy).not.toHaveBeenCalled();
|
|
853
|
+
expect(smsFindSpy).not.toHaveBeenCalled();
|
|
854
|
+
});
|
|
674
855
|
});
|
|
675
856
|
|
|
676
857
|
/*
|
|
@@ -795,6 +976,8 @@ describe("UserNotificationRuleService.executeFallbackNotification", () => {
|
|
|
795
976
|
rule.userCall,
|
|
796
977
|
rule.userWhatsApp,
|
|
797
978
|
rule.userTelegram,
|
|
979
|
+
rule.userSlack,
|
|
980
|
+
rule.userMicrosoftTeams,
|
|
798
981
|
rule.userWebhook,
|
|
799
982
|
].filter((method: unknown): boolean => {
|
|
800
983
|
return Boolean(method);
|