@oneuptime/common 12.0.18 → 12.0.19
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/UserMicrosoftTeamsAPI.ts +127 -0
- package/Server/API/UserSlackAPI.ts +125 -0
- package/Server/EnvironmentConfig.ts +12 -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 +67 -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/Workspace/MicrosoftTeams/MicrosoftTeams.ts +191 -4
- package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +22 -14
- package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +22 -11
- 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/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/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/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/UI/Utils/NotificationMethodUtil.test.ts +137 -9
- package/Tests/UI/Utils/PermissionGate.test.ts +105 -0
- package/Types/Marketing/MarketingEvent.ts +97 -0
- package/UI/Utils/NotificationMethodUtil.ts +41 -1
- package/UI/Utils/PermissionGate.ts +56 -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/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 +10 -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 +56 -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/Workspace/MicrosoftTeams/MicrosoftTeams.js +141 -4
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Types/Marketing/MarketingEvent.js +43 -0
- package/build/dist/Types/Marketing/MarketingEvent.js.map +1 -0
- 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/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
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
import UserNotificationSettingService from "../../../Server/Services/UserNotificationSettingService";
|
|
2
|
+
import UserSlackService from "../../../Server/Services/UserSlackService";
|
|
3
|
+
import UserMicrosoftTeamsService from "../../../Server/Services/UserMicrosoftTeamsService";
|
|
4
|
+
import WorkspaceUserNotificationService from "../../../Server/Services/WorkspaceUserNotificationService";
|
|
5
|
+
import ProjectCallSMSConfigService from "../../../Server/Services/ProjectCallSMSConfigService";
|
|
6
|
+
import logger from "../../../Server/Utils/Logger";
|
|
7
|
+
import UserNotificationSetting from "../../../Models/DatabaseModels/UserNotificationSetting";
|
|
8
|
+
import UserSlack from "../../../Models/DatabaseModels/UserSlack";
|
|
9
|
+
import UserMicrosoftTeams from "../../../Models/DatabaseModels/UserMicrosoftTeams";
|
|
10
|
+
import { CallRequestMessage } from "../../../Types/Call/CallRequest";
|
|
11
|
+
import { EmailEnvelope } from "../../../Types/Email/EmailMessage";
|
|
12
|
+
import EmailTemplateType from "../../../Types/Email/EmailTemplateType";
|
|
13
|
+
import NotificationSettingEventType from "../../../Types/NotificationSetting/NotificationSettingEventType";
|
|
14
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
15
|
+
import PushNotificationMessage from "../../../Types/PushNotification/PushNotificationMessage";
|
|
16
|
+
import { SMSMessage } from "../../../Types/SMS/SMS";
|
|
17
|
+
import { WhatsAppMessagePayload } from "../../../Types/WhatsApp/WhatsAppMessage";
|
|
18
|
+
import {
|
|
19
|
+
WorkspaceMessageBlock,
|
|
20
|
+
WorkspacePayloadMarkdown,
|
|
21
|
+
} from "../../../Types/Workspace/WorkspaceMessagePayload";
|
|
22
|
+
import WorkspaceType from "../../../Types/Workspace/WorkspaceType";
|
|
23
|
+
import { describe, expect, test, beforeEach, afterEach } from "@jest/globals";
|
|
24
|
+
|
|
25
|
+
/*
|
|
26
|
+
* sendUserNotification is the settings-based (non-on-call-rule) delivery path:
|
|
27
|
+
* "incident created and I own it", "I go on-call", and the ~40 other
|
|
28
|
+
* NotificationSettingEventType rows. Its callers were all written before the
|
|
29
|
+
* workspace channels existed, so they hand over payloads for the older
|
|
30
|
+
* channels only — which is why the Slack / Microsoft Teams block SYNTHESISES
|
|
31
|
+
* its markdown from the email subject + SMS body, exactly the way the
|
|
32
|
+
* Telegram fallback body works. Pinned here:
|
|
33
|
+
*
|
|
34
|
+
* 1. THE TOGGLES. alertBySlack / alertByMicrosoftTeams each gate their own
|
|
35
|
+
* channel and nothing else, and a settings row with both off sends no
|
|
36
|
+
* workspace message at all (including not looking the methods up).
|
|
37
|
+
*
|
|
38
|
+
* 2. THE ADDRESSES. Only VERIFIED method rows are read, each one gets its
|
|
39
|
+
* own send, and a row whose address column is empty is skipped.
|
|
40
|
+
*
|
|
41
|
+
* 3. THE BODY. `🔔 **{subject}**` + blank line + SMS body; subject-less
|
|
42
|
+
* notifications fall back to the generic headline; a notification with
|
|
43
|
+
* neither subject nor SMS body sends nothing rather than a blank DM.
|
|
44
|
+
*
|
|
45
|
+
* 4. ISOLATION. Sends are fire-and-forget: a rejected workspace send is
|
|
46
|
+
* logged and never rejects sendUserNotification.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
const PROJECT_ID: ObjectID = new ObjectID(
|
|
50
|
+
"11111111-1111-4111-8111-111111111111",
|
|
51
|
+
);
|
|
52
|
+
const USER_ID: ObjectID = new ObjectID("22222222-2222-4222-8222-222222222222");
|
|
53
|
+
const INCIDENT_ID: ObjectID = new ObjectID(
|
|
54
|
+
"33333333-3333-4333-8333-333333333333",
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const SLACK_USER_ID: string = "U0123ABCD";
|
|
58
|
+
const SECOND_SLACK_USER_ID: string = "U0456EFGH";
|
|
59
|
+
const TEAMS_USER_ID: string = "entra-object-id-1";
|
|
60
|
+
|
|
61
|
+
const EVENT_TYPE: NotificationSettingEventType =
|
|
62
|
+
NotificationSettingEventType.SEND_INCIDENT_CREATED_OWNER_NOTIFICATION;
|
|
63
|
+
|
|
64
|
+
type SendUserNotificationData = Parameters<
|
|
65
|
+
typeof UserNotificationSettingService.sendUserNotification
|
|
66
|
+
>[0];
|
|
67
|
+
|
|
68
|
+
function settingsRow(
|
|
69
|
+
overrides: Partial<UserNotificationSetting> = {},
|
|
70
|
+
): UserNotificationSetting {
|
|
71
|
+
return {
|
|
72
|
+
alertByEmail: false,
|
|
73
|
+
alertBySMS: false,
|
|
74
|
+
alertByCall: false,
|
|
75
|
+
alertByPush: false,
|
|
76
|
+
alertByWhatsApp: false,
|
|
77
|
+
alertByTelegram: false,
|
|
78
|
+
alertBySlack: false,
|
|
79
|
+
alertByMicrosoftTeams: false,
|
|
80
|
+
alertByWebhook: false,
|
|
81
|
+
...overrides,
|
|
82
|
+
} as unknown as UserNotificationSetting;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function notificationData(
|
|
86
|
+
overrides: Partial<SendUserNotificationData> = {},
|
|
87
|
+
): SendUserNotificationData {
|
|
88
|
+
const emailEnvelope: EmailEnvelope = {
|
|
89
|
+
subject: "Incident created: Checkout is down",
|
|
90
|
+
templateType: EmailTemplateType.BlankTemplate,
|
|
91
|
+
vars: {},
|
|
92
|
+
} as unknown as EmailEnvelope;
|
|
93
|
+
|
|
94
|
+
const smsMessage: SMSMessage = {
|
|
95
|
+
message:
|
|
96
|
+
"OneUptime: New incident created: Checkout is down. Please acknowledge.",
|
|
97
|
+
} as SMSMessage;
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
userId: USER_ID,
|
|
101
|
+
projectId: PROJECT_ID,
|
|
102
|
+
eventType: EVENT_TYPE,
|
|
103
|
+
emailEnvelope: emailEnvelope,
|
|
104
|
+
smsMessage: smsMessage,
|
|
105
|
+
callRequestMessage: {} as CallRequestMessage,
|
|
106
|
+
pushNotificationMessage: {} as PushNotificationMessage,
|
|
107
|
+
whatsAppMessage: {} as WhatsAppMessagePayload,
|
|
108
|
+
incidentId: INCIDENT_ID,
|
|
109
|
+
...overrides,
|
|
110
|
+
} as SendUserNotificationData;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
describe("UserNotificationSettingService.sendUserNotification - workspace channels", () => {
|
|
114
|
+
let findSettings: jest.SpyInstance;
|
|
115
|
+
let findSlacks: jest.SpyInstance;
|
|
116
|
+
let findTeams: jest.SpyInstance;
|
|
117
|
+
let sendDm: jest.SpyInstance;
|
|
118
|
+
let loggerError: jest.SpyInstance;
|
|
119
|
+
|
|
120
|
+
beforeEach(() => {
|
|
121
|
+
loggerError = jest.spyOn(logger, "error").mockImplementation((): void => {
|
|
122
|
+
return undefined;
|
|
123
|
+
});
|
|
124
|
+
jest.spyOn(logger, "warn").mockImplementation((): void => {
|
|
125
|
+
return undefined;
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
findSettings = jest
|
|
129
|
+
.spyOn(UserNotificationSettingService, "findOneBy")
|
|
130
|
+
.mockResolvedValue(settingsRow({ alertBySlack: true }) as never);
|
|
131
|
+
|
|
132
|
+
jest
|
|
133
|
+
.spyOn(ProjectCallSMSConfigService, "getProjectDefaultTwilioConfig")
|
|
134
|
+
.mockResolvedValue(undefined as never);
|
|
135
|
+
|
|
136
|
+
findSlacks = jest.spyOn(UserSlackService, "findBy").mockResolvedValue([
|
|
137
|
+
{
|
|
138
|
+
id: new ObjectID("44444444-4444-4444-8444-444444444444"),
|
|
139
|
+
slackUserId: SLACK_USER_ID,
|
|
140
|
+
} as unknown as UserSlack,
|
|
141
|
+
] as never);
|
|
142
|
+
|
|
143
|
+
findTeams = jest
|
|
144
|
+
.spyOn(UserMicrosoftTeamsService, "findBy")
|
|
145
|
+
.mockResolvedValue([
|
|
146
|
+
{
|
|
147
|
+
id: new ObjectID("55555555-5555-4555-8555-555555555555"),
|
|
148
|
+
microsoftTeamsUserId: TEAMS_USER_ID,
|
|
149
|
+
} as unknown as UserMicrosoftTeams,
|
|
150
|
+
] as never);
|
|
151
|
+
|
|
152
|
+
sendDm = jest
|
|
153
|
+
.spyOn(WorkspaceUserNotificationService, "sendDirectMessageToUser")
|
|
154
|
+
.mockResolvedValue(undefined as never);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
afterEach(() => {
|
|
158
|
+
jest.restoreAllMocks();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
function flushMicrotasks(): Promise<void> {
|
|
162
|
+
return Promise.resolve()
|
|
163
|
+
.then((): Promise<void> => {
|
|
164
|
+
return Promise.resolve();
|
|
165
|
+
})
|
|
166
|
+
.then((): Promise<void> => {
|
|
167
|
+
return Promise.resolve();
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
interface CapturedSendArg {
|
|
172
|
+
projectId: ObjectID;
|
|
173
|
+
workspaceType: WorkspaceType;
|
|
174
|
+
workspaceUserId: string;
|
|
175
|
+
messageBlocks: Array<WorkspaceMessageBlock>;
|
|
176
|
+
userId: ObjectID;
|
|
177
|
+
incidentId?: ObjectID;
|
|
178
|
+
userOnCallLogTimelineId?: ObjectID;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function sendArgs(): Array<CapturedSendArg> {
|
|
182
|
+
return sendDm.mock.calls.map((call: Array<unknown>) => {
|
|
183
|
+
return call[0] as CapturedSendArg;
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/*
|
|
188
|
+
* ----------------------------------------------------------------------- *
|
|
189
|
+
* (A) The toggles.
|
|
190
|
+
* -----------------------------------------------------------------------
|
|
191
|
+
*/
|
|
192
|
+
|
|
193
|
+
describe("the per-channel toggles", () => {
|
|
194
|
+
test("alertBySlack on sends to Slack and never reads the Teams methods", async () => {
|
|
195
|
+
await UserNotificationSettingService.sendUserNotification(
|
|
196
|
+
notificationData(),
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
expect(sendDm).toHaveBeenCalledTimes(1);
|
|
200
|
+
expect(sendArgs()[0]?.workspaceType).toBe(WorkspaceType.Slack);
|
|
201
|
+
expect(sendArgs()[0]?.workspaceUserId).toBe(SLACK_USER_ID);
|
|
202
|
+
expect(findTeams).not.toHaveBeenCalled();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test("alertByMicrosoftTeams on sends to Teams and never reads the Slack methods", async () => {
|
|
206
|
+
findSettings.mockResolvedValue(
|
|
207
|
+
settingsRow({ alertByMicrosoftTeams: true }) as never,
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
await UserNotificationSettingService.sendUserNotification(
|
|
211
|
+
notificationData(),
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
expect(sendDm).toHaveBeenCalledTimes(1);
|
|
215
|
+
expect(sendArgs()[0]?.workspaceType).toBe(WorkspaceType.MicrosoftTeams);
|
|
216
|
+
expect(sendArgs()[0]?.workspaceUserId).toBe(TEAMS_USER_ID);
|
|
217
|
+
expect(findSlacks).not.toHaveBeenCalled();
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test("both toggles on sends one message per channel", async () => {
|
|
221
|
+
findSettings.mockResolvedValue(
|
|
222
|
+
settingsRow({
|
|
223
|
+
alertBySlack: true,
|
|
224
|
+
alertByMicrosoftTeams: true,
|
|
225
|
+
}) as never,
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
await UserNotificationSettingService.sendUserNotification(
|
|
229
|
+
notificationData(),
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
expect(sendDm).toHaveBeenCalledTimes(2);
|
|
233
|
+
const workspaceTypes: Array<WorkspaceType> = sendArgs().map(
|
|
234
|
+
(arg: CapturedSendArg) => {
|
|
235
|
+
return arg.workspaceType;
|
|
236
|
+
},
|
|
237
|
+
);
|
|
238
|
+
expect(workspaceTypes).toContain(WorkspaceType.Slack);
|
|
239
|
+
expect(workspaceTypes).toContain(WorkspaceType.MicrosoftTeams);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
test("both toggles off sends nothing and does not even look the methods up", async () => {
|
|
243
|
+
findSettings.mockResolvedValue(settingsRow() as never);
|
|
244
|
+
|
|
245
|
+
await UserNotificationSettingService.sendUserNotification(
|
|
246
|
+
notificationData(),
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
expect(sendDm).not.toHaveBeenCalled();
|
|
250
|
+
expect(findSlacks).not.toHaveBeenCalled();
|
|
251
|
+
expect(findTeams).not.toHaveBeenCalled();
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test("no settings row at all sends nothing", async () => {
|
|
255
|
+
findSettings.mockResolvedValue(null as never);
|
|
256
|
+
|
|
257
|
+
await UserNotificationSettingService.sendUserNotification(
|
|
258
|
+
notificationData(),
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
expect(sendDm).not.toHaveBeenCalled();
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
/*
|
|
266
|
+
* ----------------------------------------------------------------------- *
|
|
267
|
+
* (B) The address reads.
|
|
268
|
+
* -----------------------------------------------------------------------
|
|
269
|
+
*/
|
|
270
|
+
|
|
271
|
+
describe("the address reads", () => {
|
|
272
|
+
test("only VERIFIED Slack rows are read, scoped to this user and project", async () => {
|
|
273
|
+
await UserNotificationSettingService.sendUserNotification(
|
|
274
|
+
notificationData(),
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
const arg: {
|
|
278
|
+
query: { userId: ObjectID; projectId: ObjectID; isVerified: boolean };
|
|
279
|
+
props: { isRoot: boolean };
|
|
280
|
+
} = findSlacks.mock.calls[0][0] as {
|
|
281
|
+
query: { userId: ObjectID; projectId: ObjectID; isVerified: boolean };
|
|
282
|
+
props: { isRoot: boolean };
|
|
283
|
+
};
|
|
284
|
+
expect(arg.query.userId.toString()).toBe(USER_ID.toString());
|
|
285
|
+
expect(arg.query.projectId.toString()).toBe(PROJECT_ID.toString());
|
|
286
|
+
expect(arg.query.isVerified).toBe(true);
|
|
287
|
+
expect(arg.props.isRoot).toBe(true);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test("every linked account gets its own send", async () => {
|
|
291
|
+
findSlacks.mockResolvedValue([
|
|
292
|
+
{ slackUserId: SLACK_USER_ID } as unknown as UserSlack,
|
|
293
|
+
{ slackUserId: SECOND_SLACK_USER_ID } as unknown as UserSlack,
|
|
294
|
+
] as never);
|
|
295
|
+
|
|
296
|
+
await UserNotificationSettingService.sendUserNotification(
|
|
297
|
+
notificationData(),
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
expect(sendDm).toHaveBeenCalledTimes(2);
|
|
301
|
+
const targets: Array<string> = sendArgs().map((arg: CapturedSendArg) => {
|
|
302
|
+
return arg.workspaceUserId;
|
|
303
|
+
});
|
|
304
|
+
expect(targets).toContain(SLACK_USER_ID);
|
|
305
|
+
expect(targets).toContain(SECOND_SLACK_USER_ID);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test("a row whose address column is empty is skipped rather than sent to nobody", async () => {
|
|
309
|
+
findSlacks.mockResolvedValue([
|
|
310
|
+
{ slackUserId: "" } as unknown as UserSlack,
|
|
311
|
+
{ slackUserId: SLACK_USER_ID } as unknown as UserSlack,
|
|
312
|
+
] as never);
|
|
313
|
+
|
|
314
|
+
await UserNotificationSettingService.sendUserNotification(
|
|
315
|
+
notificationData(),
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
expect(sendDm).toHaveBeenCalledTimes(1);
|
|
319
|
+
expect(sendArgs()[0]?.workspaceUserId).toBe(SLACK_USER_ID);
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
/*
|
|
324
|
+
* ----------------------------------------------------------------------- *
|
|
325
|
+
* (C) The synthesised body.
|
|
326
|
+
* -----------------------------------------------------------------------
|
|
327
|
+
*/
|
|
328
|
+
|
|
329
|
+
describe("the synthesised markdown body", () => {
|
|
330
|
+
function firstBlockText(): string {
|
|
331
|
+
const block: WorkspaceMessageBlock | undefined =
|
|
332
|
+
sendArgs()[0]?.messageBlocks[0];
|
|
333
|
+
return (block as WorkspacePayloadMarkdown).text;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
test("is built from the email subject (bold, belled) plus the SMS body", async () => {
|
|
337
|
+
await UserNotificationSettingService.sendUserNotification(
|
|
338
|
+
notificationData(),
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
const text: string = firstBlockText();
|
|
342
|
+
expect(text).toContain("🔔 **Incident created: Checkout is down**");
|
|
343
|
+
expect(text).toContain(
|
|
344
|
+
"OneUptime: New incident created: Checkout is down. Please acknowledge.",
|
|
345
|
+
);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
test("a subject-less notification falls back to the generic headline", async () => {
|
|
349
|
+
await UserNotificationSettingService.sendUserNotification(
|
|
350
|
+
notificationData({
|
|
351
|
+
emailEnvelope: {
|
|
352
|
+
subject: "",
|
|
353
|
+
templateType: EmailTemplateType.BlankTemplate,
|
|
354
|
+
vars: {},
|
|
355
|
+
} as unknown as EmailEnvelope,
|
|
356
|
+
}),
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
expect(firstBlockText()).toContain("🔔 **OneUptime notification**");
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
test("neither subject nor SMS body sends nothing rather than a blank DM", async () => {
|
|
363
|
+
await UserNotificationSettingService.sendUserNotification(
|
|
364
|
+
notificationData({
|
|
365
|
+
emailEnvelope: {
|
|
366
|
+
subject: "",
|
|
367
|
+
templateType: EmailTemplateType.BlankTemplate,
|
|
368
|
+
vars: {},
|
|
369
|
+
} as unknown as EmailEnvelope,
|
|
370
|
+
smsMessage: { message: "" } as SMSMessage,
|
|
371
|
+
}),
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
expect(sendDm).not.toHaveBeenCalled();
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
test("the context ids ride along so the workspace log can attribute the message", async () => {
|
|
378
|
+
await UserNotificationSettingService.sendUserNotification(
|
|
379
|
+
notificationData(),
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
expect(sendArgs()[0]?.incidentId?.toString()).toBe(
|
|
383
|
+
INCIDENT_ID.toString(),
|
|
384
|
+
);
|
|
385
|
+
expect(sendArgs()[0]?.userId.toString()).toBe(USER_ID.toString());
|
|
386
|
+
// The settings path has no on-call timeline row to flip.
|
|
387
|
+
expect(sendArgs()[0]?.userOnCallLogTimelineId).toBeUndefined();
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
/*
|
|
392
|
+
* ----------------------------------------------------------------------- *
|
|
393
|
+
* (D) Failure isolation.
|
|
394
|
+
* -----------------------------------------------------------------------
|
|
395
|
+
*/
|
|
396
|
+
|
|
397
|
+
describe("failure isolation", () => {
|
|
398
|
+
test("a rejected workspace send is logged and never rejects sendUserNotification", async () => {
|
|
399
|
+
sendDm.mockRejectedValue(new Error("workspace unreachable") as never);
|
|
400
|
+
|
|
401
|
+
await expect(
|
|
402
|
+
UserNotificationSettingService.sendUserNotification(notificationData()),
|
|
403
|
+
).resolves.toBeUndefined();
|
|
404
|
+
|
|
405
|
+
await flushMicrotasks();
|
|
406
|
+
|
|
407
|
+
expect(loggerError).toHaveBeenCalled();
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
});
|