@oneuptime/common 7.0.4039 → 7.0.4064
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/Index.ts +9 -1
- package/Models/DatabaseModels/OnCallDutyPolicy.ts +20 -0
- package/Models/DatabaseModels/OnCallDutyPolicyFeed.ts +527 -0
- package/Models/DatabaseModels/OnCallDutyPolicyOwnerTeam.ts +426 -0
- package/Models/DatabaseModels/OnCallDutyPolicyOwnerUser.ts +425 -0
- package/Server/API/SlackAPI.ts +14 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1744804990712-MigrationName.ts +17 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1744809770336-MigrationName.ts +173 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +71 -2
- package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +14 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +69 -2
- package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +77 -2
- package/Server/Services/OnCallDutyPolicyExecutionLogService.ts +1 -1
- package/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.ts +1 -1
- package/Server/Services/OnCallDutyPolicyFeedService.ts +156 -0
- package/Server/Services/OnCallDutyPolicyOwnerTeamService.ts +181 -0
- package/Server/Services/OnCallDutyPolicyOwnerUserService.ts +174 -0
- package/Server/Services/OnCallDutyPolicyScheduleService.ts +101 -9
- package/Server/Services/OnCallDutyPolicyService.ts +219 -1
- package/Server/Services/OnCallDutyPolicyUserOverrideService.ts +184 -1
- package/Server/Services/WorkspaceNotificationRuleService.ts +93 -0
- package/Server/Utils/StartServer.ts +5 -2
- package/Server/Utils/Workspace/Slack/Actions/ActionTypes.ts +3 -0
- package/Server/Utils/Workspace/Slack/Actions/OnCallDutyPolicy.ts +48 -0
- package/Server/Utils/Workspace/Slack/Messages/OnCallDutyPolicy.ts +62 -0
- package/Server/Utils/Workspace/WorkspaceMessages/OnCallDutyPolicy.ts +75 -0
- package/Types/Permission.ts +112 -7
- package/Types/Workspace/NotificationRules/EventType.ts +1 -0
- package/Types/Workspace/NotificationRules/NotificationRuleCondition.ts +5 -0
- package/UI/webpack-middleware.js +65 -0
- package/build/dist/Models/DatabaseModels/Index.js +8 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicy.js +20 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicy.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyFeed.js +549 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyOwnerTeam.js +442 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyOwnerUser.js +441 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyOwnerUser.js.map +1 -0
- package/build/dist/Server/API/SlackAPI.js +11 -0
- package/build/dist/Server/API/SlackAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1744804990712-MigrationName.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1744804990712-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1744809770336-MigrationName.js +66 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1744809770336-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +52 -3
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +12 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +52 -3
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +63 -3
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js +119 -0
- package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js.map +1 -0
- package/build/dist/Server/Services/OnCallDutyPolicyOwnerTeamService.js +161 -0
- package/build/dist/Server/Services/OnCallDutyPolicyOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/OnCallDutyPolicyOwnerUserService.js +154 -0
- package/build/dist/Server/Services/OnCallDutyPolicyOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +87 -20
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyService.js +174 -2
- package/build/dist/Server/Services/OnCallDutyPolicyService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js +122 -0
- package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +71 -0
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +5 -2
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js +2 -0
- package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/OnCallDutyPolicy.js +50 -0
- package/build/dist/Server/Utils/Workspace/Slack/Actions/OnCallDutyPolicy.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/Slack/Messages/OnCallDutyPolicy.js +52 -0
- package/build/dist/Server/Utils/Workspace/Slack/Messages/OnCallDutyPolicy.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/WorkspaceMessages/OnCallDutyPolicy.js +69 -0
- package/build/dist/Server/Utils/Workspace/WorkspaceMessages/OnCallDutyPolicy.js.map +1 -0
- package/build/dist/Types/Permission.js +95 -7
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Workspace/NotificationRules/EventType.js +1 -0
- package/build/dist/Types/Workspace/NotificationRules/EventType.js.map +1 -1
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js +4 -0
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js.map +1 -1
- package/package.json +2 -2
|
@@ -21,14 +21,211 @@ import OnCallDutyPolicyEscalationRuleTeamService from "./OnCallDutyPolicyEscalat
|
|
|
21
21
|
import QueryHelper from "../Types/Database/QueryHelper";
|
|
22
22
|
import OnCallDutyPolicyEscalationRuleSchedule from "../../Models/DatabaseModels/OnCallDutyPolicyEscalationRuleSchedule";
|
|
23
23
|
import OnCallDutyPolicyEscalationRuleScheduleService from "./OnCallDutyPolicyEscalationRuleScheduleService";
|
|
24
|
+
import WorkspaceType from "../../Types/Workspace/WorkspaceType";
|
|
25
|
+
import NotificationRuleWorkspaceChannel from "../../Types/Workspace/NotificationRules/NotificationRuleWorkspaceChannel";
|
|
26
|
+
import DeleteBy from "../Types/Database/DeleteBy";
|
|
27
|
+
import { OnCreate, OnDelete } from "../Types/Database/Hooks";
|
|
28
|
+
import { FindWhere } from "../../Types/BaseDatabase/Query";
|
|
29
|
+
import QueryOperator from "../../Types/BaseDatabase/QueryOperator";
|
|
30
|
+
import WorkspaceNotificationRuleService, {
|
|
31
|
+
MessageBlocksByWorkspaceType,
|
|
32
|
+
} from "./WorkspaceNotificationRuleService";
|
|
33
|
+
import logger from "../Utils/Logger";
|
|
34
|
+
import OnCallDutyPolicyWorkspaceMessages from "../Utils/Workspace/WorkspaceMessages/OnCallDutyPolicy";
|
|
35
|
+
import OnCallDutyPolicyFeedService from "./OnCallDutyPolicyFeedService";
|
|
36
|
+
import { OnCallDutyPolicyFeedEventType } from "../../Models/DatabaseModels/OnCallDutyPolicyFeed";
|
|
37
|
+
import { Green500 } from "../../Types/BrandColors";
|
|
24
38
|
|
|
25
39
|
export class Service extends DatabaseService<OnCallDutyPolicy> {
|
|
26
40
|
public constructor() {
|
|
27
41
|
super(OnCallDutyPolicy);
|
|
28
42
|
}
|
|
29
43
|
|
|
44
|
+
protected override async onCreateSuccess(
|
|
45
|
+
_onCreate: OnCreate<OnCallDutyPolicy>,
|
|
46
|
+
createdItem: OnCallDutyPolicy,
|
|
47
|
+
): Promise<OnCallDutyPolicy> {
|
|
48
|
+
if (!createdItem.id) {
|
|
49
|
+
throw new BadDataException("On Call Policy id not found.");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const onCallPolicy: OnCallDutyPolicy | null = await this.findOneById({
|
|
53
|
+
id: createdItem.id,
|
|
54
|
+
select: {
|
|
55
|
+
projectId: true,
|
|
56
|
+
name: true,
|
|
57
|
+
description: true,
|
|
58
|
+
labels: {
|
|
59
|
+
name: true,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
props: {
|
|
63
|
+
isRoot: true,
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (!onCallPolicy) {
|
|
68
|
+
throw new BadDataException("On Call Policy not found.");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const createdByUserId: ObjectID | undefined | null =
|
|
72
|
+
createdItem.createdByUserId || createdItem.createdByUser?.id;
|
|
73
|
+
|
|
74
|
+
let feedInfoInMarkdown: string = `#### 📞 On Call Policy Created:
|
|
75
|
+
|
|
76
|
+
**${onCallPolicy.name || "No name provided."}**:
|
|
77
|
+
|
|
78
|
+
${onCallPolicy.description || "No description provided."}
|
|
79
|
+
|
|
80
|
+
`;
|
|
81
|
+
|
|
82
|
+
if (onCallPolicy?.labels && onCallPolicy.labels.length > 0) {
|
|
83
|
+
feedInfoInMarkdown += `🏷️ **Labels**:\n`;
|
|
84
|
+
|
|
85
|
+
for (const label of onCallPolicy.labels) {
|
|
86
|
+
feedInfoInMarkdown += `- ${label.name}\n`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
feedInfoInMarkdown += `\n\n`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// send message to workspaces - slack, teams, etc.
|
|
93
|
+
const workspaceResult: {
|
|
94
|
+
channelsCreated: Array<NotificationRuleWorkspaceChannel>;
|
|
95
|
+
} | null =
|
|
96
|
+
await OnCallDutyPolicyWorkspaceMessages.createChannelsAndInviteUsersToChannels(
|
|
97
|
+
{
|
|
98
|
+
projectId: onCallPolicy.projectId!,
|
|
99
|
+
onCallDutyPolicyId: onCallPolicy.id!,
|
|
100
|
+
onCallDutyPolicyName: onCallPolicy.name!,
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
if (workspaceResult && workspaceResult.channelsCreated?.length > 0) {
|
|
105
|
+
// update incident with these channels.
|
|
106
|
+
await this.updateOneById({
|
|
107
|
+
id: createdItem.id!,
|
|
108
|
+
data: {
|
|
109
|
+
postUpdatesToWorkspaceChannels: workspaceResult.channelsCreated || [],
|
|
110
|
+
},
|
|
111
|
+
props: {
|
|
112
|
+
isRoot: true,
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const onCallDutyPolicyCreateMessageBlocks: Array<MessageBlocksByWorkspaceType> =
|
|
118
|
+
await OnCallDutyPolicyWorkspaceMessages.getOnCallDutyPolicyCreateMessageBlocks(
|
|
119
|
+
{
|
|
120
|
+
onCallDutyPolicyId: createdItem.id!,
|
|
121
|
+
projectId: createdItem.projectId!,
|
|
122
|
+
},
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
await OnCallDutyPolicyFeedService.createOnCallDutyPolicyFeedItem({
|
|
126
|
+
onCallDutyPolicyId: createdItem.id!,
|
|
127
|
+
projectId: createdItem.projectId!,
|
|
128
|
+
onCallDutyPolicyFeedEventType:
|
|
129
|
+
OnCallDutyPolicyFeedEventType.OnCallDutyPolicyCreated,
|
|
130
|
+
displayColor: Green500,
|
|
131
|
+
feedInfoInMarkdown: feedInfoInMarkdown,
|
|
132
|
+
userId: createdByUserId || undefined,
|
|
133
|
+
workspaceNotification: {
|
|
134
|
+
appendMessageBlocks: onCallDutyPolicyCreateMessageBlocks,
|
|
135
|
+
sendWorkspaceNotification: true,
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return createdItem;
|
|
140
|
+
}
|
|
141
|
+
|
|
30
142
|
@CaptureSpan()
|
|
31
|
-
|
|
143
|
+
protected override async onBeforeDelete(
|
|
144
|
+
deleteBy: DeleteBy<OnCallDutyPolicy>,
|
|
145
|
+
): Promise<OnDelete<OnCallDutyPolicy>> {
|
|
146
|
+
if (deleteBy.query._id) {
|
|
147
|
+
let projectId: FindWhere<ObjectID> | QueryOperator<ObjectID> | undefined =
|
|
148
|
+
deleteBy.query.projectId || deleteBy.props.tenantId;
|
|
149
|
+
|
|
150
|
+
if (!projectId) {
|
|
151
|
+
// fetch this onCallDutyPolicy from the database to get the projectId.
|
|
152
|
+
const onCallDutyPolicy: OnCallDutyPolicy | null =
|
|
153
|
+
await this.findOneById({
|
|
154
|
+
id: new ObjectID(deleteBy.query._id as string) as ObjectID,
|
|
155
|
+
select: {
|
|
156
|
+
projectId: true,
|
|
157
|
+
},
|
|
158
|
+
props: {
|
|
159
|
+
isRoot: true,
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
if (!onCallDutyPolicy) {
|
|
164
|
+
throw new BadDataException("OnCallDutyPolicy not found.");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (!onCallDutyPolicy.id) {
|
|
168
|
+
throw new BadDataException("OnCallDutyPolicy id not found.");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
projectId = onCallDutyPolicy.projectId!;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
await WorkspaceNotificationRuleService.archiveWorkspaceChannels({
|
|
176
|
+
projectId: projectId as ObjectID,
|
|
177
|
+
notificationFor: {
|
|
178
|
+
onCallDutyPolicyId: new ObjectID(
|
|
179
|
+
deleteBy.query._id as string,
|
|
180
|
+
) as ObjectID,
|
|
181
|
+
},
|
|
182
|
+
sendMessageBeforeArchiving: {
|
|
183
|
+
_type: "WorkspacePayloadMarkdown",
|
|
184
|
+
text: `🗑️ This on-call policy is deleted. The channel is being archived.`,
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
} catch (error) {
|
|
188
|
+
logger.error(
|
|
189
|
+
`Error while archiving workspace channels for onCallDutyPolicy ${deleteBy.query._id}: ${error}`,
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return { deleteBy, carryForward: null };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
@CaptureSpan()
|
|
198
|
+
public async getWorkspaceChannelForOnCallDutyPolicy(data: {
|
|
199
|
+
onCallDutyPolicyId: ObjectID;
|
|
200
|
+
workspaceType?: WorkspaceType | null;
|
|
201
|
+
}): Promise<Array<NotificationRuleWorkspaceChannel>> {
|
|
202
|
+
const onCallDutyPolicy: OnCallDutyPolicy | null = await this.findOneById({
|
|
203
|
+
id: data.onCallDutyPolicyId,
|
|
204
|
+
select: {
|
|
205
|
+
postUpdatesToWorkspaceChannels: true,
|
|
206
|
+
},
|
|
207
|
+
props: {
|
|
208
|
+
isRoot: true,
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
if (!onCallDutyPolicy) {
|
|
213
|
+
throw new BadDataException("OnCallDutyPolicy not found.");
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return (onCallDutyPolicy.postUpdatesToWorkspaceChannels || []).filter(
|
|
217
|
+
(channel: NotificationRuleWorkspaceChannel) => {
|
|
218
|
+
if (!data.workspaceType) {
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return channel.workspaceType === data.workspaceType;
|
|
223
|
+
},
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
@CaptureSpan()
|
|
228
|
+
public async getOnCallDutyPolicyLinkInDashboard(
|
|
32
229
|
projectId: ObjectID,
|
|
33
230
|
onCallDutyPolicyId: ObjectID,
|
|
34
231
|
): Promise<URL> {
|
|
@@ -39,6 +236,27 @@ export class Service extends DatabaseService<OnCallDutyPolicy> {
|
|
|
39
236
|
);
|
|
40
237
|
}
|
|
41
238
|
|
|
239
|
+
@CaptureSpan()
|
|
240
|
+
public async getOnCallDutyPolicyName(data: {
|
|
241
|
+
onCallDutyPolicyId: ObjectID;
|
|
242
|
+
}): Promise<string | null> {
|
|
243
|
+
const { onCallDutyPolicyId } = data;
|
|
244
|
+
|
|
245
|
+
const onCallDutyPolicy: OnCallDutyPolicy | null = await this.findOneById({
|
|
246
|
+
id: onCallDutyPolicyId,
|
|
247
|
+
select: {
|
|
248
|
+
name: true,
|
|
249
|
+
},
|
|
250
|
+
props: {
|
|
251
|
+
isRoot: true,
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
return onCallDutyPolicy && onCallDutyPolicy.name
|
|
256
|
+
? onCallDutyPolicy.name.toString()
|
|
257
|
+
: null;
|
|
258
|
+
}
|
|
259
|
+
|
|
42
260
|
@CaptureSpan()
|
|
43
261
|
public async executePolicy(
|
|
44
262
|
policyId: ObjectID,
|
|
@@ -4,10 +4,18 @@ import DatabaseConfig from "../DatabaseConfig";
|
|
|
4
4
|
import URL from "../../Types/API/URL";
|
|
5
5
|
import OnCallDutyPolicyUserOverride from "../../Models/DatabaseModels/OnCallDutyPolicyUserOverride";
|
|
6
6
|
import CreateBy from "../Types/Database/CreateBy";
|
|
7
|
-
import { OnCreate } from "../Types/Database/Hooks";
|
|
7
|
+
import { OnCreate, OnDelete } from "../Types/Database/Hooks";
|
|
8
8
|
import OneUptimeDate from "../../Types/Date";
|
|
9
9
|
import BadDataException from "../../Types/Exception/BadDataException";
|
|
10
10
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
11
|
+
import OnCallDutyPolicyFeedService from "./OnCallDutyPolicyFeedService";
|
|
12
|
+
import { OnCallDutyPolicyFeedEventType } from "../../Models/DatabaseModels/OnCallDutyPolicyFeed";
|
|
13
|
+
import { Gray500 } from "../../Types/BrandColors";
|
|
14
|
+
import UserService from "./UserService";
|
|
15
|
+
import OnCallDutyPolicyService from "./OnCallDutyPolicyService";
|
|
16
|
+
import Timezone from "../../Types/Timezone";
|
|
17
|
+
import DeleteBy from "../Types/Database/DeleteBy";
|
|
18
|
+
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
11
19
|
|
|
12
20
|
export class Service extends DatabaseService<OnCallDutyPolicyUserOverride> {
|
|
13
21
|
public constructor() {
|
|
@@ -54,6 +62,181 @@ export class Service extends DatabaseService<OnCallDutyPolicyUserOverride> {
|
|
|
54
62
|
};
|
|
55
63
|
}
|
|
56
64
|
|
|
65
|
+
protected override async onCreateSuccess(
|
|
66
|
+
_onCreate: OnCreate<OnCallDutyPolicyUserOverride>,
|
|
67
|
+
createdItem: OnCallDutyPolicyUserOverride,
|
|
68
|
+
): Promise<OnCallDutyPolicyUserOverride> {
|
|
69
|
+
// add to on call feed.
|
|
70
|
+
const onCallDutyPolicyId: ObjectID | undefined | null =
|
|
71
|
+
createdItem.onCallDutyPolicyId || createdItem.onCallDutyPolicy?.id;
|
|
72
|
+
|
|
73
|
+
const projectId: ObjectID | undefined | null =
|
|
74
|
+
createdItem.projectId || createdItem.project?.id;
|
|
75
|
+
|
|
76
|
+
const overrideUserId: ObjectID | undefined | null =
|
|
77
|
+
createdItem.overrideUserId || createdItem.overrideUser?.id;
|
|
78
|
+
|
|
79
|
+
const routeAlertsToUserId: ObjectID | undefined | null =
|
|
80
|
+
createdItem.routeAlertsToUserId || createdItem.routeAlertsToUser?.id;
|
|
81
|
+
|
|
82
|
+
if (
|
|
83
|
+
onCallDutyPolicyId &&
|
|
84
|
+
projectId &&
|
|
85
|
+
overrideUserId &&
|
|
86
|
+
routeAlertsToUserId
|
|
87
|
+
) {
|
|
88
|
+
const onCallPolicyName: string | null =
|
|
89
|
+
await OnCallDutyPolicyService.getOnCallDutyPolicyName({
|
|
90
|
+
onCallDutyPolicyId: onCallDutyPolicyId,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const overrideUserTimezone: Timezone | null =
|
|
94
|
+
await UserService.getTimezoneForUser(overrideUserId);
|
|
95
|
+
|
|
96
|
+
const routeAlertsToUserTimezone: Timezone | null =
|
|
97
|
+
await UserService.getTimezoneForUser(routeAlertsToUserId);
|
|
98
|
+
|
|
99
|
+
const timezones: Timezone[] = [];
|
|
100
|
+
if (overrideUserTimezone) {
|
|
101
|
+
timezones.push(overrideUserTimezone);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (routeAlertsToUserTimezone) {
|
|
105
|
+
timezones.push(routeAlertsToUserTimezone);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
await OnCallDutyPolicyFeedService.createOnCallDutyPolicyFeedItem({
|
|
109
|
+
onCallDutyPolicyId: onCallDutyPolicyId,
|
|
110
|
+
projectId: projectId!,
|
|
111
|
+
onCallDutyPolicyFeedEventType:
|
|
112
|
+
OnCallDutyPolicyFeedEventType.UserOverrideAdded,
|
|
113
|
+
displayColor: Gray500,
|
|
114
|
+
feedInfoInMarkdown: `🔁 Added a User Override Rule for user **${await UserService.getUserMarkdownString(
|
|
115
|
+
{
|
|
116
|
+
userId: overrideUserId,
|
|
117
|
+
projectId: projectId!,
|
|
118
|
+
},
|
|
119
|
+
)}** for the [On-Call Policy ${onCallPolicyName}](${(await OnCallDutyPolicyService.getOnCallDutyPolicyLinkInDashboard(projectId!, onCallDutyPolicyId!)).toString()}). All alerts will be routed to **${await UserService.getUserMarkdownString(
|
|
120
|
+
{
|
|
121
|
+
userId: routeAlertsToUserId,
|
|
122
|
+
projectId: projectId!,
|
|
123
|
+
},
|
|
124
|
+
)}** from **${OneUptimeDate.getDateAsFormattedStringInMultipleTimezones(
|
|
125
|
+
{
|
|
126
|
+
date: createdItem.startsAt!,
|
|
127
|
+
timezones: timezones,
|
|
128
|
+
},
|
|
129
|
+
)}** to **${OneUptimeDate.getDateAsFormattedStringInMultipleTimezones({
|
|
130
|
+
date: createdItem.endsAt!,
|
|
131
|
+
timezones: timezones,
|
|
132
|
+
})}**. `,
|
|
133
|
+
|
|
134
|
+
userId: createdItem.createdByUserId! || undefined,
|
|
135
|
+
workspaceNotification: {
|
|
136
|
+
sendWorkspaceNotification: true,
|
|
137
|
+
notifyUserId: createdItem.createdByUserId! || undefined,
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return createdItem;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
protected override async onBeforeDelete(
|
|
146
|
+
deleteBy: DeleteBy<OnCallDutyPolicyUserOverride>,
|
|
147
|
+
): Promise<OnDelete<OnCallDutyPolicyUserOverride>> {
|
|
148
|
+
const itemsToDelete: OnCallDutyPolicyUserOverride[] = await this.findBy({
|
|
149
|
+
query: deleteBy.query,
|
|
150
|
+
select: {
|
|
151
|
+
onCallDutyPolicyId: true,
|
|
152
|
+
projectId: true,
|
|
153
|
+
overrideUserId: true,
|
|
154
|
+
routeAlertsToUserId: true,
|
|
155
|
+
startsAt: true,
|
|
156
|
+
endsAt: true,
|
|
157
|
+
createdByUserId: true,
|
|
158
|
+
},
|
|
159
|
+
props: {
|
|
160
|
+
isRoot: true,
|
|
161
|
+
},
|
|
162
|
+
skip: 0,
|
|
163
|
+
limit: LIMIT_PER_PROJECT,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
for (const item of itemsToDelete) {
|
|
167
|
+
const onCallDutyPolicyId: ObjectID | undefined | null =
|
|
168
|
+
item.onCallDutyPolicyId || item.onCallDutyPolicy?.id;
|
|
169
|
+
|
|
170
|
+
const projectId: ObjectID | undefined | null =
|
|
171
|
+
item.projectId || item.project?.id;
|
|
172
|
+
|
|
173
|
+
const overrideUserId: ObjectID | undefined | null =
|
|
174
|
+
item.overrideUserId || item.overrideUser?.id;
|
|
175
|
+
|
|
176
|
+
const routeAlertsToUserId: ObjectID | undefined | null =
|
|
177
|
+
item.routeAlertsToUserId || item.routeAlertsToUser?.id;
|
|
178
|
+
|
|
179
|
+
if (
|
|
180
|
+
onCallDutyPolicyId &&
|
|
181
|
+
projectId &&
|
|
182
|
+
overrideUserId &&
|
|
183
|
+
routeAlertsToUserId
|
|
184
|
+
) {
|
|
185
|
+
const onCallPolicyName: string | null =
|
|
186
|
+
await OnCallDutyPolicyService.getOnCallDutyPolicyName({
|
|
187
|
+
onCallDutyPolicyId: onCallDutyPolicyId,
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const overrideUserTimezone: Timezone | null =
|
|
191
|
+
await UserService.getTimezoneForUser(overrideUserId);
|
|
192
|
+
|
|
193
|
+
const routeAlertsToUserTimezone: Timezone | null =
|
|
194
|
+
await UserService.getTimezoneForUser(routeAlertsToUserId);
|
|
195
|
+
|
|
196
|
+
const timezones: Timezone[] = [];
|
|
197
|
+
if (overrideUserTimezone) {
|
|
198
|
+
timezones.push(overrideUserTimezone);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (routeAlertsToUserTimezone) {
|
|
202
|
+
timezones.push(routeAlertsToUserTimezone);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const deleteByUserId: ObjectID | undefined | null =
|
|
206
|
+
deleteBy.props.userId;
|
|
207
|
+
|
|
208
|
+
await OnCallDutyPolicyFeedService.createOnCallDutyPolicyFeedItem({
|
|
209
|
+
onCallDutyPolicyId: onCallDutyPolicyId,
|
|
210
|
+
projectId: projectId!,
|
|
211
|
+
onCallDutyPolicyFeedEventType:
|
|
212
|
+
OnCallDutyPolicyFeedEventType.UserOverrideRemoved,
|
|
213
|
+
displayColor: Gray500,
|
|
214
|
+
feedInfoInMarkdown: `❌ Removed a User Override Rule for user **${await UserService.getUserMarkdownString(
|
|
215
|
+
{
|
|
216
|
+
userId: overrideUserId,
|
|
217
|
+
projectId: projectId!,
|
|
218
|
+
},
|
|
219
|
+
)}** for the [On-Call Policy ${onCallPolicyName}](${(await OnCallDutyPolicyService.getOnCallDutyPolicyLinkInDashboard(projectId!, onCallDutyPolicyId!)).toString()}). All alerts will be routed back to **${await UserService.getUserMarkdownString(
|
|
220
|
+
{
|
|
221
|
+
userId: overrideUserId,
|
|
222
|
+
projectId: projectId!,
|
|
223
|
+
},
|
|
224
|
+
)}**`,
|
|
225
|
+
userId: deleteByUserId || undefined,
|
|
226
|
+
workspaceNotification: {
|
|
227
|
+
sendWorkspaceNotification: true,
|
|
228
|
+
notifyUserId: deleteByUserId || undefined,
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
deleteBy,
|
|
236
|
+
carryForward: null,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
57
240
|
@CaptureSpan()
|
|
58
241
|
public async getOnCallDutyPolicyUserOverrideLinkInDashboard(data: {
|
|
59
242
|
projectId: ObjectID;
|
|
@@ -40,6 +40,8 @@ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
|
40
40
|
import Monitor from "../../Models/DatabaseModels/Monitor";
|
|
41
41
|
import Text from "../../Types/Text";
|
|
42
42
|
import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
43
|
+
import OnCallDutyPolicyService from "./OnCallDutyPolicyService";
|
|
44
|
+
import OnCallDutyPolicy from "../../Models/DatabaseModels/OnCallDutyPolicy";
|
|
43
45
|
|
|
44
46
|
export interface MessageBlocksByWorkspaceType {
|
|
45
47
|
workspaceType: WorkspaceType;
|
|
@@ -51,6 +53,7 @@ export interface NotificationFor {
|
|
|
51
53
|
alertId?: ObjectID | undefined;
|
|
52
54
|
scheduledMaintenanceId?: ObjectID | undefined;
|
|
53
55
|
monitorId?: ObjectID | undefined;
|
|
56
|
+
onCallDutyPolicyId?: ObjectID | undefined;
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
@@ -438,6 +441,14 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
438
441
|
});
|
|
439
442
|
}
|
|
440
443
|
|
|
444
|
+
if (data.notificationFor.onCallDutyPolicyId) {
|
|
445
|
+
monitorChannels =
|
|
446
|
+
await OnCallDutyPolicyService.getWorkspaceChannelForOnCallDutyPolicy({
|
|
447
|
+
onCallDutyPolicyId: data.notificationFor.onCallDutyPolicyId,
|
|
448
|
+
workspaceType: data.workspaceType,
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
|
|
441
452
|
// incidents
|
|
442
453
|
if (data.notificationFor.incidentId) {
|
|
443
454
|
monitorChannels = await IncidentService.getWorkspaceChannelForIncident({
|
|
@@ -482,6 +493,10 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
482
493
|
return NotificationRuleEventType.Monitor;
|
|
483
494
|
}
|
|
484
495
|
|
|
496
|
+
if (notificationFor.onCallDutyPolicyId) {
|
|
497
|
+
return NotificationRuleEventType.OnCallDutyPolicy;
|
|
498
|
+
}
|
|
499
|
+
|
|
485
500
|
if (notificationFor.scheduledMaintenanceId) {
|
|
486
501
|
return NotificationRuleEventType.ScheduledMaintenance;
|
|
487
502
|
}
|
|
@@ -1451,6 +1466,11 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
1451
1466
|
incident.monitors?.map((monitor: Incident) => {
|
|
1452
1467
|
return monitor._id?.toString() || "";
|
|
1453
1468
|
}) || [],
|
|
1469
|
+
|
|
1470
|
+
[NotificationRuleConditionCheckOn.OnCallDutyPolicyName]: undefined,
|
|
1471
|
+
[NotificationRuleConditionCheckOn.OnCallDutyPolicyDescription]:
|
|
1472
|
+
undefined,
|
|
1473
|
+
[NotificationRuleConditionCheckOn.OnCallDutyPolicyLabels]: undefined,
|
|
1454
1474
|
};
|
|
1455
1475
|
}
|
|
1456
1476
|
|
|
@@ -1523,6 +1543,11 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
1523
1543
|
[NotificationRuleConditionCheckOn.Monitors]: [
|
|
1524
1544
|
alert.monitor?.id!.toString() || "",
|
|
1525
1545
|
],
|
|
1546
|
+
|
|
1547
|
+
[NotificationRuleConditionCheckOn.OnCallDutyPolicyName]: undefined,
|
|
1548
|
+
[NotificationRuleConditionCheckOn.OnCallDutyPolicyDescription]:
|
|
1549
|
+
undefined,
|
|
1550
|
+
[NotificationRuleConditionCheckOn.OnCallDutyPolicyLabels]: undefined,
|
|
1526
1551
|
};
|
|
1527
1552
|
}
|
|
1528
1553
|
|
|
@@ -1602,6 +1627,10 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
1602
1627
|
return monitor._id?.toString() || "";
|
|
1603
1628
|
},
|
|
1604
1629
|
) || [],
|
|
1630
|
+
[NotificationRuleConditionCheckOn.OnCallDutyPolicyName]: undefined,
|
|
1631
|
+
[NotificationRuleConditionCheckOn.OnCallDutyPolicyDescription]:
|
|
1632
|
+
undefined,
|
|
1633
|
+
[NotificationRuleConditionCheckOn.OnCallDutyPolicyLabels]: undefined,
|
|
1605
1634
|
};
|
|
1606
1635
|
}
|
|
1607
1636
|
|
|
@@ -1659,6 +1688,70 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
1659
1688
|
[NotificationRuleConditionCheckOn.Monitors]: [
|
|
1660
1689
|
monitor?._id?.toString() || "",
|
|
1661
1690
|
],
|
|
1691
|
+
[NotificationRuleConditionCheckOn.OnCallDutyPolicyName]: undefined,
|
|
1692
|
+
[NotificationRuleConditionCheckOn.OnCallDutyPolicyDescription]:
|
|
1693
|
+
undefined,
|
|
1694
|
+
[NotificationRuleConditionCheckOn.OnCallDutyPolicyLabels]: undefined,
|
|
1695
|
+
};
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
if (data.notificationFor.onCallDutyPolicyId) {
|
|
1699
|
+
logger.debug("Fetching on call policy details for ID:");
|
|
1700
|
+
logger.debug(data.notificationFor.onCallDutyPolicyId);
|
|
1701
|
+
|
|
1702
|
+
const onCallDutyPolicy: OnCallDutyPolicy | null =
|
|
1703
|
+
await OnCallDutyPolicyService.findOneById({
|
|
1704
|
+
id: data.notificationFor.onCallDutyPolicyId,
|
|
1705
|
+
select: {
|
|
1706
|
+
name: true,
|
|
1707
|
+
labels: true,
|
|
1708
|
+
description: true,
|
|
1709
|
+
},
|
|
1710
|
+
props: {
|
|
1711
|
+
isRoot: true,
|
|
1712
|
+
},
|
|
1713
|
+
});
|
|
1714
|
+
|
|
1715
|
+
if (!onCallDutyPolicy) {
|
|
1716
|
+
logger.debug("On Call Duty Policy not found for ID:");
|
|
1717
|
+
logger.debug(data.notificationFor.onCallDutyPolicyId);
|
|
1718
|
+
throw new BadDataException("On Call Duty Policy ID not found");
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
const onCallDutyPolicyLabels: Array<Label> =
|
|
1722
|
+
onCallDutyPolicy?.labels || [];
|
|
1723
|
+
|
|
1724
|
+
return {
|
|
1725
|
+
[NotificationRuleConditionCheckOn.OnCallDutyPolicyName]:
|
|
1726
|
+
onCallDutyPolicy?.name || "",
|
|
1727
|
+
[NotificationRuleConditionCheckOn.OnCallDutyPolicyDescription]:
|
|
1728
|
+
onCallDutyPolicy?.description || "",
|
|
1729
|
+
[NotificationRuleConditionCheckOn.OnCallDutyPolicyLabels]:
|
|
1730
|
+
onCallDutyPolicyLabels.map((label: Label) => {
|
|
1731
|
+
return label._id?.toString() || "";
|
|
1732
|
+
}) || [],
|
|
1733
|
+
|
|
1734
|
+
[NotificationRuleConditionCheckOn.MonitorName]: undefined,
|
|
1735
|
+
[NotificationRuleConditionCheckOn.IncidentTitle]: undefined,
|
|
1736
|
+
[NotificationRuleConditionCheckOn.IncidentDescription]: undefined,
|
|
1737
|
+
[NotificationRuleConditionCheckOn.IncidentSeverity]: undefined,
|
|
1738
|
+
[NotificationRuleConditionCheckOn.IncidentState]: undefined,
|
|
1739
|
+
[NotificationRuleConditionCheckOn.MonitorType]: undefined,
|
|
1740
|
+
[NotificationRuleConditionCheckOn.MonitorStatus]: "",
|
|
1741
|
+
[NotificationRuleConditionCheckOn.AlertTitle]: undefined,
|
|
1742
|
+
[NotificationRuleConditionCheckOn.AlertDescription]: undefined,
|
|
1743
|
+
[NotificationRuleConditionCheckOn.AlertSeverity]: undefined,
|
|
1744
|
+
[NotificationRuleConditionCheckOn.AlertState]: undefined,
|
|
1745
|
+
[NotificationRuleConditionCheckOn.ScheduledMaintenanceTitle]: undefined,
|
|
1746
|
+
[NotificationRuleConditionCheckOn.ScheduledMaintenanceDescription]:
|
|
1747
|
+
undefined,
|
|
1748
|
+
[NotificationRuleConditionCheckOn.ScheduledMaintenanceState]: undefined,
|
|
1749
|
+
[NotificationRuleConditionCheckOn.IncidentLabels]: undefined,
|
|
1750
|
+
[NotificationRuleConditionCheckOn.AlertLabels]: undefined,
|
|
1751
|
+
[NotificationRuleConditionCheckOn.MonitorLabels]: undefined,
|
|
1752
|
+
[NotificationRuleConditionCheckOn.ScheduledMaintenanceLabels]:
|
|
1753
|
+
undefined,
|
|
1754
|
+
[NotificationRuleConditionCheckOn.Monitors]: undefined,
|
|
1662
1755
|
};
|
|
1663
1756
|
}
|
|
1664
1757
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Connect common api's.
|
|
2
2
|
import CommonAPI from "../API/Index";
|
|
3
3
|
import { StatusAPIOptions } from "../API/StatusAPI";
|
|
4
|
-
import { AppVersion } from "../EnvironmentConfig";
|
|
4
|
+
import { AppVersion, IsBillingEnabled } from "../EnvironmentConfig";
|
|
5
5
|
import LocalCache from "../Infrastructure/LocalCache";
|
|
6
6
|
import "./Environment";
|
|
7
7
|
import Express, {
|
|
@@ -31,6 +31,7 @@ import Typeof from "Common/Types/Typeof";
|
|
|
31
31
|
import CookieParser from "cookie-parser";
|
|
32
32
|
import cors from "cors";
|
|
33
33
|
import zlib from "zlib";
|
|
34
|
+
import "ejs";
|
|
34
35
|
// Make sure we have stack trace for debugging.
|
|
35
36
|
Error.stackTraceLimit = Infinity;
|
|
36
37
|
|
|
@@ -200,7 +201,9 @@ const init: InitFunction = async (
|
|
|
200
201
|
);
|
|
201
202
|
|
|
202
203
|
app.get("/*", (_req: ExpressRequest, res: ExpressResponse) => {
|
|
203
|
-
res.
|
|
204
|
+
return res.render("/usr/src/app/public/index.ejs", {
|
|
205
|
+
enableGoogleTagManager: IsBillingEnabled || false,
|
|
206
|
+
});
|
|
204
207
|
});
|
|
205
208
|
}
|
|
206
209
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import BadDataException from "../../../../../Types/Exception/BadDataException";
|
|
2
|
+
import { ExpressRequest, ExpressResponse } from "../../../Express";
|
|
3
|
+
import SlackActionType from "./ActionTypes";
|
|
4
|
+
import { SlackAction, SlackRequest } from "./Auth";
|
|
5
|
+
import Response from "../../../Response";
|
|
6
|
+
import CaptureSpan from "../../../Telemetry/CaptureSpan";
|
|
7
|
+
|
|
8
|
+
export default class SlackOnCallDutyActions {
|
|
9
|
+
@CaptureSpan()
|
|
10
|
+
public static isOnCallDutyAction(data: {
|
|
11
|
+
actionType: SlackActionType;
|
|
12
|
+
}): boolean {
|
|
13
|
+
const { actionType } = data;
|
|
14
|
+
|
|
15
|
+
switch (actionType) {
|
|
16
|
+
case SlackActionType.ViewOnCallPolicy:
|
|
17
|
+
return true;
|
|
18
|
+
default:
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@CaptureSpan()
|
|
24
|
+
public static async handleOnCallDutyAction(data: {
|
|
25
|
+
slackRequest: SlackRequest;
|
|
26
|
+
action: SlackAction;
|
|
27
|
+
req: ExpressRequest;
|
|
28
|
+
res: ExpressResponse;
|
|
29
|
+
}): Promise<void> {
|
|
30
|
+
// now we should be all set, project is authorized and user is authorized. Lets perform some actions based on the action type.
|
|
31
|
+
const actionType: SlackActionType | undefined = data.action.actionType;
|
|
32
|
+
|
|
33
|
+
if (actionType === SlackActionType.ViewOnCallPolicy) {
|
|
34
|
+
// do nothing. This is just a view alert action.
|
|
35
|
+
// clear response.
|
|
36
|
+
return Response.sendJsonObjectResponse(data.req, data.res, {
|
|
37
|
+
response_action: "clear",
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// invalid action type.
|
|
42
|
+
return Response.sendErrorResponse(
|
|
43
|
+
data.req,
|
|
44
|
+
data.res,
|
|
45
|
+
new BadDataException("Invalid Action Type"),
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|