@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
|
@@ -13,10 +13,13 @@ import UserEmailService from "./UserEmailService";
|
|
|
13
13
|
import UserSmsService from "./UserSmsService";
|
|
14
14
|
import PushNotificationService from "./PushNotificationService";
|
|
15
15
|
import UserTelegramService from "./UserTelegramService";
|
|
16
|
+
import UserSlackService from "./UserSlackService";
|
|
17
|
+
import UserMicrosoftTeamsService from "./UserMicrosoftTeamsService";
|
|
16
18
|
import UserWebhookService from "./UserWebhookService";
|
|
17
19
|
import UserWhatsAppService from "./UserWhatsAppService";
|
|
18
20
|
import WebhookService from "./WebhookService";
|
|
19
21
|
import WhatsAppService from "./WhatsAppService";
|
|
22
|
+
import WorkspaceUserNotificationService from "./WorkspaceUserNotificationService";
|
|
20
23
|
import { CallRequestMessage } from "../../Types/Call/CallRequest";
|
|
21
24
|
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
22
25
|
import { EmailEnvelope } from "../../Types/Email/EmailMessage";
|
|
@@ -39,8 +42,15 @@ import UserEmail from "../../Models/DatabaseModels/UserEmail";
|
|
|
39
42
|
import UserNotificationSetting from "../../Models/DatabaseModels/UserNotificationSetting";
|
|
40
43
|
import UserSMS from "../../Models/DatabaseModels/UserSMS";
|
|
41
44
|
import UserTelegram from "../../Models/DatabaseModels/UserTelegram";
|
|
45
|
+
import UserSlack from "../../Models/DatabaseModels/UserSlack";
|
|
46
|
+
import UserMicrosoftTeams from "../../Models/DatabaseModels/UserMicrosoftTeams";
|
|
42
47
|
import UserWebhook from "../../Models/DatabaseModels/UserWebhook";
|
|
43
48
|
import UserWhatsApp from "../../Models/DatabaseModels/UserWhatsApp";
|
|
49
|
+
import WorkspaceType from "../../Types/Workspace/WorkspaceType";
|
|
50
|
+
import {
|
|
51
|
+
WorkspaceMessageBlock,
|
|
52
|
+
WorkspacePayloadMarkdown,
|
|
53
|
+
} from "../../Types/Workspace/WorkspaceMessagePayload";
|
|
44
54
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
45
55
|
import { appendRecipientToWhatsAppMessage } from "../Utils/WhatsAppTemplateUtil";
|
|
46
56
|
|
|
@@ -93,6 +103,8 @@ export class Service extends DatabaseService<UserNotificationSetting> {
|
|
|
93
103
|
alertBySMS: true,
|
|
94
104
|
alertByWhatsApp: true,
|
|
95
105
|
alertByTelegram: true,
|
|
106
|
+
alertBySlack: true,
|
|
107
|
+
alertByMicrosoftTeams: true,
|
|
96
108
|
alertByCall: true,
|
|
97
109
|
alertByPush: true,
|
|
98
110
|
alertByWebhook: true,
|
|
@@ -370,6 +382,132 @@ export class Service extends DatabaseService<UserNotificationSetting> {
|
|
|
370
382
|
}
|
|
371
383
|
}
|
|
372
384
|
|
|
385
|
+
if (
|
|
386
|
+
notificationSettings.alertBySlack ||
|
|
387
|
+
notificationSettings.alertByMicrosoftTeams
|
|
388
|
+
) {
|
|
389
|
+
/*
|
|
390
|
+
* Slack and Microsoft Teams share one derived message: callers hand
|
|
391
|
+
* this method channel payloads for the older channels only, so the
|
|
392
|
+
* workspace body is synthesised from the email subject + SMS body the
|
|
393
|
+
* same way the Telegram fallback body is. Standard markdown — Slack
|
|
394
|
+
* slackifies it and Teams renders it into an adaptive card.
|
|
395
|
+
*/
|
|
396
|
+
const subject: string = data.emailEnvelope.subject || "";
|
|
397
|
+
const smsBody: string = data.smsMessage.message || "";
|
|
398
|
+
|
|
399
|
+
let workspaceMarkdown: string = "";
|
|
400
|
+
|
|
401
|
+
if (subject || smsBody) {
|
|
402
|
+
const lines: Array<string> = [];
|
|
403
|
+
lines.push(`🔔 **${subject || "OneUptime notification"}**`);
|
|
404
|
+
if (smsBody) {
|
|
405
|
+
lines.push("");
|
|
406
|
+
lines.push(smsBody);
|
|
407
|
+
}
|
|
408
|
+
workspaceMarkdown = lines.join("\n");
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (!workspaceMarkdown) {
|
|
412
|
+
logger.warn(
|
|
413
|
+
"Skipping workspace notification because message body is empty.",
|
|
414
|
+
);
|
|
415
|
+
} else {
|
|
416
|
+
const markdownBlock: WorkspacePayloadMarkdown = {
|
|
417
|
+
_type: "WorkspacePayloadMarkdown",
|
|
418
|
+
text: workspaceMarkdown,
|
|
419
|
+
};
|
|
420
|
+
const messageBlocks: Array<WorkspaceMessageBlock> = [markdownBlock];
|
|
421
|
+
|
|
422
|
+
if (notificationSettings.alertBySlack) {
|
|
423
|
+
const userSlacks: Array<UserSlack> = await UserSlackService.findBy({
|
|
424
|
+
query: {
|
|
425
|
+
userId: data.userId,
|
|
426
|
+
projectId: data.projectId,
|
|
427
|
+
isVerified: true,
|
|
428
|
+
},
|
|
429
|
+
select: {
|
|
430
|
+
slackUserId: true,
|
|
431
|
+
},
|
|
432
|
+
limit: LIMIT_PER_PROJECT,
|
|
433
|
+
skip: 0,
|
|
434
|
+
props: {
|
|
435
|
+
isRoot: true,
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
for (const userSlack of userSlacks) {
|
|
440
|
+
if (!userSlack.slackUserId) {
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
WorkspaceUserNotificationService.sendDirectMessageToUser({
|
|
445
|
+
projectId: data.projectId,
|
|
446
|
+
workspaceType: WorkspaceType.Slack,
|
|
447
|
+
workspaceUserId: userSlack.slackUserId,
|
|
448
|
+
messageBlocks: messageBlocks,
|
|
449
|
+
messageSummary: subject || smsBody,
|
|
450
|
+
userId: data.userId,
|
|
451
|
+
incidentId: data.incidentId,
|
|
452
|
+
alertId: data.alertId,
|
|
453
|
+
alertEpisodeId: data.alertEpisodeId,
|
|
454
|
+
incidentEpisodeId: data.incidentEpisodeId,
|
|
455
|
+
teamId: data.teamId,
|
|
456
|
+
onCallPolicyId: data.onCallPolicyId,
|
|
457
|
+
onCallPolicyEscalationRuleId: data.onCallPolicyEscalationRuleId,
|
|
458
|
+
onCallScheduleId: data.onCallScheduleId,
|
|
459
|
+
}).catch((err: Error) => {
|
|
460
|
+
logger.error(err);
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (notificationSettings.alertByMicrosoftTeams) {
|
|
466
|
+
const userMicrosoftTeamsAccounts: Array<UserMicrosoftTeams> =
|
|
467
|
+
await UserMicrosoftTeamsService.findBy({
|
|
468
|
+
query: {
|
|
469
|
+
userId: data.userId,
|
|
470
|
+
projectId: data.projectId,
|
|
471
|
+
isVerified: true,
|
|
472
|
+
},
|
|
473
|
+
select: {
|
|
474
|
+
microsoftTeamsUserId: true,
|
|
475
|
+
},
|
|
476
|
+
limit: LIMIT_PER_PROJECT,
|
|
477
|
+
skip: 0,
|
|
478
|
+
props: {
|
|
479
|
+
isRoot: true,
|
|
480
|
+
},
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
for (const userMicrosoftTeams of userMicrosoftTeamsAccounts) {
|
|
484
|
+
if (!userMicrosoftTeams.microsoftTeamsUserId) {
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
WorkspaceUserNotificationService.sendDirectMessageToUser({
|
|
489
|
+
projectId: data.projectId,
|
|
490
|
+
workspaceType: WorkspaceType.MicrosoftTeams,
|
|
491
|
+
workspaceUserId: userMicrosoftTeams.microsoftTeamsUserId,
|
|
492
|
+
messageBlocks: messageBlocks,
|
|
493
|
+
messageSummary: subject || smsBody,
|
|
494
|
+
userId: data.userId,
|
|
495
|
+
incidentId: data.incidentId,
|
|
496
|
+
alertId: data.alertId,
|
|
497
|
+
alertEpisodeId: data.alertEpisodeId,
|
|
498
|
+
incidentEpisodeId: data.incidentEpisodeId,
|
|
499
|
+
teamId: data.teamId,
|
|
500
|
+
onCallPolicyId: data.onCallPolicyId,
|
|
501
|
+
onCallPolicyEscalationRuleId: data.onCallPolicyEscalationRuleId,
|
|
502
|
+
onCallScheduleId: data.onCallScheduleId,
|
|
503
|
+
}).catch((err: Error) => {
|
|
504
|
+
logger.error(err);
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
373
511
|
if (notificationSettings.alertByCall) {
|
|
374
512
|
const userCalls: Array<UserCall> = await UserCallService.findBy({
|
|
375
513
|
query: {
|
|
@@ -42,6 +42,8 @@ import TeamMember from "../../Models/DatabaseModels/TeamMember";
|
|
|
42
42
|
import Model from "../../Models/DatabaseModels/User";
|
|
43
43
|
import SlackUtil from "../Utils/Workspace/Slack/Slack";
|
|
44
44
|
import ProductAnalytics from "../Utils/ProductAnalytics";
|
|
45
|
+
import MarketingEventUtil from "../Utils/Marketing/MarketingEventUtil";
|
|
46
|
+
import { MarketingEventType } from "../../Types/Marketing/MarketingEvent";
|
|
45
47
|
import UserTotpAuthService from "./UserTotpAuthService";
|
|
46
48
|
import UserWebAuthnService from "./UserWebAuthnService";
|
|
47
49
|
import BadDataException from "../../Types/Exception/BadDataException";
|
|
@@ -249,6 +251,32 @@ export class Service extends DatabaseService<Model> {
|
|
|
249
251
|
first_touch: createdItem.firstTouchAttribution || {},
|
|
250
252
|
},
|
|
251
253
|
});
|
|
254
|
+
|
|
255
|
+
/*
|
|
256
|
+
* The outbound sign_up conversion.
|
|
257
|
+
*
|
|
258
|
+
* Emitted here rather than from the register endpoint so a signup
|
|
259
|
+
* reached any other way still counts, and keyed on the user id so a
|
|
260
|
+
* retried delivery cannot become a second conversion.
|
|
261
|
+
*
|
|
262
|
+
* hasPassword separates a direct signup from a user created by a team
|
|
263
|
+
* invite, exactly as the analytics event above does — both are real
|
|
264
|
+
* users, only one is an acquisition, and the receiver decides which it
|
|
265
|
+
* cares about rather than us deciding for it here.
|
|
266
|
+
*/
|
|
267
|
+
MarketingEventUtil.emitInBackground(
|
|
268
|
+
MarketingEventUtil.buildEvent({
|
|
269
|
+
eventType: MarketingEventType.SignUp,
|
|
270
|
+
eventId: `${MarketingEventType.SignUp}:${createdItem.id?.toString()}`,
|
|
271
|
+
occurredAt: createdItem.createdAt || new Date(),
|
|
272
|
+
email: createdItem.email.toString(),
|
|
273
|
+
attributionSource: createdItem,
|
|
274
|
+
data: {
|
|
275
|
+
userId: createdItem.id?.toString() || "",
|
|
276
|
+
hasPassword: Boolean(createdItem.password),
|
|
277
|
+
},
|
|
278
|
+
}),
|
|
279
|
+
);
|
|
252
280
|
}
|
|
253
281
|
|
|
254
282
|
// A place holder method used for overriding.
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import CreateBy from "../Types/Database/CreateBy";
|
|
2
|
+
import DeleteBy from "../Types/Database/DeleteBy";
|
|
3
|
+
import { OnCreate, OnDelete } from "../Types/Database/Hooks";
|
|
4
|
+
import DatabaseService from "./DatabaseService";
|
|
5
|
+
import UserNotificationRuleService, {
|
|
6
|
+
NotificationDeletionImpact,
|
|
7
|
+
NotificationMethodChannel,
|
|
8
|
+
} from "./UserNotificationRuleService";
|
|
9
|
+
import WorkspaceProjectAuthTokenService from "./WorkspaceProjectAuthTokenService";
|
|
10
|
+
import WorkspaceUserAuthTokenService from "./WorkspaceUserAuthTokenService";
|
|
11
|
+
import SlackUtil from "../Utils/Workspace/Slack/Slack";
|
|
12
|
+
import logger from "../Utils/Logger";
|
|
13
|
+
import LIMIT_MAX from "../../Types/Database/LimitMax";
|
|
14
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
15
|
+
import ObjectID from "../../Types/ObjectID";
|
|
16
|
+
import WorkspaceType from "../../Types/Workspace/WorkspaceType";
|
|
17
|
+
import WorkspaceProjectAuthToken from "../../Models/DatabaseModels/WorkspaceProjectAuthToken";
|
|
18
|
+
import WorkspaceUserAuthToken from "../../Models/DatabaseModels/WorkspaceUserAuthToken";
|
|
19
|
+
import Model from "../../Models/DatabaseModels/UserSlack";
|
|
20
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
21
|
+
|
|
22
|
+
export class Service extends DatabaseService<Model> {
|
|
23
|
+
public constructor() {
|
|
24
|
+
super(Model);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@CaptureSpan()
|
|
28
|
+
protected override async onBeforeDelete(
|
|
29
|
+
deleteBy: DeleteBy<Model>,
|
|
30
|
+
): Promise<OnDelete<Model>> {
|
|
31
|
+
const itemsToDelete: Array<Model> = await this.findBy({
|
|
32
|
+
query: deleteBy.query,
|
|
33
|
+
select: {
|
|
34
|
+
_id: true,
|
|
35
|
+
projectId: true,
|
|
36
|
+
},
|
|
37
|
+
skip: 0,
|
|
38
|
+
limit: LIMIT_MAX,
|
|
39
|
+
props: {
|
|
40
|
+
isRoot: true,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
for (const item of itemsToDelete) {
|
|
45
|
+
await UserNotificationRuleService.deleteBy({
|
|
46
|
+
query: {
|
|
47
|
+
userSlackId: item.id!,
|
|
48
|
+
projectId: item.projectId!,
|
|
49
|
+
},
|
|
50
|
+
limit: LIMIT_MAX,
|
|
51
|
+
skip: 0,
|
|
52
|
+
props: {
|
|
53
|
+
isRoot: true,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
deleteBy,
|
|
60
|
+
carryForward: null,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* What this user would lose if this Slack account were deleted. Ask BEFORE
|
|
66
|
+
* calling delete; nothing here refuses anything.
|
|
67
|
+
*
|
|
68
|
+
* The hook directly above deletes every UserNotificationRule that points at
|
|
69
|
+
* this account, and the foreign key is onDelete: "CASCADE" so the rows would
|
|
70
|
+
* go even if it did not.
|
|
71
|
+
*/
|
|
72
|
+
@CaptureSpan()
|
|
73
|
+
public async getDeletionImpact(data: {
|
|
74
|
+
itemId: ObjectID;
|
|
75
|
+
projectId: ObjectID;
|
|
76
|
+
}): Promise<NotificationDeletionImpact> {
|
|
77
|
+
return UserNotificationRuleService.getNotificationMethodDeletionImpact({
|
|
78
|
+
projectId: data.projectId,
|
|
79
|
+
methodType: NotificationMethodChannel.Slack,
|
|
80
|
+
methodId: data.itemId,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/*
|
|
85
|
+
* A Slack notification method is a POINTER at the user's existing workspace
|
|
86
|
+
* link, not a hand-typed address: the Slack member id is resolved from the
|
|
87
|
+
* user's own WorkspaceUserAuthToken and never accepted from the request.
|
|
88
|
+
* That is why creation IS verification — the OAuth dance that wrote the
|
|
89
|
+
* auth-token row already proved the person controls that Slack account.
|
|
90
|
+
*/
|
|
91
|
+
@CaptureSpan()
|
|
92
|
+
protected override async onBeforeCreate(
|
|
93
|
+
createBy: CreateBy<Model>,
|
|
94
|
+
): Promise<OnCreate<Model>> {
|
|
95
|
+
if (!createBy.props.isRoot && createBy.data.isVerified) {
|
|
96
|
+
throw new BadDataException("isVerified cannot be set to true");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!createBy.props.isRoot && createBy.data.slackUserId) {
|
|
100
|
+
throw new BadDataException("slackUserId cannot be set directly");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!createBy.data.projectId || !createBy.data.userId) {
|
|
104
|
+
throw new BadDataException("projectId and userId are required");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const projectId: ObjectID = new ObjectID(
|
|
108
|
+
createBy.data.projectId.toString(),
|
|
109
|
+
);
|
|
110
|
+
const userId: ObjectID = new ObjectID(createBy.data.userId.toString());
|
|
111
|
+
|
|
112
|
+
/*
|
|
113
|
+
* One workspace link per (user, project) means a second row would be an
|
|
114
|
+
* exact duplicate of the first.
|
|
115
|
+
*/
|
|
116
|
+
const existingCount: number = (
|
|
117
|
+
await this.countBy({
|
|
118
|
+
query: {
|
|
119
|
+
projectId: projectId,
|
|
120
|
+
userId: userId,
|
|
121
|
+
},
|
|
122
|
+
props: {
|
|
123
|
+
isRoot: true,
|
|
124
|
+
},
|
|
125
|
+
})
|
|
126
|
+
).toNumber();
|
|
127
|
+
|
|
128
|
+
if (existingCount > 0) {
|
|
129
|
+
throw new BadDataException(
|
|
130
|
+
"Slack is already added as a notification method for this project.",
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const projectAuth: WorkspaceProjectAuthToken | null =
|
|
135
|
+
await WorkspaceProjectAuthTokenService.getProjectAuth({
|
|
136
|
+
projectId: projectId,
|
|
137
|
+
workspaceType: WorkspaceType.Slack,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
if (!projectAuth || !projectAuth.authToken) {
|
|
141
|
+
throw new BadDataException(
|
|
142
|
+
"This project is not connected to Slack. Please ask a project admin to connect Slack in Project Settings > Slack Integration.",
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const userAuth: WorkspaceUserAuthToken | null =
|
|
147
|
+
await WorkspaceUserAuthTokenService.getUserAuth({
|
|
148
|
+
projectId: projectId,
|
|
149
|
+
userId: userId,
|
|
150
|
+
workspaceType: WorkspaceType.Slack,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
if (!userAuth || !userAuth.workspaceUserId) {
|
|
154
|
+
throw new BadDataException(
|
|
155
|
+
"Your Slack account is not connected to OneUptime for this project. Please go to User Settings > Slack Integration and connect your Slack account first.",
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
createBy.data.slackUserId = userAuth.workspaceUserId;
|
|
160
|
+
createBy.data.isVerified = true;
|
|
161
|
+
|
|
162
|
+
/*
|
|
163
|
+
* Display label only — best effort. A Slack API hiccup must not stop the
|
|
164
|
+
* method from being added.
|
|
165
|
+
*/
|
|
166
|
+
try {
|
|
167
|
+
const slackUserName: string | null =
|
|
168
|
+
await SlackUtil.getUsernameFromUserId({
|
|
169
|
+
authToken: projectAuth.authToken,
|
|
170
|
+
userId: userAuth.workspaceUserId,
|
|
171
|
+
projectId: projectId,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
if (slackUserName) {
|
|
175
|
+
createBy.data.slackUserName = slackUserName;
|
|
176
|
+
}
|
|
177
|
+
} catch (err) {
|
|
178
|
+
logger.error("Could not resolve Slack username for new UserSlack row.");
|
|
179
|
+
logger.error(err);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
createBy,
|
|
184
|
+
carryForward: null,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@CaptureSpan()
|
|
189
|
+
protected override async onCreateSuccess(
|
|
190
|
+
_onCreate: OnCreate<Model>,
|
|
191
|
+
createdItem: Model,
|
|
192
|
+
): Promise<Model> {
|
|
193
|
+
/*
|
|
194
|
+
* The row is born verified (creation is gated on the live workspace
|
|
195
|
+
* link), so default on-call rules are seeded at create time — same as
|
|
196
|
+
* webhooks.
|
|
197
|
+
*/
|
|
198
|
+
if (createdItem.projectId && createdItem.userId && createdItem.id) {
|
|
199
|
+
try {
|
|
200
|
+
await UserNotificationRuleService.addDefaultNotificationRulesForVerifiedMethod(
|
|
201
|
+
{
|
|
202
|
+
projectId: createdItem.projectId,
|
|
203
|
+
userId: createdItem.userId,
|
|
204
|
+
notificationMethod: {
|
|
205
|
+
userSlackId: createdItem.id,
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
);
|
|
209
|
+
} catch (err) {
|
|
210
|
+
logger.error(err);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return createdItem;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export default new Service();
|
|
@@ -3,10 +3,13 @@ import WorkspaceType, {
|
|
|
3
3
|
getWorkspaceTypeDisplayName,
|
|
4
4
|
} from "../../Types/Workspace/WorkspaceType";
|
|
5
5
|
import DatabaseService from "./DatabaseService";
|
|
6
|
+
import WorkspaceUserAuthTokenService from "./WorkspaceUserAuthTokenService";
|
|
7
|
+
import DeleteBy from "../Types/Database/DeleteBy";
|
|
8
|
+
import { OnDelete } from "../Types/Database/Hooks";
|
|
6
9
|
import Model, {
|
|
7
10
|
WorkspaceMiscData,
|
|
8
11
|
} from "../../Models/DatabaseModels/WorkspaceProjectAuthToken";
|
|
9
|
-
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
12
|
+
import LIMIT_MAX, { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
10
13
|
import BadDataException from "../../Types/Exception/BadDataException";
|
|
11
14
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
12
15
|
import logger from "../Utils/Logger";
|
|
@@ -16,6 +19,69 @@ export class Service extends DatabaseService<Model> {
|
|
|
16
19
|
super(Model);
|
|
17
20
|
}
|
|
18
21
|
|
|
22
|
+
/*
|
|
23
|
+
* Disconnecting a WORKSPACE disconnects every user link inside it.
|
|
24
|
+
*
|
|
25
|
+
* The dashboard's "Uninstall OneUptime from Slack / Microsoft Teams" button
|
|
26
|
+
* deletes this row through the generic CRUD path, and nothing else about
|
|
27
|
+
* the workspace survives that in a usable state: the user auth tokens were
|
|
28
|
+
* minted against this workspace's OAuth app, and the UserSlack /
|
|
29
|
+
* UserMicrosoftTeams notification methods are pointers at those links that
|
|
30
|
+
* WorkspaceUserNotificationService will deterministically refuse to send
|
|
31
|
+
* through once this row is gone ("This project is not connected to ...").
|
|
32
|
+
*
|
|
33
|
+
* Left behind, those verified-looking methods are worse than dead: the
|
|
34
|
+
* on-call fallback selects them into its zero-cost tier and stops looking,
|
|
35
|
+
* and the readiness surface keeps reporting the responder reachable. So the
|
|
36
|
+
* user tokens are deleted THROUGH THEIR SERVICE here, whose own
|
|
37
|
+
* onBeforeDelete cascades to the notification methods and their rules -
|
|
38
|
+
* returning every affected responder to the "no rule" state the
|
|
39
|
+
* verified-method fallback is built to rescue. This mirrors what the
|
|
40
|
+
* Slack-side app_uninstall webhook already did; the webhook remains for
|
|
41
|
+
* uninstalls initiated inside Slack, where this hook never fires.
|
|
42
|
+
*/
|
|
43
|
+
@CaptureSpan()
|
|
44
|
+
protected override async onBeforeDelete(
|
|
45
|
+
deleteBy: DeleteBy<Model>,
|
|
46
|
+
): Promise<OnDelete<Model>> {
|
|
47
|
+
const itemsToDelete: Array<Model> = await this.findBy({
|
|
48
|
+
query: deleteBy.query,
|
|
49
|
+
select: {
|
|
50
|
+
_id: true,
|
|
51
|
+
projectId: true,
|
|
52
|
+
workspaceType: true,
|
|
53
|
+
},
|
|
54
|
+
skip: 0,
|
|
55
|
+
limit: LIMIT_MAX,
|
|
56
|
+
props: {
|
|
57
|
+
isRoot: true,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
for (const item of itemsToDelete) {
|
|
62
|
+
if (!item.projectId || !item.workspaceType) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
await WorkspaceUserAuthTokenService.deleteBy({
|
|
67
|
+
query: {
|
|
68
|
+
projectId: item.projectId,
|
|
69
|
+
workspaceType: item.workspaceType,
|
|
70
|
+
},
|
|
71
|
+
limit: LIMIT_MAX,
|
|
72
|
+
skip: 0,
|
|
73
|
+
props: {
|
|
74
|
+
isRoot: true,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
deleteBy,
|
|
81
|
+
carryForward: null,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
19
85
|
@CaptureSpan()
|
|
20
86
|
public async getProjectAuth(data: {
|
|
21
87
|
projectId: ObjectID;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import ObjectID from "../../Types/ObjectID";
|
|
2
2
|
import WorkspaceType from "../../Types/Workspace/WorkspaceType";
|
|
3
|
+
import LIMIT_MAX from "../../Types/Database/LimitMax";
|
|
3
4
|
import DatabaseService from "./DatabaseService";
|
|
5
|
+
import UserSlackService from "./UserSlackService";
|
|
6
|
+
import UserMicrosoftTeamsService from "./UserMicrosoftTeamsService";
|
|
7
|
+
import DeleteBy from "../Types/Database/DeleteBy";
|
|
8
|
+
import { OnDelete } from "../Types/Database/Hooks";
|
|
4
9
|
import Model, {
|
|
5
10
|
SlackMiscData,
|
|
6
11
|
} from "../../Models/DatabaseModels/WorkspaceUserAuthToken";
|
|
@@ -11,6 +16,74 @@ export class Service extends DatabaseService<Model> {
|
|
|
11
16
|
super(Model);
|
|
12
17
|
}
|
|
13
18
|
|
|
19
|
+
/*
|
|
20
|
+
* A UserSlack / UserMicrosoftTeams notification method is a pointer at the
|
|
21
|
+
* workspace link being deleted here, so it goes down with it (which also
|
|
22
|
+
* deletes the notification rules routing to it, via that service's own
|
|
23
|
+
* delete hook). Leaving the method row behind would be worse than deleting
|
|
24
|
+
* it: a rule pointing at a dead link fails with an error row and no re-page,
|
|
25
|
+
* while a user with NO matching rule is rescued by the verified-method
|
|
26
|
+
* fallback.
|
|
27
|
+
*/
|
|
28
|
+
@CaptureSpan()
|
|
29
|
+
protected override async onBeforeDelete(
|
|
30
|
+
deleteBy: DeleteBy<Model>,
|
|
31
|
+
): Promise<OnDelete<Model>> {
|
|
32
|
+
const itemsToDelete: Array<Model> = await this.findBy({
|
|
33
|
+
query: deleteBy.query,
|
|
34
|
+
select: {
|
|
35
|
+
_id: true,
|
|
36
|
+
projectId: true,
|
|
37
|
+
userId: true,
|
|
38
|
+
workspaceType: true,
|
|
39
|
+
},
|
|
40
|
+
skip: 0,
|
|
41
|
+
limit: LIMIT_MAX,
|
|
42
|
+
props: {
|
|
43
|
+
isRoot: true,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
for (const item of itemsToDelete) {
|
|
48
|
+
if (!item.projectId || !item.userId) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (item.workspaceType === WorkspaceType.Slack) {
|
|
53
|
+
await UserSlackService.deleteBy({
|
|
54
|
+
query: {
|
|
55
|
+
projectId: item.projectId,
|
|
56
|
+
userId: item.userId,
|
|
57
|
+
},
|
|
58
|
+
limit: LIMIT_MAX,
|
|
59
|
+
skip: 0,
|
|
60
|
+
props: {
|
|
61
|
+
isRoot: true,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (item.workspaceType === WorkspaceType.MicrosoftTeams) {
|
|
67
|
+
await UserMicrosoftTeamsService.deleteBy({
|
|
68
|
+
query: {
|
|
69
|
+
projectId: item.projectId,
|
|
70
|
+
userId: item.userId,
|
|
71
|
+
},
|
|
72
|
+
limit: LIMIT_MAX,
|
|
73
|
+
skip: 0,
|
|
74
|
+
props: {
|
|
75
|
+
isRoot: true,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
deleteBy,
|
|
83
|
+
carryForward: null,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
14
87
|
@CaptureSpan()
|
|
15
88
|
public async getUserAuth(data: {
|
|
16
89
|
projectId: ObjectID;
|