@oneuptime/common 12.0.17 → 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/BillingService.ts +8 -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/App/Dashboard/PayAsYouGoNotices.test.tsx +17 -0
- 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/BillingService.test.ts +20 -0
- 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/Types/Kubernetes/KubernetesObjectParsers.test.ts +794 -0
- package/Tests/Types/Kubernetes/KubernetesRightSizing.test.ts +53 -0
- package/Tests/Types/Measurement/MeasurementAggregationType.test.ts +100 -0
- package/Tests/Types/Monitor/MonitorStepConfigHelpers.test.ts +114 -0
- package/Tests/Types/Workspace/WorkspaceType.test.ts +53 -0
- package/Tests/UI/Utils/NotificationMethodUtil.test.ts +137 -9
- package/Tests/UI/Utils/PermissionGate.test.ts +105 -0
- package/Tests/Utils/Dashboard/Components/DashboardComponentDefaults.test.ts +257 -0
- package/Types/Billing/PayAsYouGoPricing.ts +1 -1
- 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/BillingService.js +6 -0
- package/build/dist/Server/Services/BillingService.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/Billing/PayAsYouGoPricing.js +1 -1
- package/build/dist/Types/Billing/PayAsYouGoPricing.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
|
@@ -23,8 +23,11 @@ import UserCallService from "./UserCallService";
|
|
|
23
23
|
import UserPushService from "./UserPushService";
|
|
24
24
|
import UserSmsService from "./UserSmsService";
|
|
25
25
|
import UserTelegramService from "./UserTelegramService";
|
|
26
|
+
import UserSlackService from "./UserSlackService";
|
|
27
|
+
import UserMicrosoftTeamsService from "./UserMicrosoftTeamsService";
|
|
26
28
|
import UserWebhookService from "./UserWebhookService";
|
|
27
29
|
import UserWhatsAppService from "./UserWhatsAppService";
|
|
30
|
+
import WorkspaceUserNotificationService from "./WorkspaceUserNotificationService";
|
|
28
31
|
import ProjectService from "./ProjectService";
|
|
29
32
|
import UserNotificationRuleAdminService, {
|
|
30
33
|
RuleColumnCarrier,
|
|
@@ -84,6 +87,8 @@ import UserEmail from "../../Models/DatabaseModels/UserEmail";
|
|
|
84
87
|
import UserPush from "../../Models/DatabaseModels/UserPush";
|
|
85
88
|
import UserSMS from "../../Models/DatabaseModels/UserSMS";
|
|
86
89
|
import UserTelegram from "../../Models/DatabaseModels/UserTelegram";
|
|
90
|
+
import UserSlack from "../../Models/DatabaseModels/UserSlack";
|
|
91
|
+
import UserMicrosoftTeams from "../../Models/DatabaseModels/UserMicrosoftTeams";
|
|
87
92
|
import UserWebhook from "../../Models/DatabaseModels/UserWebhook";
|
|
88
93
|
import UserWhatsApp from "../../Models/DatabaseModels/UserWhatsApp";
|
|
89
94
|
import Model from "../../Models/DatabaseModels/UserNotificationRule";
|
|
@@ -106,6 +111,13 @@ import WorkspaceNotificationRuleService from "./WorkspaceNotificationRuleService
|
|
|
106
111
|
import PushNotificationService from "./PushNotificationService";
|
|
107
112
|
import NotificationRuleEventType from "../../Types/Workspace/NotificationRules/EventType";
|
|
108
113
|
import NotificationRuleWorkspaceChannel from "../../Types/Workspace/NotificationRules/NotificationRuleWorkspaceChannel";
|
|
114
|
+
import WorkspaceType, {
|
|
115
|
+
getWorkspaceTypeDisplayName,
|
|
116
|
+
} from "../../Types/Workspace/WorkspaceType";
|
|
117
|
+
import {
|
|
118
|
+
WorkspaceMessageBlock,
|
|
119
|
+
WorkspacePayloadMarkdown,
|
|
120
|
+
} from "../../Types/Workspace/WorkspaceMessagePayload";
|
|
109
121
|
import PushNotificationUtil from "../Utils/PushNotificationUtil";
|
|
110
122
|
import PushNotificationMessage from "../../Types/PushNotification/PushNotificationMessage";
|
|
111
123
|
import logger, { LogAttributes } from "../Utils/Logger";
|
|
@@ -117,6 +129,8 @@ export interface NotificationMethodDescriptor {
|
|
|
117
129
|
userCallId?: ObjectID;
|
|
118
130
|
userWhatsAppId?: ObjectID;
|
|
119
131
|
userTelegramId?: ObjectID;
|
|
132
|
+
userSlackId?: ObjectID;
|
|
133
|
+
userMicrosoftTeamsId?: ObjectID;
|
|
120
134
|
userPushId?: ObjectID;
|
|
121
135
|
userWebhookId?: ObjectID;
|
|
122
136
|
}
|
|
@@ -504,12 +518,13 @@ const HANDOFF_RULE_TYPES: Array<NotificationRuleType> = [
|
|
|
504
518
|
type ChannelListFunction = () => Array<string>;
|
|
505
519
|
|
|
506
520
|
/**
|
|
507
|
-
* The
|
|
508
|
-
* zero-cost
|
|
509
|
-
*
|
|
510
|
-
*
|
|
511
|
-
*
|
|
512
|
-
*
|
|
521
|
+
* The channels no project setting can switch off. Push and Email are
|
|
522
|
+
* zero-cost, Webhook is somebody else's endpoint, and Slack / Microsoft Teams
|
|
523
|
+
* ride on the project's own workspace connection at no per-message cost, so
|
|
524
|
+
* nothing gates them — which is what makes "a verified one of these survives"
|
|
525
|
+
* a CERTAIN answer to "can this person still be paged" rather than a hopeful
|
|
526
|
+
* one. Kept in step with OnCallReadinessService.isChannelEnabled, which
|
|
527
|
+
* returns true for exactly these five unconditionally.
|
|
513
528
|
*
|
|
514
529
|
* A FUNCTION rather than a module-level constant, and that is load-bearing
|
|
515
530
|
* rather than stylistic: this module and OnCallReadinessService import each
|
|
@@ -525,6 +540,8 @@ const channelsWithNoProjectSwitch: ChannelListFunction = (): Array<string> => {
|
|
|
525
540
|
return [
|
|
526
541
|
ReadinessMethodType.Push,
|
|
527
542
|
ReadinessMethodType.Email,
|
|
543
|
+
ReadinessMethodType.Slack,
|
|
544
|
+
ReadinessMethodType.MicrosoftTeams,
|
|
528
545
|
ReadinessMethodType.Webhook,
|
|
529
546
|
];
|
|
530
547
|
};
|
|
@@ -628,6 +645,18 @@ export class Service extends DatabaseService<Model> {
|
|
|
628
645
|
isVerified: true,
|
|
629
646
|
userId: true,
|
|
630
647
|
},
|
|
648
|
+
userSlack: {
|
|
649
|
+
slackUserId: true,
|
|
650
|
+
slackUserName: true,
|
|
651
|
+
isVerified: true,
|
|
652
|
+
userId: true,
|
|
653
|
+
},
|
|
654
|
+
userMicrosoftTeams: {
|
|
655
|
+
microsoftTeamsUserId: true,
|
|
656
|
+
microsoftTeamsUserName: true,
|
|
657
|
+
isVerified: true,
|
|
658
|
+
userId: true,
|
|
659
|
+
},
|
|
631
660
|
userWebhook: {
|
|
632
661
|
webhookUrl: true,
|
|
633
662
|
name: true,
|
|
@@ -732,6 +761,14 @@ export class Service extends DatabaseService<Model> {
|
|
|
732
761
|
label: "Telegram",
|
|
733
762
|
ownerUserId: notificationRuleItem.userTelegram?.userId,
|
|
734
763
|
},
|
|
764
|
+
{
|
|
765
|
+
label: "Slack",
|
|
766
|
+
ownerUserId: notificationRuleItem.userSlack?.userId,
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
label: "Microsoft Teams",
|
|
770
|
+
ownerUserId: notificationRuleItem.userMicrosoftTeams?.userId,
|
|
771
|
+
},
|
|
735
772
|
{ label: "Push", ownerUserId: notificationRuleItem.userPush?.userId },
|
|
736
773
|
{
|
|
737
774
|
label: "Webhook",
|
|
@@ -1987,6 +2024,84 @@ export class Service extends DatabaseService<Model> {
|
|
|
1987
2024
|
});
|
|
1988
2025
|
}
|
|
1989
2026
|
|
|
2027
|
+
// send Slack.
|
|
2028
|
+
if (
|
|
2029
|
+
notificationRuleItem.userSlack?.slackUserId &&
|
|
2030
|
+
notificationRuleItem.userSlack?.isVerified
|
|
2031
|
+
) {
|
|
2032
|
+
const attempted: boolean =
|
|
2033
|
+
await this.deliverWorkspaceDirectMessageForRule({
|
|
2034
|
+
workspaceType: WorkspaceType.Slack,
|
|
2035
|
+
methodId: notificationRuleItem.userSlack.id!,
|
|
2036
|
+
workspaceUserId: notificationRuleItem.userSlack.slackUserId,
|
|
2037
|
+
notificationRuleItem: notificationRuleItem,
|
|
2038
|
+
options: options,
|
|
2039
|
+
logTimelineItem: logTimelineItem,
|
|
2040
|
+
incident: incident,
|
|
2041
|
+
alert: alert,
|
|
2042
|
+
alertEpisode: alertEpisode,
|
|
2043
|
+
incidentEpisode: incidentEpisode,
|
|
2044
|
+
});
|
|
2045
|
+
|
|
2046
|
+
deliveryAttempted = deliveryAttempted || attempted;
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
if (
|
|
2050
|
+
notificationRuleItem.userSlack &&
|
|
2051
|
+
!notificationRuleItem.userSlack?.isVerified
|
|
2052
|
+
) {
|
|
2053
|
+
logTimelineItem.status = UserNotificationStatus.Error;
|
|
2054
|
+
logTimelineItem.statusMessage = `Slack message not sent because the Slack account is not verified.`;
|
|
2055
|
+
logTimelineItem.userSlackId = notificationRuleItem.userSlack.id!;
|
|
2056
|
+
|
|
2057
|
+
await UserOnCallLogTimelineService.create({
|
|
2058
|
+
data: logTimelineItem,
|
|
2059
|
+
props: {
|
|
2060
|
+
isRoot: true,
|
|
2061
|
+
},
|
|
2062
|
+
});
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
// send Microsoft Teams.
|
|
2066
|
+
if (
|
|
2067
|
+
notificationRuleItem.userMicrosoftTeams?.microsoftTeamsUserId &&
|
|
2068
|
+
notificationRuleItem.userMicrosoftTeams?.isVerified
|
|
2069
|
+
) {
|
|
2070
|
+
const attempted: boolean =
|
|
2071
|
+
await this.deliverWorkspaceDirectMessageForRule({
|
|
2072
|
+
workspaceType: WorkspaceType.MicrosoftTeams,
|
|
2073
|
+
methodId: notificationRuleItem.userMicrosoftTeams.id!,
|
|
2074
|
+
workspaceUserId:
|
|
2075
|
+
notificationRuleItem.userMicrosoftTeams.microsoftTeamsUserId,
|
|
2076
|
+
notificationRuleItem: notificationRuleItem,
|
|
2077
|
+
options: options,
|
|
2078
|
+
logTimelineItem: logTimelineItem,
|
|
2079
|
+
incident: incident,
|
|
2080
|
+
alert: alert,
|
|
2081
|
+
alertEpisode: alertEpisode,
|
|
2082
|
+
incidentEpisode: incidentEpisode,
|
|
2083
|
+
});
|
|
2084
|
+
|
|
2085
|
+
deliveryAttempted = deliveryAttempted || attempted;
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
if (
|
|
2089
|
+
notificationRuleItem.userMicrosoftTeams &&
|
|
2090
|
+
!notificationRuleItem.userMicrosoftTeams?.isVerified
|
|
2091
|
+
) {
|
|
2092
|
+
logTimelineItem.status = UserNotificationStatus.Error;
|
|
2093
|
+
logTimelineItem.statusMessage = `Microsoft Teams message not sent because the Microsoft Teams account is not verified.`;
|
|
2094
|
+
logTimelineItem.userMicrosoftTeamsId =
|
|
2095
|
+
notificationRuleItem.userMicrosoftTeams.id!;
|
|
2096
|
+
|
|
2097
|
+
await UserOnCallLogTimelineService.create({
|
|
2098
|
+
data: logTimelineItem,
|
|
2099
|
+
props: {
|
|
2100
|
+
isRoot: true,
|
|
2101
|
+
},
|
|
2102
|
+
});
|
|
2103
|
+
}
|
|
2104
|
+
|
|
1990
2105
|
// send webhook.
|
|
1991
2106
|
if (notificationRuleItem.userWebhook?.webhookUrl) {
|
|
1992
2107
|
const webhookUrl: string = notificationRuleItem.userWebhook.webhookUrl;
|
|
@@ -2819,6 +2934,191 @@ export class Service extends DatabaseService<Model> {
|
|
|
2819
2934
|
return deliveryAttempted;
|
|
2820
2935
|
}
|
|
2821
2936
|
|
|
2937
|
+
/*
|
|
2938
|
+
* The Slack and Microsoft Teams halves of deliverNotificationForRule. Both
|
|
2939
|
+
* channels deliver the same way — the same generated message blocks handed
|
|
2940
|
+
* to the same direct-message sender, with only the workspace type and the
|
|
2941
|
+
* timeline method column differing — so one helper carries both instead of
|
|
2942
|
+
* two more copies of the per-event ladder above.
|
|
2943
|
+
*
|
|
2944
|
+
* Returns whether a delivery was attempted. `false` means this event type
|
|
2945
|
+
* has no workspace template, and the caller's fell-through guard turns that
|
|
2946
|
+
* into a loud Error row rather than a silent nothing.
|
|
2947
|
+
*/
|
|
2948
|
+
private async deliverWorkspaceDirectMessageForRule(data: {
|
|
2949
|
+
workspaceType: WorkspaceType;
|
|
2950
|
+
methodId: ObjectID;
|
|
2951
|
+
workspaceUserId: string;
|
|
2952
|
+
notificationRuleItem: Model;
|
|
2953
|
+
options: ExecuteNotificationRuleOptions;
|
|
2954
|
+
logTimelineItem: UserOnCallLogTimeline;
|
|
2955
|
+
incident: Incident | null;
|
|
2956
|
+
alert: Alert | null;
|
|
2957
|
+
alertEpisode: AlertEpisode | null;
|
|
2958
|
+
incidentEpisode: IncidentEpisode | null;
|
|
2959
|
+
}): Promise<boolean> {
|
|
2960
|
+
const channelDisplayName: string = getWorkspaceTypeDisplayName(
|
|
2961
|
+
data.workspaceType,
|
|
2962
|
+
);
|
|
2963
|
+
const options: ExecuteNotificationRuleOptions = data.options;
|
|
2964
|
+
|
|
2965
|
+
/*
|
|
2966
|
+
* Resolve the event into the entity being paged about, the block
|
|
2967
|
+
* generator for it, and the ids the send should be correlated with. The
|
|
2968
|
+
* generator is deferred because the message embeds the timeline row id,
|
|
2969
|
+
* which does not exist until the row below is created.
|
|
2970
|
+
*/
|
|
2971
|
+
let entityProjectId: ObjectID | undefined = undefined;
|
|
2972
|
+
let incidentId: ObjectID | undefined = undefined;
|
|
2973
|
+
let alertId: ObjectID | undefined = undefined;
|
|
2974
|
+
let alertEpisodeId: ObjectID | undefined = undefined;
|
|
2975
|
+
let incidentEpisodeId: ObjectID | undefined = undefined;
|
|
2976
|
+
let generateBlocks:
|
|
2977
|
+
| ((timelineId: ObjectID) => Promise<Array<WorkspaceMessageBlock>>)
|
|
2978
|
+
| null = null;
|
|
2979
|
+
let messageSummary: string = "";
|
|
2980
|
+
|
|
2981
|
+
if (
|
|
2982
|
+
options.userNotificationEventType ===
|
|
2983
|
+
UserNotificationEventType.IncidentCreated &&
|
|
2984
|
+
data.incident
|
|
2985
|
+
) {
|
|
2986
|
+
const incident: Incident = data.incident;
|
|
2987
|
+
entityProjectId = incident.projectId;
|
|
2988
|
+
incidentId = incident.id!;
|
|
2989
|
+
messageSummary = `On-call notification: incident created.`;
|
|
2990
|
+
generateBlocks = (
|
|
2991
|
+
timelineId: ObjectID,
|
|
2992
|
+
): Promise<Array<WorkspaceMessageBlock>> => {
|
|
2993
|
+
return this.generateWorkspaceMessageBlocksForIncidentCreated(
|
|
2994
|
+
incident,
|
|
2995
|
+
timelineId,
|
|
2996
|
+
);
|
|
2997
|
+
};
|
|
2998
|
+
}
|
|
2999
|
+
|
|
3000
|
+
if (
|
|
3001
|
+
options.userNotificationEventType ===
|
|
3002
|
+
UserNotificationEventType.AlertCreated &&
|
|
3003
|
+
data.alert
|
|
3004
|
+
) {
|
|
3005
|
+
const alert: Alert = data.alert;
|
|
3006
|
+
entityProjectId = alert.projectId;
|
|
3007
|
+
alertId = alert.id!;
|
|
3008
|
+
messageSummary = `On-call notification: alert created.`;
|
|
3009
|
+
generateBlocks = (
|
|
3010
|
+
timelineId: ObjectID,
|
|
3011
|
+
): Promise<Array<WorkspaceMessageBlock>> => {
|
|
3012
|
+
return this.generateWorkspaceMessageBlocksForAlertCreated(
|
|
3013
|
+
alert,
|
|
3014
|
+
timelineId,
|
|
3015
|
+
);
|
|
3016
|
+
};
|
|
3017
|
+
}
|
|
3018
|
+
|
|
3019
|
+
if (
|
|
3020
|
+
options.userNotificationEventType ===
|
|
3021
|
+
UserNotificationEventType.AlertEpisodeCreated &&
|
|
3022
|
+
data.alertEpisode
|
|
3023
|
+
) {
|
|
3024
|
+
const alertEpisode: AlertEpisode = data.alertEpisode;
|
|
3025
|
+
entityProjectId = alertEpisode.projectId;
|
|
3026
|
+
alertEpisodeId = alertEpisode.id!;
|
|
3027
|
+
messageSummary = `On-call notification: alert episode created.`;
|
|
3028
|
+
generateBlocks = (
|
|
3029
|
+
timelineId: ObjectID,
|
|
3030
|
+
): Promise<Array<WorkspaceMessageBlock>> => {
|
|
3031
|
+
return this.generateWorkspaceMessageBlocksForAlertEpisodeCreated(
|
|
3032
|
+
alertEpisode,
|
|
3033
|
+
timelineId,
|
|
3034
|
+
);
|
|
3035
|
+
};
|
|
3036
|
+
}
|
|
3037
|
+
|
|
3038
|
+
if (
|
|
3039
|
+
options.userNotificationEventType ===
|
|
3040
|
+
UserNotificationEventType.IncidentEpisodeCreated &&
|
|
3041
|
+
data.incidentEpisode
|
|
3042
|
+
) {
|
|
3043
|
+
const incidentEpisode: IncidentEpisode = data.incidentEpisode;
|
|
3044
|
+
entityProjectId = incidentEpisode.projectId;
|
|
3045
|
+
incidentEpisodeId = incidentEpisode.id!;
|
|
3046
|
+
messageSummary = `On-call notification: incident episode created.`;
|
|
3047
|
+
generateBlocks = (
|
|
3048
|
+
timelineId: ObjectID,
|
|
3049
|
+
): Promise<Array<WorkspaceMessageBlock>> => {
|
|
3050
|
+
return this.generateWorkspaceMessageBlocksForIncidentEpisodeCreated(
|
|
3051
|
+
incidentEpisode,
|
|
3052
|
+
timelineId,
|
|
3053
|
+
);
|
|
3054
|
+
};
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
if (!generateBlocks) {
|
|
3058
|
+
return false;
|
|
3059
|
+
}
|
|
3060
|
+
|
|
3061
|
+
data.logTimelineItem.status = UserNotificationStatus.Sending;
|
|
3062
|
+
data.logTimelineItem.statusMessage = `Sending ${channelDisplayName} message.`;
|
|
3063
|
+
|
|
3064
|
+
if (data.workspaceType === WorkspaceType.Slack) {
|
|
3065
|
+
data.logTimelineItem.userSlackId = data.methodId;
|
|
3066
|
+
}
|
|
3067
|
+
|
|
3068
|
+
if (data.workspaceType === WorkspaceType.MicrosoftTeams) {
|
|
3069
|
+
data.logTimelineItem.userMicrosoftTeamsId = data.methodId;
|
|
3070
|
+
}
|
|
3071
|
+
|
|
3072
|
+
const updatedLog: UserOnCallLogTimeline =
|
|
3073
|
+
await UserOnCallLogTimelineService.create({
|
|
3074
|
+
data: data.logTimelineItem,
|
|
3075
|
+
props: {
|
|
3076
|
+
isRoot: true,
|
|
3077
|
+
},
|
|
3078
|
+
});
|
|
3079
|
+
|
|
3080
|
+
const messageBlocks: Array<WorkspaceMessageBlock> = await generateBlocks(
|
|
3081
|
+
updatedLog.id!,
|
|
3082
|
+
);
|
|
3083
|
+
|
|
3084
|
+
/*
|
|
3085
|
+
* Fire-and-forget like every other channel: the sender flips the timeline
|
|
3086
|
+
* row to Sent / Error itself, and the .catch is the safety net for a
|
|
3087
|
+
* rejection raised before it gets that far.
|
|
3088
|
+
*/
|
|
3089
|
+
WorkspaceUserNotificationService.sendDirectMessageToUser({
|
|
3090
|
+
projectId: entityProjectId || options.projectId,
|
|
3091
|
+
workspaceType: data.workspaceType,
|
|
3092
|
+
workspaceUserId: data.workspaceUserId,
|
|
3093
|
+
messageBlocks: messageBlocks,
|
|
3094
|
+
messageSummary: messageSummary,
|
|
3095
|
+
userId: data.notificationRuleItem.userId!,
|
|
3096
|
+
userOnCallLogTimelineId: updatedLog.id!,
|
|
3097
|
+
incidentId: incidentId,
|
|
3098
|
+
alertId: alertId,
|
|
3099
|
+
alertEpisodeId: alertEpisodeId,
|
|
3100
|
+
incidentEpisodeId: incidentEpisodeId,
|
|
3101
|
+
onCallPolicyId: options.onCallPolicyId,
|
|
3102
|
+
onCallPolicyEscalationRuleId: options.onCallPolicyEscalationRuleId,
|
|
3103
|
+
teamId: options.userBelongsToTeamId,
|
|
3104
|
+
onCallScheduleId: options.onCallScheduleId,
|
|
3105
|
+
}).catch(async (err: Error) => {
|
|
3106
|
+
await UserOnCallLogTimelineService.updateOneById({
|
|
3107
|
+
id: updatedLog.id!,
|
|
3108
|
+
data: {
|
|
3109
|
+
status: UserNotificationStatus.Error,
|
|
3110
|
+
statusMessage:
|
|
3111
|
+
err.message || `Error sending ${channelDisplayName} message.`,
|
|
3112
|
+
},
|
|
3113
|
+
props: {
|
|
3114
|
+
isRoot: true,
|
|
3115
|
+
},
|
|
3116
|
+
});
|
|
3117
|
+
});
|
|
3118
|
+
|
|
3119
|
+
return true;
|
|
3120
|
+
}
|
|
3121
|
+
|
|
2822
3122
|
/*
|
|
2823
3123
|
* The channels this rule could actually reach the user on, by display name.
|
|
2824
3124
|
*
|
|
@@ -2861,6 +3161,20 @@ export class Service extends DatabaseService<Model> {
|
|
|
2861
3161
|
channels.push("Telegram");
|
|
2862
3162
|
}
|
|
2863
3163
|
|
|
3164
|
+
if (
|
|
3165
|
+
notificationRuleItem.userSlack?.slackUserId &&
|
|
3166
|
+
notificationRuleItem.userSlack?.isVerified
|
|
3167
|
+
) {
|
|
3168
|
+
channels.push("Slack");
|
|
3169
|
+
}
|
|
3170
|
+
|
|
3171
|
+
if (
|
|
3172
|
+
notificationRuleItem.userMicrosoftTeams?.microsoftTeamsUserId &&
|
|
3173
|
+
notificationRuleItem.userMicrosoftTeams?.isVerified
|
|
3174
|
+
) {
|
|
3175
|
+
channels.push("Microsoft Teams");
|
|
3176
|
+
}
|
|
3177
|
+
|
|
2864
3178
|
if (notificationRuleItem.userWebhook?.webhookUrl) {
|
|
2865
3179
|
channels.push("Webhook");
|
|
2866
3180
|
}
|
|
@@ -3021,10 +3335,11 @@ export class Service extends DatabaseService<Model> {
|
|
|
3021
3335
|
/*
|
|
3022
3336
|
* Pick what to page the user on, and build an unsaved rule for each choice.
|
|
3023
3337
|
*
|
|
3024
|
-
* Zero-cost channels win: push
|
|
3025
|
-
* and no billing surprise, and there is no reason
|
|
3026
|
-
* user who has
|
|
3027
|
-
* and then just once, in
|
|
3338
|
+
* Zero-cost channels win: push, email, Slack and Microsoft Teams reach the
|
|
3339
|
+
* most people for no money and no billing surprise, and there is no reason
|
|
3340
|
+
* to pick between them, so a user who has several gets all of them. Only a
|
|
3341
|
+
* user with none of these is worth spending on, and then just once, in
|
|
3342
|
+
* escalating-intrusiveness order.
|
|
3028
3343
|
*
|
|
3029
3344
|
* Paid channels are additionally gated on the project's own enable flags.
|
|
3030
3345
|
* SmsService and CallService enforce those at send time, but WhatsApp and
|
|
@@ -3083,6 +3398,55 @@ export class Service extends DatabaseService<Model> {
|
|
|
3083
3398
|
chosen.push({ channelName: "Email", rule: rule });
|
|
3084
3399
|
}
|
|
3085
3400
|
|
|
3401
|
+
const userSlack: UserSlack | null = await UserSlackService.findOneBy({
|
|
3402
|
+
query: {
|
|
3403
|
+
projectId: options.projectId,
|
|
3404
|
+
userId: options.userId,
|
|
3405
|
+
isVerified: true,
|
|
3406
|
+
},
|
|
3407
|
+
select: {
|
|
3408
|
+
_id: true,
|
|
3409
|
+
slackUserId: true,
|
|
3410
|
+
slackUserName: true,
|
|
3411
|
+
isVerified: true,
|
|
3412
|
+
},
|
|
3413
|
+
props: {
|
|
3414
|
+
isRoot: true,
|
|
3415
|
+
},
|
|
3416
|
+
});
|
|
3417
|
+
|
|
3418
|
+
if (userSlack) {
|
|
3419
|
+
const rule: Model = this.buildUnsavedFallbackRule(options);
|
|
3420
|
+
rule.userSlack = userSlack;
|
|
3421
|
+
rule.userSlackId = userSlack.id!;
|
|
3422
|
+
chosen.push({ channelName: "Slack", rule: rule });
|
|
3423
|
+
}
|
|
3424
|
+
|
|
3425
|
+
const userMicrosoftTeams: UserMicrosoftTeams | null =
|
|
3426
|
+
await UserMicrosoftTeamsService.findOneBy({
|
|
3427
|
+
query: {
|
|
3428
|
+
projectId: options.projectId,
|
|
3429
|
+
userId: options.userId,
|
|
3430
|
+
isVerified: true,
|
|
3431
|
+
},
|
|
3432
|
+
select: {
|
|
3433
|
+
_id: true,
|
|
3434
|
+
microsoftTeamsUserId: true,
|
|
3435
|
+
microsoftTeamsUserName: true,
|
|
3436
|
+
isVerified: true,
|
|
3437
|
+
},
|
|
3438
|
+
props: {
|
|
3439
|
+
isRoot: true,
|
|
3440
|
+
},
|
|
3441
|
+
});
|
|
3442
|
+
|
|
3443
|
+
if (userMicrosoftTeams) {
|
|
3444
|
+
const rule: Model = this.buildUnsavedFallbackRule(options);
|
|
3445
|
+
rule.userMicrosoftTeams = userMicrosoftTeams;
|
|
3446
|
+
rule.userMicrosoftTeamsId = userMicrosoftTeams.id!;
|
|
3447
|
+
chosen.push({ channelName: "Microsoft Teams", rule: rule });
|
|
3448
|
+
}
|
|
3449
|
+
|
|
3086
3450
|
if (chosen.length > 0) {
|
|
3087
3451
|
return chosen;
|
|
3088
3452
|
}
|
|
@@ -3809,6 +4173,180 @@ export class Service extends DatabaseService<Model> {
|
|
|
3809
4173
|
return lines.join("\n");
|
|
3810
4174
|
}
|
|
3811
4175
|
|
|
4176
|
+
/*
|
|
4177
|
+
* ---------------------------------------------------------------------- *
|
|
4178
|
+
* Workspace (Slack / Microsoft Teams) direct-message generators.
|
|
4179
|
+
*
|
|
4180
|
+
* One generator family serves BOTH workspace channels: the blocks are
|
|
4181
|
+
* written in standard markdown, which SlackUtil slackifies and
|
|
4182
|
+
* MicrosoftTeamsUtil renders into an adaptive card. Keep them to the block
|
|
4183
|
+
* types both platforms implement (markdown / header / divider / buttons) —
|
|
4184
|
+
* anything else throws NotImplementedException on Teams.
|
|
4185
|
+
* ---------------------------------------------------------------------- *
|
|
4186
|
+
*/
|
|
4187
|
+
|
|
4188
|
+
private buildWorkspaceMessageBlocks(data: {
|
|
4189
|
+
headline: string;
|
|
4190
|
+
identifier: string;
|
|
4191
|
+
dashboardUrl: URL | null;
|
|
4192
|
+
dashboardLinkText: string;
|
|
4193
|
+
ackUrl: URL;
|
|
4194
|
+
}): Array<WorkspaceMessageBlock> {
|
|
4195
|
+
const lines: Array<string> = [
|
|
4196
|
+
`🚨 **${data.headline}**`,
|
|
4197
|
+
"",
|
|
4198
|
+
`📋 **${data.identifier}**`,
|
|
4199
|
+
"",
|
|
4200
|
+
"👤 You're getting this because you're on call.",
|
|
4201
|
+
];
|
|
4202
|
+
|
|
4203
|
+
if (data.dashboardUrl) {
|
|
4204
|
+
lines.push(
|
|
4205
|
+
"",
|
|
4206
|
+
`🔎 [${data.dashboardLinkText}](${data.dashboardUrl.toString()})`,
|
|
4207
|
+
);
|
|
4208
|
+
}
|
|
4209
|
+
|
|
4210
|
+
lines.push("", `✅ [Acknowledge](${data.ackUrl.toString()})`);
|
|
4211
|
+
|
|
4212
|
+
const markdownBlock: WorkspacePayloadMarkdown = {
|
|
4213
|
+
_type: "WorkspacePayloadMarkdown",
|
|
4214
|
+
text: lines.join("\n"),
|
|
4215
|
+
};
|
|
4216
|
+
|
|
4217
|
+
return [markdownBlock];
|
|
4218
|
+
}
|
|
4219
|
+
|
|
4220
|
+
@CaptureSpan()
|
|
4221
|
+
public async generateWorkspaceMessageBlocksForAlertCreated(
|
|
4222
|
+
alert: Alert,
|
|
4223
|
+
userOnCallLogTimelineId: ObjectID,
|
|
4224
|
+
): Promise<Array<WorkspaceMessageBlock>> {
|
|
4225
|
+
const ackUrl: URL = await this.buildOnCallAcknowledgeShortUrl(
|
|
4226
|
+
userOnCallLogTimelineId,
|
|
4227
|
+
);
|
|
4228
|
+
|
|
4229
|
+
const alertIdentifier: string =
|
|
4230
|
+
alert.alertNumber !== undefined
|
|
4231
|
+
? `${alert.alertNumberWithPrefix || "#" + alert.alertNumber} — ${alert.title || "Alert"}`
|
|
4232
|
+
: alert.title || "Alert";
|
|
4233
|
+
|
|
4234
|
+
let dashboardUrl: URL | null = null;
|
|
4235
|
+
|
|
4236
|
+
if (alert.projectId && alert.id) {
|
|
4237
|
+
dashboardUrl = await AlertService.getAlertLinkInDashboard(
|
|
4238
|
+
alert.projectId,
|
|
4239
|
+
alert.id,
|
|
4240
|
+
);
|
|
4241
|
+
}
|
|
4242
|
+
|
|
4243
|
+
return this.buildWorkspaceMessageBlocks({
|
|
4244
|
+
headline: "New alert assigned to you",
|
|
4245
|
+
identifier: alertIdentifier,
|
|
4246
|
+
dashboardUrl: dashboardUrl,
|
|
4247
|
+
dashboardLinkText: "View alert in OneUptime",
|
|
4248
|
+
ackUrl: ackUrl,
|
|
4249
|
+
});
|
|
4250
|
+
}
|
|
4251
|
+
|
|
4252
|
+
@CaptureSpan()
|
|
4253
|
+
public async generateWorkspaceMessageBlocksForIncidentCreated(
|
|
4254
|
+
incident: Incident,
|
|
4255
|
+
userOnCallLogTimelineId: ObjectID,
|
|
4256
|
+
): Promise<Array<WorkspaceMessageBlock>> {
|
|
4257
|
+
const ackUrl: URL = await this.buildOnCallAcknowledgeShortUrl(
|
|
4258
|
+
userOnCallLogTimelineId,
|
|
4259
|
+
);
|
|
4260
|
+
|
|
4261
|
+
const incidentIdentifier: string =
|
|
4262
|
+
incident.incidentNumber !== undefined
|
|
4263
|
+
? `${incident.incidentNumberWithPrefix || "#" + incident.incidentNumber} — ${incident.title || "Incident"}`
|
|
4264
|
+
: incident.title || "Incident";
|
|
4265
|
+
|
|
4266
|
+
let dashboardUrl: URL | null = null;
|
|
4267
|
+
|
|
4268
|
+
if (incident.projectId && incident.id) {
|
|
4269
|
+
dashboardUrl = await IncidentService.getIncidentLinkInDashboard(
|
|
4270
|
+
incident.projectId,
|
|
4271
|
+
incident.id,
|
|
4272
|
+
);
|
|
4273
|
+
}
|
|
4274
|
+
|
|
4275
|
+
return this.buildWorkspaceMessageBlocks({
|
|
4276
|
+
headline: "New incident assigned to you",
|
|
4277
|
+
identifier: incidentIdentifier,
|
|
4278
|
+
dashboardUrl: dashboardUrl,
|
|
4279
|
+
dashboardLinkText: "View incident in OneUptime",
|
|
4280
|
+
ackUrl: ackUrl,
|
|
4281
|
+
});
|
|
4282
|
+
}
|
|
4283
|
+
|
|
4284
|
+
@CaptureSpan()
|
|
4285
|
+
public async generateWorkspaceMessageBlocksForAlertEpisodeCreated(
|
|
4286
|
+
alertEpisode: AlertEpisode,
|
|
4287
|
+
userOnCallLogTimelineId: ObjectID,
|
|
4288
|
+
): Promise<Array<WorkspaceMessageBlock>> {
|
|
4289
|
+
const ackUrl: URL = await this.buildOnCallAcknowledgeShortUrl(
|
|
4290
|
+
userOnCallLogTimelineId,
|
|
4291
|
+
);
|
|
4292
|
+
|
|
4293
|
+
const episodeIdentifier: string = alertEpisode.episodeNumberWithPrefix
|
|
4294
|
+
? `${alertEpisode.episodeNumberWithPrefix} — ${alertEpisode.title || "Alert Episode"}`
|
|
4295
|
+
: alertEpisode.episodeNumber !== undefined
|
|
4296
|
+
? `#${alertEpisode.episodeNumber} — ${alertEpisode.title || "Alert Episode"}`
|
|
4297
|
+
: alertEpisode.title || "Alert Episode";
|
|
4298
|
+
|
|
4299
|
+
let dashboardUrl: URL | null = null;
|
|
4300
|
+
|
|
4301
|
+
if (alertEpisode.projectId && alertEpisode.id) {
|
|
4302
|
+
dashboardUrl = await AlertEpisodeService.getEpisodeLinkInDashboard(
|
|
4303
|
+
alertEpisode.projectId,
|
|
4304
|
+
alertEpisode.id,
|
|
4305
|
+
);
|
|
4306
|
+
}
|
|
4307
|
+
|
|
4308
|
+
return this.buildWorkspaceMessageBlocks({
|
|
4309
|
+
headline: "New alert episode assigned to you",
|
|
4310
|
+
identifier: episodeIdentifier,
|
|
4311
|
+
dashboardUrl: dashboardUrl,
|
|
4312
|
+
dashboardLinkText: "View alert episode in OneUptime",
|
|
4313
|
+
ackUrl: ackUrl,
|
|
4314
|
+
});
|
|
4315
|
+
}
|
|
4316
|
+
|
|
4317
|
+
@CaptureSpan()
|
|
4318
|
+
public async generateWorkspaceMessageBlocksForIncidentEpisodeCreated(
|
|
4319
|
+
incidentEpisode: IncidentEpisode,
|
|
4320
|
+
userOnCallLogTimelineId: ObjectID,
|
|
4321
|
+
): Promise<Array<WorkspaceMessageBlock>> {
|
|
4322
|
+
const ackUrl: URL = await this.buildOnCallAcknowledgeShortUrl(
|
|
4323
|
+
userOnCallLogTimelineId,
|
|
4324
|
+
);
|
|
4325
|
+
|
|
4326
|
+
const episodeIdentifier: string = incidentEpisode.episodeNumberWithPrefix
|
|
4327
|
+
? `${incidentEpisode.episodeNumberWithPrefix} — ${incidentEpisode.title || "Incident Episode"}`
|
|
4328
|
+
: incidentEpisode.episodeNumber !== undefined
|
|
4329
|
+
? `#${incidentEpisode.episodeNumber} — ${incidentEpisode.title || "Incident Episode"}`
|
|
4330
|
+
: incidentEpisode.title || "Incident Episode";
|
|
4331
|
+
|
|
4332
|
+
let dashboardUrl: URL | null = null;
|
|
4333
|
+
|
|
4334
|
+
if (incidentEpisode.projectId && incidentEpisode.id) {
|
|
4335
|
+
dashboardUrl = await IncidentEpisodeService.getEpisodeLinkInDashboard(
|
|
4336
|
+
incidentEpisode.projectId,
|
|
4337
|
+
incidentEpisode.id,
|
|
4338
|
+
);
|
|
4339
|
+
}
|
|
4340
|
+
|
|
4341
|
+
return this.buildWorkspaceMessageBlocks({
|
|
4342
|
+
headline: "New incident episode assigned to you",
|
|
4343
|
+
identifier: episodeIdentifier,
|
|
4344
|
+
dashboardUrl: dashboardUrl,
|
|
4345
|
+
dashboardLinkText: "View incident episode in OneUptime",
|
|
4346
|
+
ackUrl: ackUrl,
|
|
4347
|
+
});
|
|
4348
|
+
}
|
|
4349
|
+
|
|
3812
4350
|
@CaptureSpan()
|
|
3813
4351
|
public async generateWhatsAppTemplateForAlertCreated(
|
|
3814
4352
|
to: Phone,
|
|
@@ -4722,7 +5260,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
4722
5260
|
|
|
4723
5261
|
if (!data.isOptOut && !data.hasNotificationMethod) {
|
|
4724
5262
|
throw new BadDataException(
|
|
4725
|
-
"Call, SMS, WhatsApp, Telegram, Webhook, Email, or Push notification is required",
|
|
5263
|
+
"Call, SMS, WhatsApp, Telegram, Slack, Microsoft Teams, Webhook, Email, or Push notification is required",
|
|
4726
5264
|
);
|
|
4727
5265
|
}
|
|
4728
5266
|
}
|
|
@@ -5021,6 +5559,8 @@ export class Service extends DatabaseService<Model> {
|
|
|
5021
5559
|
userCallId: true,
|
|
5022
5560
|
userWhatsAppId: true,
|
|
5023
5561
|
userTelegramId: true,
|
|
5562
|
+
userSlackId: true,
|
|
5563
|
+
userMicrosoftTeamsId: true,
|
|
5024
5564
|
userPushId: true,
|
|
5025
5565
|
userWebhookId: true,
|
|
5026
5566
|
},
|
|
@@ -5274,6 +5814,8 @@ export class Service extends DatabaseService<Model> {
|
|
|
5274
5814
|
userCallId: true,
|
|
5275
5815
|
userWhatsAppId: true,
|
|
5276
5816
|
userTelegramId: true,
|
|
5817
|
+
userSlackId: true,
|
|
5818
|
+
userMicrosoftTeamsId: true,
|
|
5277
5819
|
userPushId: true,
|
|
5278
5820
|
userWebhookId: true,
|
|
5279
5821
|
},
|
|
@@ -5439,6 +5981,12 @@ export class Service extends DatabaseService<Model> {
|
|
|
5439
5981
|
if (descriptor.userTelegramId) {
|
|
5440
5982
|
rule.userTelegramId = descriptor.userTelegramId;
|
|
5441
5983
|
}
|
|
5984
|
+
if (descriptor.userSlackId) {
|
|
5985
|
+
rule.userSlackId = descriptor.userSlackId;
|
|
5986
|
+
}
|
|
5987
|
+
if (descriptor.userMicrosoftTeamsId) {
|
|
5988
|
+
rule.userMicrosoftTeamsId = descriptor.userMicrosoftTeamsId;
|
|
5989
|
+
}
|
|
5442
5990
|
if (descriptor.userWebhookId) {
|
|
5443
5991
|
rule.userWebhookId = descriptor.userWebhookId;
|
|
5444
5992
|
}
|
|
@@ -5466,6 +6014,12 @@ export class Service extends DatabaseService<Model> {
|
|
|
5466
6014
|
if (descriptor.userTelegramId) {
|
|
5467
6015
|
query["userTelegramId"] = descriptor.userTelegramId;
|
|
5468
6016
|
}
|
|
6017
|
+
if (descriptor.userSlackId) {
|
|
6018
|
+
query["userSlackId"] = descriptor.userSlackId;
|
|
6019
|
+
}
|
|
6020
|
+
if (descriptor.userMicrosoftTeamsId) {
|
|
6021
|
+
query["userMicrosoftTeamsId"] = descriptor.userMicrosoftTeamsId;
|
|
6022
|
+
}
|
|
5469
6023
|
if (descriptor.userWebhookId) {
|
|
5470
6024
|
query["userWebhookId"] = descriptor.userWebhookId;
|
|
5471
6025
|
}
|
|
@@ -5834,6 +6388,20 @@ export class Service extends DatabaseService<Model> {
|
|
|
5834
6388
|
props: props,
|
|
5835
6389
|
});
|
|
5836
6390
|
isVerified = Boolean(row?.isVerified);
|
|
6391
|
+
} else if (data.methodType === ReadinessMethodType.Slack) {
|
|
6392
|
+
row = await UserSlackService.findOneBy({
|
|
6393
|
+
query: query,
|
|
6394
|
+
select: { _id: true, userId: true, isVerified: true },
|
|
6395
|
+
props: props,
|
|
6396
|
+
});
|
|
6397
|
+
isVerified = Boolean(row?.isVerified);
|
|
6398
|
+
} else if (data.methodType === ReadinessMethodType.MicrosoftTeams) {
|
|
6399
|
+
row = await UserMicrosoftTeamsService.findOneBy({
|
|
6400
|
+
query: query,
|
|
6401
|
+
select: { _id: true, userId: true, isVerified: true },
|
|
6402
|
+
props: props,
|
|
6403
|
+
});
|
|
6404
|
+
isVerified = Boolean(row?.isVerified);
|
|
5837
6405
|
} else if (data.methodType === ReadinessMethodType.Webhook) {
|
|
5838
6406
|
row = await UserWebhookService.findOneBy({
|
|
5839
6407
|
query: query,
|
|
@@ -5893,6 +6461,14 @@ export class Service extends DatabaseService<Model> {
|
|
|
5893
6461
|
return rule.userTelegramId;
|
|
5894
6462
|
}
|
|
5895
6463
|
|
|
6464
|
+
if (methodType === ReadinessMethodType.Slack) {
|
|
6465
|
+
return rule.userSlackId;
|
|
6466
|
+
}
|
|
6467
|
+
|
|
6468
|
+
if (methodType === ReadinessMethodType.MicrosoftTeams) {
|
|
6469
|
+
return rule.userMicrosoftTeamsId;
|
|
6470
|
+
}
|
|
6471
|
+
|
|
5896
6472
|
if (methodType === ReadinessMethodType.Webhook) {
|
|
5897
6473
|
return rule.userWebhookId;
|
|
5898
6474
|
}
|
|
@@ -6227,6 +6803,8 @@ export class Service extends DatabaseService<Model> {
|
|
|
6227
6803
|
userPushId: true,
|
|
6228
6804
|
userWhatsAppId: true,
|
|
6229
6805
|
userTelegramId: true,
|
|
6806
|
+
userSlackId: true,
|
|
6807
|
+
userMicrosoftTeamsId: true,
|
|
6230
6808
|
userWebhookId: true,
|
|
6231
6809
|
},
|
|
6232
6810
|
sort: {
|