@oneuptime/common 7.0.4007 → 7.0.4026
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/Server/Services/AlertStateTimelineService.ts +66 -0
- package/Server/Services/IncidentStateTimelineService.ts +66 -0
- package/Server/Services/MonitorService.ts +72 -1
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +243 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +46 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +237 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +210 -0
- package/Server/Services/OnCallDutyPolicyScheduleService.ts +392 -14
- package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +76 -0
- package/Server/Services/UserNotificationSettingService.ts +114 -237
- package/Server/Services/UserService.ts +21 -0
- package/Server/Services/WorkspaceNotificationRuleService.ts +128 -35
- package/Server/Utils/Workspace/Slack/Actions/Alert.ts +2 -2
- package/Server/Utils/Workspace/Slack/Actions/Incident.ts +3 -3
- package/Server/Utils/Workspace/Slack/Slack.ts +59 -0
- package/Server/Utils/Workspace/WorkspaceBase.ts +10 -0
- package/Types/Email/EmailTemplateType.ts +6 -0
- package/Types/NotificationSetting/NotificationSettingEventType.ts +7 -0
- package/Types/Workspace/NotificationRules/CreateChannelNotificationRule.ts +4 -0
- package/build/dist/Server/Services/AlertStateTimelineService.js +50 -0
- package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +50 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +56 -1
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +170 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +40 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +170 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +152 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +266 -10
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +52 -0
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js +35 -202
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +17 -0
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +101 -29
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js +2 -2
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js +3 -3
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +46 -0
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/WorkspaceBase.js +9 -0
- package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
- package/build/dist/Types/Email/EmailTemplateType.js +5 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js +6 -0
- package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js.map +1 -1
- package/package.json +2 -2
|
@@ -21,6 +21,8 @@ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
|
21
21
|
import logger from "../Utils/Logger";
|
|
22
22
|
import AlertFeedService from "./AlertFeedService";
|
|
23
23
|
import { AlertFeedEventType } from "../../Models/DatabaseModels/AlertFeed";
|
|
24
|
+
import WorkspaceNotificationRuleService from "./WorkspaceNotificationRuleService";
|
|
25
|
+
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
24
26
|
|
|
25
27
|
export class Service extends DatabaseService<AlertStateTimeline> {
|
|
26
28
|
public constructor() {
|
|
@@ -336,9 +338,73 @@ ${createdItem.rootCause}`,
|
|
|
336
338
|
logger.error(error);
|
|
337
339
|
});
|
|
338
340
|
|
|
341
|
+
const isLastAlertState: boolean = await this.isLastAlertState({
|
|
342
|
+
projectId: createdItem.projectId!,
|
|
343
|
+
alertStateId: createdItem.alertStateId,
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
if (isLastAlertState) {
|
|
347
|
+
WorkspaceNotificationRuleService.archiveWorkspaceChannels({
|
|
348
|
+
projectId: createdItem.projectId!,
|
|
349
|
+
notificationFor: {
|
|
350
|
+
alertId: createdItem.alertId,
|
|
351
|
+
},
|
|
352
|
+
sendMessageBeforeArchiving: {
|
|
353
|
+
_type: "WorkspacePayloadMarkdown",
|
|
354
|
+
text: `**[Alert ${alertNumber}](${(
|
|
355
|
+
await AlertService.getAlertLinkInDashboard(
|
|
356
|
+
createdItem.projectId!,
|
|
357
|
+
createdItem.alertId!,
|
|
358
|
+
)
|
|
359
|
+
).toString()})** is resolved. Archiving channel.`,
|
|
360
|
+
},
|
|
361
|
+
}).catch((error: Error) => {
|
|
362
|
+
logger.error(`Error while archiving workspace channels:`);
|
|
363
|
+
logger.error(error);
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
|
|
339
367
|
return createdItem;
|
|
340
368
|
}
|
|
341
369
|
|
|
370
|
+
private async isLastAlertState(data: {
|
|
371
|
+
projectId: ObjectID;
|
|
372
|
+
alertStateId: ObjectID;
|
|
373
|
+
}): Promise<boolean> {
|
|
374
|
+
// find all the states for this project and sort it by order. Then, check if this is the last state.
|
|
375
|
+
const alertStates: AlertState[] = await AlertStateService.findBy({
|
|
376
|
+
query: {
|
|
377
|
+
projectId: data.projectId,
|
|
378
|
+
},
|
|
379
|
+
limit: LIMIT_PER_PROJECT,
|
|
380
|
+
skip: 0,
|
|
381
|
+
sort: {
|
|
382
|
+
order: SortOrder.Ascending,
|
|
383
|
+
},
|
|
384
|
+
props: {
|
|
385
|
+
isRoot: true,
|
|
386
|
+
},
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
const alertState: AlertState | null =
|
|
390
|
+
alertStates.find((alertState: AlertState) => {
|
|
391
|
+
return alertState.id?.toString() === data.alertStateId.toString();
|
|
392
|
+
}) || null;
|
|
393
|
+
|
|
394
|
+
if (!alertState) {
|
|
395
|
+
throw new BadDataException("Alert state not found.");
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const lastAlertState: AlertState | undefined =
|
|
399
|
+
alertStates[alertStates.length - 1];
|
|
400
|
+
|
|
401
|
+
if (lastAlertState && lastAlertState.id) {
|
|
402
|
+
return lastAlertState.id.toString() === alertState.id?.toString();
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
|
|
342
408
|
@CaptureSpan()
|
|
343
409
|
protected override async onBeforeDelete(
|
|
344
410
|
deleteBy: DeleteBy<AlertStateTimeline>,
|
|
@@ -22,6 +22,8 @@ import logger from "../Utils/Logger";
|
|
|
22
22
|
import IncidentFeedService from "./IncidentFeedService";
|
|
23
23
|
import { IncidentFeedEventType } from "../../Models/DatabaseModels/IncidentFeed";
|
|
24
24
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
25
|
+
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
26
|
+
import WorkspaceNotificationRuleService from "./WorkspaceNotificationRuleService";
|
|
25
27
|
|
|
26
28
|
export class Service extends DatabaseService<IncidentStateTimeline> {
|
|
27
29
|
public constructor() {
|
|
@@ -359,9 +361,73 @@ ${createdItem.rootCause}`,
|
|
|
359
361
|
logger.error(error);
|
|
360
362
|
});
|
|
361
363
|
|
|
364
|
+
const isLastIncidentState: boolean = await this.isLastIncidentState({
|
|
365
|
+
projectId: createdItem.projectId!,
|
|
366
|
+
incidentStateId: createdItem.incidentStateId,
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
if (isLastIncidentState) {
|
|
370
|
+
WorkspaceNotificationRuleService.archiveWorkspaceChannels({
|
|
371
|
+
projectId: createdItem.projectId!,
|
|
372
|
+
notificationFor: {
|
|
373
|
+
incidentId: createdItem.incidentId,
|
|
374
|
+
},
|
|
375
|
+
sendMessageBeforeArchiving: {
|
|
376
|
+
_type: "WorkspacePayloadMarkdown",
|
|
377
|
+
text: `**[Incident ${incidentNumber}](${(
|
|
378
|
+
await IncidentService.getIncidentLinkInDashboard(
|
|
379
|
+
createdItem.projectId!,
|
|
380
|
+
createdItem.incidentId!,
|
|
381
|
+
)
|
|
382
|
+
).toString()})** is resolved. Archiving channel.`,
|
|
383
|
+
},
|
|
384
|
+
}).catch((error: Error) => {
|
|
385
|
+
logger.error(`Error while archiving workspace channels:`);
|
|
386
|
+
logger.error(error);
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
|
|
362
390
|
return createdItem;
|
|
363
391
|
}
|
|
364
392
|
|
|
393
|
+
private async isLastIncidentState(data: {
|
|
394
|
+
projectId: ObjectID;
|
|
395
|
+
incidentStateId: ObjectID;
|
|
396
|
+
}): Promise<boolean> {
|
|
397
|
+
// find all the states for this project and sort it by order. Then, check if this is the last state.
|
|
398
|
+
const incidentStates: IncidentState[] = await IncidentStateService.findBy({
|
|
399
|
+
query: {
|
|
400
|
+
projectId: data.projectId,
|
|
401
|
+
},
|
|
402
|
+
limit: LIMIT_PER_PROJECT,
|
|
403
|
+
skip: 0,
|
|
404
|
+
sort: {
|
|
405
|
+
order: SortOrder.Ascending,
|
|
406
|
+
},
|
|
407
|
+
props: {
|
|
408
|
+
isRoot: true,
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
const incidentState: IncidentState | null =
|
|
413
|
+
incidentStates.find((incidentState: IncidentState) => {
|
|
414
|
+
return incidentState.id?.toString() === data.incidentStateId.toString();
|
|
415
|
+
}) || null;
|
|
416
|
+
|
|
417
|
+
if (!incidentState) {
|
|
418
|
+
throw new BadDataException("Incident state not found.");
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const lastIncidentState: IncidentState | undefined =
|
|
422
|
+
incidentStates[incidentStates.length - 1];
|
|
423
|
+
|
|
424
|
+
if (lastIncidentState && lastIncidentState.id) {
|
|
425
|
+
return lastIncidentState.id.toString() === incidentState.id?.toString();
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
|
|
365
431
|
@CaptureSpan()
|
|
366
432
|
protected override async onBeforeDelete(
|
|
367
433
|
deleteBy: DeleteBy<IncidentStateTimeline>,
|
|
@@ -56,12 +56,17 @@ import Label from "../../Models/DatabaseModels/Label";
|
|
|
56
56
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
57
57
|
import WorkspaceType from "../../Types/Workspace/WorkspaceType";
|
|
58
58
|
import NotificationRuleWorkspaceChannel from "../../Types/Workspace/NotificationRules/NotificationRuleWorkspaceChannel";
|
|
59
|
-
import {
|
|
59
|
+
import WorkspaceNotificationRuleService, {
|
|
60
|
+
MessageBlocksByWorkspaceType,
|
|
61
|
+
} from "./WorkspaceNotificationRuleService";
|
|
60
62
|
import MonitorWorkspaceMessages from "../Utils/Workspace/WorkspaceMessages/Monitor";
|
|
61
63
|
import MonitorFeedService from "./MonitorFeedService";
|
|
62
64
|
import { MonitorFeedEventType } from "../../Models/DatabaseModels/MonitorFeed";
|
|
63
65
|
import { Gray500, Green500 } from "../../Types/BrandColors";
|
|
64
66
|
import LabelService from "./LabelService";
|
|
67
|
+
import QueryOperator from "../../Types/BaseDatabase/QueryOperator";
|
|
68
|
+
import { FindWhere } from "../../Types/BaseDatabase/Query";
|
|
69
|
+
import logger from "../Utils/Logger";
|
|
65
70
|
|
|
66
71
|
export class Service extends DatabaseService<Model> {
|
|
67
72
|
public constructor() {
|
|
@@ -85,6 +90,49 @@ export class Service extends DatabaseService<Model> {
|
|
|
85
90
|
isRoot: true,
|
|
86
91
|
},
|
|
87
92
|
});
|
|
93
|
+
|
|
94
|
+
let projectId: FindWhere<ObjectID> | QueryOperator<ObjectID> | undefined =
|
|
95
|
+
deleteBy.query.projectId || deleteBy.props.tenantId;
|
|
96
|
+
|
|
97
|
+
if (!projectId) {
|
|
98
|
+
// fetch this monitor from the database to get the projectId.
|
|
99
|
+
const monitor: Model | null = await this.findOneById({
|
|
100
|
+
id: new ObjectID(deleteBy.query._id as string) as ObjectID,
|
|
101
|
+
select: {
|
|
102
|
+
projectId: true,
|
|
103
|
+
},
|
|
104
|
+
props: {
|
|
105
|
+
isRoot: true,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
if (!monitor) {
|
|
110
|
+
throw new BadDataException("Monitor not found.");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (!monitor.id) {
|
|
114
|
+
throw new BadDataException("Monitor id not found.");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
projectId = monitor.projectId!;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
await WorkspaceNotificationRuleService.archiveWorkspaceChannels({
|
|
122
|
+
projectId: projectId as ObjectID,
|
|
123
|
+
notificationFor: {
|
|
124
|
+
monitorId: new ObjectID(deleteBy.query._id as string) as ObjectID,
|
|
125
|
+
},
|
|
126
|
+
sendMessageBeforeArchiving: {
|
|
127
|
+
_type: "WorkspacePayloadMarkdown",
|
|
128
|
+
text: `🗑️ This monitor is deleted. The channel is being archived.`,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
} catch (error) {
|
|
132
|
+
logger.error(
|
|
133
|
+
`Error while archiving workspace channels for monitor ${deleteBy.query._id}: ${error}`,
|
|
134
|
+
);
|
|
135
|
+
}
|
|
88
136
|
}
|
|
89
137
|
|
|
90
138
|
return { deleteBy, carryForward: null };
|
|
@@ -434,6 +482,29 @@ ${createdItem.description || "No description provided."}
|
|
|
434
482
|
feedInfoInMarkdown += `\n\n`;
|
|
435
483
|
}
|
|
436
484
|
|
|
485
|
+
// send message to workspaces - slack, teams, etc.
|
|
486
|
+
const workspaceResult: {
|
|
487
|
+
channelsCreated: Array<NotificationRuleWorkspaceChannel>;
|
|
488
|
+
} | null =
|
|
489
|
+
await MonitorWorkspaceMessages.createChannelsAndInviteUsersToChannels({
|
|
490
|
+
projectId: createdItem.projectId,
|
|
491
|
+
monitorId: createdItem.id!,
|
|
492
|
+
monitorName: createdItem.name!,
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
if (workspaceResult && workspaceResult.channelsCreated?.length > 0) {
|
|
496
|
+
// update incident with these channels.
|
|
497
|
+
await this.updateOneById({
|
|
498
|
+
id: createdItem.id!,
|
|
499
|
+
data: {
|
|
500
|
+
postUpdatesToWorkspaceChannels: workspaceResult.channelsCreated || [],
|
|
501
|
+
},
|
|
502
|
+
props: {
|
|
503
|
+
isRoot: true,
|
|
504
|
+
},
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
|
|
437
508
|
const monitorCreateMessageBlocks: Array<MessageBlocksByWorkspaceType> =
|
|
438
509
|
await MonitorWorkspaceMessages.getMonitorCreateMessageBlocks({
|
|
439
510
|
monitorId: createdItem.id!,
|
|
@@ -1,10 +1,253 @@
|
|
|
1
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
2
|
+
import ObjectID from "../../Types/ObjectID";
|
|
3
|
+
import { OnCreate, OnDelete } from "../Types/Database/Hooks";
|
|
1
4
|
import DatabaseService from "./DatabaseService";
|
|
2
5
|
import Model from "Common/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleSchedule";
|
|
6
|
+
import Dictionary from "../../Types/Dictionary";
|
|
7
|
+
import OnCallDutyPolicyService from "./OnCallDutyPolicyService";
|
|
8
|
+
import EmailTemplateType from "../../Types/Email/EmailTemplateType";
|
|
9
|
+
import { EmailEnvelope } from "../../Types/Email/EmailMessage";
|
|
10
|
+
import { SMSMessage } from "../../Types/SMS/SMS";
|
|
11
|
+
import UserNotificationSettingService from "./UserNotificationSettingService";
|
|
12
|
+
import NotificationSettingEventType from "../../Types/NotificationSetting/NotificationSettingEventType";
|
|
13
|
+
import { CallRequestMessage } from "../../Types/Call/CallRequest";
|
|
14
|
+
import DeleteBy from "../Types/Database/DeleteBy";
|
|
15
|
+
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
16
|
+
import OnCallDutyPolicyScheduleService from "./OnCallDutyPolicyScheduleService";
|
|
3
17
|
|
|
4
18
|
export class Service extends DatabaseService<Model> {
|
|
5
19
|
public constructor() {
|
|
6
20
|
super(Model);
|
|
7
21
|
}
|
|
22
|
+
|
|
23
|
+
protected override async onCreateSuccess(
|
|
24
|
+
_onCreate: OnCreate<Model>,
|
|
25
|
+
createdItem: Model,
|
|
26
|
+
): Promise<Model> {
|
|
27
|
+
const createdItemId: ObjectID = createdItem.id!;
|
|
28
|
+
|
|
29
|
+
if (!createdItemId) {
|
|
30
|
+
throw new BadDataException("Created item does not have an ID");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const createdModel: Model | null = await this.findOneById({
|
|
34
|
+
id: createdItemId,
|
|
35
|
+
select: {
|
|
36
|
+
projectId: true,
|
|
37
|
+
onCallDutyPolicyScheduleId: true,
|
|
38
|
+
onCallDutyPolicySchedule: {
|
|
39
|
+
name: true,
|
|
40
|
+
},
|
|
41
|
+
onCallDutyPolicyEscalationRule: {
|
|
42
|
+
name: true,
|
|
43
|
+
_id: true,
|
|
44
|
+
order: true,
|
|
45
|
+
},
|
|
46
|
+
onCallDutyPolicy: {
|
|
47
|
+
name: true,
|
|
48
|
+
_id: true,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
props: {
|
|
52
|
+
isRoot: true,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (!createdModel) {
|
|
57
|
+
throw new BadDataException("Created item does not have an ID");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!createdModel.onCallDutyPolicyScheduleId) {
|
|
61
|
+
throw new BadDataException(
|
|
62
|
+
"Created item does not have a onCallDutyPolicyScheduleId",
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// send notification to the new current user.
|
|
67
|
+
|
|
68
|
+
const userOnSchedule: ObjectID | null =
|
|
69
|
+
await OnCallDutyPolicyScheduleService.getCurrentUserIdInSchedule(
|
|
70
|
+
createdModel.onCallDutyPolicyScheduleId,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
if (!userOnSchedule) {
|
|
74
|
+
return createdItem;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const scheduleName: string =
|
|
78
|
+
createdModel.onCallDutyPolicySchedule?.name || "No name provided";
|
|
79
|
+
|
|
80
|
+
const sendEmailToUserId: ObjectID | undefined | null = userOnSchedule;
|
|
81
|
+
|
|
82
|
+
if (!sendEmailToUserId) {
|
|
83
|
+
return createdItem;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!createdModel) {
|
|
87
|
+
return createdItem;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const vars: Dictionary<string> = {
|
|
91
|
+
onCallPolicyName:
|
|
92
|
+
createdModel.onCallDutyPolicy?.name || "No name provided",
|
|
93
|
+
escalationRuleName:
|
|
94
|
+
createdModel.onCallDutyPolicyEscalationRule?.name || "No name provided",
|
|
95
|
+
escalationRuleOrder:
|
|
96
|
+
createdModel.onCallDutyPolicyEscalationRule?.order?.toString() ||
|
|
97
|
+
"No order provided",
|
|
98
|
+
reason: "You are currently on roster for schedule " + scheduleName,
|
|
99
|
+
onCallPolicyViewLink: (
|
|
100
|
+
await OnCallDutyPolicyService.getOnCallPolicyLinkInDashboard(
|
|
101
|
+
createdModel!.projectId!,
|
|
102
|
+
createdModel.onCallDutyPolicy!.id!,
|
|
103
|
+
)
|
|
104
|
+
).toString(),
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Notify the current user about being added to the schedule.
|
|
108
|
+
const emailMessage: EmailEnvelope = {
|
|
109
|
+
templateType: EmailTemplateType.UserAddedToOnCallPolicy,
|
|
110
|
+
vars: vars,
|
|
111
|
+
subject: `You have been added to the on-call duty policy ${createdModel.onCallDutyPolicy?.name} for schedule ${scheduleName}`,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const sms: SMSMessage = {
|
|
115
|
+
message: `This is a message from OneUptime. You have been added to the on-call duty policy ${createdModel.onCallDutyPolicy?.name} for schedule ${scheduleName} and escalation rule ${createdModel.onCallDutyPolicyEscalationRule?.name} with order ${createdModel.onCallDutyPolicyEscalationRule?.order}. To unsubscribe from this notification, go to User Settings in the OneUptime Dashboard.`,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const callMessage: CallRequestMessage = {
|
|
119
|
+
data: [
|
|
120
|
+
{
|
|
121
|
+
sayMessage: `This is a message from OneUptime. You have been added to the on-call duty policy ${createdModel.onCallDutyPolicy?.name} for schedule ${scheduleName} and escalation rule ${createdModel.onCallDutyPolicyEscalationRule?.name} with order ${createdModel.onCallDutyPolicyEscalationRule?.order}. To unsubscribe from this notification, go to User Settings in the OneUptime Dashboard. Goodbye.`,
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
await UserNotificationSettingService.sendUserNotification({
|
|
127
|
+
userId: sendEmailToUserId,
|
|
128
|
+
projectId: createdModel!.projectId!,
|
|
129
|
+
emailEnvelope: emailMessage,
|
|
130
|
+
smsMessage: sms,
|
|
131
|
+
callRequestMessage: callMessage,
|
|
132
|
+
eventType:
|
|
133
|
+
NotificationSettingEventType.SEND_WHEN_USER_IS_ADDED_TO_ON_CALL_POLICY,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
return createdItem;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
protected override async onBeforeDelete(
|
|
140
|
+
deleteBy: DeleteBy<Model>,
|
|
141
|
+
): Promise<OnDelete<Model>> {
|
|
142
|
+
const itemsToFetchBeforeDelete: Array<Model> = await this.findBy({
|
|
143
|
+
query: deleteBy.query,
|
|
144
|
+
props: {
|
|
145
|
+
isRoot: true,
|
|
146
|
+
},
|
|
147
|
+
select: {
|
|
148
|
+
projectId: true,
|
|
149
|
+
onCallDutyPolicyScheduleId: true,
|
|
150
|
+
onCallDutyPolicySchedule: {
|
|
151
|
+
name: true,
|
|
152
|
+
_id: true,
|
|
153
|
+
},
|
|
154
|
+
onCallDutyPolicyEscalationRule: {
|
|
155
|
+
name: true,
|
|
156
|
+
_id: true,
|
|
157
|
+
order: true,
|
|
158
|
+
},
|
|
159
|
+
onCallDutyPolicy: {
|
|
160
|
+
name: true,
|
|
161
|
+
_id: true,
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
limit: LIMIT_PER_PROJECT,
|
|
165
|
+
skip: 0,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
deleteBy,
|
|
170
|
+
carryForward: {
|
|
171
|
+
deletedItems: itemsToFetchBeforeDelete,
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
protected override async onDeleteSuccess(
|
|
177
|
+
onDelete: OnDelete<Model>,
|
|
178
|
+
_itemIdsBeforeDelete: Array<ObjectID>,
|
|
179
|
+
): Promise<OnDelete<Model>> {
|
|
180
|
+
const deletedItems: Array<Model> = onDelete.carryForward.deletedItems;
|
|
181
|
+
|
|
182
|
+
for (const deletedItem of deletedItems) {
|
|
183
|
+
const userOnSchedule: ObjectID | null =
|
|
184
|
+
await OnCallDutyPolicyScheduleService.getCurrentUserIdInSchedule(
|
|
185
|
+
deletedItem.onCallDutyPolicyScheduleId!,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
if (!userOnSchedule) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const sendEmailToUserId: ObjectID | undefined | null = userOnSchedule;
|
|
193
|
+
|
|
194
|
+
if (!sendEmailToUserId) {
|
|
195
|
+
return onDelete;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const scheduleName: string =
|
|
199
|
+
deletedItem.onCallDutyPolicySchedule?.name || "No name provided";
|
|
200
|
+
|
|
201
|
+
const vars: Dictionary<string> = {
|
|
202
|
+
onCallPolicyName:
|
|
203
|
+
deletedItem.onCallDutyPolicy?.name || "No name provided",
|
|
204
|
+
escalationRuleName:
|
|
205
|
+
deletedItem.onCallDutyPolicyEscalationRule?.name ||
|
|
206
|
+
"No name provided",
|
|
207
|
+
escalationRuleOrder:
|
|
208
|
+
deletedItem.onCallDutyPolicyEscalationRule?.order?.toString() ||
|
|
209
|
+
"No order provided",
|
|
210
|
+
reason: `You have been removed from the on-call duty policy escalation rule for schedule ${scheduleName}.`,
|
|
211
|
+
onCallPolicyViewLink: (
|
|
212
|
+
await OnCallDutyPolicyService.getOnCallPolicyLinkInDashboard(
|
|
213
|
+
deletedItem!.projectId!,
|
|
214
|
+
deletedItem.onCallDutyPolicy!.id!,
|
|
215
|
+
)
|
|
216
|
+
).toString(),
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// Notify the current user about being removed from the schedule.
|
|
220
|
+
const emailMessage: EmailEnvelope = {
|
|
221
|
+
templateType: EmailTemplateType.UserRemovedFromOnCallPolicy,
|
|
222
|
+
vars: vars,
|
|
223
|
+
subject: `You have been removed from the on-call duty policy ${deletedItem.onCallDutyPolicy?.name} for schedule ${scheduleName}`,
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const sms: SMSMessage = {
|
|
227
|
+
message: `This is a message from OneUptime. You have been removed from the on-call duty policy ${deletedItem.onCallDutyPolicy?.name} for schedule ${scheduleName} and escalation rule ${deletedItem.onCallDutyPolicyEscalationRule?.name} with order ${deletedItem.onCallDutyPolicyEscalationRule?.order}. To unsubscribe from this notification go to User Settings in OneUptime Dashboard.`,
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
const callMessage: CallRequestMessage = {
|
|
231
|
+
data: [
|
|
232
|
+
{
|
|
233
|
+
sayMessage: `This is a message from OneUptime. You have been removed from the on-call duty policy ${deletedItem.onCallDutyPolicy?.name} for schedule ${scheduleName} and escalation rule ${deletedItem.onCallDutyPolicyEscalationRule?.name} with order ${deletedItem.onCallDutyPolicyEscalationRule?.order}. To unsubscribe from this notification go to User Settings in OneUptime Dashboard. Good Bye`,
|
|
234
|
+
},
|
|
235
|
+
],
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
await UserNotificationSettingService.sendUserNotification({
|
|
239
|
+
userId: sendEmailToUserId,
|
|
240
|
+
projectId: deletedItem!.projectId!,
|
|
241
|
+
emailEnvelope: emailMessage,
|
|
242
|
+
smsMessage: sms,
|
|
243
|
+
callRequestMessage: callMessage,
|
|
244
|
+
eventType:
|
|
245
|
+
NotificationSettingEventType.SEND_WHEN_USER_IS_REMOVED_FROM_ON_CALL_POLICY,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return onDelete;
|
|
250
|
+
}
|
|
8
251
|
}
|
|
9
252
|
|
|
10
253
|
export default new Service();
|
|
@@ -671,6 +671,52 @@ export class Service extends DatabaseService<Model> {
|
|
|
671
671
|
select: {
|
|
672
672
|
order: true,
|
|
673
673
|
onCallDutyPolicyId: true,
|
|
674
|
+
projectId: true,
|
|
675
|
+
},
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
if (!resource) {
|
|
679
|
+
throw new BadDataException(
|
|
680
|
+
"OnCallDutyPolicyEscalationRule with this id not found",
|
|
681
|
+
);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// delete users in escalation rule, teams in escalation rule and schedules in escalation rule.
|
|
685
|
+
await OnCallDutyPolicyEscalationRuleScheduleService.deleteBy({
|
|
686
|
+
query: {
|
|
687
|
+
onCallDutyPolicyEscalationRuleId: resource.id!,
|
|
688
|
+
projectId: resource.projectId!,
|
|
689
|
+
},
|
|
690
|
+
limit: LIMIT_PER_PROJECT,
|
|
691
|
+
skip: 0,
|
|
692
|
+
props: {
|
|
693
|
+
isRoot: true,
|
|
694
|
+
},
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
// delete users in escalation rule.
|
|
698
|
+
await OnCallDutyPolicyEscalationRuleUserService.deleteBy({
|
|
699
|
+
query: {
|
|
700
|
+
onCallDutyPolicyEscalationRuleId: resource.id!,
|
|
701
|
+
projectId: resource.projectId!,
|
|
702
|
+
},
|
|
703
|
+
limit: LIMIT_PER_PROJECT,
|
|
704
|
+
skip: 0,
|
|
705
|
+
props: {
|
|
706
|
+
isRoot: true,
|
|
707
|
+
},
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
// delete teams in escalation rule.
|
|
711
|
+
await OnCallDutyPolicyEscalationRuleTeamService.deleteBy({
|
|
712
|
+
query: {
|
|
713
|
+
onCallDutyPolicyEscalationRuleId: resource.id!,
|
|
714
|
+
projectId: resource.projectId!,
|
|
715
|
+
},
|
|
716
|
+
limit: LIMIT_PER_PROJECT,
|
|
717
|
+
skip: 0,
|
|
718
|
+
props: {
|
|
719
|
+
isRoot: true,
|
|
674
720
|
},
|
|
675
721
|
});
|
|
676
722
|
}
|