@oneuptime/common 7.0.3652 → 7.0.3668
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/Alert.ts +19 -0
- package/Models/DatabaseModels/Incident.ts +19 -0
- package/Models/DatabaseModels/ScheduledMaintenance.ts +19 -0
- package/Server/API/BaseAPI.ts +48 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1739282331053-MigrationName.ts +29 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1739374537088-MigrationName.ts +29 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Services/IncidentService.ts +101 -0
- package/Server/Services/MonitorService.ts +43 -0
- package/Server/Services/ProjectService.ts +3 -3
- package/Server/Services/TeamMemberService.ts +1 -0
- package/Server/Services/UserService.ts +6 -1
- package/Server/Services/WorkspaceNotificationRuleService.ts +442 -7
- package/Server/Services/WorkspaceProjectAuthTokenService.ts +43 -15
- package/Server/Types/Workflow/Components/Slack/SendMessageToChannel.ts +1 -1
- package/Server/Utils/Slack/Slack.ts +361 -26
- package/Types/Workspace/NotificationRules/BaseNotificationRule.ts +9 -0
- package/Types/Workspace/NotificationRules/NotificationRuleCondition.ts +23 -32
- package/Types/Workspace/NotificationRules/NotificationRuleTypes/AlertNotificationRule.ts +15 -0
- package/Types/Workspace/NotificationRules/NotificationRuleTypes/IncidentNotificationRule.ts +15 -0
- package/Types/Workspace/NotificationRules/NotificationRuleTypes/MonitorStatusNotificationRule.ts +7 -0
- package/Types/Workspace/NotificationRules/NotificationRuleTypes/ScheduledMaintenanceNotificationRule.ts +14 -0
- package/Types/Workspace/NotificationRules/NotificationRuleUtil.ts +261 -0
- package/Types/Workspace/WorkspaceChannelInvitationPayload.ts +4 -0
- package/Types/Workspace/WorkspaceMessagePayload.ts +30 -0
- package/build/dist/Models/DatabaseModels/Alert.js +21 -0
- package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Incident.js +21 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +21 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +34 -2
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1739282331053-MigrationName.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1739282331053-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1739374537088-MigrationName.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1739374537088-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/IncidentService.js +84 -0
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +34 -0
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +3 -3
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +1 -0
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +4 -1
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +316 -4
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +29 -4
- package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Slack/SendMessageToChannel.js +1 -1
- package/build/dist/Server/Types/Workflow/Components/Slack/SendMessageToChannel.js.map +1 -1
- package/build/dist/Server/Utils/Slack/Slack.js +227 -18
- package/build/dist/Server/Utils/Slack/Slack.js.map +1 -1
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js +20 -21
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js.map +1 -1
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleTypes/AlertNotificationRule.js +2 -0
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleTypes/AlertNotificationRule.js.map +1 -0
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleTypes/IncidentNotificationRule.js +2 -0
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleTypes/IncidentNotificationRule.js.map +1 -0
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleTypes/MonitorStatusNotificationRule.js +2 -0
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleTypes/MonitorStatusNotificationRule.js.map +1 -0
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleTypes/ScheduledMaintenanceNotificationRule.js +2 -0
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleTypes/ScheduledMaintenanceNotificationRule.js.map +1 -0
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleUtil.js +216 -0
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleUtil.js.map +1 -0
- package/build/dist/Types/Workspace/WorkspaceChannelInvitationPayload.js +2 -0
- package/build/dist/Types/Workspace/WorkspaceChannelInvitationPayload.js.map +1 -0
- package/build/dist/Types/Workspace/WorkspaceMessagePayload.js +2 -0
- package/build/dist/Types/Workspace/WorkspaceMessagePayload.js.map +1 -0
- package/package.json +2 -2
- package/Types/Workspace/NotificationRules/SlackNotificationRule.ts +0 -19
- package/Types/Workspace/WorkspaceNotificationPayload.ts +0 -3
- package/build/dist/Types/Workspace/NotificationRules/SlackNotificationRule.js +0 -2
- package/build/dist/Types/Workspace/NotificationRules/SlackNotificationRule.js.map +0 -1
- package/build/dist/Types/Workspace/WorkspaceNotificationPayload.js +0 -2
- package/build/dist/Types/Workspace/WorkspaceNotificationPayload.js.map +0 -1
|
@@ -3,49 +3,342 @@ import HTTPResponse from "Common/Types/API/HTTPResponse";
|
|
|
3
3
|
import URL from "Common/Types/API/URL";
|
|
4
4
|
import { JSONObject } from "Common/Types/JSON";
|
|
5
5
|
import API from "Common/Utils/API";
|
|
6
|
+
import WorkspaceMessagePayload, {
|
|
7
|
+
WorkspaceMessagePayloadButton,
|
|
8
|
+
WorkspacePayloadButtons,
|
|
9
|
+
WorkspacePayloadHeader,
|
|
10
|
+
WorkspacePayloadMarkdown,
|
|
11
|
+
} from "../../../Types/Workspace/WorkspaceMessagePayload";
|
|
12
|
+
import logger from "../Logger";
|
|
13
|
+
import Dictionary from "../../../Types/Dictionary";
|
|
14
|
+
import BadRequestException from "../../../Types/Exception/BadRequestException";
|
|
15
|
+
import WorkspaceChannelInvitationPayload from "../../../Types/Workspace/WorkspaceChannelInvitationPayload";
|
|
16
|
+
|
|
17
|
+
export interface JobResponse {
|
|
18
|
+
isSuccessful: boolean;
|
|
19
|
+
errorMessage?: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface SlackChannel {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
}
|
|
6
26
|
|
|
7
27
|
export default class SlackUtil {
|
|
8
|
-
public async
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
public static async inviteUsersToChannels(data: {
|
|
29
|
+
authToken: string;
|
|
30
|
+
workspaceChannelInvitationPayload: WorkspaceChannelInvitationPayload;
|
|
31
|
+
}): Promise<void> {
|
|
32
|
+
const channelIds: Array<string> = [];
|
|
33
|
+
|
|
34
|
+
for (const channelName of data.workspaceChannelInvitationPayload
|
|
35
|
+
.workspaceChannelNames) {
|
|
36
|
+
const channel: SlackChannel = await this.createChannel({
|
|
37
|
+
authToken: data.authToken,
|
|
38
|
+
channelName: channelName,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
channelIds.push(channel.id);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
for (const channelId of channelIds) {
|
|
45
|
+
await this.inviteUsersToChannel({
|
|
46
|
+
authToken: data.authToken,
|
|
47
|
+
channelId: channelId,
|
|
48
|
+
userIds: data.workspaceChannelInvitationPayload.workspaceUserIds,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private static async inviteUsersToChannel(data: {
|
|
54
|
+
authToken: string;
|
|
55
|
+
channelId: string;
|
|
56
|
+
userIds: Array<string>;
|
|
57
|
+
}): Promise<void> {
|
|
58
|
+
for (const userId of data.userIds) {
|
|
59
|
+
await this.inviteUserToChannel({
|
|
60
|
+
authToken: data.authToken,
|
|
61
|
+
channelId: data.channelId,
|
|
62
|
+
userId: userId,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private static async inviteUserToChannel(data: {
|
|
68
|
+
authToken: string;
|
|
69
|
+
channelId: string;
|
|
70
|
+
userId: string;
|
|
71
|
+
}): Promise<void> {
|
|
72
|
+
const response: HTTPErrorResponse | HTTPResponse<JSONObject> =
|
|
73
|
+
await API.post(
|
|
74
|
+
URL.fromString("https://slack.com/api/conversations.invite"),
|
|
75
|
+
{
|
|
76
|
+
channel: data.channelId,
|
|
77
|
+
users: data.userId,
|
|
22
78
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
79
|
+
{
|
|
80
|
+
Authorization: `Bearer ${data.authToken}`,
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
if (response instanceof HTTPErrorResponse) {
|
|
85
|
+
throw response;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if ((response.jsonData as JSONObject)?.["ok"] !== true) {
|
|
89
|
+
throw new BadRequestException("Invalid response");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public static async createChannelIfDoesNotExist(data: {
|
|
94
|
+
authToken: string;
|
|
95
|
+
channelNamesToCreate: Array<string>;
|
|
96
|
+
}): Promise<Array<string>> {
|
|
97
|
+
// check existing channels and only create if they dont exist.
|
|
98
|
+
const channelIds: Array<string> = [];
|
|
99
|
+
const existingSlackChannels: Dictionary<SlackChannel> =
|
|
100
|
+
await this.getSlackChannels({
|
|
101
|
+
authToken: data.authToken,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
for (const channelName of data.channelNamesToCreate) {
|
|
105
|
+
if (existingSlackChannels[channelName]) {
|
|
106
|
+
logger.debug(`Channel ${channelName} already exists.`);
|
|
107
|
+
|
|
108
|
+
channelIds.push(existingSlackChannels[channelName]!.id);
|
|
109
|
+
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const channel: SlackChannel = await this.createChannel({
|
|
114
|
+
authToken: data.authToken,
|
|
115
|
+
channelName: channelName,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
if (channel) {
|
|
119
|
+
channelIds.push(channel.id);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return channelIds;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public static async getChannelNameFromChannelId(data: {
|
|
127
|
+
authToken: string;
|
|
128
|
+
channelId: string;
|
|
129
|
+
}): Promise<string> {
|
|
130
|
+
const response: HTTPErrorResponse | HTTPResponse<JSONObject> =
|
|
131
|
+
await API.get<JSONObject>(
|
|
132
|
+
URL.fromString("https://slack.com/api/conversations.info"),
|
|
133
|
+
{
|
|
134
|
+
headers: {
|
|
135
|
+
Authorization: `Bearer ${data.authToken}`,
|
|
136
|
+
},
|
|
137
|
+
params: {
|
|
138
|
+
channel: data.channelId,
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
if (response instanceof HTTPErrorResponse) {
|
|
144
|
+
throw response;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (
|
|
148
|
+
!((response.jsonData as JSONObject)?.["channel"] as JSONObject)?.["name"]
|
|
149
|
+
) {
|
|
150
|
+
throw new Error("Invalid response");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return ((response.jsonData as JSONObject)["channel"] as JSONObject)[
|
|
154
|
+
"name"
|
|
155
|
+
] as string;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
public static async sendMessage(data: {
|
|
159
|
+
workspaceMessagePayload: WorkspaceMessagePayload;
|
|
160
|
+
authToken: string; // which auth token should we use to send.
|
|
161
|
+
}): Promise<void> {
|
|
162
|
+
logger.debug("Notify Slack");
|
|
163
|
+
logger.debug(data);
|
|
164
|
+
|
|
165
|
+
const blocks: Array<JSONObject> =
|
|
166
|
+
this.getSlackBlocksFromWorkspaceMessagePayload(
|
|
167
|
+
data.workspaceMessagePayload,
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
const existingSlackChannels: Dictionary<SlackChannel> =
|
|
171
|
+
await this.getSlackChannels({
|
|
172
|
+
authToken: data.authToken,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const channelIdsToPostTo: Array<string> = [];
|
|
176
|
+
|
|
177
|
+
for (const channelName of data.workspaceMessagePayload.channelNames) {
|
|
178
|
+
// get channel ids from existingSlackChannels. IF channel doesn't exist, create it if createChannelsIfItDoesNotExist is true.
|
|
179
|
+
let channel: SlackChannel | null = null;
|
|
180
|
+
|
|
181
|
+
if (existingSlackChannels[channelName]) {
|
|
182
|
+
channel = existingSlackChannels[channelName]!;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (channel) {
|
|
186
|
+
channelIdsToPostTo.push(channel.id);
|
|
187
|
+
} else {
|
|
188
|
+
logger.debug(`Channel ${channelName} does not exist.`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
for (const channelId of channelIdsToPostTo) {
|
|
193
|
+
try {
|
|
194
|
+
// try catch here to prevent failure of one channel to prevent posting to other channels.
|
|
195
|
+
await this.sendPayloadBlocksToChannel({
|
|
196
|
+
authToken: data.authToken,
|
|
197
|
+
channelId: channelId,
|
|
198
|
+
blocks: blocks,
|
|
199
|
+
});
|
|
200
|
+
} catch (e) {
|
|
201
|
+
logger.error(e);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
public static async sendPayloadBlocksToChannel(data: {
|
|
207
|
+
authToken: string;
|
|
208
|
+
channelId: string;
|
|
209
|
+
blocks: Array<JSONObject>;
|
|
210
|
+
}): Promise<void> {
|
|
211
|
+
const response: HTTPErrorResponse | HTTPResponse<JSONObject> =
|
|
212
|
+
await API.post(
|
|
213
|
+
URL.fromString("https://slack.com/api/chat.postMessage"),
|
|
214
|
+
{
|
|
215
|
+
channel: data.channelId,
|
|
216
|
+
blocks: data.blocks,
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
Authorization: `Bearer ${data.authToken}`,
|
|
220
|
+
},
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
if (response instanceof HTTPErrorResponse) {
|
|
224
|
+
throw response;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if ((response.jsonData as JSONObject)?.["ok"] !== true) {
|
|
228
|
+
throw new BadRequestException("Invalid response");
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
public static async createChannel(data: {
|
|
233
|
+
authToken: string;
|
|
234
|
+
channelName: string;
|
|
235
|
+
}): Promise<SlackChannel> {
|
|
236
|
+
const response: HTTPResponse<JSONObject> | HTTPErrorResponse =
|
|
237
|
+
await API.post(
|
|
238
|
+
URL.fromString("https://slack.com/api/conversations.create"),
|
|
239
|
+
{
|
|
240
|
+
name: data.channelName,
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
Authorization: `Bearer ${data.authToken}`,
|
|
244
|
+
},
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
if (response instanceof HTTPErrorResponse) {
|
|
248
|
+
throw response;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (
|
|
252
|
+
!((response.jsonData as JSONObject)?.["channel"] as JSONObject)?.["id"] ||
|
|
253
|
+
!((response.jsonData as JSONObject)?.["channel"] as JSONObject)?.["name"]
|
|
254
|
+
) {
|
|
255
|
+
throw new Error("Invalid response");
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
id: ((response.jsonData as JSONObject)["channel"] as JSONObject)[
|
|
260
|
+
"id"
|
|
261
|
+
] as string,
|
|
262
|
+
name: ((response.jsonData as JSONObject)["channel"] as JSONObject)[
|
|
263
|
+
"name"
|
|
264
|
+
] as string,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
public static getHeaderBlock(data: {
|
|
269
|
+
payloadHeaderBlock: WorkspacePayloadHeader;
|
|
270
|
+
}): JSONObject {
|
|
271
|
+
return {
|
|
272
|
+
type: "header",
|
|
273
|
+
text: {
|
|
26
274
|
type: "plain_text",
|
|
27
|
-
text: data.
|
|
275
|
+
text: data.payloadHeaderBlock.text,
|
|
28
276
|
},
|
|
29
277
|
};
|
|
30
278
|
}
|
|
31
279
|
|
|
32
|
-
public
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
280
|
+
public static getMarkdownBlock(data: {
|
|
281
|
+
payloadMarkdownBlock: WorkspacePayloadMarkdown;
|
|
282
|
+
}): JSONObject {
|
|
283
|
+
return {
|
|
284
|
+
type: "section",
|
|
285
|
+
text: {
|
|
286
|
+
type: "mrkdwn",
|
|
287
|
+
text: data.payloadMarkdownBlock.text,
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
public static async getSlackChannels(data: {
|
|
293
|
+
authToken: string;
|
|
294
|
+
}): Promise<Dictionary<SlackChannel>> {
|
|
295
|
+
const response: HTTPErrorResponse | HTTPResponse<JSONObject> =
|
|
296
|
+
await API.get<JSONObject>(
|
|
297
|
+
URL.fromString("https://slack.com/api/conversations.list"),
|
|
298
|
+
{
|
|
299
|
+
headers: {
|
|
300
|
+
Authorization: `Bearer ${data.authToken}`,
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
if (response instanceof HTTPErrorResponse) {
|
|
306
|
+
throw response;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const channels: Dictionary<SlackChannel> = {};
|
|
310
|
+
|
|
311
|
+
for (const channel of (response.jsonData as JSONObject)[
|
|
312
|
+
"channels"
|
|
313
|
+
] as Array<JSONObject>) {
|
|
314
|
+
if (!channel["id"] || !channel["name"]) {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
channels[channel["name"].toString()] = {
|
|
319
|
+
id: channel["id"] as string,
|
|
320
|
+
name: channel["name"] as string,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return channels;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
public static getButtonBlock(data: {
|
|
328
|
+
payloadButtonBlock: WorkspaceMessagePayloadButton;
|
|
36
329
|
}): JSONObject {
|
|
37
330
|
return {
|
|
38
331
|
type: "button",
|
|
39
332
|
text: {
|
|
40
333
|
type: "plain_text",
|
|
41
|
-
text: data.
|
|
334
|
+
text: data.payloadButtonBlock.title,
|
|
42
335
|
},
|
|
43
|
-
|
|
44
|
-
|
|
336
|
+
value: data.payloadButtonBlock.title,
|
|
337
|
+
action_id: data.payloadButtonBlock.title,
|
|
45
338
|
};
|
|
46
339
|
}
|
|
47
340
|
|
|
48
|
-
public static async
|
|
341
|
+
public static async sendMessageToChannelViaIncomingWebhook(data: {
|
|
49
342
|
url: URL;
|
|
50
343
|
text: string;
|
|
51
344
|
}): Promise<HTTPResponse<JSONObject> | HTTPErrorResponse> {
|
|
@@ -66,4 +359,46 @@ export default class SlackUtil {
|
|
|
66
359
|
|
|
67
360
|
return apiResult;
|
|
68
361
|
}
|
|
362
|
+
|
|
363
|
+
private static getSlackBlocksFromWorkspaceMessagePayload(
|
|
364
|
+
data: WorkspaceMessagePayload,
|
|
365
|
+
): Array<JSONObject> {
|
|
366
|
+
const blocks: Array<JSONObject> = [];
|
|
367
|
+
const buttons: Array<JSONObject> = [];
|
|
368
|
+
for (const block of data.messageBlocks) {
|
|
369
|
+
switch (block._type) {
|
|
370
|
+
case "WorkspacePayloadHeader":
|
|
371
|
+
blocks.push(
|
|
372
|
+
this.getHeaderBlock({
|
|
373
|
+
payloadHeaderBlock: block as WorkspacePayloadHeader,
|
|
374
|
+
}),
|
|
375
|
+
);
|
|
376
|
+
break;
|
|
377
|
+
case "WorkspacePayloadMarkdown":
|
|
378
|
+
blocks.push(
|
|
379
|
+
this.getMarkdownBlock({
|
|
380
|
+
payloadMarkdownBlock: block as WorkspacePayloadMarkdown,
|
|
381
|
+
}),
|
|
382
|
+
);
|
|
383
|
+
break;
|
|
384
|
+
case "WorkspacePayloadButtons":
|
|
385
|
+
for (const button of (block as WorkspacePayloadButtons).buttons) {
|
|
386
|
+
buttons.push(
|
|
387
|
+
this.getButtonBlock({
|
|
388
|
+
payloadButtonBlock: button,
|
|
389
|
+
}),
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
blocks.push({
|
|
393
|
+
type: "actions",
|
|
394
|
+
elements: buttons,
|
|
395
|
+
});
|
|
396
|
+
break;
|
|
397
|
+
default:
|
|
398
|
+
logger.error("Unknown block type: " + block._type);
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
return blocks;
|
|
403
|
+
}
|
|
69
404
|
}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
import FilterCondition from "../../Filter/FilterCondition";
|
|
2
|
+
import NotificationRuleCondition from "./NotificationRuleCondition";
|
|
3
|
+
|
|
1
4
|
export default interface BaseNotificationRule {
|
|
2
5
|
_type: string;
|
|
6
|
+
// filters for notification rule
|
|
7
|
+
filterCondition: FilterCondition; // and OR or. Default is AND
|
|
8
|
+
filters: Array<NotificationRuleCondition>; // if this array is empty then it will be considered as all filters are matched.
|
|
9
|
+
|
|
10
|
+
shouldPostToExistingChannel: boolean;
|
|
11
|
+
existingChannelNames: string; // seperate by comma
|
|
3
12
|
}
|
|
@@ -7,24 +7,23 @@ import Monitor from "../../../Models/DatabaseModels/Monitor";
|
|
|
7
7
|
import MonitorStatus from "../../../Models/DatabaseModels/MonitorStatus";
|
|
8
8
|
import ScheduledMaintenanceState from "../../../Models/DatabaseModels/ScheduledMaintenanceState";
|
|
9
9
|
import { DropdownOption } from "../../../UI/Components/Dropdown/Dropdown";
|
|
10
|
-
import ObjectID from "../../ObjectID";
|
|
11
10
|
import WorkspaceType from "../WorkspaceType";
|
|
12
11
|
import NotificationRuleEventType from "./EventType";
|
|
13
|
-
import
|
|
12
|
+
import IncidentNotificationRule from "./NotificationRuleTypes/IncidentNotificationRule";
|
|
14
13
|
|
|
15
14
|
export enum NotificationRuleConditionCheckOn {
|
|
16
15
|
MonitorName = "Monitor Name",
|
|
17
|
-
|
|
16
|
+
IncidentTitle = "Incident Title",
|
|
18
17
|
IncidentDescription = "Incident Description",
|
|
19
18
|
IncidentSeverity = "Incident Severity",
|
|
20
19
|
IncidentState = "Incident State",
|
|
21
20
|
MonitorType = "Monitor Type",
|
|
22
21
|
MonitorStatus = "Monitor Status",
|
|
23
|
-
|
|
22
|
+
AlertTitle = "Alert Title",
|
|
24
23
|
AlertDescription = "Alert Description",
|
|
25
24
|
AlertSeverity = "Alert Severity",
|
|
26
25
|
AlertState = "Alert State",
|
|
27
|
-
|
|
26
|
+
ScheduledMaintenanceTitle = "Scheduled Maintenance Title",
|
|
28
27
|
ScheduledMaintenanceDescription = "Scheduled Maintenance Description",
|
|
29
28
|
ScheduledMaintenanceState = "Scheduled Maintenance State",
|
|
30
29
|
IncidentLabels = "Incident Labels",
|
|
@@ -41,7 +40,7 @@ export enum ConditionType {
|
|
|
41
40
|
LessThan = "Less Than",
|
|
42
41
|
GreaterThanOrEqualTo = "Greater Than Or Equal To",
|
|
43
42
|
LessThanOrEqualTo = "Less Than Or Equal To",
|
|
44
|
-
|
|
43
|
+
ContainsAny = "Contains Any",
|
|
45
44
|
NotContains = "Not Contains",
|
|
46
45
|
StartsWith = "Starts With",
|
|
47
46
|
EndsWith = "Ends With",
|
|
@@ -49,26 +48,18 @@ export enum ConditionType {
|
|
|
49
48
|
IsNotEmpty = "Is Not Empty",
|
|
50
49
|
True = "True",
|
|
51
50
|
False = "False",
|
|
52
|
-
|
|
53
|
-
// could be used for labels.
|
|
54
51
|
ContainsAll = "Contains All",
|
|
55
52
|
}
|
|
56
53
|
|
|
57
54
|
export default interface NotificationRuleCondition {
|
|
58
55
|
checkOn: NotificationRuleConditionCheckOn;
|
|
59
56
|
conditionType: ConditionType | undefined;
|
|
60
|
-
value:
|
|
61
|
-
| string
|
|
62
|
-
| number
|
|
63
|
-
| boolean
|
|
64
|
-
| Array<string>
|
|
65
|
-
| Array<ObjectID>
|
|
66
|
-
| undefined;
|
|
57
|
+
value: string | Array<string> | undefined;
|
|
67
58
|
}
|
|
68
59
|
|
|
69
60
|
export class NotificationRuleConditionUtil {
|
|
70
61
|
public static getValidationError(data: {
|
|
71
|
-
notificationRule:
|
|
62
|
+
notificationRule: IncidentNotificationRule;
|
|
72
63
|
eventType: NotificationRuleEventType;
|
|
73
64
|
workspaceType: WorkspaceType;
|
|
74
65
|
}): string | null {
|
|
@@ -97,14 +88,14 @@ export class NotificationRuleConditionUtil {
|
|
|
97
88
|
|
|
98
89
|
if (workspaceType === WorkspaceType.Slack) {
|
|
99
90
|
if (
|
|
100
|
-
!notificationRule.
|
|
101
|
-
!notificationRule.
|
|
91
|
+
!notificationRule.shouldCreateNewChannel &&
|
|
92
|
+
!notificationRule.shouldPostToExistingChannel
|
|
102
93
|
) {
|
|
103
94
|
return "Please select either create slack channel or post to existing slack channel";
|
|
104
95
|
}
|
|
105
96
|
|
|
106
|
-
if (notificationRule.
|
|
107
|
-
if (!notificationRule.
|
|
97
|
+
if (notificationRule.shouldPostToExistingChannel) {
|
|
98
|
+
if (!notificationRule.existingChannelNames?.trim()) {
|
|
108
99
|
return "Existing Slack channel name is required";
|
|
109
100
|
}
|
|
110
101
|
}
|
|
@@ -262,7 +253,7 @@ export class NotificationRuleConditionUtil {
|
|
|
262
253
|
switch (eventType) {
|
|
263
254
|
case NotificationRuleEventType.Incident:
|
|
264
255
|
return [
|
|
265
|
-
NotificationRuleConditionCheckOn.
|
|
256
|
+
NotificationRuleConditionCheckOn.IncidentTitle,
|
|
266
257
|
NotificationRuleConditionCheckOn.IncidentDescription,
|
|
267
258
|
NotificationRuleConditionCheckOn.IncidentSeverity,
|
|
268
259
|
NotificationRuleConditionCheckOn.IncidentState,
|
|
@@ -272,7 +263,7 @@ export class NotificationRuleConditionUtil {
|
|
|
272
263
|
];
|
|
273
264
|
case NotificationRuleEventType.Alert:
|
|
274
265
|
return [
|
|
275
|
-
NotificationRuleConditionCheckOn.
|
|
266
|
+
NotificationRuleConditionCheckOn.AlertTitle,
|
|
276
267
|
NotificationRuleConditionCheckOn.AlertDescription,
|
|
277
268
|
NotificationRuleConditionCheckOn.AlertSeverity,
|
|
278
269
|
NotificationRuleConditionCheckOn.AlertState,
|
|
@@ -292,7 +283,7 @@ export class NotificationRuleConditionUtil {
|
|
|
292
283
|
];
|
|
293
284
|
case NotificationRuleEventType.ScheduledMaintenance:
|
|
294
285
|
return [
|
|
295
|
-
NotificationRuleConditionCheckOn.
|
|
286
|
+
NotificationRuleConditionCheckOn.ScheduledMaintenanceTitle,
|
|
296
287
|
NotificationRuleConditionCheckOn.ScheduledMaintenanceDescription,
|
|
297
288
|
NotificationRuleConditionCheckOn.ScheduledMaintenanceState,
|
|
298
289
|
NotificationRuleConditionCheckOn.ScheduledMaintenanceLabels,
|
|
@@ -309,42 +300,42 @@ export class NotificationRuleConditionUtil {
|
|
|
309
300
|
): Array<ConditionType> {
|
|
310
301
|
switch (checkOn) {
|
|
311
302
|
case NotificationRuleConditionCheckOn.MonitorName:
|
|
312
|
-
case NotificationRuleConditionCheckOn.
|
|
303
|
+
case NotificationRuleConditionCheckOn.IncidentTitle:
|
|
313
304
|
case NotificationRuleConditionCheckOn.IncidentDescription:
|
|
314
|
-
case NotificationRuleConditionCheckOn.
|
|
305
|
+
case NotificationRuleConditionCheckOn.AlertTitle:
|
|
315
306
|
case NotificationRuleConditionCheckOn.AlertDescription:
|
|
316
|
-
case NotificationRuleConditionCheckOn.
|
|
307
|
+
case NotificationRuleConditionCheckOn.ScheduledMaintenanceTitle:
|
|
317
308
|
case NotificationRuleConditionCheckOn.ScheduledMaintenanceDescription:
|
|
318
309
|
return [
|
|
319
310
|
ConditionType.EqualTo,
|
|
320
311
|
ConditionType.NotEqualTo,
|
|
321
|
-
ConditionType.
|
|
312
|
+
ConditionType.ContainsAny,
|
|
322
313
|
ConditionType.NotContains,
|
|
323
314
|
ConditionType.StartsWith,
|
|
324
315
|
ConditionType.EndsWith,
|
|
325
316
|
];
|
|
326
317
|
case NotificationRuleConditionCheckOn.IncidentSeverity:
|
|
327
318
|
case NotificationRuleConditionCheckOn.AlertSeverity:
|
|
328
|
-
return [ConditionType.
|
|
319
|
+
return [ConditionType.ContainsAny, ConditionType.NotContains];
|
|
329
320
|
case NotificationRuleConditionCheckOn.IncidentState:
|
|
330
321
|
case NotificationRuleConditionCheckOn.AlertState:
|
|
331
322
|
case NotificationRuleConditionCheckOn.MonitorStatus:
|
|
332
323
|
case NotificationRuleConditionCheckOn.ScheduledMaintenanceState:
|
|
333
|
-
return [ConditionType.
|
|
324
|
+
return [ConditionType.ContainsAny, ConditionType.NotContains];
|
|
334
325
|
case NotificationRuleConditionCheckOn.MonitorType:
|
|
335
|
-
return [ConditionType.
|
|
326
|
+
return [ConditionType.ContainsAny, ConditionType.NotContains];
|
|
336
327
|
case NotificationRuleConditionCheckOn.AlertLabels:
|
|
337
328
|
case NotificationRuleConditionCheckOn.IncidentLabels:
|
|
338
329
|
case NotificationRuleConditionCheckOn.MonitorLabels:
|
|
339
330
|
case NotificationRuleConditionCheckOn.ScheduledMaintenanceLabels:
|
|
340
331
|
return [
|
|
341
|
-
ConditionType.
|
|
332
|
+
ConditionType.ContainsAny,
|
|
342
333
|
ConditionType.NotContains,
|
|
343
334
|
ConditionType.ContainsAll,
|
|
344
335
|
];
|
|
345
336
|
case NotificationRuleConditionCheckOn.Monitors:
|
|
346
337
|
return [
|
|
347
|
-
ConditionType.
|
|
338
|
+
ConditionType.ContainsAny,
|
|
348
339
|
ConditionType.NotContains,
|
|
349
340
|
ConditionType.ContainsAll,
|
|
350
341
|
];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import ObjectID from "../../../ObjectID";
|
|
2
|
+
import BaseNotificationRule from "../BaseNotificationRule";
|
|
3
|
+
|
|
4
|
+
export default interface AlertNotificationRule extends BaseNotificationRule {
|
|
5
|
+
_type: "AlertNotificationRule";
|
|
6
|
+
|
|
7
|
+
// if filters match then do:
|
|
8
|
+
shouldCreateNewChannel: boolean;
|
|
9
|
+
inviteTeamsToNewChannel: Array<ObjectID>;
|
|
10
|
+
inviteUsersToNewChannel: Array<ObjectID>;
|
|
11
|
+
|
|
12
|
+
shouldInviteOwnersToNewChannel: boolean;
|
|
13
|
+
|
|
14
|
+
shouldAutomaticallyInviteOnCallUsersToNewChannel: boolean;
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import ObjectID from "../../../ObjectID";
|
|
2
|
+
import BaseNotificationRule from "../BaseNotificationRule";
|
|
3
|
+
|
|
4
|
+
export default interface IncidentNotificationRule extends BaseNotificationRule {
|
|
5
|
+
_type: "IncidentNotificationRule";
|
|
6
|
+
|
|
7
|
+
// if filters match then do:
|
|
8
|
+
shouldCreateNewChannel: boolean;
|
|
9
|
+
inviteTeamsToNewChannel: Array<ObjectID>;
|
|
10
|
+
inviteUsersToNewChannel: Array<ObjectID>;
|
|
11
|
+
|
|
12
|
+
shouldInviteOwnersToNewChannel: boolean;
|
|
13
|
+
|
|
14
|
+
shouldAutomaticallyInviteOnCallUsersToNewChannel: boolean;
|
|
15
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import ObjectID from "../../../ObjectID";
|
|
2
|
+
import BaseNotificationRule from "../BaseNotificationRule";
|
|
3
|
+
|
|
4
|
+
export default interface ScheduledMaintenanceNotificationRule
|
|
5
|
+
extends BaseNotificationRule {
|
|
6
|
+
_type: "ScheduledMaintenanceNotificationRule";
|
|
7
|
+
|
|
8
|
+
// if filters match then do:
|
|
9
|
+
shouldCreateNewChannel: boolean;
|
|
10
|
+
inviteTeamsToNewChannel: Array<ObjectID>;
|
|
11
|
+
inviteUsersToNewChannel: Array<ObjectID>;
|
|
12
|
+
|
|
13
|
+
shouldInviteOwnersToNewChannel: boolean;
|
|
14
|
+
}
|