@oneuptime/common 9.4.8 → 9.4.11

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.
Files changed (75) hide show
  1. package/Models/DatabaseModels/Alert.ts +1 -0
  2. package/Models/DatabaseModels/AlertFeed.ts +1 -0
  3. package/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.ts +59 -0
  4. package/Models/DatabaseModels/UserOnCallLog.ts +48 -0
  5. package/Models/DatabaseModels/UserOnCallLogTimeline.ts +49 -0
  6. package/Server/API/UserOnCallLogTimelineAPI.ts +65 -25
  7. package/Server/Infrastructure/Postgres/SchemaMigrations/1769469813786-MigrationName.ts +71 -0
  8. package/Server/Infrastructure/Postgres/SchemaMigrations/1769517677937-RenameNotificationRuleTypes.ts +67 -0
  9. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  10. package/Server/Services/AlertEpisodeMemberService.ts +49 -1
  11. package/Server/Services/AlertEpisodeService.ts +134 -26
  12. package/Server/Services/AlertGroupingEngineService.ts +3 -168
  13. package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +18 -1
  14. package/Server/Services/OnCallDutyPolicyExecutionLogService.ts +64 -2
  15. package/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.ts +27 -1
  16. package/Server/Services/OnCallDutyPolicyService.ts +11 -1
  17. package/Server/Services/PushNotificationService.ts +1 -0
  18. package/Server/Services/UserNotificationRuleService.ts +670 -10
  19. package/Server/Services/UserOnCallLogService.ts +58 -14
  20. package/Server/Utils/PushNotificationUtil.ts +75 -16
  21. package/Types/Database/TableColumn.ts +1 -0
  22. package/Types/Email/EmailTemplateType.ts +1 -0
  23. package/Types/NotificationRule/NotificationRuleType.ts +3 -2
  24. package/Types/WhatsApp/WhatsAppTemplates.ts +4 -0
  25. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +1 -1
  26. package/Utils/Schema/ModelSchema.ts +2 -0
  27. package/build/dist/Models/DatabaseModels/Alert.js +1 -0
  28. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  29. package/build/dist/Models/DatabaseModels/AlertFeed.js +1 -0
  30. package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
  31. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.js +58 -0
  32. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.js.map +1 -1
  33. package/build/dist/Models/DatabaseModels/UserOnCallLog.js +47 -0
  34. package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
  35. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +48 -0
  36. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
  37. package/build/dist/Server/API/UserOnCallLogTimelineAPI.js +55 -15
  38. package/build/dist/Server/API/UserOnCallLogTimelineAPI.js.map +1 -1
  39. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769469813786-MigrationName.js +30 -0
  40. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769469813786-MigrationName.js.map +1 -0
  41. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769517677937-RenameNotificationRuleTypes.js +67 -0
  42. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769517677937-RenameNotificationRuleTypes.js.map +1 -0
  43. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  44. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  45. package/build/dist/Server/Services/AlertEpisodeMemberService.js +43 -1
  46. package/build/dist/Server/Services/AlertEpisodeMemberService.js.map +1 -1
  47. package/build/dist/Server/Services/AlertEpisodeService.js +111 -23
  48. package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
  49. package/build/dist/Server/Services/AlertGroupingEngineService.js +8 -137
  50. package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -1
  51. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +10 -1
  52. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
  53. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js +49 -2
  54. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js.map +1 -1
  55. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js +21 -1
  56. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js.map +1 -1
  57. package/build/dist/Server/Services/OnCallDutyPolicyService.js +6 -1
  58. package/build/dist/Server/Services/OnCallDutyPolicyService.js.map +1 -1
  59. package/build/dist/Server/Services/PushNotificationService.js.map +1 -1
  60. package/build/dist/Server/Services/UserNotificationRuleService.js +540 -51
  61. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  62. package/build/dist/Server/Services/UserOnCallLogService.js +48 -12
  63. package/build/dist/Server/Services/UserOnCallLogService.js.map +1 -1
  64. package/build/dist/Server/Utils/PushNotificationUtil.js +51 -16
  65. package/build/dist/Server/Utils/PushNotificationUtil.js.map +1 -1
  66. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  67. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  68. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  69. package/build/dist/Types/NotificationRule/NotificationRuleType.js +3 -2
  70. package/build/dist/Types/NotificationRule/NotificationRuleType.js.map +1 -1
  71. package/build/dist/Types/WhatsApp/WhatsAppTemplates.js +3 -0
  72. package/build/dist/Types/WhatsApp/WhatsAppTemplates.js.map +1 -1
  73. package/build/dist/Utils/Schema/ModelSchema.js +2 -0
  74. package/build/dist/Utils/Schema/ModelSchema.js.map +1 -1
  75. package/package.json +1 -1
@@ -24,6 +24,7 @@ import { AppApiRoute } from "../../ServiceRoute";
24
24
  import Route from "../../Types/API/Route";
25
25
  import URL from "../../Types/API/URL";
26
26
  import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
27
+ import QueryHelper from "../Types/Database/QueryHelper";
27
28
  import OneUptimeDate from "../../Types/Date";
28
29
  import Email from "../../Types/Email";
29
30
  import EmailTemplateType from "../../Types/Email/EmailTemplateType";
@@ -43,6 +44,9 @@ import UserOnCallLogTimeline from "../../Models/DatabaseModels/UserOnCallLogTime
43
44
  import Alert from "../../Models/DatabaseModels/Alert";
44
45
  import AlertService from "./AlertService";
45
46
  import AlertSeverityService from "./AlertSeverityService";
47
+ import AlertEpisode from "../../Models/DatabaseModels/AlertEpisode";
48
+ import AlertEpisodeService from "./AlertEpisodeService";
49
+ import AlertEpisodeMemberService from "./AlertEpisodeMemberService";
46
50
  import WorkspaceNotificationRuleService from "./WorkspaceNotificationRuleService";
47
51
  import PushNotificationService from "./PushNotificationService";
48
52
  import NotificationRuleEventType from "../../Types/Workspace/NotificationRules/EventType";
@@ -55,7 +59,7 @@ export class Service extends DatabaseService {
55
59
  }
