@oneuptime/common 7.0.3652 → 7.0.3655
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/Infrastructure/Postgres/SchemaMigrations/1739282331053-MigrationName.ts +29 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -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 +11 -2
- package/Server/Types/Workflow/Components/Slack/SendMessageToChannel.ts +1 -1
- package/Server/Utils/Slack/Slack.ts +228 -26
- package/Types/Workspace/WorkspaceNotificationPayload.ts +27 -1
- 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/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/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.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 +9 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.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 +141 -18
- package/build/dist/Server/Utils/Slack/Slack.js.map +1 -1
- package/package.json +2 -2
|
@@ -1035,4 +1035,23 @@ export default class Alert extends BaseModel {
|
|
|
1035
1035
|
nullable: true,
|
|
1036
1036
|
})
|
|
1037
1037
|
public alertNumber?: number = undefined;
|
|
1038
|
+
|
|
1039
|
+
@ColumnAccessControl({
|
|
1040
|
+
create: [],
|
|
1041
|
+
read: [],
|
|
1042
|
+
update: [],
|
|
1043
|
+
})
|
|
1044
|
+
@TableColumn({
|
|
1045
|
+
isDefaultValueColumn: false,
|
|
1046
|
+
required: false,
|
|
1047
|
+
type: TableColumnType.ShortText,
|
|
1048
|
+
title: "Post Updates To Slack Channel ID",
|
|
1049
|
+
description: "Post Updates To Slack Channel ID",
|
|
1050
|
+
})
|
|
1051
|
+
@Column({
|
|
1052
|
+
type: ColumnType.ShortText,
|
|
1053
|
+
length: ColumnLength.ShortText,
|
|
1054
|
+
nullable: true,
|
|
1055
|
+
})
|
|
1056
|
+
public postUpdatesToSlackChannelId?: number = undefined;
|
|
1038
1057
|
}
|
|
@@ -1120,4 +1120,23 @@ export default class Incident extends BaseModel {
|
|
|
1120
1120
|
nullable: true,
|
|
1121
1121
|
})
|
|
1122
1122
|
public incidentNumber?: number = undefined;
|
|
1123
|
+
|
|
1124
|
+
@ColumnAccessControl({
|
|
1125
|
+
create: [],
|
|
1126
|
+
read: [],
|
|
1127
|
+
update: [],
|
|
1128
|
+
})
|
|
1129
|
+
@TableColumn({
|
|
1130
|
+
isDefaultValueColumn: false,
|
|
1131
|
+
required: false,
|
|
1132
|
+
type: TableColumnType.ShortText,
|
|
1133
|
+
title: "Post Updates To Slack Channel ID",
|
|
1134
|
+
description: "Post Updates To Slack Channel ID",
|
|
1135
|
+
})
|
|
1136
|
+
@Column({
|
|
1137
|
+
type: ColumnType.ShortText,
|
|
1138
|
+
length: ColumnLength.ShortText,
|
|
1139
|
+
nullable: true,
|
|
1140
|
+
})
|
|
1141
|
+
public postUpdatesToSlackChannelId?: number = undefined;
|
|
1123
1142
|
}
|
|
@@ -979,4 +979,23 @@ export default class ScheduledMaintenance extends BaseModel {
|
|
|
979
979
|
nullable: true,
|
|
980
980
|
})
|
|
981
981
|
public scheduledMaintenanceNumber?: number = undefined;
|
|
982
|
+
|
|
983
|
+
@ColumnAccessControl({
|
|
984
|
+
create: [],
|
|
985
|
+
read: [],
|
|
986
|
+
update: [],
|
|
987
|
+
})
|
|
988
|
+
@TableColumn({
|
|
989
|
+
isDefaultValueColumn: false,
|
|
990
|
+
required: false,
|
|
991
|
+
type: TableColumnType.ShortText,
|
|
992
|
+
title: "Post Updates To Slack Channel ID",
|
|
993
|
+
description: "Post Updates To Slack Channel ID",
|
|
994
|
+
})
|
|
995
|
+
@Column({
|
|
996
|
+
type: ColumnType.ShortText,
|
|
997
|
+
length: ColumnLength.ShortText,
|
|
998
|
+
nullable: true,
|
|
999
|
+
})
|
|
1000
|
+
public postUpdatesToSlackChannelId?: number = undefined;
|
|
982
1001
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
export class MigrationName1739282331053 implements MigrationInterface {
|
|
4
|
+
public name = "MigrationName1739282331053";
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
await queryRunner.query(
|
|
8
|
+
`ALTER TABLE "Incident" ADD "postUpdatesToSlackChannelId" character varying(100)`,
|
|
9
|
+
);
|
|
10
|
+
await queryRunner.query(
|
|
11
|
+
`ALTER TABLE "Alert" ADD "postUpdatesToSlackChannelId" character varying(100)`,
|
|
12
|
+
);
|
|
13
|
+
await queryRunner.query(
|
|
14
|
+
`ALTER TABLE "ScheduledMaintenance" ADD "postUpdatesToSlackChannelId" character varying(100)`,
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
19
|
+
await queryRunner.query(
|
|
20
|
+
`ALTER TABLE "ScheduledMaintenance" DROP COLUMN "postUpdatesToSlackChannelId"`,
|
|
21
|
+
);
|
|
22
|
+
await queryRunner.query(
|
|
23
|
+
`ALTER TABLE "Alert" DROP COLUMN "postUpdatesToSlackChannelId"`,
|
|
24
|
+
);
|
|
25
|
+
await queryRunner.query(
|
|
26
|
+
`ALTER TABLE "Incident" DROP COLUMN "postUpdatesToSlackChannelId"`,
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -102,6 +102,7 @@ import { MigrationName1737997557974 } from "./1737997557974-MigrationName";
|
|
|
102
102
|
import { MigrationName1739209832500 } from "./1739209832500-MigrationName";
|
|
103
103
|
import { MigrationName1739210586538 } from "./1739210586538-MigrationName";
|
|
104
104
|
import { MigrationName1739217257089 } from "./1739217257089-MigrationName";
|
|
105
|
+
import { MigrationName1739282331053 } from "./1739282331053-MigrationName";
|
|
105
106
|
|
|
106
107
|
export default [
|
|
107
108
|
InitialMigration,
|
|
@@ -208,4 +209,5 @@ export default [
|
|
|
208
209
|
MigrationName1739209832500,
|
|
209
210
|
MigrationName1739210586538,
|
|
210
211
|
MigrationName1739217257089,
|
|
212
|
+
MigrationName1739282331053,
|
|
211
213
|
];
|
|
@@ -465,7 +465,7 @@ export class ProjectService extends DatabaseService<Model> {
|
|
|
465
465
|
`;
|
|
466
466
|
}
|
|
467
467
|
|
|
468
|
-
SlackUtil.
|
|
468
|
+
SlackUtil.sendMessageToChannelViaIncomingWebhook({
|
|
469
469
|
url: URL.fromString(NotificationSlackWebhookOnSubscriptionUpdate),
|
|
470
470
|
text: slackMessage,
|
|
471
471
|
}).catch((error: Exception) => {
|
|
@@ -668,7 +668,7 @@ export class ProjectService extends DatabaseService<Model> {
|
|
|
668
668
|
`;
|
|
669
669
|
}
|
|
670
670
|
|
|
671
|
-
SlackUtil.
|
|
671
|
+
SlackUtil.sendMessageToChannelViaIncomingWebhook({
|
|
672
672
|
url: URL.fromString(NotificationSlackWebhookOnCreateProject),
|
|
673
673
|
text: slackMessage,
|
|
674
674
|
}).catch((error: Exception) => {
|
|
@@ -1178,7 +1178,7 @@ export class ProjectService extends DatabaseService<Model> {
|
|
|
1178
1178
|
`;
|
|
1179
1179
|
}
|
|
1180
1180
|
|
|
1181
|
-
SlackUtil.
|
|
1181
|
+
SlackUtil.sendMessageToChannelViaIncomingWebhook({
|
|
1182
1182
|
url: URL.fromString(NotificationSlackWebhookOnDeleteProject),
|
|
1183
1183
|
text: slackMessage,
|
|
1184
1184
|
}).catch((err: Error) => {
|
|
@@ -32,6 +32,7 @@ import SlackUtil from "../Utils/Slack/Slack";
|
|
|
32
32
|
import UserTwoFactorAuth from "Common/Models/DatabaseModels/UserTwoFactorAuth";
|
|
33
33
|
import UserTwoFactorAuthService from "./UserTwoFactorAuthService";
|
|
34
34
|
import BadDataException from "../../Types/Exception/BadDataException";
|
|
35
|
+
import Name from "../../Types/Name";
|
|
35
36
|
|
|
36
37
|
export class Service extends DatabaseService<Model> {
|
|
37
38
|
public constructor() {
|
|
@@ -43,7 +44,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
43
44
|
createdItem: Model,
|
|
44
45
|
): Promise<Model> {
|
|
45
46
|
if (NotificationSlackWebhookOnCreateUser) {
|
|
46
|
-
SlackUtil.
|
|
47
|
+
SlackUtil.sendMessageToChannelViaIncomingWebhook({
|
|
47
48
|
url: URL.fromString(NotificationSlackWebhookOnCreateUser),
|
|
48
49
|
text: `*New OneUptime User:*
|
|
49
50
|
*Email:* ${createdItem.email?.toString() || "N/A"}
|
|
@@ -292,6 +293,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
292
293
|
|
|
293
294
|
public async createByEmail(data: {
|
|
294
295
|
email: Email;
|
|
296
|
+
name: Name | undefined;
|
|
295
297
|
isEmailVerified?: boolean;
|
|
296
298
|
generateRandomPassword?: boolean;
|
|
297
299
|
props: DatabaseCommonInteractionProps;
|
|
@@ -300,6 +302,9 @@ export class Service extends DatabaseService<Model> {
|
|
|
300
302
|
|
|
301
303
|
const user: Model = new Model();
|
|
302
304
|
user.email = email;
|
|
305
|
+
if (data.name) {
|
|
306
|
+
user.name = data.name;
|
|
307
|
+
}
|
|
303
308
|
user.isEmailVerified = data.isEmailVerified || false;
|
|
304
309
|
|
|
305
310
|
if (data.generateRandomPassword) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import NotificationRuleEventType from "../../Types/Workspace/NotificationRules/EventType";
|
|
2
|
-
import
|
|
2
|
+
import WorkspaceNotificationPayload from "../../Types/Workspace/WorkspaceNotificationPayload";
|
|
3
3
|
import WorkspaceType from "../../Types/Workspace/WorkspaceType";
|
|
4
4
|
import logger from "../Utils/Logger";
|
|
5
|
+
import SlackUtil from "../Utils/Slack/Slack";
|
|
5
6
|
import DatabaseService from "./DatabaseService";
|
|
6
7
|
import Model from "Common/Models/DatabaseModels/WorkspaceNotificationRule";
|
|
7
8
|
|
|
@@ -10,13 +11,21 @@ export class Service extends DatabaseService<Model> {
|
|
|
10
11
|
super(Model);
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
public async
|
|
14
|
+
public async sendMessage(data: {
|
|
14
15
|
workspaceType: WorkspaceType;
|
|
15
16
|
notificationRuleEventType: NotificationRuleEventType;
|
|
16
17
|
workspaceNotificationPayload: WorkspaceNotificationPayload;
|
|
18
|
+
authToken: string; // which auth token should we use to send.
|
|
17
19
|
}): Promise<void> {
|
|
18
20
|
logger.debug("Notify Workspace");
|
|
19
21
|
logger.debug(data);
|
|
22
|
+
|
|
23
|
+
if (data.workspaceType === WorkspaceType.Slack) {
|
|
24
|
+
await SlackUtil.sendMessage({
|
|
25
|
+
workspaceNotificationPayload: data.workspaceNotificationPayload,
|
|
26
|
+
authToken: data.authToken,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
20
29
|
}
|
|
21
30
|
}
|
|
22
31
|
export default new Service();
|
|
@@ -69,7 +69,7 @@ export default class SendMessageToChannel extends ComponentCode {
|
|
|
69
69
|
|
|
70
70
|
try {
|
|
71
71
|
// https://api.slack.com/messaging/webhooks#advanced_message_formatting
|
|
72
|
-
apiResult = await SlackUtil.
|
|
72
|
+
apiResult = await SlackUtil.sendMessageToChannelViaIncomingWebhook({
|
|
73
73
|
url: args["webhook-url"] as URL,
|
|
74
74
|
text: args["text"] as string,
|
|
75
75
|
});
|
|
@@ -3,49 +3,209 @@ 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 WorkspaceNotificationPayload, {
|
|
7
|
+
WorkspaceNotificationPayloadButton,
|
|
8
|
+
WorkspacePayloadButtons,
|
|
9
|
+
WorkspacePayloadHeader,
|
|
10
|
+
WorkspacePayloadMarkdown,
|
|
11
|
+
} from "../../../Types/Workspace/WorkspaceNotificationPayload";
|
|
12
|
+
import logger from "../Logger";
|
|
13
|
+
import Dictionary from "../../../Types/Dictionary";
|
|
14
|
+
import BadRequestException from "../../../Types/Exception/BadRequestException";
|
|
15
|
+
|
|
16
|
+
export interface JobResponse {
|
|
17
|
+
isSuccessful: boolean;
|
|
18
|
+
errorMessage?: string | undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface SlackChannel {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
}
|
|
6
25
|
|
|
7
26
|
export default class SlackUtil {
|
|
8
|
-
public async
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
public static async sendMessage(data: {
|
|
28
|
+
workspaceNotificationPayload: WorkspaceNotificationPayload;
|
|
29
|
+
authToken: string; // which auth token should we use to send.
|
|
30
|
+
}): Promise<void> {
|
|
31
|
+
logger.debug("Notify Slack");
|
|
32
|
+
logger.debug(data);
|
|
33
|
+
|
|
34
|
+
const blocks: Array<JSONObject> =
|
|
35
|
+
this.getSlackBlocksFromWorkspaceNotificationPayload(
|
|
36
|
+
data.workspaceNotificationPayload,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const existingSlackChannels: Dictionary<SlackChannel> =
|
|
40
|
+
await this.getSlackChannels({
|
|
41
|
+
authToken: data.authToken,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
for (const channelName of data.workspaceNotificationPayload.channelNames) {
|
|
45
|
+
// get channel ids from existingSlackChannels. IF channel doesn't exist, create it if createChannelsIfItDoesNotExist is true.
|
|
46
|
+
let channel: SlackChannel | null = null;
|
|
47
|
+
|
|
48
|
+
if (existingSlackChannels[channelName]) {
|
|
49
|
+
channel = existingSlackChannels[channelName]!;
|
|
50
|
+
} else if (
|
|
51
|
+
data.workspaceNotificationPayload.createChannelsIfItDoesNotExist
|
|
52
|
+
) {
|
|
53
|
+
channel = await this.createChannel({
|
|
54
|
+
authToken: data.authToken,
|
|
55
|
+
channelName: channelName,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (channel) {
|
|
60
|
+
await this.sendPayloadBlocksToChannel({
|
|
61
|
+
authToken: data.authToken,
|
|
62
|
+
channelId: channel.id,
|
|
63
|
+
blocks: blocks,
|
|
64
|
+
});
|
|
65
|
+
} else {
|
|
66
|
+
logger.debug(
|
|
67
|
+
`Channel ${channelName} does not exist and createChannelsIfItDoesNotExist is false.`,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public static async sendPayloadBlocksToChannel(data: {
|
|
74
|
+
authToken: string;
|
|
75
|
+
channelId: string;
|
|
76
|
+
blocks: Array<JSONObject>;
|
|
77
|
+
}): Promise<void> {
|
|
78
|
+
const response: HTTPErrorResponse | HTTPResponse<JSONObject> =
|
|
79
|
+
await API.post(
|
|
80
|
+
URL.fromString("https://slack.com/api/chat.postMessage"),
|
|
81
|
+
{
|
|
82
|
+
channel: data.channelId,
|
|
83
|
+
blocks: data.blocks,
|
|
22
84
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
85
|
+
{
|
|
86
|
+
Authorization: `Bearer ${data.authToken}`,
|
|
87
|
+
},
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
if (response instanceof HTTPErrorResponse) {
|
|
91
|
+
throw response;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if ((response.jsonData as JSONObject)?.["ok"] !== true) {
|
|
95
|
+
throw new BadRequestException("Invalid response");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public static async createChannel(data: {
|
|
100
|
+
authToken: string;
|
|
101
|
+
channelName: string;
|
|
102
|
+
}): Promise<SlackChannel> {
|
|
103
|
+
const response: HTTPResponse<JSONObject> | HTTPErrorResponse =
|
|
104
|
+
await API.post(
|
|
105
|
+
URL.fromString("https://slack.com/api/conversations.create"),
|
|
106
|
+
{
|
|
107
|
+
name: data.channelName,
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
Authorization: `Bearer ${data.authToken}`,
|
|
111
|
+
},
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
if (response instanceof HTTPErrorResponse) {
|
|
115
|
+
throw response;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (
|
|
119
|
+
!((response.jsonData as JSONObject)?.["channel"] as JSONObject)?.["id"] ||
|
|
120
|
+
!((response.jsonData as JSONObject)?.["channel"] as JSONObject)?.["name"]
|
|
121
|
+
) {
|
|
122
|
+
throw new Error("Invalid response");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
id: ((response.jsonData as JSONObject)["channel"] as JSONObject)[
|
|
127
|
+
"id"
|
|
128
|
+
] as string,
|
|
129
|
+
name: ((response.jsonData as JSONObject)["channel"] as JSONObject)[
|
|
130
|
+
"name"
|
|
131
|
+
] as string,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public static getHeaderBlock(data: {
|
|
136
|
+
payloadHeaderBlock: WorkspacePayloadHeader;
|
|
137
|
+
}): JSONObject {
|
|
138
|
+
return {
|
|
139
|
+
type: "header",
|
|
140
|
+
text: {
|
|
26
141
|
type: "plain_text",
|
|
27
|
-
text: data.
|
|
142
|
+
text: data.payloadHeaderBlock.text,
|
|
28
143
|
},
|
|
29
144
|
};
|
|
30
145
|
}
|
|
31
146
|
|
|
32
|
-
public
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
147
|
+
public static getMarkdownBlock(data: {
|
|
148
|
+
payloadMarkdownBlock: WorkspacePayloadMarkdown;
|
|
149
|
+
}): JSONObject {
|
|
150
|
+
return {
|
|
151
|
+
type: "section",
|
|
152
|
+
text: {
|
|
153
|
+
type: "mrkdwn",
|
|
154
|
+
text: data.payloadMarkdownBlock.text,
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
public static async getSlackChannels(data: {
|
|
160
|
+
authToken: string;
|
|
161
|
+
}): Promise<Dictionary<SlackChannel>> {
|
|
162
|
+
const response: HTTPErrorResponse | HTTPResponse<JSONObject> =
|
|
163
|
+
await API.get<JSONObject>(
|
|
164
|
+
URL.fromString("https://slack.com/api/conversations.list"),
|
|
165
|
+
{
|
|
166
|
+
headers: {
|
|
167
|
+
Authorization: `Bearer ${data.authToken}`,
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
if (response instanceof HTTPErrorResponse) {
|
|
173
|
+
throw response;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const channels: Dictionary<SlackChannel> = {};
|
|
177
|
+
|
|
178
|
+
for (const channel of (response.jsonData as JSONObject)[
|
|
179
|
+
"channels"
|
|
180
|
+
] as Array<JSONObject>) {
|
|
181
|
+
if (!channel["id"] || !channel["name"]) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
channels[channel["name"].toString()] = {
|
|
186
|
+
id: channel["id"] as string,
|
|
187
|
+
name: channel["name"] as string,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return channels;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
public static getButtonBlock(data: {
|
|
195
|
+
payloadButtonBlock: WorkspaceNotificationPayloadButton;
|
|
36
196
|
}): JSONObject {
|
|
37
197
|
return {
|
|
38
198
|
type: "button",
|
|
39
199
|
text: {
|
|
40
200
|
type: "plain_text",
|
|
41
|
-
text: data.
|
|
201
|
+
text: data.payloadButtonBlock.title,
|
|
42
202
|
},
|
|
43
|
-
|
|
44
|
-
|
|
203
|
+
value: data.payloadButtonBlock.title,
|
|
204
|
+
action_id: data.payloadButtonBlock.title,
|
|
45
205
|
};
|
|
46
206
|
}
|
|
47
207
|
|
|
48
|
-
public static async
|
|
208
|
+
public static async sendMessageToChannelViaIncomingWebhook(data: {
|
|
49
209
|
url: URL;
|
|
50
210
|
text: string;
|
|
51
211
|
}): Promise<HTTPResponse<JSONObject> | HTTPErrorResponse> {
|
|
@@ -66,4 +226,46 @@ export default class SlackUtil {
|
|
|
66
226
|
|
|
67
227
|
return apiResult;
|
|
68
228
|
}
|
|
229
|
+
|
|
230
|
+
private static getSlackBlocksFromWorkspaceNotificationPayload(
|
|
231
|
+
data: WorkspaceNotificationPayload,
|
|
232
|
+
): Array<JSONObject> {
|
|
233
|
+
const blocks: Array<JSONObject> = [];
|
|
234
|
+
const buttons: Array<JSONObject> = [];
|
|
235
|
+
for (const block of data.blocks) {
|
|
236
|
+
switch (block._type) {
|
|
237
|
+
case "WorkspacePayloadHeader":
|
|
238
|
+
blocks.push(
|
|
239
|
+
this.getHeaderBlock({
|
|
240
|
+
payloadHeaderBlock: block as WorkspacePayloadHeader,
|
|
241
|
+
}),
|
|
242
|
+
);
|
|
243
|
+
break;
|
|
244
|
+
case "WorkspacePayloadMarkdown":
|
|
245
|
+
blocks.push(
|
|
246
|
+
this.getMarkdownBlock({
|
|
247
|
+
payloadMarkdownBlock: block as WorkspacePayloadMarkdown,
|
|
248
|
+
}),
|
|
249
|
+
);
|
|
250
|
+
break;
|
|
251
|
+
case "WorkspacePayloadButtons":
|
|
252
|
+
for (const button of (block as WorkspacePayloadButtons).buttons) {
|
|
253
|
+
buttons.push(
|
|
254
|
+
this.getButtonBlock({
|
|
255
|
+
payloadButtonBlock: button,
|
|
256
|
+
}),
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
blocks.push({
|
|
260
|
+
type: "actions",
|
|
261
|
+
elements: buttons,
|
|
262
|
+
});
|
|
263
|
+
break;
|
|
264
|
+
default:
|
|
265
|
+
logger.error("Unknown block type: " + block._type);
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return blocks;
|
|
270
|
+
}
|
|
69
271
|
}
|
|
@@ -1,3 +1,29 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface WorkspacePayloadBlocks {
|
|
2
|
+
_type: string;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export interface WorkspaceNotificationPayloadButton {
|
|
6
|
+
title: string; // Button title.
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface WorkspacePayloadHeader extends WorkspacePayloadBlocks {
|
|
10
|
+
_type: "WorkspacePayloadHeader";
|
|
11
|
+
text: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface WorkspacePayloadMarkdown extends WorkspacePayloadBlocks {
|
|
15
|
+
_type: "WorkspacePayloadMarkdown";
|
|
16
|
+
text: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface WorkspacePayloadButtons extends WorkspacePayloadBlocks {
|
|
20
|
+
_type: "WorkspacePayloadButtons";
|
|
21
|
+
buttons: Array<WorkspaceNotificationPayloadButton>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default interface WorkspaceNotificationPayload {
|
|
2
25
|
_type: "WorkspaceNotificationPayload";
|
|
26
|
+
channelNames: Array<string>; // which channels to post to.
|
|
27
|
+
blocks: Array<WorkspacePayloadBlocks>; // Buttons to add to the message.
|
|
28
|
+
createChannelsIfItDoesNotExist: boolean; // Should we create the channels if they don't exist.
|
|
3
29
|
}
|
|
@@ -68,6 +68,7 @@ let Alert = class Alert extends BaseModel {
|
|
|
68
68
|
this.remediationNotes = undefined;
|
|
69
69
|
this.telemetryQuery = undefined;
|
|
70
70
|
this.alertNumber = undefined;
|
|
71
|
+
this.postUpdatesToSlackChannelId = undefined;
|
|
71
72
|
}
|
|
72
73
|
};
|
|
73
74
|
__decorate([
|
|
@@ -1000,6 +1001,26 @@ __decorate([
|
|
|
1000
1001
|
}),
|
|
1001
1002
|
__metadata("design:type", Number)
|
|
1002
1003
|
], Alert.prototype, "alertNumber", void 0);
|
|
1004
|
+
__decorate([
|
|
1005
|
+
ColumnAccessControl({
|
|
1006
|
+
create: [],
|
|
1007
|
+
read: [],
|
|
1008
|
+
update: [],
|
|
1009
|
+
}),
|
|
1010
|
+
TableColumn({
|
|
1011
|
+
isDefaultValueColumn: false,
|
|
1012
|
+
required: false,
|
|
1013
|
+
type: TableColumnType.ShortText,
|
|
1014
|
+
title: "Post Updates To Slack Channel ID",
|
|
1015
|
+
description: "Post Updates To Slack Channel ID",
|
|
1016
|
+
}),
|
|
1017
|
+
Column({
|
|
1018
|
+
type: ColumnType.ShortText,
|
|
1019
|
+
length: ColumnLength.ShortText,
|
|
1020
|
+
nullable: true,
|
|
1021
|
+
}),
|
|
1022
|
+
__metadata("design:type", Number)
|
|
1023
|
+
], Alert.prototype, "postUpdatesToSlackChannelId", void 0);
|
|
1003
1024
|
Alert = __decorate([
|
|
1004
1025
|
EnableDocumentation(),
|
|
1005
1026
|
AccessControlColumn("labels"),
|