@oneuptime/common 7.0.3526 → 7.0.3546
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/Server/Services/WorkflowLogService.ts +1 -1
- 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/Server/Services/WorkflowLogService.js +1 -1
- package/build/dist/Server/Services/WorkflowLogService.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
|
@@ -1,10 +1,122 @@
|
|
|
1
|
+
import Team from "../../Models/DatabaseModels/Team";
|
|
2
|
+
import ObjectID from "../../Types/ObjectID";
|
|
3
|
+
import DeleteBy from "../Types/Database/DeleteBy";
|
|
4
|
+
import { OnCreate, OnDelete } from "../Types/Database/Hooks";
|
|
1
5
|
import DatabaseService from "./DatabaseService";
|
|
2
6
|
import Model from "Common/Models/DatabaseModels/AlertOwnerTeam";
|
|
7
|
+
import TeamService from "./TeamService";
|
|
8
|
+
import AlertFeedService from "./AlertFeedService";
|
|
9
|
+
import { AlertFeedEventType } from "../../Models/DatabaseModels/AlertFeed";
|
|
10
|
+
import { Gray500, Red500 } from "../../Types/BrandColors";
|
|
3
11
|
|
|
4
12
|
export class Service extends DatabaseService<Model> {
|
|
5
13
|
public constructor() {
|
|
6
14
|
super(Model);
|
|
7
15
|
}
|
|
16
|
+
|
|
17
|
+
protected override async onBeforeDelete(
|
|
18
|
+
deleteBy: DeleteBy<Model>,
|
|
19
|
+
): Promise<OnDelete<Model>> {
|
|
20
|
+
const itemsToDelete: Model[] = await this.findBy({
|
|
21
|
+
query: deleteBy.query,
|
|
22
|
+
limit: deleteBy.limit,
|
|
23
|
+
skip: deleteBy.skip,
|
|
24
|
+
props: {
|
|
25
|
+
isRoot: true,
|
|
26
|
+
},
|
|
27
|
+
select: {
|
|
28
|
+
alertId: true,
|
|
29
|
+
projectId: true,
|
|
30
|
+
teamId: true,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
carryForward: {
|
|
36
|
+
itemsToDelete: itemsToDelete,
|
|
37
|
+
},
|
|
38
|
+
deleteBy: deleteBy,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
protected override async onDeleteSuccess(
|
|
43
|
+
onDelete: OnDelete<Model>,
|
|
44
|
+
_itemIdsBeforeDelete: Array<ObjectID>,
|
|
45
|
+
): Promise<OnDelete<Model>> {
|
|
46
|
+
const deleteByUserId: ObjectID | undefined =
|
|
47
|
+
onDelete.deleteBy.deletedByUser?.id || onDelete.deleteBy.props.userId;
|
|
48
|
+
|
|
49
|
+
const itemsToDelete: Model[] = onDelete.carryForward.itemsToDelete;
|
|
50
|
+
|
|
51
|
+
for (const item of itemsToDelete) {
|
|
52
|
+
const alertId: ObjectID | undefined = item.alertId;
|
|
53
|
+
const projectId: ObjectID | undefined = item.projectId;
|
|
54
|
+
const teamId: ObjectID | undefined = item.teamId;
|
|
55
|
+
|
|
56
|
+
if (alertId && teamId && projectId) {
|
|
57
|
+
const team: Team | null = await TeamService.findOneById({
|
|
58
|
+
id: teamId,
|
|
59
|
+
select: {
|
|
60
|
+
name: true,
|
|
61
|
+
},
|
|
62
|
+
props: {
|
|
63
|
+
isRoot: true,
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (team && team.name) {
|
|
68
|
+
await AlertFeedService.createAlertFeed({
|
|
69
|
+
alertId: alertId,
|
|
70
|
+
projectId: projectId,
|
|
71
|
+
alertFeedEventType: AlertFeedEventType.OwnerTeamRemoved,
|
|
72
|
+
displayColor: Red500,
|
|
73
|
+
feedInfoInMarkdown: `**Team ${team.name}** was removed from the alert as the owner.`,
|
|
74
|
+
userId: deleteByUserId || undefined,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return onDelete;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public override async onCreateSuccess(
|
|
84
|
+
onCreate: OnCreate<Model>,
|
|
85
|
+
createdItem: Model,
|
|
86
|
+
): Promise<Model> {
|
|
87
|
+
// add alert feed.
|
|
88
|
+
|
|
89
|
+
const alertId: ObjectID | undefined = createdItem.alertId;
|
|
90
|
+
const projectId: ObjectID | undefined = createdItem.projectId;
|
|
91
|
+
const teamId: ObjectID | undefined = createdItem.teamId;
|
|
92
|
+
const createdByUserId: ObjectID | undefined =
|
|
93
|
+
createdItem.createdByUserId || onCreate.createBy.props.userId;
|
|
94
|
+
|
|
95
|
+
if (alertId && teamId && projectId) {
|
|
96
|
+
const team: Team | null = await TeamService.findOneById({
|
|
97
|
+
id: teamId,
|
|
98
|
+
select: {
|
|
99
|
+
name: true,
|
|
100
|
+
},
|
|
101
|
+
props: {
|
|
102
|
+
isRoot: true,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (team && team.name) {
|
|
107
|
+
await AlertFeedService.createAlertFeed({
|
|
108
|
+
alertId: alertId,
|
|
109
|
+
projectId: projectId,
|
|
110
|
+
alertFeedEventType: AlertFeedEventType.OwnerTeamAdded,
|
|
111
|
+
displayColor: Gray500,
|
|
112
|
+
feedInfoInMarkdown: `**Team ${team.name}** was added to the alert as the owner.`,
|
|
113
|
+
userId: createdByUserId || undefined,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return createdItem;
|
|
119
|
+
}
|
|
8
120
|
}
|
|
9
121
|
|
|
10
122
|
export default new Service();
|
|
@@ -1,10 +1,124 @@
|
|
|
1
|
+
import User from "../../Models/DatabaseModels/User";
|
|
2
|
+
import ObjectID from "../../Types/ObjectID";
|
|
3
|
+
import DeleteBy from "../Types/Database/DeleteBy";
|
|
4
|
+
import { OnCreate, OnDelete } from "../Types/Database/Hooks";
|
|
1
5
|
import DatabaseService from "./DatabaseService";
|
|
2
6
|
import Model from "Common/Models/DatabaseModels/AlertOwnerUser";
|
|
7
|
+
import UserService from "./UserService";
|
|
8
|
+
import AlertFeedService from "./AlertFeedService";
|
|
9
|
+
import { AlertFeedEventType } from "../../Models/DatabaseModels/AlertFeed";
|
|
10
|
+
import { Gray500, Red500 } from "../../Types/BrandColors";
|
|
3
11
|
|
|
4
12
|
export class Service extends DatabaseService<Model> {
|
|
5
13
|
public constructor() {
|
|
6
14
|
super(Model);
|
|
7
15
|
}
|
|
16
|
+
|
|
17
|
+
protected override async onBeforeDelete(
|
|
18
|
+
deleteBy: DeleteBy<Model>,
|
|
19
|
+
): Promise<OnDelete<Model>> {
|
|
20
|
+
const itemsToDelete: Model[] = await this.findBy({
|
|
21
|
+
query: deleteBy.query,
|
|
22
|
+
limit: deleteBy.limit,
|
|
23
|
+
skip: deleteBy.skip,
|
|
24
|
+
props: {
|
|
25
|
+
isRoot: true,
|
|
26
|
+
},
|
|
27
|
+
select: {
|
|
28
|
+
alertId: true,
|
|
29
|
+
projectId: true,
|
|
30
|
+
userId: true,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
carryForward: {
|
|
36
|
+
itemsToDelete: itemsToDelete,
|
|
37
|
+
},
|
|
38
|
+
deleteBy: deleteBy,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
protected override async onDeleteSuccess(
|
|
43
|
+
onDelete: OnDelete<Model>,
|
|
44
|
+
_itemIdsBeforeDelete: Array<ObjectID>,
|
|
45
|
+
): Promise<OnDelete<Model>> {
|
|
46
|
+
const deleteByUserId: ObjectID | undefined =
|
|
47
|
+
onDelete.deleteBy.deletedByUser?.id || onDelete.deleteBy.props.userId;
|
|
48
|
+
|
|
49
|
+
const itemsToDelete: Model[] = onDelete.carryForward.itemsToDelete;
|
|
50
|
+
|
|
51
|
+
for (const item of itemsToDelete) {
|
|
52
|
+
const alertId: ObjectID | undefined = item.alertId;
|
|
53
|
+
const projectId: ObjectID | undefined = item.projectId;
|
|
54
|
+
const userId: ObjectID | undefined = item.userId;
|
|
55
|
+
|
|
56
|
+
if (alertId && userId && projectId) {
|
|
57
|
+
const user: User | null = await UserService.findOneById({
|
|
58
|
+
id: userId,
|
|
59
|
+
select: {
|
|
60
|
+
name: true,
|
|
61
|
+
email: true,
|
|
62
|
+
},
|
|
63
|
+
props: {
|
|
64
|
+
isRoot: true,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if (user && user.name) {
|
|
69
|
+
await AlertFeedService.createAlertFeed({
|
|
70
|
+
alertId: alertId,
|
|
71
|
+
projectId: projectId,
|
|
72
|
+
alertFeedEventType: AlertFeedEventType.OwnerUserRemoved,
|
|
73
|
+
displayColor: Red500,
|
|
74
|
+
feedInfoInMarkdown: `**${user.name.toString()}** (${user.email?.toString()}) was removed from the alert as the owner.`,
|
|
75
|
+
userId: deleteByUserId || undefined,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return onDelete;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public override async onCreateSuccess(
|
|
85
|
+
onCreate: OnCreate<Model>,
|
|
86
|
+
createdItem: Model,
|
|
87
|
+
): Promise<Model> {
|
|
88
|
+
// add alert feed.
|
|
89
|
+
|
|
90
|
+
const alertId: ObjectID | undefined = createdItem.alertId;
|
|
91
|
+
const projectId: ObjectID | undefined = createdItem.projectId;
|
|
92
|
+
const userId: ObjectID | undefined = createdItem.userId;
|
|
93
|
+
const createdByUserId: ObjectID | undefined =
|
|
94
|
+
createdItem.createdByUserId || onCreate.createBy.props.userId;
|
|
95
|
+
|
|
96
|
+
if (alertId && userId && projectId) {
|
|
97
|
+
const user: User | null = await UserService.findOneById({
|
|
98
|
+
id: userId,
|
|
99
|
+
select: {
|
|
100
|
+
name: true,
|
|
101
|
+
email: true,
|
|
102
|
+
},
|
|
103
|
+
props: {
|
|
104
|
+
isRoot: true,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (user && user.name) {
|
|
109
|
+
await AlertFeedService.createAlertFeed({
|
|
110
|
+
alertId: alertId,
|
|
111
|
+
projectId: projectId,
|
|
112
|
+
alertFeedEventType: AlertFeedEventType.OwnerUserAdded,
|
|
113
|
+
displayColor: Gray500,
|
|
114
|
+
feedInfoInMarkdown: `**${user.name.toString()}** (${user.email?.toString()}) was added to the alert as the owner.`,
|
|
115
|
+
userId: createdByUserId || undefined,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return createdItem;
|
|
121
|
+
}
|
|
8
122
|
}
|
|
9
123
|
|
|
10
124
|
export default new Service();
|
|
@@ -38,6 +38,9 @@ import Metric, {
|
|
|
38
38
|
ServiceType,
|
|
39
39
|
} from "../../Models/AnalyticsModels/Metric";
|
|
40
40
|
import AlertMetricType from "../../Types/Alerts/AlertMetricType";
|
|
41
|
+
import AlertFeedService from "./AlertFeedService";
|
|
42
|
+
import { AlertFeedEventType } from "../../Models/DatabaseModels/AlertFeed";
|
|
43
|
+
import { Gray500, Red500 } from "../../Types/BrandColors";
|
|
41
44
|
|
|
42
45
|
export class Service extends DatabaseService<Model> {
|
|
43
46
|
public constructor() {
|
|
@@ -224,6 +227,48 @@ export class Service extends DatabaseService<Model> {
|
|
|
224
227
|
throw new BadDataException("currentAlertStateId is required");
|
|
225
228
|
}
|
|
226
229
|
|
|
230
|
+
const createdByUserId: ObjectID | undefined | null =
|
|
231
|
+
createdItem.createdByUserId || createdItem.createdByUser?.id;
|
|
232
|
+
|
|
233
|
+
await AlertFeedService.createAlertFeed({
|
|
234
|
+
alertId: createdItem.id!,
|
|
235
|
+
projectId: createdItem.projectId!,
|
|
236
|
+
alertFeedEventType: AlertFeedEventType.AlertCreated,
|
|
237
|
+
displayColor: Red500,
|
|
238
|
+
feedInfoInMarkdown: `**Alert Created**:
|
|
239
|
+
|
|
240
|
+
**Alert Title**:
|
|
241
|
+
|
|
242
|
+
${createdItem.title || "No title provided."}
|
|
243
|
+
|
|
244
|
+
**Description**:
|
|
245
|
+
|
|
246
|
+
${createdItem.description || "No description provided."}
|
|
247
|
+
|
|
248
|
+
`,
|
|
249
|
+
userId: createdByUserId || undefined,
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
await AlertFeedService.createAlertFeed({
|
|
253
|
+
alertId: createdItem.id!,
|
|
254
|
+
projectId: createdItem.projectId!,
|
|
255
|
+
alertFeedEventType: AlertFeedEventType.RootCause,
|
|
256
|
+
displayColor: Red500,
|
|
257
|
+
feedInfoInMarkdown: `**Root Cause**
|
|
258
|
+
|
|
259
|
+
${createdItem.rootCause || "No root cause provided."}`,
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
await AlertFeedService.createAlertFeed({
|
|
263
|
+
alertId: createdItem.id!,
|
|
264
|
+
projectId: createdItem.projectId!,
|
|
265
|
+
alertFeedEventType: AlertFeedEventType.RemediationNotes,
|
|
266
|
+
displayColor: Red500,
|
|
267
|
+
feedInfoInMarkdown: `**Remediation Notes**
|
|
268
|
+
|
|
269
|
+
${createdItem.remediationNotes || "No remediation notes provided."}`,
|
|
270
|
+
});
|
|
271
|
+
|
|
227
272
|
await this.changeAlertState({
|
|
228
273
|
projectId: createdItem.projectId,
|
|
229
274
|
alertId: createdItem.id,
|
|
@@ -445,6 +490,82 @@ export class Service extends DatabaseService<Model> {
|
|
|
445
490
|
}
|
|
446
491
|
}
|
|
447
492
|
|
|
493
|
+
if (updatedItemIds.length > 0) {
|
|
494
|
+
for (const alertId of updatedItemIds) {
|
|
495
|
+
if (onUpdate.updateBy.data.title) {
|
|
496
|
+
// add alert feed.
|
|
497
|
+
const createdByUserId: ObjectID | undefined | null =
|
|
498
|
+
onUpdate.updateBy.props.userId;
|
|
499
|
+
|
|
500
|
+
await AlertFeedService.createAlertFeed({
|
|
501
|
+
alertId: alertId,
|
|
502
|
+
projectId: onUpdate.updateBy.props.tenantId as ObjectID,
|
|
503
|
+
alertFeedEventType: AlertFeedEventType.AlertUpdated,
|
|
504
|
+
displayColor: Gray500,
|
|
505
|
+
feedInfoInMarkdown: `**Alert title was updated.** Here's the new title.
|
|
506
|
+
|
|
507
|
+
${onUpdate.updateBy.data.title || "No title provided."}
|
|
508
|
+
`,
|
|
509
|
+
userId: createdByUserId || undefined,
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
if (onUpdate.updateBy.data.rootCause) {
|
|
514
|
+
// add alert feed.
|
|
515
|
+
const createdByUserId: ObjectID | undefined | null =
|
|
516
|
+
onUpdate.updateBy.props.userId;
|
|
517
|
+
|
|
518
|
+
await AlertFeedService.createAlertFeed({
|
|
519
|
+
alertId: alertId,
|
|
520
|
+
projectId: onUpdate.updateBy.props.tenantId as ObjectID,
|
|
521
|
+
alertFeedEventType: AlertFeedEventType.AlertUpdated,
|
|
522
|
+
displayColor: Gray500,
|
|
523
|
+
feedInfoInMarkdown: `**Alert root cause was updated.** Here's the new root cause.
|
|
524
|
+
|
|
525
|
+
${onUpdate.updateBy.data.rootCause || "No root cause provided."}
|
|
526
|
+
`,
|
|
527
|
+
userId: createdByUserId || undefined,
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (onUpdate.updateBy.data.description) {
|
|
532
|
+
// add alert feed.
|
|
533
|
+
const createdByUserId: ObjectID | undefined | null =
|
|
534
|
+
onUpdate.updateBy.props.userId;
|
|
535
|
+
|
|
536
|
+
await AlertFeedService.createAlertFeed({
|
|
537
|
+
alertId: alertId,
|
|
538
|
+
projectId: onUpdate.updateBy.props.tenantId as ObjectID,
|
|
539
|
+
alertFeedEventType: AlertFeedEventType.AlertUpdated,
|
|
540
|
+
displayColor: Gray500,
|
|
541
|
+
feedInfoInMarkdown: `**Alert description was updated.** Here's the new description.
|
|
542
|
+
|
|
543
|
+
${onUpdate.updateBy.data.description || "No description provided."}
|
|
544
|
+
`,
|
|
545
|
+
userId: createdByUserId || undefined,
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (onUpdate.updateBy.data.remediationNotes) {
|
|
550
|
+
// add alert feed.
|
|
551
|
+
const createdByUserId: ObjectID | undefined | null =
|
|
552
|
+
onUpdate.updateBy.props.userId;
|
|
553
|
+
|
|
554
|
+
await AlertFeedService.createAlertFeed({
|
|
555
|
+
alertId: alertId,
|
|
556
|
+
projectId: onUpdate.updateBy.props.tenantId as ObjectID,
|
|
557
|
+
alertFeedEventType: AlertFeedEventType.AlertUpdated,
|
|
558
|
+
displayColor: Gray500,
|
|
559
|
+
feedInfoInMarkdown: `**Remediation notes were updated.** Here are the new notes.
|
|
560
|
+
|
|
561
|
+
${onUpdate.updateBy.data.remediationNotes || "No remediation notes provided."}
|
|
562
|
+
`,
|
|
563
|
+
userId: createdByUserId || undefined,
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
448
569
|
return onUpdate;
|
|
449
570
|
}
|
|
450
571
|
|
|
@@ -19,6 +19,8 @@ import { JSONObject } from "../../Types/JSON";
|
|
|
19
19
|
import AlertInternalNote from "../../Models/DatabaseModels/AlertInternalNote";
|
|
20
20
|
import AlertInternalNoteService from "./AlertInternalNoteService";
|
|
21
21
|
import logger from "../Utils/Logger";
|
|
22
|
+
import AlertFeedService from "./AlertFeedService";
|
|
23
|
+
import { AlertFeedEventType } from "../../Models/DatabaseModels/AlertFeed";
|
|
22
24
|
|
|
23
25
|
export class Service extends DatabaseService<AlertStateTimeline> {
|
|
24
26
|
public constructor() {
|
|
@@ -130,10 +132,15 @@ export class Service extends DatabaseService<AlertStateTimeline> {
|
|
|
130
132
|
});
|
|
131
133
|
}
|
|
132
134
|
|
|
135
|
+
const privateNote: string | undefined = (
|
|
136
|
+
createBy.miscDataProps as JSONObject | undefined
|
|
137
|
+
)?.["privateNote"] as string | undefined;
|
|
138
|
+
|
|
133
139
|
return {
|
|
134
140
|
createBy,
|
|
135
141
|
carryForward: {
|
|
136
142
|
lastAlertStateTimelineId: lastAlertStateTimeline?.id || null,
|
|
143
|
+
privateNote: privateNote,
|
|
137
144
|
},
|
|
138
145
|
};
|
|
139
146
|
}
|
|
@@ -164,6 +171,36 @@ export class Service extends DatabaseService<AlertStateTimeline> {
|
|
|
164
171
|
});
|
|
165
172
|
}
|
|
166
173
|
|
|
174
|
+
const alertState: AlertState | null = await AlertStateService.findOneBy({
|
|
175
|
+
query: {
|
|
176
|
+
_id: createdItem.alertStateId.toString()!,
|
|
177
|
+
},
|
|
178
|
+
props: {
|
|
179
|
+
isRoot: true,
|
|
180
|
+
},
|
|
181
|
+
select: {
|
|
182
|
+
_id: true,
|
|
183
|
+
isResolvedState: true,
|
|
184
|
+
isAcknowledgedState: true,
|
|
185
|
+
isCreatedState: true,
|
|
186
|
+
color: true,
|
|
187
|
+
name: true,
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const stateName: string = alertState?.name || "";
|
|
192
|
+
|
|
193
|
+
await AlertFeedService.createAlertFeed({
|
|
194
|
+
alertId: createdItem.alertId!,
|
|
195
|
+
projectId: createdItem.projectId!,
|
|
196
|
+
alertFeedEventType: AlertFeedEventType.AlertStateChanged,
|
|
197
|
+
displayColor: alertState?.color,
|
|
198
|
+
feedInfoInMarkdown: "**Alert State** changed to **" + stateName + "**",
|
|
199
|
+
moreInformationInMarkdown: `**Cause:**
|
|
200
|
+
${createdItem.rootCause}`,
|
|
201
|
+
userId: createdItem.createdByUserId || onCreate.createBy.props.userId,
|
|
202
|
+
});
|
|
203
|
+
|
|
167
204
|
await AlertService.updateOneBy({
|
|
168
205
|
query: {
|
|
169
206
|
_id: createdItem.alertId?.toString(),
|
|
@@ -174,6 +211,21 @@ export class Service extends DatabaseService<AlertStateTimeline> {
|
|
|
174
211
|
props: onCreate.createBy.props,
|
|
175
212
|
});
|
|
176
213
|
|
|
214
|
+
if (onCreate.carryForward.privateNote) {
|
|
215
|
+
const privateNote: string = onCreate.carryForward.privateNote;
|
|
216
|
+
|
|
217
|
+
const alertInternalNote: AlertInternalNote = new AlertInternalNote();
|
|
218
|
+
alertInternalNote.alertId = createdItem.alertId;
|
|
219
|
+
alertInternalNote.note = privateNote;
|
|
220
|
+
alertInternalNote.createdAt = createdItem.startsAt!;
|
|
221
|
+
alertInternalNote.projectId = createdItem.projectId!;
|
|
222
|
+
|
|
223
|
+
await AlertInternalNoteService.create({
|
|
224
|
+
data: alertInternalNote,
|
|
225
|
+
props: onCreate.createBy.props,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
177
229
|
AlertService.refreshAlertMetrics({
|
|
178
230
|
alertId: createdItem.alertId,
|
|
179
231
|
}).catch((error: Error) => {
|
|
@@ -30,6 +30,7 @@ import OnCallDutyPolicyEscalationRuleTeam from "Common/Models/DatabaseModels/OnC
|
|
|
30
30
|
import OnCallDutyPolicyEscalationRuleUser from "Common/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleUser";
|
|
31
31
|
import OnCallDutyPolicyExecutionLogTimeline from "Common/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline";
|
|
32
32
|
import User from "Common/Models/DatabaseModels/User";
|
|
33
|
+
import logger from "../Utils/Logger";
|
|
33
34
|
|
|
34
35
|
export class Service extends DatabaseService<Model> {
|
|
35
36
|
public async startRuleExecution(
|
|
@@ -37,12 +38,13 @@ export class Service extends DatabaseService<Model> {
|
|
|
37
38
|
options: {
|
|
38
39
|
projectId: ObjectID;
|
|
39
40
|
triggeredByIncidentId?: ObjectID | undefined;
|
|
41
|
+
triggeredByAlertId?: ObjectID | undefined;
|
|
40
42
|
userNotificationEventType: UserNotificationEventType;
|
|
41
43
|
onCallPolicyExecutionLogId: ObjectID;
|
|
42
44
|
onCallPolicyId: ObjectID;
|
|
43
45
|
},
|
|
44
46
|
): Promise<void> {
|
|
45
|
-
|
|
47
|
+
logger.debug(`Starting rule execution for ruleId: ${ruleId.toString()}`);
|
|
46
48
|
|
|
47
49
|
const rule: Model | null = await this.findOneById({
|
|
48
50
|
id: ruleId,
|
|
@@ -62,6 +64,8 @@ export class Service extends DatabaseService<Model> {
|
|
|
62
64
|
);
|
|
63
65
|
}
|
|
64
66
|
|
|
67
|
+
logger.debug(`Found rule: ${JSON.stringify(rule)}`);
|
|
68
|
+
|
|
65
69
|
await OnCallDutyPolicyExecutionLogService.updateOneById({
|
|
66
70
|
id: options.onCallPolicyExecutionLogId,
|
|
67
71
|
data: {
|
|
@@ -75,6 +79,8 @@ export class Service extends DatabaseService<Model> {
|
|
|
75
79
|
},
|
|
76
80
|
});
|
|
77
81
|
|
|
82
|
+
logger.debug(`Updated execution log for ruleId: ${ruleId.toString()}`);
|
|
83
|
+
|
|
78
84
|
type GetNewLogFunction = () => OnCallDutyPolicyExecutionLogTimeline;
|
|
79
85
|
|
|
80
86
|
const getNewLog: GetNewLogFunction =
|
|
@@ -92,6 +98,10 @@ export class Service extends DatabaseService<Model> {
|
|
|
92
98
|
log.triggeredByIncidentId = options.triggeredByIncidentId;
|
|
93
99
|
}
|
|
94
100
|
|
|
101
|
+
if (options.triggeredByAlertId) {
|
|
102
|
+
log.triggeredByAlertId = options.triggeredByAlertId;
|
|
103
|
+
}
|
|
104
|
+
|
|
95
105
|
return log;
|
|
96
106
|
};
|
|
97
107
|
|
|
@@ -105,6 +115,16 @@ export class Service extends DatabaseService<Model> {
|
|
|
105
115
|
);
|
|
106
116
|
}
|
|
107
117
|
|
|
118
|
+
if (
|
|
119
|
+
UserNotificationEventType.AlertCreated ===
|
|
120
|
+
options.userNotificationEventType &&
|
|
121
|
+
!options.triggeredByAlertId
|
|
122
|
+
) {
|
|
123
|
+
throw new BadDataException(
|
|
124
|
+
"triggeredByAlertId is required when userNotificationEventType is IncidentCreated",
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
108
128
|
const usersInRule: Array<OnCallDutyPolicyEscalationRuleUser> =
|
|
109
129
|
await OnCallDutyPolicyEscalationRuleUserService.findBy({
|
|
110
130
|
query: {
|
|
@@ -120,6 +140,8 @@ export class Service extends DatabaseService<Model> {
|
|
|
120
140
|
},
|
|
121
141
|
});
|
|
122
142
|
|
|
143
|
+
logger.debug(`Found users in rule: ${JSON.stringify(usersInRule)}`);
|
|
144
|
+
|
|
123
145
|
const teamsInRule: Array<OnCallDutyPolicyEscalationRuleTeam> =
|
|
124
146
|
await OnCallDutyPolicyEscalationRuleTeamService.findBy({
|
|
125
147
|
query: {
|
|
@@ -135,6 +157,8 @@ export class Service extends DatabaseService<Model> {
|
|
|
135
157
|
},
|
|
136
158
|
});
|
|
137
159
|
|
|
160
|
+
logger.debug(`Found teams in rule: ${JSON.stringify(teamsInRule)}`);
|
|
161
|
+
|
|
138
162
|
const schedulesInRule: Array<OnCallDutyPolicyEscalationRuleSchedule> =
|
|
139
163
|
await OnCallDutyPolicyEscalationRuleScheduleService.findBy({
|
|
140
164
|
query: {
|
|
@@ -150,7 +174,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
150
174
|
},
|
|
151
175
|
});
|
|
152
176
|
|
|
153
|
-
|
|
177
|
+
logger.debug(`Found schedules in rule: ${JSON.stringify(schedulesInRule)}`);
|
|
154
178
|
|
|
155
179
|
type StartUserNotificationRuleExecutionFunction = (
|
|
156
180
|
userId: ObjectID,
|
|
@@ -164,7 +188,9 @@ export class Service extends DatabaseService<Model> {
|
|
|
164
188
|
teamId: ObjectID | null,
|
|
165
189
|
scheduleId: ObjectID | null,
|
|
166
190
|
): Promise<void> => {
|
|
167
|
-
|
|
191
|
+
logger.debug(
|
|
192
|
+
`Starting notification rule execution for userId: ${userId.toString()}`,
|
|
193
|
+
);
|
|
168
194
|
let log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
|
169
195
|
log.statusMessage = "Sending notification to user.";
|
|
170
196
|
log.status = OnCallDutyExecutionLogTimelineStatus.Executing;
|
|
@@ -189,6 +215,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
189
215
|
{
|
|
190
216
|
userNotificationEventType: options.userNotificationEventType!,
|
|
191
217
|
triggeredByIncidentId: options.triggeredByIncidentId || undefined,
|
|
218
|
+
triggeredByAlertId: options.triggeredByAlertId || undefined,
|
|
192
219
|
onCallPolicyExecutionLogId: options.onCallPolicyExecutionLogId,
|
|
193
220
|
onCallPolicyId: options.onCallPolicyId,
|
|
194
221
|
onCallPolicyEscalationRuleId: ruleId,
|
|
@@ -220,7 +247,6 @@ export class Service extends DatabaseService<Model> {
|
|
|
220
247
|
null,
|
|
221
248
|
);
|
|
222
249
|
} else {
|
|
223
|
-
// no users in this rule. Skipping.
|
|
224
250
|
const log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
|
225
251
|
log.statusMessage =
|
|
226
252
|
"Skipped because notification sent to this user already.";
|
|
@@ -247,7 +273,6 @@ export class Service extends DatabaseService<Model> {
|
|
|
247
273
|
uniqueUserIds.push(userRule.userId!);
|
|
248
274
|
await startUserNotificationRuleExecution(userRule.userId!, null, null);
|
|
249
275
|
} else {
|
|
250
|
-
// no users in this rule. Skipping.
|
|
251
276
|
const log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
|
252
277
|
log.statusMessage =
|
|
253
278
|
"Skipped because notification sent to this user already.";
|
|
@@ -264,23 +289,16 @@ export class Service extends DatabaseService<Model> {
|
|
|
264
289
|
}
|
|
265
290
|
|
|
266
291
|
for (const scheduleRule of schedulesInRule) {
|
|
267
|
-
// get layers and users in this schedule and find a user to notify.
|
|
268
|
-
|
|
269
292
|
const userIdInSchedule: ObjectID | null =
|
|
270
293
|
await OnCallDutyPolicyScheduleService.getCurrentUserIdInSchedule(
|
|
271
294
|
scheduleRule.onCallDutyPolicyScheduleId!,
|
|
272
295
|
);
|
|
273
296
|
|
|
274
297
|
if (!userIdInSchedule) {
|
|
275
|
-
// no user active in this schedule. Skipping.
|
|
276
|
-
|
|
277
298
|
const log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
|
278
|
-
|
|
279
299
|
log.statusMessage =
|
|
280
300
|
"Skipped because no active users are found in this schedule.";
|
|
281
|
-
|
|
282
301
|
log.status = OnCallDutyExecutionLogTimelineStatus.Skipped;
|
|
283
|
-
|
|
284
302
|
log.onCallDutyScheduleId = scheduleRule.onCallDutyPolicyScheduleId!;
|
|
285
303
|
|
|
286
304
|
await OnCallDutyPolicyExecutionLogTimelineService.create({
|
|
@@ -305,7 +323,6 @@ export class Service extends DatabaseService<Model> {
|
|
|
305
323
|
scheduleRule.onCallDutyPolicyScheduleId!,
|
|
306
324
|
);
|
|
307
325
|
} else {
|
|
308
|
-
// no users in this rule. Skipping.
|
|
309
326
|
const log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
|
310
327
|
log.statusMessage =
|
|
311
328
|
"Skipped because notification sent to this user already.";
|
|
@@ -323,7 +340,6 @@ export class Service extends DatabaseService<Model> {
|
|
|
323
340
|
}
|
|
324
341
|
|
|
325
342
|
if (uniqueUserIds.length === 0) {
|
|
326
|
-
// no users in this rule. Skipping.
|
|
327
343
|
const log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
|
328
344
|
log.statusMessage = "Skipped because no users in this rule.";
|
|
329
345
|
log.status = OnCallDutyExecutionLogTimelineStatus.Skipped;
|
|
@@ -335,6 +351,8 @@ export class Service extends DatabaseService<Model> {
|
|
|
335
351
|
},
|
|
336
352
|
});
|
|
337
353
|
}
|
|
354
|
+
|
|
355
|
+
logger.debug(`Completed rule execution for ruleId: ${ruleId.toString()}`);
|
|
338
356
|
}
|
|
339
357
|
|
|
340
358
|
public constructor() {
|