56
60
  async executeNotificationRuleItem(userNotificationRuleId, options) {
57
61
  // get user notification log and see if this rule has already been executed. If so then skip.
58
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13;
62
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20;
59
63
  const userOnCallLog = await UserOnCallLogService.findOneById({
60
64
  id: options.userNotificationLogId,
61
65
  props: {
@@ -150,6 +154,10 @@ export class Service extends DatabaseService {
150
154
  if (options.triggeredByAlertId) {
151
155
  logTimelineItem.triggeredByAlertId = options.triggeredByAlertId;
152
156
  }
157
+ if (options.triggeredByAlertEpisodeId) {
158
+ logTimelineItem.triggeredByAlertEpisodeId =
159
+ options.triggeredByAlertEpisodeId;
160
+ }
153
161
  if (options.onCallDutyPolicyExecutionLogTimelineId) {
154
162
  logTimelineItem.onCallDutyPolicyExecutionLogTimelineId =
155
163
  options.onCallDutyPolicyExecutionLogTimelineId;
@@ -157,6 +165,7 @@ export class Service extends DatabaseService {
157
165
  // add status and status message and save.
158
166
  let incident = null;
159
167
  let alert = null;
168
+ let alertEpisode = null;
160
169
  if (options.userNotificationEventType ===
161
170
  UserNotificationEventType.IncidentCreated &&
162
171
  options.triggeredByIncidentId) {
@@ -210,8 +219,35 @@ export class Service extends DatabaseService {
210
219
  },
211
220
  });
212
221
  }
213
- if (!incident && !alert) {
214
- throw new BadDataException("Incident or Alert not found.");
222
+ if (options.userNotificationEventType ===
223
+ UserNotificationEventType.AlertEpisodeCreated &&
224
+ options.triggeredByAlertEpisodeId) {
225
+ alertEpisode = await AlertEpisodeService.findOneById({
226
+ id: options.triggeredByAlertEpisodeId,
227
+ props: {
228
+ isRoot: true,
229
+ },
230
+ select: {
231
+ _id: true,
232
+ title: true,
233
+ description: true,
234
+ projectId: true,
235
+ project: {
236
+ name: true,
237
+ },
238
+ currentAlertState: {
239
+ name: true,
240
+ },
241
+ alertSeverity: {
242
+ name: true,
243
+ },
244
+ episodeNumber: true,
245
+ rootCause: true,
246
+ },
247
+ });
248
+ }
249
+ if (!incident && !alert && !alertEpisode) {
250
+ throw new BadDataException("Incident, Alert, or Alert Episode not found.");
215
251
  }
216
252
  if (((_a = notificationRuleItem.userEmail) === null || _a === void 0 ? void 0 : _a.email) &&
217
253
  ((_b = notificationRuleItem.userEmail) === null || _b === void 0 ? void 0 : _b.isVerified)) {
@@ -293,13 +329,50 @@ export class Service extends DatabaseService {
293
329
  });
294
330
  });
295
331
  }
332
+ // send email for alert episode
333
+ if (options.userNotificationEventType ===
334
+ UserNotificationEventType.AlertEpisodeCreated &&
335
+ alertEpisode) {
336
+ logTimelineItem.status = UserNotificationStatus.Sending;
337
+ logTimelineItem.statusMessage = `Sending email to ${(_g = notificationRuleItem.userEmail) === null || _g === void 0 ? void 0 : _g.email.toString()}`;
338
+ logTimelineItem.userEmailId = notificationRuleItem.userEmail.id;
339
+ const updatedLog = await UserOnCallLogTimelineService.create({
340
+ data: logTimelineItem,
341
+ props: {
342
+ isRoot: true,
343
+ },
344
+ });
345
+ const emailMessage = await this.generateEmailTemplateForAlertEpisodeCreated((_h = notificationRuleItem.userEmail) === null || _h === void 0 ? void 0 : _h.email, alertEpisode, updatedLog.id);
346
+ MailService.sendMail(emailMessage, {
347
+ userOnCallLogTimelineId: updatedLog.id,
348
+ projectId: options.projectId,
349
+ alertEpisodeId: alertEpisode.id,
350
+ userId: notificationRuleItem.userId,
351
+ onCallPolicyId: options.onCallPolicyId,
352
+ onCallPolicyEscalationRuleId: options.onCallPolicyEscalationRuleId,
353
+ teamId: options.userBelongsToTeamId,
354
+ onCallDutyPolicyExecutionLogTimelineId: options.onCallDutyPolicyExecutionLogTimelineId,
355
+ onCallScheduleId: options.onCallScheduleId,
356
+ }).catch(async (err) => {
357
+ await UserOnCallLogTimelineService.updateOneById({
358
+ id: updatedLog.id,
359
+ data: {
360
+ status: UserNotificationStatus.Error,
361
+ statusMessage: err.message || "Error sending email.",
362
+ },
363
+ props: {
364
+ isRoot: true,
365
+ },
366
+ });
367
+ });
368
+ }
296
369
  }
297
370
  // if you have an email but is not verified, then create a log.
298
- if (((_g = notificationRuleItem.userEmail) === null || _g === void 0 ? void 0 : _g.email) &&
299
- !((_h = notificationRuleItem.userEmail) === null || _h === void 0 ? void 0 : _h.isVerified)) {
371
+ if (((_j = notificationRuleItem.userEmail) === null || _j === void 0 ? void 0 : _j.email) &&
372
+ !((_k = notificationRuleItem.userEmail) === null || _k === void 0 ? void 0 : _k.isVerified)) {
300
373
  // create an error log.
301
374
  logTimelineItem.status = UserNotificationStatus.Error;
302
- logTimelineItem.statusMessage = `Email notification not sent because email ${(_j = notificationRuleItem.userEmail) === null || _j === void 0 ? void 0 : _j.email.toString()} is not verified.`;
375
+ logTimelineItem.statusMessage = `Email notification not sent because email ${(_l = notificationRuleItem.userEmail) === null || _l === void 0 ? void 0 : _l.email.toString()} is not verified.`;
303
376
  await UserOnCallLogTimelineService.create({
304
377
  data: logTimelineItem,
305
378
  props: {
@@ -308,15 +381,15 @@ export class Service extends DatabaseService {
308
381
  });
309
382
  }
310
383
  // send sms.
311
- if (((_k = notificationRuleItem.userSms) === null || _k === void 0 ? void 0 : _k.phone) &&
312
- ((_l = notificationRuleItem.userSms) === null || _l === void 0 ? void 0 : _l.isVerified)) {
384
+ if (((_m = notificationRuleItem.userSms) === null || _m === void 0 ? void 0 : _m.phone) &&
385
+ ((_o = notificationRuleItem.userSms) === null || _o === void 0 ? void 0 : _o.isVerified)) {
313
386
  //send sms for alert
314
387
  if (options.userNotificationEventType ===
315
388
  UserNotificationEventType.AlertCreated &&
316
389
  alert) {
317
390
  // create an error log.
318
391
  logTimelineItem.status = UserNotificationStatus.Sending;
319
- logTimelineItem.statusMessage = `Sending SMS to ${(_m = notificationRuleItem.userSms) === null || _m === void 0 ? void 0 : _m.phone.toString()}.`;
392
+ logTimelineItem.statusMessage = `Sending SMS to ${(_p = notificationRuleItem.userSms) === null || _p === void 0 ? void 0 : _p.phone.toString()}.`;
320
393
  logTimelineItem.userSmsId = notificationRuleItem.userSms.id;
321
394
  const updatedLog = await UserOnCallLogTimelineService.create({
322
395
  data: logTimelineItem,
@@ -355,7 +428,7 @@ export class Service extends DatabaseService {
355
428
  incident) {
356
429
  // create an error log.
357
430
  logTimelineItem.status = UserNotificationStatus.Sending;
358
- logTimelineItem.statusMessage = `Sending SMS to ${(_o = notificationRuleItem.userSms) === null || _o === void 0 ? void 0 : _o.phone.toString()}.`;
431
+ logTimelineItem.statusMessage = `Sending SMS to ${(_q = notificationRuleItem.userSms) === null || _q === void 0 ? void 0 : _q.phone.toString()}.`;
359
432
  logTimelineItem.userSmsId = notificationRuleItem.userSms.id;
360
433
  const updatedLog = await UserOnCallLogTimelineService.create({
361
434
  data: logTimelineItem,
@@ -388,12 +461,49 @@ export class Service extends DatabaseService {
388
461
  });
389
462
  });
390
463
  }
464
+ // send sms for alert episode
465
+ if (options.userNotificationEventType ===
466
+ UserNotificationEventType.AlertEpisodeCreated &&
467
+ alertEpisode) {
468
+ logTimelineItem.status = UserNotificationStatus.Sending;
469
+ logTimelineItem.statusMessage = `Sending SMS to ${(_r = notificationRuleItem.userSms) === null || _r === void 0 ? void 0 : _r.phone.toString()}.`;
470
+ logTimelineItem.userSmsId = notificationRuleItem.userSms.id;
471
+ const updatedLog = await UserOnCallLogTimelineService.create({
472
+ data: logTimelineItem,
473
+ props: {
474
+ isRoot: true,
475
+ },
476
+ });
477
+ const smsMessage = await this.generateSmsTemplateForAlertEpisodeCreated(notificationRuleItem.userSms.phone, alertEpisode, updatedLog.id);
478
+ SmsService.sendSms(smsMessage, {
479
+ projectId: alertEpisode.projectId,
480
+ userOnCallLogTimelineId: updatedLog.id,
481
+ alertEpisodeId: alertEpisode.id,
482
+ userId: notificationRuleItem.userId,
483
+ onCallPolicyId: options.onCallPolicyId,
484
+ onCallPolicyEscalationRuleId: options.onCallPolicyEscalationRuleId,
485
+ teamId: options.userBelongsToTeamId,
486
+ onCallDutyPolicyExecutionLogTimelineId: options.onCallDutyPolicyExecutionLogTimelineId,
487
+ onCallScheduleId: options.onCallScheduleId,
488
+ }).catch(async (err) => {
489
+ await UserOnCallLogTimelineService.updateOneById({
490
+ id: updatedLog.id,
491
+ data: {
492
+ status: UserNotificationStatus.Error,
493
+ statusMessage: err.message || "Error sending SMS.",
494
+ },
495
+ props: {
496
+ isRoot: true,
497
+ },
498
+ });
499
+ });
500
+ }
391
501
  }
392
- if (((_p = notificationRuleItem.userSms) === null || _p === void 0 ? void 0 : _p.phone) &&
393
- !((_q = notificationRuleItem.userSms) === null || _q === void 0 ? void 0 : _q.isVerified)) {
502
+ if (((_s = notificationRuleItem.userSms) === null || _s === void 0 ? void 0 : _s.phone) &&
503
+ !((_t = notificationRuleItem.userSms) === null || _t === void 0 ? void 0 : _t.isVerified)) {
394
504
  // create a log.
395
505
  logTimelineItem.status = UserNotificationStatus.Error;
396
- logTimelineItem.statusMessage = `SMS not sent because phone ${(_r = notificationRuleItem.userSms) === null || _r === void 0 ? void 0 : _r.phone.toString()} is not verified.`;
506
+ logTimelineItem.statusMessage = `SMS not sent because phone ${(_u = notificationRuleItem.userSms) === null || _u === void 0 ? void 0 : _u.phone.toString()} is not verified.`;
397
507
  await UserOnCallLogTimelineService.create({
398
508
  data: logTimelineItem,
399
509
  props: {
@@ -401,13 +511,13 @@ export class Service extends DatabaseService {
401
511
  },
402
512
  });
403
513
  }
404
- if (((_s = notificationRuleItem.userWhatsApp) === null || _s === void 0 ? void 0 : _s.phone) &&
405
- ((_t = notificationRuleItem.userWhatsApp) === null || _t === void 0 ? void 0 : _t.isVerified)) {
514
+ if (((_v = notificationRuleItem.userWhatsApp) === null || _v === void 0 ? void 0 : _v.phone) &&
515
+ ((_w = notificationRuleItem.userWhatsApp) === null || _w === void 0 ? void 0 : _w.isVerified)) {
406
516
  if (options.userNotificationEventType ===
407
517
  UserNotificationEventType.AlertCreated &&
408
518
  alert) {
409
519
  logTimelineItem.status = UserNotificationStatus.Sending;
410
- logTimelineItem.statusMessage = `Sending WhatsApp message to ${(_u = notificationRuleItem.userWhatsApp) === null || _u === void 0 ? void 0 : _u.phone.toString()}.`;
520
+ logTimelineItem.statusMessage = `Sending WhatsApp message to ${(_x = notificationRuleItem.userWhatsApp) === null || _x === void 0 ? void 0 : _x.phone.toString()}.`;
411
521
  logTimelineItem.userWhatsAppId = notificationRuleItem.userWhatsApp.id;
412
522
  const updatedLog = await UserOnCallLogTimelineService.create({
413
523
  data: logTimelineItem,
@@ -443,7 +553,7 @@ export class Service extends DatabaseService {
443
553
  UserNotificationEventType.IncidentCreated &&
444
554
  incident) {
445
555
  logTimelineItem.status = UserNotificationStatus.Sending;
446
- logTimelineItem.statusMessage = `Sending WhatsApp message to ${(_v = notificationRuleItem.userWhatsApp) === null || _v === void 0 ? void 0 : _v.phone.toString()}.`;
556
+ logTimelineItem.statusMessage = `Sending WhatsApp message to ${(_y = notificationRuleItem.userWhatsApp) === null || _y === void 0 ? void 0 : _y.phone.toString()}.`;
447
557
  logTimelineItem.userWhatsAppId = notificationRuleItem.userWhatsApp.id;
448
558
  const updatedLog = await UserOnCallLogTimelineService.create({
449
559
  data: logTimelineItem,
@@ -475,11 +585,48 @@ export class Service extends DatabaseService {
475
585
  });
476
586
  });
477
587
  }
588
+ // send WhatsApp for alert episode
589
+ if (options.userNotificationEventType ===
590
+ UserNotificationEventType.AlertEpisodeCreated &&
591
+ alertEpisode) {
592
+ logTimelineItem.status = UserNotificationStatus.Sending;
593
+ logTimelineItem.statusMessage = `Sending WhatsApp message to ${(_z = notificationRuleItem.userWhatsApp) === null || _z === void 0 ? void 0 : _z.phone.toString()}.`;
594
+ logTimelineItem.userWhatsAppId = notificationRuleItem.userWhatsApp.id;
595
+ const updatedLog = await UserOnCallLogTimelineService.create({
596
+ data: logTimelineItem,
597
+ props: {
598
+ isRoot: true,
599
+ },
600
+ });
601
+ const whatsAppMessage = await this.generateWhatsAppTemplateForAlertEpisodeCreated(notificationRuleItem.userWhatsApp.phone, alertEpisode, updatedLog.id);
602
+ WhatsAppService.sendWhatsAppMessage(whatsAppMessage, {
603
+ projectId: alertEpisode.projectId,
604
+ alertEpisodeId: alertEpisode.id,
605
+ userOnCallLogTimelineId: updatedLog.id,
606
+ userId: notificationRuleItem.userId,
607
+ onCallPolicyId: options.onCallPolicyId,
608
+ onCallPolicyEscalationRuleId: options.onCallPolicyEscalationRuleId,
609
+ teamId: options.userBelongsToTeamId,
610
+ onCallDutyPolicyExecutionLogTimelineId: options.onCallDutyPolicyExecutionLogTimelineId,
611
+ onCallScheduleId: options.onCallScheduleId,
612
+ }).catch(async (err) => {
613
+ await UserOnCallLogTimelineService.updateOneById({
614
+ id: updatedLog.id,
615
+ data: {
616
+ status: UserNotificationStatus.Error,
617
+ statusMessage: err.message || "Error sending WhatsApp message.",
618
+ },
619
+ props: {
620
+ isRoot: true,
621
+ },
622
+ });
623
+ });
624
+ }
478
625
  }
479
- if (((_w = notificationRuleItem.userWhatsApp) === null || _w === void 0 ? void 0 : _w.phone) &&
480
- !((_x = notificationRuleItem.userWhatsApp) === null || _x === void 0 ? void 0 : _x.isVerified)) {
626
+ if (((_0 = notificationRuleItem.userWhatsApp) === null || _0 === void 0 ? void 0 : _0.phone) &&
627
+ !((_1 = notificationRuleItem.userWhatsApp) === null || _1 === void 0 ? void 0 : _1.isVerified)) {
481
628
  logTimelineItem.status = UserNotificationStatus.Error;
482
- logTimelineItem.statusMessage = `WhatsApp message not sent because phone ${(_y = notificationRuleItem.userWhatsApp) === null || _y === void 0 ? void 0 : _y.phone.toString()} is not verified.`;
629
+ logTimelineItem.statusMessage = `WhatsApp message not sent because phone ${(_2 = notificationRuleItem.userWhatsApp) === null || _2 === void 0 ? void 0 : _2.phone.toString()} is not verified.`;
483
630
  logTimelineItem.userWhatsAppId = notificationRuleItem.userWhatsApp.id;
484
631
  await UserOnCallLogTimelineService.create({
485
632
  data: logTimelineItem,
@@ -489,15 +636,15 @@ export class Service extends DatabaseService {
489
636
  });
490
637
  }
491
638
  // send call.
492
- if (((_z = notificationRuleItem.userCall) === null || _z === void 0 ? void 0 : _z.phone) &&
493
- ((_0 = notificationRuleItem.userCall) === null || _0 === void 0 ? void 0 : _0.isVerified)) {
639
+ if (((_3 = notificationRuleItem.userCall) === null || _3 === void 0 ? void 0 : _3.phone) &&
640
+ ((_4 = notificationRuleItem.userCall) === null || _4 === void 0 ? void 0 : _4.isVerified)) {
494
641
  // send call for alert
495
642
  if (options.userNotificationEventType ===
496
643
  UserNotificationEventType.AlertCreated &&
497
644
  alert) {
498
645
  // create an error log.
499
646
  logTimelineItem.status = UserNotificationStatus.Sending;
500
- logTimelineItem.statusMessage = `Making a call to ${(_1 = notificationRuleItem.userCall) === null || _1 === void 0 ? void 0 : _1.phone.toString()}.`;
647
+ logTimelineItem.statusMessage = `Making a call to ${(_5 = notificationRuleItem.userCall) === null || _5 === void 0 ? void 0 : _5.phone.toString()}.`;
501
648
  logTimelineItem.userCallId = notificationRuleItem.userCall.id;
502
649
  const updatedLog = await UserOnCallLogTimelineService.create({
503
650
  data: logTimelineItem,
@@ -505,7 +652,7 @@ export class Service extends DatabaseService {
505
652
  isRoot: true,
506
653
  },
507
654
  });
508
- const callRequest = await this.generateCallTemplateForAlertCreated((_2 = notificationRuleItem.userCall) === null || _2 === void 0 ? void 0 : _2.phone, alert, updatedLog.id);
655
+ const callRequest = await this.generateCallTemplateForAlertCreated((_6 = notificationRuleItem.userCall) === null || _6 === void 0 ? void 0 : _6.phone, alert, updatedLog.id);
509
656
  // send call.
510
657
  CallService.makeCall(callRequest, {
511
658
  projectId: alert.projectId,
@@ -535,7 +682,7 @@ export class Service extends DatabaseService {
535
682
  incident) {
536
683
  // send call for incident
537
684
  logTimelineItem.status = UserNotificationStatus.Sending;
538
- logTimelineItem.statusMessage = `Making a call to ${(_3 = notificationRuleItem.userCall) === null || _3 === void 0 ? void 0 : _3.phone.toString()}.`;
685
+ logTimelineItem.statusMessage = `Making a call to ${(_7 = notificationRuleItem.userCall) === null || _7 === void 0 ? void 0 : _7.phone.toString()}.`;
539
686
  logTimelineItem.userCallId = notificationRuleItem.userCall.id;
540
687
  const updatedLog = await UserOnCallLogTimelineService.create({
541
688
  data: logTimelineItem,
@@ -543,7 +690,7 @@ export class Service extends DatabaseService {
543
690
  isRoot: true,
544
691
  },
545
692
  });
546
- const callRequest = await this.generateCallTemplateForIncidentCreated((_4 = notificationRuleItem.userCall) === null || _4 === void 0 ? void 0 : _4.phone, incident, updatedLog.id);
693
+ const callRequest = await this.generateCallTemplateForIncidentCreated((_8 = notificationRuleItem.userCall) === null || _8 === void 0 ? void 0 : _8.phone, incident, updatedLog.id);
547
694
  // send call.
548
695
  CallService.makeCall(callRequest, {
549
696
  projectId: incident.projectId,
@@ -568,12 +715,49 @@ export class Service extends DatabaseService {
568
715
  });
569
716
  });
570
717
  }
718
+ // send call for alert episode
719
+ if (options.userNotificationEventType ===
720
+ UserNotificationEventType.AlertEpisodeCreated &&
721
+ alertEpisode) {
722
+ logTimelineItem.status = UserNotificationStatus.Sending;
723
+ logTimelineItem.statusMessage = `Making a call to ${(_9 = notificationRuleItem.userCall) === null || _9 === void 0 ? void 0 : _9.phone.toString()}.`;
724
+ logTimelineItem.userCallId = notificationRuleItem.userCall.id;
725
+ const updatedLog = await UserOnCallLogTimelineService.create({
726
+ data: logTimelineItem,
727
+ props: {
728
+ isRoot: true,
729
+ },
730
+ });
731
+ const callRequest = await this.generateCallTemplateForAlertEpisodeCreated((_10 = notificationRuleItem.userCall) === null || _10 === void 0 ? void 0 : _10.phone, alertEpisode, updatedLog.id);
732
+ CallService.makeCall(callRequest, {
733
+ projectId: alertEpisode.projectId,
734
+ userOnCallLogTimelineId: updatedLog.id,
735
+ alertEpisodeId: alertEpisode.id,
736
+ userId: notificationRuleItem.userId,
737
+ onCallPolicyId: options.onCallPolicyId,
738
+ onCallPolicyEscalationRuleId: options.onCallPolicyEscalationRuleId,
739
+ teamId: options.userBelongsToTeamId,
740
+ onCallDutyPolicyExecutionLogTimelineId: options.onCallDutyPolicyExecutionLogTimelineId,
741
+ onCallScheduleId: options.onCallScheduleId,
742
+ }).catch(async (err) => {
743
+ await UserOnCallLogTimelineService.updateOneById({
744
+ id: updatedLog.id,
745
+ data: {
746
+ status: UserNotificationStatus.Error,
747
+ statusMessage: err.message || "Error making call.",
748
+ },
749
+ props: {
750
+ isRoot: true,
751
+ },
752
+ });
753
+ });
754
+ }
571
755
  }
572
- if (((_5 = notificationRuleItem.userCall) === null || _5 === void 0 ? void 0 : _5.phone) &&
573
- !((_6 = notificationRuleItem.userCall) === null || _6 === void 0 ? void 0 : _6.isVerified)) {
756
+ if (((_11 = notificationRuleItem.userCall) === null || _11 === void 0 ? void 0 : _11.phone) &&
757
+ !((_12 = notificationRuleItem.userCall) === null || _12 === void 0 ? void 0 : _12.isVerified)) {
574
758
  // create a log.
575
759
  logTimelineItem.status = UserNotificationStatus.Error;
576
- logTimelineItem.statusMessage = `Call not sent because phone ${(_7 = notificationRuleItem.userCall) === null || _7 === void 0 ? void 0 : _7.phone.toString()} is not verified.`;
760
+ logTimelineItem.statusMessage = `Call not sent because phone ${(_13 = notificationRuleItem.userCall) === null || _13 === void 0 ? void 0 : _13.phone.toString()} is not verified.`;
577
761
  await UserOnCallLogTimelineService.create({
578
762
  data: logTimelineItem,
579
763
  props: {
@@ -582,8 +766,8 @@ export class Service extends DatabaseService {
582
766
  });
583
767
  }
584
768
  // send push notification.
585
- if (((_8 = notificationRuleItem.userPush) === null || _8 === void 0 ? void 0 : _8.deviceToken) &&
586
- ((_9 = notificationRuleItem.userPush) === null || _9 === void 0 ? void 0 : _9.isVerified)) {
769
+ if (((_14 = notificationRuleItem.userPush) === null || _14 === void 0 ? void 0 : _14.deviceToken) &&
770
+ ((_15 = notificationRuleItem.userPush) === null || _15 === void 0 ? void 0 : _15.isVerified)) {
587
771
  // send push notification for alert
588
772
  if (options.userNotificationEventType ===
589
773
  UserNotificationEventType.AlertCreated &&
@@ -598,11 +782,9 @@ export class Service extends DatabaseService {
598
782
  isRoot: true,
599
783
  },
600
784
  });
601
- const pushMessage = PushNotificationUtil.createAlertCreatedNotification({
602
- alertTitle: alert.title,
603
- projectName: ((_10 = alert.project) === null || _10 === void 0 ? void 0 : _10.name) || "OneUptime",
604
- alertViewLink: (await AlertService.getAlertLinkInDashboard(alert.projectId, alert.id)).toString(),
605
- });
785
+ const pushMessage = PushNotificationUtil.createAlertCreatedNotification(Object.assign({ alertTitle: alert.title, projectName: ((_16 = alert.project) === null || _16 === void 0 ? void 0 : _16.name) || "OneUptime", alertViewLink: (await AlertService.getAlertLinkInDashboard(alert.projectId, alert.id)).toString() }, (alert.alertNumber !== undefined && {
786
+ alertNumber: alert.alertNumber,
787
+ })));
606
788
  // send push notification.
607
789
  PushNotificationService.sendPushNotification({
608
790
  devices: [
@@ -649,11 +831,9 @@ export class Service extends DatabaseService {
649
831
  isRoot: true,
650
832
  },
651
833
  });
652
- const pushMessage = PushNotificationUtil.createIncidentCreatedNotification({
653
- incidentTitle: incident.title,
654
- projectName: ((_11 = incident.project) === null || _11 === void 0 ? void 0 : _11.name) || "OneUptime",
655
- incidentViewLink: (await IncidentService.getIncidentLinkInDashboard(incident.projectId, incident.id)).toString(),
656
- });
834
+ const pushMessage = PushNotificationUtil.createIncidentCreatedNotification(Object.assign({ incidentTitle: incident.title, projectName: ((_17 = incident.project) === null || _17 === void 0 ? void 0 : _17.name) || "OneUptime", incidentViewLink: (await IncidentService.getIncidentLinkInDashboard(incident.projectId, incident.id)).toString() }, (incident.incidentNumber !== undefined && {
835
+ incidentNumber: incident.incidentNumber,
836
+ })));
657
837
  // send push notification.
658
838
  PushNotificationService.sendPushNotification({
659
839
  devices: [
@@ -686,9 +866,56 @@ export class Service extends DatabaseService {
686
866
  });
687
867
  });
688
868
  }
869
+ // send push notification for alert episode
870
+ if (options.userNotificationEventType ===
871
+ UserNotificationEventType.AlertEpisodeCreated &&
872
+ alertEpisode) {
873
+ logTimelineItem.status = UserNotificationStatus.Sending;
874
+ logTimelineItem.statusMessage = `Sending push notification to device.`;
875
+ logTimelineItem.userPushId = notificationRuleItem.userPush.id;
876
+ const updatedLog = await UserOnCallLogTimelineService.create({
877
+ data: logTimelineItem,
878
+ props: {
879
+ isRoot: true,
880
+ },
881
+ });
882
+ const pushMessage = PushNotificationUtil.createAlertEpisodeCreatedNotification(Object.assign({ alertEpisodeTitle: alertEpisode.title, projectName: ((_18 = alertEpisode.project) === null || _18 === void 0 ? void 0 : _18.name) || "OneUptime", alertEpisodeViewLink: (await AlertEpisodeService.getEpisodeLinkInDashboard(alertEpisode.projectId, alertEpisode.id)).toString() }, (alertEpisode.episodeNumber !== undefined && {
883
+ episodeNumber: alertEpisode.episodeNumber,
884
+ })));
885
+ PushNotificationService.sendPushNotification({
886
+ devices: [
887
+ Object.assign({ token: notificationRuleItem.userPush.deviceToken }, (notificationRuleItem.userPush.deviceName && {
888
+ name: notificationRuleItem.userPush.deviceName,
889
+ })),
890
+ ],
891
+ message: pushMessage,
892
+ deviceType: notificationRuleItem.userPush.deviceType,
893
+ }, {
894
+ projectId: options.projectId,
895
+ userOnCallLogTimelineId: updatedLog.id,
896
+ alertEpisodeId: alertEpisode.id,
897
+ userId: notificationRuleItem.userId,
898
+ onCallPolicyId: options.onCallPolicyId,
899
+ onCallPolicyEscalationRuleId: options.onCallPolicyEscalationRuleId,
900
+ teamId: options.userBelongsToTeamId,
901
+ onCallDutyPolicyExecutionLogTimelineId: options.onCallDutyPolicyExecutionLogTimelineId,
902
+ onCallScheduleId: options.onCallScheduleId,
903
+ }).catch(async (err) => {
904
+ await UserOnCallLogTimelineService.updateOneById({
905
+ id: updatedLog.id,
906
+ data: {
907
+ status: UserNotificationStatus.Error,
908
+ statusMessage: err.message || "Error sending push notification.",
909
+ },
910
+ props: {
911
+ isRoot: true,
912
+ },
913
+ });
914
+ });
915
+ }
689
916
  }
690
- if (((_12 = notificationRuleItem.userPush) === null || _12 === void 0 ? void 0 : _12.deviceToken) &&
691
- !((_13 = notificationRuleItem.userPush) === null || _13 === void 0 ? void 0 : _13.isVerified)) {
917
+ if (((_19 = notificationRuleItem.userPush) === null || _19 === void 0 ? void 0 : _19.deviceToken) &&
918
+ !((_20 = notificationRuleItem.userPush) === null || _20 === void 0 ? void 0 : _20.isVerified)) {
692
919
  // create a log.
693
920
  logTimelineItem.status = UserNotificationStatus.Error;
694
921
  logTimelineItem.statusMessage = `Push notification not sent because device is not verified.`;
@@ -703,6 +930,9 @@ export class Service extends DatabaseService {
703
930
  async generateCallTemplateForAlertCreated(to, alert, userOnCallLogTimelineId) {
704
931
  const host = await DatabaseConfig.getHost();
705
932
  const httpProtocol = await DatabaseConfig.getHttpProtocol();
933
+ const alertIdentifier = alert.alertNumber !== undefined
934
+ ? `Alert number ${alert.alertNumber}, ${alert.title || "Alert"}`
935
+ : alert.title || "Alert";
706
936
  const callRequest = {
707
937
  to: to,
708
938
  data: [
@@ -713,7 +943,7 @@ export class Service extends DatabaseService {
713
943
  sayMessage: "A new alert has been created",
714
944
  },
715
945
  {
716
- sayMessage: alert.title,
946
+ sayMessage: alertIdentifier,
717
947
  },
718
948
  {
719
949
  introMessage: "To acknowledge this alert press 1",
@@ -739,6 +969,9 @@ export class Service extends DatabaseService {
739
969
  async generateCallTemplateForIncidentCreated(to, incident, userOnCallLogTimelineId) {
740
970
  const host = await DatabaseConfig.getHost();
741
971
  const httpProtocol = await DatabaseConfig.getHttpProtocol();
972
+ const incidentIdentifier = incident.incidentNumber !== undefined
973
+ ? `Incident number ${incident.incidentNumber}, ${incident.title || "Incident"}`
974
+ : incident.title || "Incident";
742
975
  const callRequest = {
743
976
  to: to,
744
977
  data: [
@@ -749,7 +982,7 @@ export class Service extends DatabaseService {
749
982
  sayMessage: "A new incident has been created",
750
983
  },
751
984
  {
752
- sayMessage: incident.title,
985
+ sayMessage: incidentIdentifier,
753
986
  },
754
987
  {
755
988
  introMessage: "To acknowledge this incident press 1",
@@ -772,6 +1005,45 @@ export class Service extends DatabaseService {
772
1005
  };
773
1006
  return callRequest;
774
1007
  }
1008
+ async generateCallTemplateForAlertEpisodeCreated(to, alertEpisode, userOnCallLogTimelineId) {
1009
+ const host = await DatabaseConfig.getHost();
1010
+ const httpProtocol = await DatabaseConfig.getHttpProtocol();
1011
+ const episodeIdentifier = alertEpisode.episodeNumber !== undefined
1012
+ ? `Alert episode number ${alertEpisode.episodeNumber}, ${alertEpisode.title || "Alert Episode"}`
1013
+ : alertEpisode.title || "Alert Episode";
1014
+ const callRequest = {
1015
+ to: to,
1016
+ data: [
1017
+ {
1018
+ sayMessage: "This is a call from OneUptime",
1019
+ },
1020
+ {
1021
+ sayMessage: "A new alert episode has been created",
1022
+ },
1023
+ {
1024
+ sayMessage: episodeIdentifier,
1025
+ },
1026
+ {
1027
+ introMessage: "To acknowledge this alert episode press 1",
1028
+ numDigits: 1,
1029
+ timeoutInSeconds: 10,
1030
+ noInputMessage: "You have not entered any input. Good bye",
1031
+ onInputCallRequest: {
1032
+ "1": {
1033
+ sayMessage: "You have acknowledged this alert episode. Good bye",
1034
+ },
1035
+ default: {
1036
+ sayMessage: "Invalid input. Good bye",
1037
+ },
1038
+ },
1039
+ responseUrl: new URL(httpProtocol, host, new Route(AppApiRoute.toString())
1040
+ .addRoute(new UserOnCallLogTimeline().crudApiPath)
1041
+ .addRoute("/call/gather-input/" + userOnCallLogTimelineId.toString())),
1042
+ },
1043
+ ],
1044
+ };
1045
+ return callRequest;
1046
+ }
775
1047
  async generateSmsTemplateForAlertCreated(to, alert, userOnCallLogTimelineId) {
776
1048
  const host = await DatabaseConfig.getHost();
777
1049
  const httpProtocol = await DatabaseConfig.getHttpProtocol();
@@ -804,6 +1076,22 @@ export class Service extends DatabaseService {
804
1076
  };
805
1077
  return sms;
806
1078
  }
1079
+ async generateSmsTemplateForAlertEpisodeCreated(to, alertEpisode, userOnCallLogTimelineId) {
1080
+ const host = await DatabaseConfig.getHost();
1081
+ const httpProtocol = await DatabaseConfig.getHttpProtocol();
1082
+ const shortUrl = await ShortLinkService.saveShortLinkFor(new URL(httpProtocol, host, new Route(AppApiRoute.toString())
1083
+ .addRoute(new UserOnCallLogTimeline().crudApiPath)
1084
+ .addRoute("/acknowledge-page/" + userOnCallLogTimelineId.toString())));
1085
+ const url = await ShortLinkService.getShortenedUrl(shortUrl);
1086
+ const episodeIdentifier = alertEpisode.episodeNumber !== undefined
1087
+ ? `#${alertEpisode.episodeNumber} (${alertEpisode.title || "Alert Episode"})`
1088
+ : alertEpisode.title || "Alert Episode";
1089
+ const sms = {
1090
+ to,
1091
+ message: `This is a message from OneUptime. A new alert episode has been created: ${episodeIdentifier}. To acknowledge this alert episode, please click on the following link ${url.toString()}`,
1092
+ };
1093
+ return sms;
1094
+ }
807
1095
  async generateWhatsAppTemplateForAlertCreated(to, alert, userOnCallLogTimelineId) {
808
1096
  var _a;
809
1097
  const host = await DatabaseConfig.getHost();
@@ -862,11 +1150,45 @@ export class Service extends DatabaseService {
862
1150
  templateLanguageCode: WhatsAppTemplateLanguage[templateKey],
863
1151
  };
864
1152
  }
1153
+ async generateWhatsAppTemplateForAlertEpisodeCreated(to, alertEpisode, userOnCallLogTimelineId) {
1154
+ var _a;
1155
+ const host = await DatabaseConfig.getHost();
1156
+ const httpProtocol = await DatabaseConfig.getHttpProtocol();
1157
+ const acknowledgeShortLink = await ShortLinkService.saveShortLinkFor(new URL(httpProtocol, host, new Route(AppApiRoute.toString())
1158
+ .addRoute(new UserOnCallLogTimeline().crudApiPath)
1159
+ .addRoute("/acknowledge-page/" + userOnCallLogTimelineId.toString())));
1160
+ const acknowledgeUrl = await ShortLinkService.getShortenedUrl(acknowledgeShortLink);
1161
+ const episodeLinkOnDashboard = alertEpisode.projectId && alertEpisode.id
1162
+ ? (await AlertEpisodeService.getEpisodeLinkInDashboard(alertEpisode.projectId, alertEpisode.id)).toString()
1163
+ : acknowledgeUrl.toString();
1164
+ const templateKey = WhatsAppTemplateIds.AlertEpisodeCreated;
1165
+ const templateVariables = {
1166
+ project_name: ((_a = alertEpisode.project) === null || _a === void 0 ? void 0 : _a.name) || "OneUptime",
1167
+ episode_title: alertEpisode.title || "",
1168
+ acknowledge_url: acknowledgeUrl.toString(),
1169
+ episode_number: alertEpisode.episodeNumber !== undefined
1170
+ ? alertEpisode.episodeNumber.toString()
1171
+ : "",
1172
+ episode_link: episodeLinkOnDashboard,
1173
+ };
1174
+ const body = renderWhatsAppTemplate(templateKey, templateVariables);
1175
+ return {
1176
+ to,
1177
+ body,
1178
+ templateKey,
1179
+ templateVariables,
1180
+ templateLanguageCode: WhatsAppTemplateLanguage[templateKey],
1181
+ };
1182
+ }
865
1183
  async generateEmailTemplateForAlertCreated(to, alert, userOnCallLogTimelineId) {
866
1184
  const host = await DatabaseConfig.getHost();
867
1185
  const httpProtocol = await DatabaseConfig.getHttpProtocol();
1186
+ const alertNumber = alert.alertNumber
1187
+ ? `#${alert.alertNumber}`
1188
+ : "";
868
1189
  const vars = {
869
1190
  alertTitle: alert.title,
1191
+ alertNumber: alertNumber,
870
1192
  projectName: alert.project.name,
871
1193
  currentState: alert.currentAlertState.name,
872
1194
  alertDescription: await Markdown.convertToHTML(alert.description || "", MarkdownContentType.Email),
@@ -880,15 +1202,19 @@ export class Service extends DatabaseService {
880
1202
  toEmail: to,
881
1203
  templateType: EmailTemplateType.AcknowledgeAlert,
882
1204
  vars: vars,
883
- subject: "ACTION REQUIRED: Alert created - " + alert.title,
1205
+ subject: `ACTION REQUIRED: Alert ${alertNumber} created - ${alert.title}`,
884
1206
  };
885
1207
  return emailMessage;
886
1208
  }
887
1209
  async generateEmailTemplateForIncidentCreated(to, incident, userOnCallLogTimelineId) {
888
1210
  const host = await DatabaseConfig.getHost();
889
1211
  const httpProtocol = await DatabaseConfig.getHttpProtocol();
1212
+ const incidentNumber = incident.incidentNumber
1213
+ ? `#${incident.incidentNumber}`
1214
+ : "";
890
1215
  const vars = {
891
1216
  incidentTitle: incident.title,
1217
+ incidentNumber: incidentNumber,
892
1218
  projectName: incident.project.name,
893
1219
  currentState: incident.currentIncidentState.name,
894
1220
  incidentDescription: await Markdown.convertToHTML(incident.description || "", MarkdownContentType.Email),
@@ -903,7 +1229,133 @@ export class Service extends DatabaseService {
903
1229
  toEmail: to,
904
1230
  templateType: EmailTemplateType.AcknowledgeIncident,
905
1231
  vars: vars,
906
- subject: "ACTION REQUIRED: Incident created - " + incident.title,
1232
+ subject: `ACTION REQUIRED: Incident ${incidentNumber} created - ${incident.title}`,
1233
+ };
1234
+ return emailMessage;
1235
+ }
1236
+ async generateEmailTemplateForAlertEpisodeCreated(to, alertEpisode, userOnCallLogTimelineId) {
1237
+ var _a, _b;
1238
+ const host = await DatabaseConfig.getHost();
1239
+ const httpProtocol = await DatabaseConfig.getHttpProtocol();
1240
+ // Fetch alerts that are members of this episode
1241
+ const episodeMembers = await AlertEpisodeMemberService.findBy({
1242
+ query: {
1243
+ alertEpisodeId: alertEpisode.id,
1244
+ },
1245
+ select: {
1246
+ alertId: true,
1247
+ },
1248
+ props: {
1249
+ isRoot: true,
1250
+ },
1251
+ limit: LIMIT_PER_PROJECT,
1252
+ skip: 0,
1253
+ });
1254
+ // Get the alert IDs
1255
+ const alertIds = episodeMembers
1256
+ .map((member) => {
1257
+ return member.alertId;
1258
+ })
1259
+ .filter((id) => {
1260
+ return id !== undefined;
1261
+ });
1262
+ // Fetch full alert data with monitors
1263
+ const alerts = alertIds.length > 0
1264
+ ? await AlertService.findBy({
1265
+ query: {
1266
+ _id: QueryHelper.any(alertIds),
1267
+ },
1268
+ select: {
1269
+ _id: true,
1270
+ title: true,
1271
+ alertNumber: true,
1272
+ monitor: {
1273
+ _id: true,
1274
+ name: true,
1275
+ },
1276
+ },
1277
+ props: {
1278
+ isRoot: true,
1279
+ },
1280
+ limit: LIMIT_PER_PROJECT,
1281
+ skip: 0,
1282
+ })
1283
+ : [];
1284
+ // Get unique monitors (resources affected)
1285
+ const monitorNames = new Set();
1286
+ for (const alert of alerts) {
1287
+ if ((_a = alert.monitor) === null || _a === void 0 ? void 0 : _a.name) {
1288
+ monitorNames.add(alert.monitor.name);
1289
+ }
1290
+ }
1291
+ const resourcesAffected = monitorNames.size > 0
1292
+ ? Array.from(monitorNames).join(", ")
1293
+ : "No resources identified";
1294
+ // Build alerts list HTML with proper email styling
1295
+ let alertsListHtml = "";
1296
+ if (alerts.length > 0) {
1297
+ const alertRows = [];
1298
+ for (const alert of alerts) {
1299
+ const alertTitle = alert.title || "Untitled Alert";
1300
+ const alertNumber = alert.alertNumber
1301
+ ? `#${alert.alertNumber}`
1302
+ : "";
1303
+ const alertLink = (await AlertService.getAlertLinkInDashboard(alertEpisode.projectId, alert.id)).toString();
1304
+ const monitorName = ((_b = alert.monitor) === null || _b === void 0 ? void 0 : _b.name) || "";
1305
+ alertRows.push(`
1306
+ <tr>
1307
+ <td style="padding: 12px 16px; border-bottom: 1px solid #e2e8f0;">
1308
+ <table cellpadding="0" cellspacing="0" width="100%">
1309
+ <tr>
1310
+ <td style="vertical-align: middle;">
1311
+ <span style="display: inline-block; background-color: #dbeafe; color: #1e40af; font-size: 12px; font-weight: 600; padding: 2px 8px; border-radius: 4px; margin-right: 8px;">${alertNumber}</span>
1312
+ <a href="${alertLink}" style="color: #2563eb; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 14px; font-weight: 500; text-decoration: none;">${alertTitle}</a>
1313
+ ${monitorName ? `<span style="display: block; color: #64748b; font-size: 12px; margin-top: 4px;">Monitor: ${monitorName}</span>` : ""}
1314
+ </td>
1315
+ <td style="text-align: right; vertical-align: middle;">
1316
+ <a href="${alertLink}" style="color: #2563eb; font-size: 12px; text-decoration: none;">View →</a>
1317
+ </td>
1318
+ </tr>
1319
+ </table>
1320
+ </td>
1321
+ </tr>
1322
+ `);
1323
+ }
1324
+ if (alertRows.length > 0) {
1325
+ alertsListHtml = `
1326
+ <table cellpadding="0" cellspacing="0" width="100%" style="background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%); border-radius: 8px; border: 1px solid #e2e8f0; margin: 8px 0 16px 0;">
1327
+ <tbody>
1328
+ ${alertRows.join("")}
1329
+ </tbody>
1330
+ </table>
1331
+ `;
1332
+ }
1333
+ }
1334
+ const episodeNumber = alertEpisode.episodeNumber
1335
+ ? `#${alertEpisode.episodeNumber}`
1336
+ : "";
1337
+ const vars = {
1338
+ alertEpisodeTitle: alertEpisode.title,
1339
+ episodeNumber: episodeNumber,
1340
+ projectName: alertEpisode.project.name,
1341
+ currentState: alertEpisode.currentAlertState.name,
1342
+ alertEpisodeDescription: await Markdown.convertToHTML(alertEpisode.description || "", MarkdownContentType.Email),
1343
+ alertEpisodeSeverity: alertEpisode.alertSeverity.name,
1344
+ resourcesAffected: resourcesAffected,
1345
+ rootCause: alertEpisode.rootCause ||
1346
+ "No root cause identified for this alert episode",
1347
+ alertsList: alertsListHtml,
1348
+ alertsCount: alerts.length.toString(),
1349
+ alertEpisodeViewLink: (await AlertEpisodeService.getEpisodeLinkInDashboard(alertEpisode.projectId, alertEpisode.id)).toString(),
1350
+ acknowledgeAlertEpisodeLink: new URL(httpProtocol, host, new Route(AppApiRoute.toString())
1351
+ .addRoute(new UserOnCallLogTimeline().crudApiPath)
1352
+ .addRoute("/acknowledge-page/" + userOnCallLogTimelineId.toString())).toString(),
1353
+ };
1354
+ const emailMessage = {
1355
+ toEmail: to,
1356
+ templateType: EmailTemplateType.AcknowledgeAlertEpisode,
1357
+ vars: vars,
1358
+ subject: `ACTION REQUIRED: Alert Episode ${episodeNumber} created - ${alertEpisode.title}`,
907
1359
  };
908
1360
  return emailMessage;
909
1361
  }
@@ -918,6 +1370,10 @@ export class Service extends DatabaseService {
918
1370
  if (options.triggeredByAlertId) {
919
1371
  userOnCallLog.triggeredByAlertId = options.triggeredByAlertId;
920
1372
  }
1373
+ if (options.triggeredByAlertEpisodeId) {
1374
+ userOnCallLog.triggeredByAlertEpisodeId =
1375
+ options.triggeredByAlertEpisodeId;
1376
+ }
921
1377
  userOnCallLog.userNotificationEventType = options.userNotificationEventType;
922
1378
  if (options.onCallPolicyExecutionLogId) {
923
1379
  userOnCallLog.onCallDutyPolicyExecutionLogId =
@@ -1043,7 +1499,7 @@ export class Service extends DatabaseService {
1043
1499
  userId,
1044
1500
  userEmailId: userEmail.id,
1045
1501
  incidentSeverityId: incidentSeverity.id,
1046
- ruleType: NotificationRuleType.ON_CALL_EXECUTED,
1502
+ ruleType: NotificationRuleType.ON_CALL_EXECUTED_INCIDENT,
1047
1503
  },
1048
1504
  props: {
1049
1505
  isRoot: true,
@@ -1058,7 +1514,8 @@ export class Service extends DatabaseService {
1058
1514
  notificationRule.userEmailId = userEmail.id;
1059
1515
  notificationRule.incidentSeverityId = incidentSeverity.id;
1060
1516
  notificationRule.notifyAfterMinutes = 0;
1061
- notificationRule.ruleType = NotificationRuleType.ON_CALL_EXECUTED;
1517
+ notificationRule.ruleType =
1518
+ NotificationRuleType.ON_CALL_EXECUTED_INCIDENT;
1062
1519
  await this.create({
1063
1520
  data: notificationRule,
1064
1521
  props: {
@@ -1091,7 +1548,7 @@ export class Service extends DatabaseService {
1091
1548
  userId,
1092
1549
  userEmailId: userEmail.id,
1093
1550
  alertSeverityId: alertSeverity.id,
1094
- ruleType: NotificationRuleType.ON_CALL_EXECUTED,
1551
+ ruleType: NotificationRuleType.ON_CALL_EXECUTED_ALERT,
1095
1552
  },
1096
1553
  props: {
1097
1554
  isRoot: true,
@@ -1106,7 +1563,7 @@ export class Service extends DatabaseService {
1106
1563
  notificationRule.userEmailId = userEmail.id;
1107
1564
  notificationRule.alertSeverityId = alertSeverity.id;
1108
1565
  notificationRule.notifyAfterMinutes = 0;
1109
- notificationRule.ruleType = NotificationRuleType.ON_CALL_EXECUTED;
1566
+ notificationRule.ruleType = NotificationRuleType.ON_CALL_EXECUTED_ALERT;
1110
1567
  await this.create({
1111
1568
  data: notificationRule,
1112
1569
  props: {
@@ -1229,6 +1686,14 @@ __decorate([
1229
1686
  ObjectID]),
1230
1687
  __metadata("design:returntype", Promise)
1231
1688
  ], Service.prototype, "generateCallTemplateForIncidentCreated", null);
1689
+ __decorate([
1690
+ CaptureSpan(),
1691
+ __metadata("design:type", Function),
1692
+ __metadata("design:paramtypes", [Phone,
1693
+ AlertEpisode,
1694
+ ObjectID]),
1695
+ __metadata("design:returntype", Promise)
1696
+ ], Service.prototype, "generateCallTemplateForAlertEpisodeCreated", null);
1232
1697
  __decorate([
1233
1698
  CaptureSpan(),
1234
1699
  __metadata("design:type", Function),
@@ -1245,6 +1710,14 @@ __decorate([
1245
1710
  ObjectID]),
1246
1711
  __metadata("design:returntype", Promise)
1247
1712
  ], Service.prototype, "generateSmsTemplateForIncidentCreated", null);
1713
+ __decorate([
1714
+ CaptureSpan(),
1715
+ __metadata("design:type", Function),
1716
+ __metadata("design:paramtypes", [Phone,
1717
+ AlertEpisode,
1718
+ ObjectID]),
1719
+ __metadata("design:returntype", Promise)
1720
+ ], Service.prototype, "generateSmsTemplateForAlertEpisodeCreated", null);
1248
1721
  __decorate([
1249
1722
  CaptureSpan(),
1250
1723
  __metadata("design:type", Function),
@@ -1261,6 +1734,14 @@ __decorate([
1261
1734
  ObjectID]),
1262
1735
  __metadata("design:returntype", Promise)
1263
1736
  ], Service.prototype, "generateWhatsAppTemplateForIncidentCreated", null);
1737
+ __decorate([
1738
+ CaptureSpan(),
1739
+ __metadata("design:type", Function),
1740
+ __metadata("design:paramtypes", [Phone,
1741
+ AlertEpisode,
1742
+ ObjectID]),
1743
+ __metadata("design:returntype", Promise)
1744
+ ], Service.prototype, "generateWhatsAppTemplateForAlertEpisodeCreated", null);
1264
1745
  __decorate([
1265
1746
  CaptureSpan(),
1266
1747
  __metadata("design:type", Function),
@@ -1277,6 +1758,14 @@ __decorate([
1277
1758
  ObjectID]),
1278
1759
  __metadata("design:returntype", Promise)
1279
1760
  ], Service.prototype, "generateEmailTemplateForIncidentCreated", null);
1761
+ __decorate([
1762
+ CaptureSpan(),
1763
+ __metadata("design:type", Function),
1764
+ __metadata("design:paramtypes", [Email,
1765
+ AlertEpisode,
1766
+ ObjectID]),
1767
+ __metadata("design:returntype", Promise)
1768
+ ], Service.prototype, "generateEmailTemplateForAlertEpisodeCreated", null);
1280
1769
  __decorate([
1281
1770
  CaptureSpan(),
1282
1771
  __metadata("design:type", Function),