@oneuptime/common 10.2.2 → 10.2.4
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/Index.ts +6 -0
- package/Models/DatabaseModels/StatusPage.ts +43 -0
- package/Models/DatabaseModels/StatusPageOidc.ts +689 -0
- package/Models/DatabaseModels/UserNotificationRule.ts +49 -0
- package/Models/DatabaseModels/UserNotificationSetting.ts +17 -0
- package/Models/DatabaseModels/UserOnCallLogTimeline.ts +48 -0
- package/Models/DatabaseModels/UserWebhook.ts +290 -0
- package/Models/DatabaseModels/WebhookLog.ts +992 -0
- package/Server/API/StatusPageAPI.ts +78 -3
- package/Server/API/UserWebhookAPI.ts +159 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1778506655291-AddProjectOIDC.ts +1 -1
- package/Server/Infrastructure/Postgres/SchemaMigrations/1778514515756-MigrationName.ts +259 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1778521361934-MigrationName.ts +17 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1778522070962-AddStatusPageOIDC.ts +63 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/ScheduledMaintenanceService.ts +34 -0
- package/Server/Services/StatusPageOidcService.ts +10 -0
- package/Server/Services/StatusPageSubscriberService.ts +101 -0
- package/Server/Services/UserNotificationRuleService.ts +213 -1
- package/Server/Services/UserNotificationSettingService.ts +95 -0
- package/Server/Services/UserWebhookService.ts +208 -0
- package/Server/Services/WebhookLogService.ts +15 -0
- package/Server/Services/WebhookService.ts +126 -0
- package/Server/Utils/StatusPageSubscriberWebhook.ts +39 -0
- package/Types/Permission.ts +58 -0
- package/Types/Webhook/WebhookMessage.ts +8 -0
- package/Types/WebhookStatus.ts +6 -0
- package/build/dist/Models/DatabaseModels/Index.js +6 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +45 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageOidc.js +718 -0
- package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserNotificationRule.js +49 -0
- package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserNotificationSetting.js +19 -0
- package/build/dist/Models/DatabaseModels/UserNotificationSetting.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +48 -0
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserWebhook.js +307 -0
- package/build/dist/Models/DatabaseModels/UserWebhook.js.map +1 -0
- package/build/dist/Models/DatabaseModels/WebhookLog.js +1021 -0
- package/build/dist/Models/DatabaseModels/WebhookLog.js.map +1 -0
- package/build/dist/Server/API/StatusPageAPI.js +80 -35
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/UserWebhookAPI.js +99 -0
- package/build/dist/Server/API/UserWebhookAPI.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1778506655291-AddProjectOIDC.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1778514515756-MigrationName.js +94 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1778514515756-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1778521361934-MigrationName.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1778521361934-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1778522070962-AddStatusPageOIDC.js +28 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1778522070962-AddStatusPageOIDC.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +31 -2
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageOidcService.js +9 -0
- package/build/dist/Server/Services/StatusPageOidcService.js.map +1 -0
- package/build/dist/Server/Services/StatusPageSubscriberService.js +99 -4
- package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +178 -21
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js +84 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Server/Services/UserWebhookService.js +190 -0
- package/build/dist/Server/Services/UserWebhookService.js.map +1 -0
- package/build/dist/Server/Services/WebhookLogService.js +13 -0
- package/build/dist/Server/Services/WebhookLogService.js.map +1 -0
- package/build/dist/Server/Services/WebhookService.js +92 -0
- package/build/dist/Server/Services/WebhookService.js.map +1 -0
- package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js +19 -0
- package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js.map +1 -0
- package/build/dist/Types/Permission.js +50 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Webhook/WebhookMessage.js +2 -0
- package/build/dist/Types/Webhook/WebhookMessage.js.map +1 -0
- package/build/dist/Types/WebhookStatus.js +7 -0
- package/build/dist/Types/WebhookStatus.js.map +1 -0
- package/package.json +1 -1
|
@@ -313,6 +313,9 @@ import { AddAlertIsPrivate1778438949454 } from "./1778438949454-AddAlertIsPrivat
|
|
|
313
313
|
import { AddPrivacyRules1778440665575 } from "./1778440665575-AddPrivacyRules";
|
|
314
314
|
import { AddEpisodePrivacyRules1778442385970 } from "./1778442385970-AddEpisodePrivacyRules";
|
|
315
315
|
import { AddProjectOIDC1778506655291 } from "./1778506655291-AddProjectOIDC";
|
|
316
|
+
import { MigrationName1778514515756 } from "./1778514515756-MigrationName";
|
|
317
|
+
import { MigrationName1778521361934 } from "./1778521361934-MigrationName";
|
|
318
|
+
import { AddStatusPageOIDC1778522070962 } from "./1778522070962-AddStatusPageOIDC";
|
|
316
319
|
export default [
|
|
317
320
|
InitialMigration,
|
|
318
321
|
MigrationName1717678334852,
|
|
@@ -629,4 +632,7 @@ export default [
|
|
|
629
632
|
AddPrivacyRules1778440665575,
|
|
630
633
|
AddEpisodePrivacyRules1778442385970,
|
|
631
634
|
AddProjectOIDC1778506655291,
|
|
635
|
+
MigrationName1778514515756,
|
|
636
|
+
MigrationName1778521361934,
|
|
637
|
+
AddStatusPageOIDC1778522070962,
|
|
632
638
|
];
|
package/Server/Services/Index.ts
CHANGED
|
@@ -130,6 +130,7 @@ import StatusPageResourceService from "./StatusPageResourceService";
|
|
|
130
130
|
// Status Page
|
|
131
131
|
import StatusPageService from "./StatusPageService";
|
|
132
132
|
import StatusPageSsoService from "./StatusPageSsoService";
|
|
133
|
+
import StatusPageOidcService from "./StatusPageOidcService";
|
|
133
134
|
import StatusPageSubscriberService from "./StatusPageSubscriberService";
|
|
134
135
|
import StatusPageSubscriberNotificationTemplateService from "./StatusPageSubscriberNotificationTemplateService";
|
|
135
136
|
import StatusPageSubscriberNotificationTemplateStatusPageService from "./StatusPageSubscriberNotificationTemplateStatusPageService";
|
|
@@ -335,6 +336,7 @@ const services: Array<BaseService> = [
|
|
|
335
336
|
StatusPageResourceService,
|
|
336
337
|
StatusPageService,
|
|
337
338
|
StatusPageSsoService,
|
|
339
|
+
StatusPageOidcService,
|
|
338
340
|
StatusPageSubscriberService,
|
|
339
341
|
StatusPageSubscriberNotificationTemplateService,
|
|
340
342
|
StatusPageSubscriberNotificationTemplateStatusPageService,
|
|
@@ -51,6 +51,7 @@ import StatusPageEventType from "../../Types/StatusPage/StatusPageEventType";
|
|
|
51
51
|
import ScheduledMaintenanceFeedService from "./ScheduledMaintenanceFeedService";
|
|
52
52
|
import { ScheduledMaintenanceFeedEventType } from "../../Models/DatabaseModels/ScheduledMaintenanceFeed";
|
|
53
53
|
import SlackUtil from "../Utils/Workspace/Slack/Slack";
|
|
54
|
+
import StatusPageSubscriberWebhookUtil from "../Utils/StatusPageSubscriberWebhook";
|
|
54
55
|
import { Gray500, Red500 } from "../../Types/BrandColors";
|
|
55
56
|
import Label from "../../Models/DatabaseModels/Label";
|
|
56
57
|
import LabelService from "./LabelService";
|
|
@@ -332,6 +333,39 @@ ${resourcesAffected ? `**Resources Affected:** ${resourcesAffected}` : ""}
|
|
|
332
333
|
});
|
|
333
334
|
}
|
|
334
335
|
|
|
336
|
+
if (subscriber.subscriberWebhook) {
|
|
337
|
+
StatusPageSubscriberWebhookUtil.sendWebhookNotification({
|
|
338
|
+
webhookUrl: subscriber.subscriberWebhook,
|
|
339
|
+
payload: {
|
|
340
|
+
eventType: "ScheduledMaintenanceCreated",
|
|
341
|
+
statusPageId: statuspage.id!.toString(),
|
|
342
|
+
statusPageName: statusPageName,
|
|
343
|
+
statusPageUrl: statusPageURL,
|
|
344
|
+
unsubscribeUrl: unsubscribeUrl,
|
|
345
|
+
data: {
|
|
346
|
+
scheduledMaintenanceId: event.id?.toString() || "",
|
|
347
|
+
scheduledMaintenanceTitle: event.title || "",
|
|
348
|
+
scheduledMaintenanceDescription: event.description || "",
|
|
349
|
+
scheduledStartTime:
|
|
350
|
+
OneUptimeDate.getDateAsUserFriendlyFormattedString(
|
|
351
|
+
event.startsAt!,
|
|
352
|
+
),
|
|
353
|
+
scheduledEndTime: event.endsAt
|
|
354
|
+
? OneUptimeDate.getDateAsUserFriendlyFormattedString(
|
|
355
|
+
event.endsAt,
|
|
356
|
+
)
|
|
357
|
+
: "",
|
|
358
|
+
resourcesAffected: resourcesAffected,
|
|
359
|
+
detailsUrl: scheduledEventDetailsUrl,
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
}).catch((err: Error) => {
|
|
363
|
+
logger.error(err, {
|
|
364
|
+
projectId: statuspage.projectId?.toString(),
|
|
365
|
+
} as LogAttributes);
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
335
369
|
if (subscriber.subscriberEmail) {
|
|
336
370
|
// send email here.
|
|
337
371
|
const statusPageIdString: string | null =
|
|
@@ -36,6 +36,7 @@ import StatusPageSubscriberNotificationMethod from "../../Types/StatusPage/Statu
|
|
|
36
36
|
import NumberUtil from "../../Utils/Number";
|
|
37
37
|
import SlackUtil from "../Utils/Workspace/Slack/Slack";
|
|
38
38
|
import MicrosoftTeamsUtil from "../Utils/Workspace/MicrosoftTeams/MicrosoftTeams";
|
|
39
|
+
import StatusPageSubscriberWebhookUtil from "../Utils/StatusPageSubscriberWebhook";
|
|
39
40
|
import StatusPageSubscriberNotificationTemplateService, {
|
|
40
41
|
Service as StatusPageSubscriberNotificationTemplateServiceClass,
|
|
41
42
|
} from "./StatusPageSubscriberNotificationTemplateService";
|
|
@@ -540,6 +541,43 @@ Stay informed about service availability! 🚀`;
|
|
|
540
541
|
});
|
|
541
542
|
}
|
|
542
543
|
|
|
544
|
+
// if generic webhook URL is provided and sendYouHaveSubscribedMessage is true, then ping the webhook with the subscription event.
|
|
545
|
+
if (
|
|
546
|
+
createdItem.subscriberWebhook &&
|
|
547
|
+
createdItem.sendYouHaveSubscribedMessage
|
|
548
|
+
) {
|
|
549
|
+
logger.debug("Sending webhook notification for new subscriber.", {
|
|
550
|
+
projectId: createdItem.projectId?.toString(),
|
|
551
|
+
} as LogAttributes);
|
|
552
|
+
|
|
553
|
+
StatusPageSubscriberWebhookUtil.sendWebhookNotification({
|
|
554
|
+
webhookUrl: URL.fromString(createdItem.subscriberWebhook.toString()),
|
|
555
|
+
payload: {
|
|
556
|
+
eventType: "SubscriberSubscribed",
|
|
557
|
+
statusPageId: createdItem.statusPageId.toString(),
|
|
558
|
+
statusPageName: statusPageName,
|
|
559
|
+
statusPageUrl: statusPageURL,
|
|
560
|
+
unsubscribeUrl: unsubscribeLink,
|
|
561
|
+
data: {
|
|
562
|
+
message: `You have been subscribed to ${statusPageName}.`,
|
|
563
|
+
},
|
|
564
|
+
},
|
|
565
|
+
})
|
|
566
|
+
.then(() => {
|
|
567
|
+
logger.debug("Webhook notification sent successfully.", {
|
|
568
|
+
projectId: createdItem.projectId?.toString(),
|
|
569
|
+
} as LogAttributes);
|
|
570
|
+
})
|
|
571
|
+
.catch((err: Error) => {
|
|
572
|
+
logger.error("Error sending webhook notification:", {
|
|
573
|
+
projectId: createdItem.projectId?.toString(),
|
|
574
|
+
} as LogAttributes);
|
|
575
|
+
logger.error(err, {
|
|
576
|
+
projectId: createdItem.projectId?.toString(),
|
|
577
|
+
} as LogAttributes);
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
|
|
543
581
|
// if Microsoft Teams incoming webhook is provided and sendYouHaveSubscribedMessage is true, then send a message to the Teams channel.
|
|
544
582
|
if (
|
|
545
583
|
createdItem.microsoftTeamsIncomingWebhookUrl &&
|
|
@@ -1345,6 +1383,69 @@ Stay informed about service availability! 🚀`;
|
|
|
1345
1383
|
return statusPages;
|
|
1346
1384
|
}
|
|
1347
1385
|
|
|
1386
|
+
@CaptureSpan()
|
|
1387
|
+
public async testSubscriberWebhook(data: {
|
|
1388
|
+
webhookUrl: string;
|
|
1389
|
+
statusPageId: ObjectID;
|
|
1390
|
+
}): Promise<void> {
|
|
1391
|
+
// basic validation - must be a valid URL
|
|
1392
|
+
let parsedUrl: URL;
|
|
1393
|
+
try {
|
|
1394
|
+
parsedUrl = URL.fromString(data.webhookUrl);
|
|
1395
|
+
} catch {
|
|
1396
|
+
throw new BadDataException("Invalid Webhook URL");
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
// get the status page info
|
|
1400
|
+
const statusPage: StatusPage | null = await StatusPageService.findOneById({
|
|
1401
|
+
id: data.statusPageId,
|
|
1402
|
+
props: {
|
|
1403
|
+
isRoot: true,
|
|
1404
|
+
},
|
|
1405
|
+
select: {
|
|
1406
|
+
name: true,
|
|
1407
|
+
pageTitle: true,
|
|
1408
|
+
projectId: true,
|
|
1409
|
+
_id: true,
|
|
1410
|
+
},
|
|
1411
|
+
});
|
|
1412
|
+
|
|
1413
|
+
if (!statusPage) {
|
|
1414
|
+
throw new BadDataException("Status page not found");
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
const statusPageName: string =
|
|
1418
|
+
statusPage.pageTitle || statusPage.name || "Status Page";
|
|
1419
|
+
const statusPageURL: string = await StatusPageService.getStatusPageURL(
|
|
1420
|
+
statusPage.id!,
|
|
1421
|
+
);
|
|
1422
|
+
|
|
1423
|
+
try {
|
|
1424
|
+
await StatusPageSubscriberWebhookUtil.sendWebhookNotification({
|
|
1425
|
+
webhookUrl: parsedUrl,
|
|
1426
|
+
payload: {
|
|
1427
|
+
eventType: "TestNotification",
|
|
1428
|
+
statusPageId: statusPage.id!.toString(),
|
|
1429
|
+
statusPageName: statusPageName,
|
|
1430
|
+
statusPageUrl: statusPageURL,
|
|
1431
|
+
unsubscribeUrl: "",
|
|
1432
|
+
data: {
|
|
1433
|
+
message:
|
|
1434
|
+
"This is a test notification from OneUptime. Your webhook is configured correctly.",
|
|
1435
|
+
},
|
|
1436
|
+
},
|
|
1437
|
+
});
|
|
1438
|
+
} catch (error) {
|
|
1439
|
+
logger.error("Error sending test webhook notification:", {
|
|
1440
|
+
projectId: statusPage?.projectId?.toString(),
|
|
1441
|
+
} as LogAttributes);
|
|
1442
|
+
logger.error(error, {
|
|
1443
|
+
projectId: statusPage?.projectId?.toString(),
|
|
1444
|
+
} as LogAttributes);
|
|
1445
|
+
throw error;
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1348
1449
|
@CaptureSpan()
|
|
1349
1450
|
public async testSlackWebhook(data: {
|
|
1350
1451
|
webhookUrl: string;
|
|
@@ -10,6 +10,7 @@ import MailService from "./MailService";
|
|
|
10
10
|
import ShortLinkService from "./ShortLinkService";
|
|
11
11
|
import SmsService from "./SmsService";
|
|
12
12
|
import TelegramService from "./TelegramService";
|
|
13
|
+
import WebhookService from "./WebhookService";
|
|
13
14
|
import WhatsAppService from "./WhatsAppService";
|
|
14
15
|
import UserEmailService from "./UserEmailService";
|
|
15
16
|
import UserOnCallLogService from "./UserOnCallLogService";
|
|
@@ -28,6 +29,7 @@ import Email from "../../Types/Email";
|
|
|
28
29
|
import EmailMessage from "../../Types/Email/EmailMessage";
|
|
29
30
|
import EmailTemplateType from "../../Types/Email/EmailTemplateType";
|
|
30
31
|
import BadDataException from "../../Types/Exception/BadDataException";
|
|
32
|
+
import { JSONObject } from "../../Types/JSON";
|
|
31
33
|
import NotificationRuleType from "../../Types/NotificationRule/NotificationRuleType";
|
|
32
34
|
import ObjectID from "../../Types/ObjectID";
|
|
33
35
|
import PushDeviceType from "../../Types/PushNotification/PushDeviceType";
|
|
@@ -78,6 +80,7 @@ export interface NotificationMethodDescriptor {
|
|
|
78
80
|
userWhatsAppId?: ObjectID;
|
|
79
81
|
userTelegramId?: ObjectID;
|
|
80
82
|
userPushId?: ObjectID;
|
|
83
|
+
userWebhookId?: ObjectID;
|
|
81
84
|
}
|
|
82
85
|
|
|
83
86
|
export class Service extends DatabaseService<Model> {
|
|
@@ -173,6 +176,11 @@ export class Service extends DatabaseService<Model> {
|
|
|
173
176
|
telegramUserHandle: true,
|
|
174
177
|
isVerified: true,
|
|
175
178
|
},
|
|
179
|
+
userWebhook: {
|
|
180
|
+
webhookUrl: true,
|
|
181
|
+
name: true,
|
|
182
|
+
secret: true,
|
|
183
|
+
},
|
|
176
184
|
userEmail: {
|
|
177
185
|
email: true,
|
|
178
186
|
isVerified: true,
|
|
@@ -1082,6 +1090,202 @@ export class Service extends DatabaseService<Model> {
|
|
|
1082
1090
|
});
|
|
1083
1091
|
}
|
|
1084
1092
|
|
|
1093
|
+
// send webhook.
|
|
1094
|
+
if (notificationRuleItem.userWebhook?.webhookUrl) {
|
|
1095
|
+
const webhookUrl: string = notificationRuleItem.userWebhook.webhookUrl;
|
|
1096
|
+
const webhookSecret: string | undefined =
|
|
1097
|
+
notificationRuleItem.userWebhook.secret;
|
|
1098
|
+
const userWebhookId: ObjectID = notificationRuleItem.userWebhook.id!;
|
|
1099
|
+
|
|
1100
|
+
const dispatchWebhook: (params: {
|
|
1101
|
+
eventType: string;
|
|
1102
|
+
payload: JSONObject;
|
|
1103
|
+
entityId?: ObjectID;
|
|
1104
|
+
entityKind: "alert" | "incident" | "alertEpisode" | "incidentEpisode";
|
|
1105
|
+
}) => Promise<void> = async (params: {
|
|
1106
|
+
eventType: string;
|
|
1107
|
+
payload: JSONObject;
|
|
1108
|
+
entityId?: ObjectID;
|
|
1109
|
+
entityKind: "alert" | "incident" | "alertEpisode" | "incidentEpisode";
|
|
1110
|
+
}): Promise<void> => {
|
|
1111
|
+
logTimelineItem.status = UserNotificationStatus.Sending;
|
|
1112
|
+
logTimelineItem.statusMessage = `Sending webhook to ${webhookUrl}.`;
|
|
1113
|
+
logTimelineItem.userWebhookId = userWebhookId;
|
|
1114
|
+
|
|
1115
|
+
const updatedLog: UserOnCallLogTimeline =
|
|
1116
|
+
await UserOnCallLogTimelineService.create({
|
|
1117
|
+
data: logTimelineItem,
|
|
1118
|
+
props: {
|
|
1119
|
+
isRoot: true,
|
|
1120
|
+
},
|
|
1121
|
+
});
|
|
1122
|
+
|
|
1123
|
+
const callbacksByKind: {
|
|
1124
|
+
alert?: { alertId?: ObjectID };
|
|
1125
|
+
incident?: { incidentId?: ObjectID };
|
|
1126
|
+
} = {};
|
|
1127
|
+
if (params.entityKind === "alert" && params.entityId) {
|
|
1128
|
+
callbacksByKind.alert = { alertId: params.entityId };
|
|
1129
|
+
} else if (params.entityKind === "incident" && params.entityId) {
|
|
1130
|
+
callbacksByKind.incident = { incidentId: params.entityId };
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
WebhookService.sendWebhook(
|
|
1134
|
+
{
|
|
1135
|
+
url: webhookUrl,
|
|
1136
|
+
eventType: params.eventType,
|
|
1137
|
+
payload: params.payload,
|
|
1138
|
+
secret: webhookSecret,
|
|
1139
|
+
},
|
|
1140
|
+
{
|
|
1141
|
+
projectId: options.projectId,
|
|
1142
|
+
userOnCallLogTimelineId: updatedLog.id!,
|
|
1143
|
+
userId: notificationRuleItem.userId!,
|
|
1144
|
+
onCallPolicyId: options.onCallPolicyId,
|
|
1145
|
+
onCallPolicyEscalationRuleId: options.onCallPolicyEscalationRuleId,
|
|
1146
|
+
teamId: options.userBelongsToTeamId,
|
|
1147
|
+
onCallDutyPolicyExecutionLogTimelineId:
|
|
1148
|
+
options.onCallDutyPolicyExecutionLogTimelineId,
|
|
1149
|
+
onCallScheduleId: options.onCallScheduleId,
|
|
1150
|
+
...callbacksByKind.alert,
|
|
1151
|
+
...callbacksByKind.incident,
|
|
1152
|
+
},
|
|
1153
|
+
).catch(async (err: Error) => {
|
|
1154
|
+
await UserOnCallLogTimelineService.updateOneById({
|
|
1155
|
+
id: updatedLog.id!,
|
|
1156
|
+
data: {
|
|
1157
|
+
status: UserNotificationStatus.Error,
|
|
1158
|
+
statusMessage: err.message || "Error sending webhook.",
|
|
1159
|
+
},
|
|
1160
|
+
props: {
|
|
1161
|
+
isRoot: true,
|
|
1162
|
+
},
|
|
1163
|
+
});
|
|
1164
|
+
});
|
|
1165
|
+
};
|
|
1166
|
+
|
|
1167
|
+
if (
|
|
1168
|
+
options.userNotificationEventType ===
|
|
1169
|
+
UserNotificationEventType.AlertCreated &&
|
|
1170
|
+
alert
|
|
1171
|
+
) {
|
|
1172
|
+
await dispatchWebhook({
|
|
1173
|
+
eventType: "on-call.alert.created",
|
|
1174
|
+
entityKind: "alert",
|
|
1175
|
+
entityId: alert.id!,
|
|
1176
|
+
payload: {
|
|
1177
|
+
eventType: "on-call.alert.created",
|
|
1178
|
+
timestamp: new Date().toISOString(),
|
|
1179
|
+
projectId: alert.projectId?.toString() || "",
|
|
1180
|
+
userId: notificationRuleItem.userId!.toString(),
|
|
1181
|
+
alert: {
|
|
1182
|
+
id: alert.id?.toString() || "",
|
|
1183
|
+
title: alert.title || "",
|
|
1184
|
+
description: alert.description || "",
|
|
1185
|
+
alertNumber: alert.alertNumber || null,
|
|
1186
|
+
alertNumberWithPrefix: alert.alertNumberWithPrefix || null,
|
|
1187
|
+
severity: alert.alertSeverity?.name || null,
|
|
1188
|
+
state: alert.currentAlertState?.name || null,
|
|
1189
|
+
},
|
|
1190
|
+
onCallPolicyId: options.onCallPolicyId?.toString() || null,
|
|
1191
|
+
onCallPolicyEscalationRuleId:
|
|
1192
|
+
options.onCallPolicyEscalationRuleId?.toString() || null,
|
|
1193
|
+
},
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
if (
|
|
1198
|
+
options.userNotificationEventType ===
|
|
1199
|
+
UserNotificationEventType.IncidentCreated &&
|
|
1200
|
+
incident
|
|
1201
|
+
) {
|
|
1202
|
+
await dispatchWebhook({
|
|
1203
|
+
eventType: "on-call.incident.created",
|
|
1204
|
+
entityKind: "incident",
|
|
1205
|
+
entityId: incident.id!,
|
|
1206
|
+
payload: {
|
|
1207
|
+
eventType: "on-call.incident.created",
|
|
1208
|
+
timestamp: new Date().toISOString(),
|
|
1209
|
+
projectId: incident.projectId?.toString() || "",
|
|
1210
|
+
userId: notificationRuleItem.userId!.toString(),
|
|
1211
|
+
incident: {
|
|
1212
|
+
id: incident.id?.toString() || "",
|
|
1213
|
+
title: incident.title || "",
|
|
1214
|
+
description: incident.description || "",
|
|
1215
|
+
incidentNumber: incident.incidentNumber || null,
|
|
1216
|
+
incidentNumberWithPrefix:
|
|
1217
|
+
incident.incidentNumberWithPrefix || null,
|
|
1218
|
+
severity: incident.incidentSeverity?.name || null,
|
|
1219
|
+
state: incident.currentIncidentState?.name || null,
|
|
1220
|
+
},
|
|
1221
|
+
onCallPolicyId: options.onCallPolicyId?.toString() || null,
|
|
1222
|
+
onCallPolicyEscalationRuleId:
|
|
1223
|
+
options.onCallPolicyEscalationRuleId?.toString() || null,
|
|
1224
|
+
},
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
if (
|
|
1229
|
+
options.userNotificationEventType ===
|
|
1230
|
+
UserNotificationEventType.AlertEpisodeCreated &&
|
|
1231
|
+
alertEpisode
|
|
1232
|
+
) {
|
|
1233
|
+
await dispatchWebhook({
|
|
1234
|
+
eventType: "on-call.alertEpisode.created",
|
|
1235
|
+
entityKind: "alertEpisode",
|
|
1236
|
+
payload: {
|
|
1237
|
+
eventType: "on-call.alertEpisode.created",
|
|
1238
|
+
timestamp: new Date().toISOString(),
|
|
1239
|
+
projectId: alertEpisode.projectId?.toString() || "",
|
|
1240
|
+
userId: notificationRuleItem.userId!.toString(),
|
|
1241
|
+
alertEpisode: {
|
|
1242
|
+
id: alertEpisode.id?.toString() || "",
|
|
1243
|
+
title: alertEpisode.title || "",
|
|
1244
|
+
description: alertEpisode.description || "",
|
|
1245
|
+
episodeNumber: alertEpisode.episodeNumber || null,
|
|
1246
|
+
episodeNumberWithPrefix:
|
|
1247
|
+
alertEpisode.episodeNumberWithPrefix || null,
|
|
1248
|
+
severity: alertEpisode.alertSeverity?.name || null,
|
|
1249
|
+
state: alertEpisode.currentAlertState?.name || null,
|
|
1250
|
+
},
|
|
1251
|
+
onCallPolicyId: options.onCallPolicyId?.toString() || null,
|
|
1252
|
+
onCallPolicyEscalationRuleId:
|
|
1253
|
+
options.onCallPolicyEscalationRuleId?.toString() || null,
|
|
1254
|
+
},
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
if (
|
|
1259
|
+
options.userNotificationEventType ===
|
|
1260
|
+
UserNotificationEventType.IncidentEpisodeCreated &&
|
|
1261
|
+
incidentEpisode
|
|
1262
|
+
) {
|
|
1263
|
+
await dispatchWebhook({
|
|
1264
|
+
eventType: "on-call.incidentEpisode.created",
|
|
1265
|
+
entityKind: "incidentEpisode",
|
|
1266
|
+
payload: {
|
|
1267
|
+
eventType: "on-call.incidentEpisode.created",
|
|
1268
|
+
timestamp: new Date().toISOString(),
|
|
1269
|
+
projectId: incidentEpisode.projectId?.toString() || "",
|
|
1270
|
+
userId: notificationRuleItem.userId!.toString(),
|
|
1271
|
+
incidentEpisode: {
|
|
1272
|
+
id: incidentEpisode.id?.toString() || "",
|
|
1273
|
+
title: incidentEpisode.title || "",
|
|
1274
|
+
description: incidentEpisode.description || "",
|
|
1275
|
+
episodeNumber: incidentEpisode.episodeNumber || null,
|
|
1276
|
+
episodeNumberWithPrefix:
|
|
1277
|
+
incidentEpisode.episodeNumberWithPrefix || null,
|
|
1278
|
+
severity: incidentEpisode.incidentSeverity?.name || null,
|
|
1279
|
+
state: incidentEpisode.currentIncidentState?.name || null,
|
|
1280
|
+
},
|
|
1281
|
+
onCallPolicyId: options.onCallPolicyId?.toString() || null,
|
|
1282
|
+
onCallPolicyEscalationRuleId:
|
|
1283
|
+
options.onCallPolicyEscalationRuleId?.toString() || null,
|
|
1284
|
+
},
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1085
1289
|
// send call.
|
|
1086
1290
|
if (
|
|
1087
1291
|
notificationRuleItem.userCall?.phone &&
|
|
@@ -2631,12 +2835,14 @@ export class Service extends DatabaseService<Model> {
|
|
|
2631
2835
|
!createBy.data.userWhatsAppId &&
|
|
2632
2836
|
!createBy.data.userTelegram &&
|
|
2633
2837
|
!createBy.data.userTelegramId &&
|
|
2838
|
+
!createBy.data.userWebhook &&
|
|
2839
|
+
!createBy.data.userWebhookId &&
|
|
2634
2840
|
!createBy.data.userEmailId &&
|
|
2635
2841
|
!createBy.data.userPushId &&
|
|
2636
2842
|
!createBy.data.userPush
|
|
2637
2843
|
) {
|
|
2638
2844
|
throw new BadDataException(
|
|
2639
|
-
"Call, SMS, WhatsApp, Telegram, Email, or Push notification is required",
|
|
2845
|
+
"Call, SMS, WhatsApp, Telegram, Webhook, Email, or Push notification is required",
|
|
2640
2846
|
);
|
|
2641
2847
|
}
|
|
2642
2848
|
|
|
@@ -2701,6 +2907,9 @@ export class Service extends DatabaseService<Model> {
|
|
|
2701
2907
|
if (descriptor.userTelegramId) {
|
|
2702
2908
|
rule.userTelegramId = descriptor.userTelegramId;
|
|
2703
2909
|
}
|
|
2910
|
+
if (descriptor.userWebhookId) {
|
|
2911
|
+
rule.userWebhookId = descriptor.userWebhookId;
|
|
2912
|
+
}
|
|
2704
2913
|
if (descriptor.userPushId) {
|
|
2705
2914
|
rule.userPushId = descriptor.userPushId;
|
|
2706
2915
|
}
|
|
@@ -2725,6 +2934,9 @@ export class Service extends DatabaseService<Model> {
|
|
|
2725
2934
|
if (descriptor.userTelegramId) {
|
|
2726
2935
|
query["userTelegramId"] = descriptor.userTelegramId;
|
|
2727
2936
|
}
|
|
2937
|
+
if (descriptor.userWebhookId) {
|
|
2938
|
+
query["userWebhookId"] = descriptor.userWebhookId;
|
|
2939
|
+
}
|
|
2728
2940
|
if (descriptor.userPushId) {
|
|
2729
2941
|
query["userPushId"] = descriptor.userPushId;
|
|
2730
2942
|
}
|
|
@@ -12,7 +12,9 @@ import UserEmailService from "./UserEmailService";
|
|
|
12
12
|
import UserSmsService from "./UserSmsService";
|
|
13
13
|
import PushNotificationService from "./PushNotificationService";
|
|
14
14
|
import UserTelegramService from "./UserTelegramService";
|
|
15
|
+
import UserWebhookService from "./UserWebhookService";
|
|
15
16
|
import UserWhatsAppService from "./UserWhatsAppService";
|
|
17
|
+
import WebhookService from "./WebhookService";
|
|
16
18
|
import WhatsAppService from "./WhatsAppService";
|
|
17
19
|
import { CallRequestMessage } from "../../Types/Call/CallRequest";
|
|
18
20
|
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
@@ -29,11 +31,13 @@ import TelegramMessage, {
|
|
|
29
31
|
import WhatsAppMessage, {
|
|
30
32
|
WhatsAppMessagePayload,
|
|
31
33
|
} from "../../Types/WhatsApp/WhatsAppMessage";
|
|
34
|
+
import { JSONObject } from "../../Types/JSON";
|
|
32
35
|
import UserCall from "../../Models/DatabaseModels/UserCall";
|
|
33
36
|
import UserEmail from "../../Models/DatabaseModels/UserEmail";
|
|
34
37
|
import UserNotificationSetting from "../../Models/DatabaseModels/UserNotificationSetting";
|
|
35
38
|
import UserSMS from "../../Models/DatabaseModels/UserSMS";
|
|
36
39
|
import UserTelegram from "../../Models/DatabaseModels/UserTelegram";
|
|
40
|
+
import UserWebhook from "../../Models/DatabaseModels/UserWebhook";
|
|
37
41
|
import UserWhatsApp from "../../Models/DatabaseModels/UserWhatsApp";
|
|
38
42
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
39
43
|
import { appendRecipientToWhatsAppMessage } from "../Utils/WhatsAppTemplateUtil";
|
|
@@ -89,6 +93,7 @@ export class Service extends DatabaseService<UserNotificationSetting> {
|
|
|
89
93
|
alertByTelegram: true,
|
|
90
94
|
alertByCall: true,
|
|
91
95
|
alertByPush: true,
|
|
96
|
+
alertByWebhook: true,
|
|
92
97
|
},
|
|
93
98
|
props: {
|
|
94
99
|
isRoot: true,
|
|
@@ -425,6 +430,96 @@ export class Service extends DatabaseService<UserNotificationSetting> {
|
|
|
425
430
|
logger.error(err);
|
|
426
431
|
});
|
|
427
432
|
}
|
|
433
|
+
|
|
434
|
+
if (notificationSettings.alertByWebhook) {
|
|
435
|
+
const userWebhooks: Array<UserWebhook> =
|
|
436
|
+
await UserWebhookService.findBy({
|
|
437
|
+
query: {
|
|
438
|
+
userId: data.userId,
|
|
439
|
+
projectId: data.projectId,
|
|
440
|
+
},
|
|
441
|
+
select: {
|
|
442
|
+
webhookUrl: true,
|
|
443
|
+
secret: true,
|
|
444
|
+
name: true,
|
|
445
|
+
},
|
|
446
|
+
limit: LIMIT_PER_PROJECT,
|
|
447
|
+
skip: 0,
|
|
448
|
+
props: {
|
|
449
|
+
isRoot: true,
|
|
450
|
+
},
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
const webhookPayload: JSONObject = {
|
|
454
|
+
eventType: data.eventType,
|
|
455
|
+
timestamp: new Date().toISOString(),
|
|
456
|
+
projectId: data.projectId.toString(),
|
|
457
|
+
userId: data.userId.toString(),
|
|
458
|
+
subject: data.emailEnvelope?.subject || "",
|
|
459
|
+
message: data.smsMessage?.message || "",
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
if (data.incidentId) {
|
|
463
|
+
webhookPayload["incidentId"] = data.incidentId.toString();
|
|
464
|
+
}
|
|
465
|
+
if (data.alertId) {
|
|
466
|
+
webhookPayload["alertId"] = data.alertId.toString();
|
|
467
|
+
}
|
|
468
|
+
if (data.monitorId) {
|
|
469
|
+
webhookPayload["monitorId"] = data.monitorId.toString();
|
|
470
|
+
}
|
|
471
|
+
if (data.scheduledMaintenanceId) {
|
|
472
|
+
webhookPayload["scheduledMaintenanceId"] =
|
|
473
|
+
data.scheduledMaintenanceId.toString();
|
|
474
|
+
}
|
|
475
|
+
if (data.statusPageId) {
|
|
476
|
+
webhookPayload["statusPageId"] = data.statusPageId.toString();
|
|
477
|
+
}
|
|
478
|
+
if (data.statusPageAnnouncementId) {
|
|
479
|
+
webhookPayload["statusPageAnnouncementId"] =
|
|
480
|
+
data.statusPageAnnouncementId.toString();
|
|
481
|
+
}
|
|
482
|
+
if (data.onCallPolicyId) {
|
|
483
|
+
webhookPayload["onCallPolicyId"] = data.onCallPolicyId.toString();
|
|
484
|
+
}
|
|
485
|
+
if (data.onCallPolicyEscalationRuleId) {
|
|
486
|
+
webhookPayload["onCallPolicyEscalationRuleId"] =
|
|
487
|
+
data.onCallPolicyEscalationRuleId.toString();
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
for (const userWebhook of userWebhooks) {
|
|
491
|
+
if (!userWebhook.webhookUrl) {
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
WebhookService.sendWebhook(
|
|
496
|
+
{
|
|
497
|
+
url: userWebhook.webhookUrl,
|
|
498
|
+
eventType: data.eventType,
|
|
499
|
+
payload: webhookPayload,
|
|
500
|
+
secret: userWebhook.secret,
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
projectId: data.projectId,
|
|
504
|
+
incidentId: data.incidentId,
|
|
505
|
+
alertId: data.alertId,
|
|
506
|
+
monitorId: data.monitorId,
|
|
507
|
+
scheduledMaintenanceId: data.scheduledMaintenanceId,
|
|
508
|
+
statusPageId: data.statusPageId,
|
|
509
|
+
statusPageAnnouncementId: data.statusPageAnnouncementId,
|
|
510
|
+
userId: data.userId,
|
|
511
|
+
teamId: data.teamId,
|
|
512
|
+
onCallPolicyId: data.onCallPolicyId,
|
|
513
|
+
onCallPolicyEscalationRuleId: data.onCallPolicyEscalationRuleId,
|
|
514
|
+
onCallDutyPolicyExecutionLogTimelineId:
|
|
515
|
+
data.onCallDutyPolicyExecutionLogTimelineId,
|
|
516
|
+
onCallScheduleId: data.onCallScheduleId,
|
|
517
|
+
},
|
|
518
|
+
).catch((err: Error) => {
|
|
519
|
+
logger.error(err);
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
}
|
|
428
523
|
}
|
|
429
524
|
}
|
|
430
525
|
|