@oneuptime/common 7.0.3526 → 7.0.3538
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/AlertFeed.ts +12 -4
- package/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.ts +2 -0
- package/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.ts +59 -2
- package/Models/DatabaseModels/UserNotificationRule.ts +50 -0
- package/Models/DatabaseModels/UserOnCallLog.ts +48 -1
- package/Models/DatabaseModels/UserOnCallLogTimeline.ts +49 -2
- package/Server/API/UserOnCallLogTimelineAPI.ts +32 -8
- package/Server/Infrastructure/Postgres/SchemaMigrations/1737141420441-MigrationName.ts +131 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/AlertInternalNoteService.ts +73 -0
- package/Server/Services/AlertOwnerTeamService.ts +112 -0
- package/Server/Services/AlertOwnerUserService.ts +114 -0
- package/Server/Services/AlertService.ts +121 -0
- package/Server/Services/AlertStateTimelineService.ts +52 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +32 -14
- package/Server/Services/OnCallDutyPolicyExecutionLogService.ts +86 -27
- package/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.ts +30 -12
- package/Server/Services/UserNotificationRuleService.ts +450 -67
- package/Server/Services/UserOnCallLogService.ts +61 -18
- package/Server/Services/UserOnCallLogTimelineService.ts +25 -11
- package/Types/Email/EmailTemplateType.ts +1 -0
- package/Types/NotificationRule/NotificationRuleType.ts +1 -1
- package/build/dist/Models/DatabaseModels/AlertFeed.js +12 -4
- package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js +2 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.js +60 -2
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserNotificationRule.js +49 -0
- package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js +48 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +50 -2
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
- package/build/dist/Server/API/UserOnCallLogTimelineAPI.js +10 -2
- package/build/dist/Server/API/UserOnCallLogTimelineAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1737141420441-MigrationName.js +50 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1737141420441-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AlertInternalNoteService.js +56 -0
- package/build/dist/Server/Services/AlertInternalNoteService.js.map +1 -1
- package/build/dist/Server/Services/AlertOwnerTeamService.js +86 -0
- package/build/dist/Server/Services/AlertOwnerTeamService.js.map +1 -1
- package/build/dist/Server/Services/AlertOwnerUserService.js +89 -0
- package/build/dist/Server/Services/AlertOwnerUserService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +107 -3
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/AlertStateTimelineService.js +44 -1
- package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +18 -8
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js +70 -24
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js +26 -11
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +334 -67
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/UserOnCallLogService.js +66 -27
- package/build/dist/Server/Services/UserOnCallLogService.js.map +1 -1
- package/build/dist/Server/Services/UserOnCallLogTimelineService.js +16 -5
- package/build/dist/Server/Services/UserOnCallLogTimelineService.js.map +1 -1
- package/build/dist/Types/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/NotificationRule/NotificationRuleType.js +1 -1
- package/build/dist/Types/NotificationRule/NotificationRuleType.js.map +1 -1
- package/package.json +2 -2
|
@@ -39,6 +39,10 @@ import UserEmail from "Common/Models/DatabaseModels/UserEmail";
|
|
|
39
39
|
import Model from "Common/Models/DatabaseModels/UserNotificationRule";
|
|
40
40
|
import UserOnCallLog from "Common/Models/DatabaseModels/UserOnCallLog";
|
|
41
41
|
import UserOnCallLogTimeline from "Common/Models/DatabaseModels/UserOnCallLogTimeline";
|
|
42
|
+
import Alert from "../../Models/DatabaseModels/Alert";
|
|
43
|
+
import AlertService from "./AlertService";
|
|
44
|
+
import AlertSeverity from "../../Models/DatabaseModels/AlertSeverity";
|
|
45
|
+
import AlertSeverityService from "./AlertSeverityService";
|
|
42
46
|
|
|
43
47
|
export class Service extends DatabaseService<Model> {
|
|
44
48
|
public constructor() {
|
|
@@ -50,6 +54,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
50
54
|
options: {
|
|
51
55
|
projectId: ObjectID;
|
|
52
56
|
triggeredByIncidentId?: ObjectID | undefined;
|
|
57
|
+
triggeredByAlertId?: ObjectID | undefined;
|
|
53
58
|
userNotificationEventType: UserNotificationEventType;
|
|
54
59
|
onCallPolicyExecutionLogId?: ObjectID | undefined;
|
|
55
60
|
onCallPolicyId: ObjectID | undefined;
|
|
@@ -164,6 +169,10 @@ export class Service extends DatabaseService<Model> {
|
|
|
164
169
|
logTimelineItem.triggeredByIncidentId = options.triggeredByIncidentId;
|
|
165
170
|
}
|
|
166
171
|
|
|
172
|
+
if (options.triggeredByAlertId) {
|
|
173
|
+
logTimelineItem.triggeredByAlertId = options.triggeredByAlertId;
|
|
174
|
+
}
|
|
175
|
+
|
|
167
176
|
if (options.onCallDutyPolicyExecutionLogTimelineId) {
|
|
168
177
|
logTimelineItem.onCallDutyPolicyExecutionLogTimelineId =
|
|
169
178
|
options.onCallDutyPolicyExecutionLogTimelineId;
|
|
@@ -172,6 +181,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
172
181
|
// add status and status message and save.
|
|
173
182
|
|
|
174
183
|
let incident: Incident | null = null;
|
|
184
|
+
let alert: Alert | null = null;
|
|
175
185
|
|
|
176
186
|
if (
|
|
177
187
|
options.userNotificationEventType ===
|
|
@@ -202,15 +212,89 @@ export class Service extends DatabaseService<Model> {
|
|
|
202
212
|
});
|
|
203
213
|
}
|
|
204
214
|
|
|
205
|
-
if (
|
|
206
|
-
|
|
215
|
+
if (
|
|
216
|
+
options.userNotificationEventType ===
|
|
217
|
+
UserNotificationEventType.AlertCreated &&
|
|
218
|
+
options.triggeredByAlertId
|
|
219
|
+
) {
|
|
220
|
+
alert = await AlertService.findOneById({
|
|
221
|
+
id: options.triggeredByAlertId!,
|
|
222
|
+
props: {
|
|
223
|
+
isRoot: true,
|
|
224
|
+
},
|
|
225
|
+
select: {
|
|
226
|
+
_id: true,
|
|
227
|
+
title: true,
|
|
228
|
+
description: true,
|
|
229
|
+
projectId: true,
|
|
230
|
+
project: {
|
|
231
|
+
name: true,
|
|
232
|
+
},
|
|
233
|
+
currentAlertState: {
|
|
234
|
+
name: true,
|
|
235
|
+
},
|
|
236
|
+
alertSeverity: {
|
|
237
|
+
name: true,
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (!incident && !alert) {
|
|
244
|
+
throw new BadDataException("Incident or Alert not found.");
|
|
207
245
|
}
|
|
208
246
|
|
|
209
247
|
if (
|
|
210
248
|
notificationRuleItem.userEmail?.email &&
|
|
211
249
|
notificationRuleItem.userEmail?.isVerified
|
|
212
250
|
) {
|
|
213
|
-
// send email.
|
|
251
|
+
// send email for alert.
|
|
252
|
+
|
|
253
|
+
if (
|
|
254
|
+
options.userNotificationEventType ===
|
|
255
|
+
UserNotificationEventType.AlertCreated &&
|
|
256
|
+
alert
|
|
257
|
+
) {
|
|
258
|
+
// create an error log.
|
|
259
|
+
logTimelineItem.status = UserNotificationStatus.Sending;
|
|
260
|
+
logTimelineItem.statusMessage = `Sending email to ${notificationRuleItem.userEmail?.email.toString()}`;
|
|
261
|
+
logTimelineItem.userEmailId = notificationRuleItem.userEmail.id!;
|
|
262
|
+
|
|
263
|
+
const updatedLog: UserOnCallLogTimeline =
|
|
264
|
+
await UserOnCallLogTimelineService.create({
|
|
265
|
+
data: logTimelineItem,
|
|
266
|
+
props: {
|
|
267
|
+
isRoot: true,
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const emailMessage: EmailMessage =
|
|
272
|
+
await this.generateEmailTemplateForAlertCreated(
|
|
273
|
+
notificationRuleItem.userEmail?.email,
|
|
274
|
+
alert,
|
|
275
|
+
updatedLog.id!,
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
// send email.
|
|
279
|
+
|
|
280
|
+
MailService.sendMail(emailMessage, {
|
|
281
|
+
userOnCallLogTimelineId: updatedLog.id!,
|
|
282
|
+
projectId: options.projectId,
|
|
283
|
+
}).catch(async (err: Error) => {
|
|
284
|
+
await UserOnCallLogTimelineService.updateOneById({
|
|
285
|
+
id: updatedLog.id!,
|
|
286
|
+
data: {
|
|
287
|
+
status: UserNotificationStatus.Error,
|
|
288
|
+
statusMessage: err.message || "Error sending email.",
|
|
289
|
+
},
|
|
290
|
+
props: {
|
|
291
|
+
isRoot: true,
|
|
292
|
+
},
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// send email for incident
|
|
214
298
|
if (
|
|
215
299
|
options.userNotificationEventType ===
|
|
216
300
|
UserNotificationEventType.IncidentCreated &&
|
|
@@ -278,7 +362,51 @@ export class Service extends DatabaseService<Model> {
|
|
|
278
362
|
notificationRuleItem.userSms?.phone &&
|
|
279
363
|
notificationRuleItem.userSms?.isVerified
|
|
280
364
|
) {
|
|
281
|
-
//
|
|
365
|
+
//send sms for alert
|
|
366
|
+
if (
|
|
367
|
+
options.userNotificationEventType ===
|
|
368
|
+
UserNotificationEventType.AlertCreated &&
|
|
369
|
+
alert
|
|
370
|
+
) {
|
|
371
|
+
// create an error log.
|
|
372
|
+
logTimelineItem.status = UserNotificationStatus.Sending;
|
|
373
|
+
logTimelineItem.statusMessage = `Sending SMS to ${notificationRuleItem.userSms?.phone.toString()}.`;
|
|
374
|
+
logTimelineItem.userSmsId = notificationRuleItem.userSms.id!;
|
|
375
|
+
|
|
376
|
+
const updatedLog: UserOnCallLogTimeline =
|
|
377
|
+
await UserOnCallLogTimelineService.create({
|
|
378
|
+
data: logTimelineItem,
|
|
379
|
+
props: {
|
|
380
|
+
isRoot: true,
|
|
381
|
+
},
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
const smsMessage: SMS = await this.generateSmsTemplateForAlertCreated(
|
|
385
|
+
notificationRuleItem.userSms.phone,
|
|
386
|
+
alert,
|
|
387
|
+
updatedLog.id!,
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
// send email.
|
|
391
|
+
|
|
392
|
+
SmsService.sendSms(smsMessage, {
|
|
393
|
+
projectId: alert.projectId,
|
|
394
|
+
userOnCallLogTimelineId: updatedLog.id!,
|
|
395
|
+
}).catch(async (err: Error) => {
|
|
396
|
+
await UserOnCallLogTimelineService.updateOneById({
|
|
397
|
+
id: updatedLog.id!,
|
|
398
|
+
data: {
|
|
399
|
+
status: UserNotificationStatus.Error,
|
|
400
|
+
statusMessage: err.message || "Error sending SMS.",
|
|
401
|
+
},
|
|
402
|
+
props: {
|
|
403
|
+
isRoot: true,
|
|
404
|
+
},
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// send sms for incident
|
|
282
410
|
if (
|
|
283
411
|
options.userNotificationEventType ===
|
|
284
412
|
UserNotificationEventType.IncidentCreated &&
|
|
@@ -345,43 +473,94 @@ export class Service extends DatabaseService<Model> {
|
|
|
345
473
|
notificationRuleItem.userCall?.phone &&
|
|
346
474
|
notificationRuleItem.userCall?.isVerified
|
|
347
475
|
) {
|
|
348
|
-
// send call
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
476
|
+
// send call for alert
|
|
477
|
+
if (
|
|
478
|
+
options.userNotificationEventType ===
|
|
479
|
+
UserNotificationEventType.AlertCreated &&
|
|
480
|
+
alert
|
|
481
|
+
) {
|
|
482
|
+
// create an error log.
|
|
483
|
+
logTimelineItem.status = UserNotificationStatus.Sending;
|
|
484
|
+
logTimelineItem.statusMessage = `Making a call to ${notificationRuleItem.userCall?.phone.toString()}.`;
|
|
485
|
+
logTimelineItem.userCallId = notificationRuleItem.userCall.id!;
|
|
486
|
+
|
|
487
|
+
const updatedLog: UserOnCallLogTimeline =
|
|
488
|
+
await UserOnCallLogTimelineService.create({
|
|
489
|
+
data: logTimelineItem,
|
|
490
|
+
props: {
|
|
491
|
+
isRoot: true,
|
|
492
|
+
},
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
const callRequest: CallRequest =
|
|
496
|
+
await this.generateCallTemplateForAlertCreated(
|
|
497
|
+
notificationRuleItem.userCall?.phone,
|
|
498
|
+
alert,
|
|
499
|
+
updatedLog.id!,
|
|
500
|
+
);
|
|
501
|
+
|
|
502
|
+
// send email.
|
|
503
|
+
|
|
504
|
+
CallService.makeCall(callRequest, {
|
|
505
|
+
projectId: alert.projectId,
|
|
506
|
+
userOnCallLogTimelineId: updatedLog.id!,
|
|
507
|
+
}).catch(async (err: Error) => {
|
|
508
|
+
await UserOnCallLogTimelineService.updateOneById({
|
|
509
|
+
id: updatedLog.id!,
|
|
510
|
+
data: {
|
|
511
|
+
status: UserNotificationStatus.Error,
|
|
512
|
+
statusMessage: err.message || "Error making call.",
|
|
513
|
+
},
|
|
514
|
+
props: {
|
|
515
|
+
isRoot: true,
|
|
516
|
+
},
|
|
517
|
+
});
|
|
359
518
|
});
|
|
519
|
+
}
|
|
360
520
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
521
|
+
if (
|
|
522
|
+
options.userNotificationEventType ===
|
|
523
|
+
UserNotificationEventType.IncidentCreated &&
|
|
524
|
+
incident
|
|
525
|
+
) {
|
|
526
|
+
// send call for incident
|
|
527
|
+
logTimelineItem.status = UserNotificationStatus.Sending;
|
|
528
|
+
logTimelineItem.statusMessage = `Making a call to ${notificationRuleItem.userCall?.phone.toString()}.`;
|
|
529
|
+
logTimelineItem.userCallId = notificationRuleItem.userCall.id!;
|
|
367
530
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
531
|
+
const updatedLog: UserOnCallLogTimeline =
|
|
532
|
+
await UserOnCallLogTimelineService.create({
|
|
533
|
+
data: logTimelineItem,
|
|
534
|
+
props: {
|
|
535
|
+
isRoot: true,
|
|
536
|
+
},
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
const callRequest: CallRequest =
|
|
540
|
+
await this.generateCallTemplateForIncidentCreated(
|
|
541
|
+
notificationRuleItem.userCall?.phone,
|
|
542
|
+
incident,
|
|
543
|
+
updatedLog.id!,
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
// send email.
|
|
547
|
+
|
|
548
|
+
CallService.makeCall(callRequest, {
|
|
549
|
+
projectId: incident.projectId,
|
|
550
|
+
userOnCallLogTimelineId: updatedLog.id!,
|
|
551
|
+
}).catch(async (err: Error) => {
|
|
552
|
+
await UserOnCallLogTimelineService.updateOneById({
|
|
553
|
+
id: updatedLog.id!,
|
|
554
|
+
data: {
|
|
555
|
+
status: UserNotificationStatus.Error,
|
|
556
|
+
statusMessage: err.message || "Error making call.",
|
|
557
|
+
},
|
|
558
|
+
props: {
|
|
559
|
+
isRoot: true,
|
|
560
|
+
},
|
|
561
|
+
});
|
|
383
562
|
});
|
|
384
|
-
}
|
|
563
|
+
}
|
|
385
564
|
}
|
|
386
565
|
|
|
387
566
|
if (
|
|
@@ -401,6 +580,56 @@ export class Service extends DatabaseService<Model> {
|
|
|
401
580
|
}
|
|
402
581
|
}
|
|
403
582
|
|
|
583
|
+
public async generateCallTemplateForAlertCreated(
|
|
584
|
+
to: Phone,
|
|
585
|
+
alert: Alert,
|
|
586
|
+
userOnCallLogTimelineId: ObjectID,
|
|
587
|
+
): Promise<CallRequest> {
|
|
588
|
+
const host: Hostname = await DatabaseConfig.getHost();
|
|
589
|
+
|
|
590
|
+
const httpProtocol: Protocol = await DatabaseConfig.getHttpProtocol();
|
|
591
|
+
|
|
592
|
+
const callRequest: CallRequest = {
|
|
593
|
+
to: to,
|
|
594
|
+
data: [
|
|
595
|
+
{
|
|
596
|
+
sayMessage: "This is a call from OneUptime",
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
sayMessage: "A new alert has been created",
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
sayMessage: alert.title!,
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
introMessage: "To acknowledge this alert press 1",
|
|
606
|
+
numDigits: 1,
|
|
607
|
+
timeoutInSeconds: 10,
|
|
608
|
+
noInputMessage: "You have not entered any input. Good bye",
|
|
609
|
+
onInputCallRequest: {
|
|
610
|
+
"1": {
|
|
611
|
+
sayMessage: "You have acknowledged this alert. Good bye",
|
|
612
|
+
},
|
|
613
|
+
default: {
|
|
614
|
+
sayMessage: "Invalid input. Good bye",
|
|
615
|
+
},
|
|
616
|
+
},
|
|
617
|
+
responseUrl: new URL(
|
|
618
|
+
httpProtocol,
|
|
619
|
+
host,
|
|
620
|
+
new Route(AppApiRoute.toString())
|
|
621
|
+
.addRoute(new UserOnCallLogTimeline().crudApiPath!)
|
|
622
|
+
.addRoute(
|
|
623
|
+
"/call/gather-input/" + userOnCallLogTimelineId.toString(),
|
|
624
|
+
),
|
|
625
|
+
),
|
|
626
|
+
},
|
|
627
|
+
],
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
return callRequest;
|
|
631
|
+
}
|
|
632
|
+
|
|
404
633
|
public async generateCallTemplateForIncidentCreated(
|
|
405
634
|
to: Phone,
|
|
406
635
|
incident: Incident,
|
|
@@ -451,6 +680,35 @@ export class Service extends DatabaseService<Model> {
|
|
|
451
680
|
return callRequest;
|
|
452
681
|
}
|
|
453
682
|
|
|
683
|
+
public async generateSmsTemplateForAlertCreated(
|
|
684
|
+
to: Phone,
|
|
685
|
+
alert: Alert,
|
|
686
|
+
userOnCallLogTimelineId: ObjectID,
|
|
687
|
+
): Promise<SMS> {
|
|
688
|
+
const host: Hostname = await DatabaseConfig.getHost();
|
|
689
|
+
const httpProtocol: Protocol = await DatabaseConfig.getHttpProtocol();
|
|
690
|
+
|
|
691
|
+
const shortUrl: ShortLink = await ShortLinkService.saveShortLinkFor(
|
|
692
|
+
new URL(
|
|
693
|
+
httpProtocol,
|
|
694
|
+
host,
|
|
695
|
+
new Route(AppApiRoute.toString())
|
|
696
|
+
.addRoute(new UserOnCallLogTimeline().crudApiPath!)
|
|
697
|
+
.addRoute("/acknowledge/" + userOnCallLogTimelineId.toString()),
|
|
698
|
+
),
|
|
699
|
+
);
|
|
700
|
+
const url: URL = await ShortLinkService.getShortenedUrl(shortUrl);
|
|
701
|
+
|
|
702
|
+
const sms: SMS = {
|
|
703
|
+
to,
|
|
704
|
+
message: `This is a message from OneUptime. A new alert has been created. ${
|
|
705
|
+
alert.title
|
|
706
|
+
}. To acknowledge this alert, please click on the following link ${url.toString()}`,
|
|
707
|
+
};
|
|
708
|
+
|
|
709
|
+
return sms;
|
|
710
|
+
}
|
|
711
|
+
|
|
454
712
|
public async generateSmsTemplateForIncidentCreated(
|
|
455
713
|
to: Phone,
|
|
456
714
|
incident: Incident,
|
|
@@ -480,6 +738,45 @@ export class Service extends DatabaseService<Model> {
|
|
|
480
738
|
return sms;
|
|
481
739
|
}
|
|
482
740
|
|
|
741
|
+
public async generateEmailTemplateForAlertCreated(
|
|
742
|
+
to: Email,
|
|
743
|
+
alert: Alert,
|
|
744
|
+
userOnCallLogTimelineId: ObjectID,
|
|
745
|
+
): Promise<EmailMessage> {
|
|
746
|
+
const host: Hostname = await DatabaseConfig.getHost();
|
|
747
|
+
const httpProtocol: Protocol = await DatabaseConfig.getHttpProtocol();
|
|
748
|
+
|
|
749
|
+
const vars: Dictionary<string> = {
|
|
750
|
+
alertTitle: alert.title!,
|
|
751
|
+
projectName: alert.project!.name!,
|
|
752
|
+
currentState: alert.currentAlertState!.name!,
|
|
753
|
+
alertDescription: await Markdown.convertToHTML(
|
|
754
|
+
alert.description! || "",
|
|
755
|
+
MarkdownContentType.Email,
|
|
756
|
+
),
|
|
757
|
+
alertSeverity: alert.alertSeverity!.name!,
|
|
758
|
+
alertViewLink: (
|
|
759
|
+
await AlertService.getAlertLinkInDashboard(alert.projectId!, alert.id!)
|
|
760
|
+
).toString(),
|
|
761
|
+
acknowledgeAlertLink: new URL(
|
|
762
|
+
httpProtocol,
|
|
763
|
+
host,
|
|
764
|
+
new Route(AppApiRoute.toString())
|
|
765
|
+
.addRoute(new UserOnCallLogTimeline().crudApiPath!)
|
|
766
|
+
.addRoute("/acknowledge/" + userOnCallLogTimelineId.toString()),
|
|
767
|
+
).toString(),
|
|
768
|
+
};
|
|
769
|
+
|
|
770
|
+
const emailMessage: EmailMessage = {
|
|
771
|
+
toEmail: to!,
|
|
772
|
+
templateType: EmailTemplateType.AcknowledgeAlert,
|
|
773
|
+
vars: vars,
|
|
774
|
+
subject: "ACTION REQUIRED: Alert created - " + alert.title!,
|
|
775
|
+
};
|
|
776
|
+
|
|
777
|
+
return emailMessage;
|
|
778
|
+
}
|
|
779
|
+
|
|
483
780
|
public async generateEmailTemplateForIncidentCreated(
|
|
484
781
|
to: Email,
|
|
485
782
|
incident: Incident,
|
|
@@ -529,6 +826,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
529
826
|
options: {
|
|
530
827
|
projectId: ObjectID;
|
|
531
828
|
triggeredByIncidentId?: ObjectID | undefined;
|
|
829
|
+
triggeredByAlertId?: ObjectID | undefined;
|
|
532
830
|
userNotificationEventType: UserNotificationEventType;
|
|
533
831
|
onCallPolicyExecutionLogId?: ObjectID | undefined;
|
|
534
832
|
onCallPolicyId: ObjectID | undefined;
|
|
@@ -548,6 +846,10 @@ export class Service extends DatabaseService<Model> {
|
|
|
548
846
|
userOnCallLog.triggeredByIncidentId = options.triggeredByIncidentId;
|
|
549
847
|
}
|
|
550
848
|
|
|
849
|
+
if (options.triggeredByAlertId) {
|
|
850
|
+
userOnCallLog.triggeredByAlertId = options.triggeredByAlertId;
|
|
851
|
+
}
|
|
852
|
+
|
|
551
853
|
userOnCallLog.userNotificationEventType = options.userNotificationEventType;
|
|
552
854
|
|
|
553
855
|
if (options.onCallPolicyExecutionLogId) {
|
|
@@ -608,11 +910,13 @@ export class Service extends DatabaseService<Model> {
|
|
|
608
910
|
};
|
|
609
911
|
}
|
|
610
912
|
|
|
611
|
-
public async
|
|
612
|
-
projectId: ObjectID
|
|
613
|
-
userId: ObjectID
|
|
614
|
-
|
|
615
|
-
): Promise<void> {
|
|
913
|
+
public async addDefaultIncidentNotificationRuleForUser(data: {
|
|
914
|
+
projectId: ObjectID;
|
|
915
|
+
userId: ObjectID;
|
|
916
|
+
userEmail: UserEmail;
|
|
917
|
+
}): Promise<void> {
|
|
918
|
+
const { projectId, userId, userEmail } = data;
|
|
919
|
+
|
|
616
920
|
const incidentSeverities: Array<IncidentSeverity> =
|
|
617
921
|
await IncidentSeverityService.findBy({
|
|
618
922
|
query: {
|
|
@@ -628,44 +932,76 @@ export class Service extends DatabaseService<Model> {
|
|
|
628
932
|
},
|
|
629
933
|
});
|
|
630
934
|
|
|
631
|
-
//
|
|
935
|
+
// create for incident severities.
|
|
936
|
+
for (const incidentSeverity of incidentSeverities) {
|
|
937
|
+
//check if this rule already exists.
|
|
938
|
+
const existingRule: Model | null = await this.findOneBy({
|
|
939
|
+
query: {
|
|
940
|
+
projectId,
|
|
941
|
+
userId,
|
|
942
|
+
userEmailId: userEmail.id!,
|
|
943
|
+
incidentSeverityId: incidentSeverity.id!,
|
|
944
|
+
ruleType: NotificationRuleType.ON_CALL_EXECUTED,
|
|
945
|
+
},
|
|
946
|
+
props: {
|
|
947
|
+
isRoot: true,
|
|
948
|
+
},
|
|
949
|
+
});
|
|
632
950
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
userId,
|
|
637
|
-
email,
|
|
638
|
-
},
|
|
639
|
-
props: {
|
|
640
|
-
isRoot: true,
|
|
641
|
-
},
|
|
642
|
-
});
|
|
951
|
+
if (existingRule) {
|
|
952
|
+
continue; // skip this rule.
|
|
953
|
+
}
|
|
643
954
|
|
|
644
|
-
|
|
645
|
-
userEmail = new UserEmail();
|
|
646
|
-
userEmail.projectId = projectId;
|
|
647
|
-
userEmail.userId = userId;
|
|
648
|
-
userEmail.email = email;
|
|
649
|
-
userEmail.isVerified = true;
|
|
955
|
+
const notificationRule: Model = new Model();
|
|
650
956
|
|
|
651
|
-
|
|
652
|
-
|
|
957
|
+
notificationRule.projectId = projectId;
|
|
958
|
+
notificationRule.userId = userId;
|
|
959
|
+
notificationRule.userEmailId = userEmail.id!;
|
|
960
|
+
notificationRule.incidentSeverityId = incidentSeverity.id!;
|
|
961
|
+
notificationRule.notifyAfterMinutes = 0;
|
|
962
|
+
notificationRule.ruleType = NotificationRuleType.ON_CALL_EXECUTED;
|
|
963
|
+
|
|
964
|
+
await this.create({
|
|
965
|
+
data: notificationRule,
|
|
653
966
|
props: {
|
|
654
967
|
isRoot: true,
|
|
655
968
|
},
|
|
656
969
|
});
|
|
657
970
|
}
|
|
971
|
+
}
|
|
658
972
|
|
|
659
|
-
|
|
660
|
-
|
|
973
|
+
public async addDefaultAlertNotificationRulesForUser(data: {
|
|
974
|
+
projectId: ObjectID;
|
|
975
|
+
userId: ObjectID;
|
|
976
|
+
userEmail: UserEmail;
|
|
977
|
+
}): Promise<void> {
|
|
978
|
+
const { projectId, userId, userEmail } = data;
|
|
979
|
+
|
|
980
|
+
const alertSeverities: Array<AlertSeverity> =
|
|
981
|
+
await AlertSeverityService.findBy({
|
|
982
|
+
query: {
|
|
983
|
+
projectId,
|
|
984
|
+
},
|
|
985
|
+
props: {
|
|
986
|
+
isRoot: true,
|
|
987
|
+
},
|
|
988
|
+
limit: LIMIT_PER_PROJECT,
|
|
989
|
+
skip: 0,
|
|
990
|
+
select: {
|
|
991
|
+
_id: true,
|
|
992
|
+
},
|
|
993
|
+
});
|
|
994
|
+
|
|
995
|
+
// create for Alert severities.
|
|
996
|
+
for (const alertSeverity of alertSeverities) {
|
|
661
997
|
//check if this rule already exists.
|
|
662
998
|
const existingRule: Model | null = await this.findOneBy({
|
|
663
999
|
query: {
|
|
664
1000
|
projectId,
|
|
665
1001
|
userId,
|
|
666
1002
|
userEmailId: userEmail.id!,
|
|
667
|
-
|
|
668
|
-
ruleType: NotificationRuleType.
|
|
1003
|
+
alertSeverityId: alertSeverity.id!,
|
|
1004
|
+
ruleType: NotificationRuleType.ON_CALL_EXECUTED,
|
|
669
1005
|
},
|
|
670
1006
|
props: {
|
|
671
1007
|
isRoot: true,
|
|
@@ -681,9 +1017,9 @@ export class Service extends DatabaseService<Model> {
|
|
|
681
1017
|
notificationRule.projectId = projectId;
|
|
682
1018
|
notificationRule.userId = userId;
|
|
683
1019
|
notificationRule.userEmailId = userEmail.id!;
|
|
684
|
-
notificationRule.
|
|
1020
|
+
notificationRule.alertSeverityId = alertSeverity.id!;
|
|
685
1021
|
notificationRule.notifyAfterMinutes = 0;
|
|
686
|
-
notificationRule.ruleType = NotificationRuleType.
|
|
1022
|
+
notificationRule.ruleType = NotificationRuleType.ON_CALL_EXECUTED;
|
|
687
1023
|
|
|
688
1024
|
await this.create({
|
|
689
1025
|
data: notificationRule,
|
|
@@ -692,6 +1028,53 @@ export class Service extends DatabaseService<Model> {
|
|
|
692
1028
|
},
|
|
693
1029
|
});
|
|
694
1030
|
}
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
public async addDefaultNotificationRuleForUser(
|
|
1034
|
+
projectId: ObjectID,
|
|
1035
|
+
userId: ObjectID,
|
|
1036
|
+
email: Email,
|
|
1037
|
+
): Promise<void> {
|
|
1038
|
+
let userEmail: UserEmail | null = await UserEmailService.findOneBy({
|
|
1039
|
+
query: {
|
|
1040
|
+
projectId,
|
|
1041
|
+
userId,
|
|
1042
|
+
email,
|
|
1043
|
+
},
|
|
1044
|
+
props: {
|
|
1045
|
+
isRoot: true,
|
|
1046
|
+
},
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
if (!userEmail) {
|
|
1050
|
+
userEmail = new UserEmail();
|
|
1051
|
+
userEmail.projectId = projectId;
|
|
1052
|
+
userEmail.userId = userId;
|
|
1053
|
+
userEmail.email = email;
|
|
1054
|
+
userEmail.isVerified = true;
|
|
1055
|
+
|
|
1056
|
+
userEmail = await UserEmailService.create({
|
|
1057
|
+
data: userEmail,
|
|
1058
|
+
props: {
|
|
1059
|
+
isRoot: true,
|
|
1060
|
+
},
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
// add default incident rules for user
|
|
1065
|
+
await this.addDefaultIncidentNotificationRuleForUser({
|
|
1066
|
+
projectId,
|
|
1067
|
+
userId,
|
|
1068
|
+
userEmail,
|
|
1069
|
+
});
|
|
1070
|
+
|
|
1071
|
+
// add default alert rules for user, just like the incident
|
|
1072
|
+
|
|
1073
|
+
await this.addDefaultAlertNotificationRulesForUser({
|
|
1074
|
+
projectId,
|
|
1075
|
+
userId,
|
|
1076
|
+
userEmail,
|
|
1077
|
+
});
|
|
695
1078
|
|
|
696
1079
|
//check if this rule already exists.
|
|
697
1080
|
const existingRuleOnCall: Model | null = await this.findOneBy({
|