@oneuptime/common 7.0.3786 → 7.0.3815

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.
Files changed (115) hide show
  1. package/Server/API/SlackAPI.ts +68 -0
  2. package/Server/Services/AccessTokenService.ts +21 -0
  3. package/Server/Services/AlertFeedService.ts +98 -0
  4. package/Server/Services/AlertInternalNoteService.ts +49 -8
  5. package/Server/Services/AlertOwnerTeamService.ts +50 -2
  6. package/Server/Services/AlertOwnerUserService.ts +52 -2
  7. package/Server/Services/AlertService.ts +236 -37
  8. package/Server/Services/AlertStateService.ts +24 -0
  9. package/Server/Services/AlertStateTimelineService.ts +30 -2
  10. package/Server/Services/IncidentInternalNoteService.ts +6 -6
  11. package/Server/Services/IncidentPublicNoteService.ts +7 -4
  12. package/Server/Services/IncidentStateTimelineService.ts +2 -1
  13. package/Server/Services/ScheduledMaintenanceFeedService.ts +103 -0
  14. package/Server/Services/ScheduledMaintenanceInternalNoteService.ts +50 -6
  15. package/Server/Services/ScheduledMaintenanceOwnerTeamService.ts +37 -0
  16. package/Server/Services/ScheduledMaintenanceOwnerUserService.ts +34 -0
  17. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +49 -7
  18. package/Server/Services/ScheduledMaintenanceService.ts +375 -12
  19. package/Server/Services/ScheduledMaintenanceStateService.ts +122 -34
  20. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +33 -1
  21. package/Server/Services/WorkspaceNotificationRuleService.ts +12 -0
  22. package/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.ts +38 -0
  23. package/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.ts +116 -0
  24. package/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.ts +36 -115
  25. package/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.ts +108 -0
  26. package/Server/Utils/Workspace/Slack/Actions/ActionTypes.ts +20 -2
  27. package/Server/Utils/Workspace/Slack/Actions/Alert.ts +697 -0
  28. package/Server/Utils/Workspace/Slack/Actions/Auth.ts +9 -2
  29. package/Server/Utils/Workspace/Slack/Actions/Incident.ts +9 -3
  30. package/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.ts +956 -0
  31. package/Server/Utils/Workspace/Slack/Messages/Alert.ts +116 -0
  32. package/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.ts +108 -0
  33. package/Server/Utils/Workspace/Slack/Slack.ts +48 -2
  34. package/Server/Utils/Workspace/Slack/app-manifest.json +3 -3
  35. package/Server/Utils/Workspace/WorkspaceBase.ts +14 -0
  36. package/Server/Utils/Workspace/WorkspaceMessages/Alert.ts +69 -0
  37. package/Server/Utils/Workspace/WorkspaceMessages/ScheduledMaintenance.ts +73 -0
  38. package/Types/Date.ts +5 -0
  39. package/Types/Workspace/WorkspaceMessagePayload.ts +9 -0
  40. package/build/dist/Server/API/SlackAPI.js +54 -0
  41. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  42. package/build/dist/Server/Services/AccessTokenService.js +11 -0
  43. package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
  44. package/build/dist/Server/Services/AlertFeedService.js +60 -0
  45. package/build/dist/Server/Services/AlertFeedService.js.map +1 -1
  46. package/build/dist/Server/Services/AlertInternalNoteService.js +39 -8
  47. package/build/dist/Server/Services/AlertInternalNoteService.js.map +1 -1
  48. package/build/dist/Server/Services/AlertOwnerTeamService.js +40 -2
  49. package/build/dist/Server/Services/AlertOwnerTeamService.js.map +1 -1
  50. package/build/dist/Server/Services/AlertOwnerUserService.js +41 -3
  51. package/build/dist/Server/Services/AlertOwnerUserService.js.map +1 -1
  52. package/build/dist/Server/Services/AlertService.js +192 -35
  53. package/build/dist/Server/Services/AlertService.js.map +1 -1
  54. package/build/dist/Server/Services/AlertStateService.js +13 -0
  55. package/build/dist/Server/Services/AlertStateService.js.map +1 -1
  56. package/build/dist/Server/Services/AlertStateTimelineService.js +26 -2
  57. package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
  58. package/build/dist/Server/Services/IncidentInternalNoteService.js +6 -6
  59. package/build/dist/Server/Services/IncidentInternalNoteService.js.map +1 -1
  60. package/build/dist/Server/Services/IncidentPublicNoteService.js +5 -4
  61. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  62. package/build/dist/Server/Services/IncidentStateTimelineService.js +1 -1
  63. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  64. package/build/dist/Server/Services/ScheduledMaintenanceFeedService.js +60 -0
  65. package/build/dist/Server/Services/ScheduledMaintenanceFeedService.js.map +1 -1
  66. package/build/dist/Server/Services/ScheduledMaintenanceInternalNoteService.js +36 -6
  67. package/build/dist/Server/Services/ScheduledMaintenanceInternalNoteService.js.map +1 -1
  68. package/build/dist/Server/Services/ScheduledMaintenanceOwnerTeamService.js +24 -0
  69. package/build/dist/Server/Services/ScheduledMaintenanceOwnerTeamService.js.map +1 -1
  70. package/build/dist/Server/Services/ScheduledMaintenanceOwnerUserService.js +22 -0
  71. package/build/dist/Server/Services/ScheduledMaintenanceOwnerUserService.js.map +1 -1
  72. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +36 -7
  73. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  74. package/build/dist/Server/Services/ScheduledMaintenanceService.js +275 -13
  75. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  76. package/build/dist/Server/Services/ScheduledMaintenanceStateService.js +52 -4
  77. package/build/dist/Server/Services/ScheduledMaintenanceStateService.js.map +1 -1
  78. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +28 -1
  79. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  80. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +10 -0
  81. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  82. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.js +37 -0
  83. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.js.map +1 -0
  84. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.js +82 -0
  85. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.js.map +1 -0
  86. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.js +33 -99
  87. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.js.map +1 -1
  88. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.js +74 -0
  89. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.js.map +1 -0
  90. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js +20 -2
  91. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js.map +1 -1
  92. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js +425 -0
  93. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js.map +1 -0
  94. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js +2 -0
  95. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js.map +1 -1
  96. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js +5 -2
  97. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js.map +1 -1
  98. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js +599 -0
  99. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js.map +1 -0
  100. package/build/dist/Server/Utils/Workspace/Slack/Messages/Alert.js +82 -0
  101. package/build/dist/Server/Utils/Workspace/Slack/Messages/Alert.js.map +1 -0
  102. package/build/dist/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.js +74 -0
  103. package/build/dist/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.js.map +1 -0
  104. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +34 -0
  105. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  106. package/build/dist/Server/Utils/Workspace/Slack/app-manifest.json +3 -3
  107. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js +8 -0
  108. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
  109. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/Alert.js +48 -0
  110. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/Alert.js.map +1 -0
  111. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/ScheduledMaintenance.js +47 -0
  112. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/ScheduledMaintenance.js.map +1 -0
  113. package/build/dist/Types/Date.js +4 -0
  114. package/build/dist/Types/Date.js.map +1 -1
  115. package/package.json +2 -2
@@ -0,0 +1,697 @@
1
+ import BadDataException from "../../../../../Types/Exception/BadDataException";
2
+ import ObjectID from "../../../../../Types/ObjectID";
3
+ import AlertService from "../../../../Services/AlertService";
4
+ import { ExpressRequest, ExpressResponse } from "../../../Express";
5
+ import SlackUtil from "../Slack";
6
+ import SlackActionType from "./ActionTypes";
7
+ import { SlackAction, SlackRequest } from "./Auth";
8
+ import Response from "../../../Response";
9
+ import {
10
+ WorkspaceDropdownBlock,
11
+ WorkspaceModalBlock,
12
+ WorkspacePayloadMarkdown,
13
+ WorkspaceTextAreaBlock,
14
+ } from "../../../../../Types/Workspace/WorkspaceMessagePayload";
15
+ import AlertInternalNoteService from "../../../../Services/AlertInternalNoteService";
16
+ import OnCallDutyPolicy from "../../../../../Models/DatabaseModels/OnCallDutyPolicy";
17
+ import OnCallDutyPolicyService from "../../../../Services/OnCallDutyPolicyService";
18
+ import { LIMIT_PER_PROJECT } from "../../../../../Types/Database/LimitMax";
19
+ import { DropdownOption } from "../../../../../UI/Components/Dropdown/Dropdown";
20
+ import UserNotificationEventType from "../../../../../Types/UserNotification/UserNotificationEventType";
21
+ import AlertState from "../../../../../Models/DatabaseModels/AlertState";
22
+ import AlertStateService from "../../../../Services/AlertStateService";
23
+ import logger from "../../../Logger";
24
+ import AccessTokenService from "../../../../Services/AccessTokenService";
25
+
26
+ export default class SlackAlertActions {
27
+ public static isAlertAction(data: { actionType: SlackActionType }): boolean {
28
+ const { actionType } = data;
29
+
30
+ switch (actionType) {
31
+ case SlackActionType.AcknowledgeAlert:
32
+ case SlackActionType.ResolveAlert:
33
+ case SlackActionType.ViewAddAlertNote:
34
+ case SlackActionType.SubmitAlertNote:
35
+ case SlackActionType.ViewChangeAlertState:
36
+ case SlackActionType.SubmitChangeAlertState:
37
+ case SlackActionType.ViewExecuteAlertOnCallPolicy:
38
+ case SlackActionType.SubmitExecuteAlertOnCallPolicy:
39
+ case SlackActionType.ViewAlert:
40
+ return true;
41
+ default:
42
+ return false;
43
+ }
44
+ }
45
+
46
+ public static async acknowledgeAlert(data: {
47
+ slackRequest: SlackRequest;
48
+ action: SlackAction;
49
+ req: ExpressRequest;
50
+ res: ExpressResponse;
51
+ }): Promise<void> {
52
+ const { slackRequest, req, res } = data;
53
+ const { botUserId, userId, projectAuthToken, slackUsername } = slackRequest;
54
+
55
+ const { actionValue } = data.action;
56
+
57
+ if (!actionValue) {
58
+ return Response.sendErrorResponse(
59
+ req,
60
+ res,
61
+ new BadDataException("Invalid Alert ID"),
62
+ );
63
+ }
64
+
65
+ if (!userId) {
66
+ return Response.sendErrorResponse(
67
+ req,
68
+ res,
69
+ new BadDataException("Invalid User ID"),
70
+ );
71
+ }
72
+
73
+ if (!projectAuthToken) {
74
+ return Response.sendErrorResponse(
75
+ req,
76
+ res,
77
+ new BadDataException("Invalid Project Auth Token"),
78
+ );
79
+ }
80
+
81
+ if (!botUserId) {
82
+ return Response.sendErrorResponse(
83
+ req,
84
+ res,
85
+ new BadDataException("Invalid Bot User ID"),
86
+ );
87
+ }
88
+
89
+ if (data.action.actionType === SlackActionType.AcknowledgeAlert) {
90
+ const alertId: ObjectID = new ObjectID(actionValue);
91
+
92
+ // We send this early let slack know we're ok. We'll do the rest in the background.
93
+ Response.sendJsonObjectResponse(req, res, {
94
+ response_action: "clear",
95
+ });
96
+
97
+ const isAlreadyAcknowledged: boolean =
98
+ await AlertService.isAlertAcknowledged({
99
+ alertId: alertId,
100
+ });
101
+
102
+ if (isAlreadyAcknowledged) {
103
+ const alertNumber: number | null = await AlertService.getAlertNumber({
104
+ alertId: alertId,
105
+ });
106
+
107
+ // send a message to the channel visible to user, that the alert has already been acknowledged.
108
+ const markdwonPayload: WorkspacePayloadMarkdown = {
109
+ _type: "WorkspacePayloadMarkdown",
110
+ text: `@${slackUsername}, unfortunately you cannot acknowledge the **[Alert ${alertNumber?.toString()}](${await AlertService.getAlertLinkInDashboard(slackRequest.projectId!, alertId)})**. It has already been acknowledged.`,
111
+ };
112
+
113
+ await SlackUtil.sendDirectMessageToUser({
114
+ messageBlocks: [markdwonPayload],
115
+ authToken: projectAuthToken,
116
+ workspaceUserId: slackRequest.slackUserId!,
117
+ });
118
+
119
+ return;
120
+ }
121
+
122
+ await AlertService.acknowledgeAlert(alertId, userId);
123
+
124
+ // Alert Feed will send a message to the channel that the alert has been Acknowledged.
125
+ return;
126
+ }
127
+
128
+ // invlaid action type.
129
+ return Response.sendErrorResponse(
130
+ req,
131
+ res,
132
+ new BadDataException("Invalid Action Type"),
133
+ );
134
+ }
135
+
136
+ public static async resolveAlert(data: {
137
+ slackRequest: SlackRequest;
138
+ action: SlackAction;
139
+ req: ExpressRequest;
140
+ res: ExpressResponse;
141
+ }): Promise<void> {
142
+ const { slackRequest, req, res } = data;
143
+ const { botUserId, userId, projectAuthToken, slackUsername } = slackRequest;
144
+
145
+ const { actionValue } = data.action;
146
+
147
+ if (!actionValue) {
148
+ return Response.sendErrorResponse(
149
+ req,
150
+ res,
151
+ new BadDataException("Invalid Alert ID"),
152
+ );
153
+ }
154
+
155
+ if (!userId) {
156
+ return Response.sendErrorResponse(
157
+ req,
158
+ res,
159
+ new BadDataException("Invalid User ID"),
160
+ );
161
+ }
162
+
163
+ if (!projectAuthToken) {
164
+ return Response.sendErrorResponse(
165
+ req,
166
+ res,
167
+ new BadDataException("Invalid Project Auth Token"),
168
+ );
169
+ }
170
+
171
+ if (!botUserId) {
172
+ return Response.sendErrorResponse(
173
+ req,
174
+ res,
175
+ new BadDataException("Invalid Bot User ID"),
176
+ );
177
+ }
178
+
179
+ if (data.action.actionType === SlackActionType.ResolveAlert) {
180
+ const alertId: ObjectID = new ObjectID(actionValue);
181
+
182
+ // We send this early let slack know we're ok. We'll do the rest in the background.
183
+ Response.sendJsonObjectResponse(req, res, {
184
+ response_action: "clear",
185
+ });
186
+
187
+ const isAlreadyResolved: boolean = await AlertService.isAlertResolved({
188
+ alertId: alertId,
189
+ });
190
+
191
+ if (isAlreadyResolved) {
192
+ const alertNumber: number | null = await AlertService.getAlertNumber({
193
+ alertId: alertId,
194
+ });
195
+ // send a message to the channel visible to user, that the alert has already been Resolved.
196
+ const markdwonPayload: WorkspacePayloadMarkdown = {
197
+ _type: "WorkspacePayloadMarkdown",
198
+ text: `@${slackUsername}, unfortunately you cannot resolve the **[Alert ${alertNumber?.toString()}](${await AlertService.getAlertLinkInDashboard(slackRequest.projectId!, alertId)})**. It has already been resolved.`,
199
+ };
200
+
201
+ await SlackUtil.sendDirectMessageToUser({
202
+ messageBlocks: [markdwonPayload],
203
+ authToken: projectAuthToken,
204
+ workspaceUserId: slackRequest.slackUserId!,
205
+ });
206
+
207
+ return;
208
+ }
209
+
210
+ await AlertService.resolveAlert(alertId, userId);
211
+
212
+ return;
213
+ }
214
+
215
+ // invlaid action type.
216
+ return Response.sendErrorResponse(
217
+ req,
218
+ res,
219
+ new BadDataException("Invalid Action Type"),
220
+ );
221
+ }
222
+
223
+ public static async viewExecuteOnCallPolicy(data: {
224
+ slackRequest: SlackRequest;
225
+ action: SlackAction;
226
+ req: ExpressRequest;
227
+ res: ExpressResponse;
228
+ }): Promise<void> {
229
+ const { req, res } = data;
230
+ const { actionValue } = data.action;
231
+
232
+ if (!actionValue) {
233
+ return Response.sendErrorResponse(
234
+ req,
235
+ res,
236
+ new BadDataException("Invalid Alert ID"),
237
+ );
238
+ }
239
+
240
+ // We send this early let slack know we're ok. We'll do the rest in the background.
241
+ Response.sendJsonObjectResponse(req, res, {
242
+ response_action: "clear",
243
+ });
244
+
245
+ // const alertId: ObjectID = new ObjectID(actionValue);
246
+
247
+ // send a modal with a dropdown that says "Public Note" or "Private Note" and a text area to add the note.
248
+
249
+ const onCallPolicies: Array<OnCallDutyPolicy> =
250
+ await OnCallDutyPolicyService.findBy({
251
+ query: {
252
+ projectId: data.slackRequest.projectId!,
253
+ },
254
+ select: {
255
+ name: true,
256
+ },
257
+ props: {
258
+ isRoot: true,
259
+ },
260
+ limit: LIMIT_PER_PROJECT,
261
+ skip: 0,
262
+ });
263
+
264
+ const dropdownOption: Array<DropdownOption> = onCallPolicies
265
+ .map((policy: OnCallDutyPolicy) => {
266
+ return {
267
+ label: policy.name || "",
268
+ value: policy._id?.toString() || "",
269
+ };
270
+ })
271
+ .filter((option: DropdownOption) => {
272
+ return option.label !== "" || option.value !== "";
273
+ });
274
+
275
+ const onCallPolicyDropdown: WorkspaceDropdownBlock = {
276
+ _type: "WorkspaceDropdownBlock",
277
+ label: "On Call Policy",
278
+ blockId: "onCallPolicy",
279
+ placeholder: "Select On Call Policy",
280
+ options: dropdownOption,
281
+ };
282
+
283
+ const modalBlock: WorkspaceModalBlock = {
284
+ _type: "WorkspaceModalBlock",
285
+ title: "Execute On Call Policy",
286
+ submitButtonTitle: "Submit",
287
+ cancelButtonTitle: "Cancel",
288
+ actionId: SlackActionType.SubmitExecuteAlertOnCallPolicy,
289
+ actionValue: actionValue,
290
+ blocks: [onCallPolicyDropdown],
291
+ };
292
+
293
+ await SlackUtil.showModalToUser({
294
+ authToken: data.slackRequest.projectAuthToken!,
295
+ modalBlock: modalBlock,
296
+ triggerId: data.slackRequest.triggerId!,
297
+ });
298
+ }
299
+
300
+ public static async viewChangeAlertState(data: {
301
+ slackRequest: SlackRequest;
302
+ action: SlackAction;
303
+ req: ExpressRequest;
304
+ res: ExpressResponse;
305
+ }): Promise<void> {
306
+ const { req, res } = data;
307
+ const { actionValue } = data.action;
308
+
309
+ if (!actionValue) {
310
+ return Response.sendErrorResponse(
311
+ req,
312
+ res,
313
+ new BadDataException("Invalid Alert ID"),
314
+ );
315
+ }
316
+
317
+ // We send this early let slack know we're ok. We'll do the rest in the background.
318
+ Response.sendJsonObjectResponse(req, res, {
319
+ response_action: "clear",
320
+ });
321
+
322
+ // const alertId: ObjectID = new ObjectID(actionValue);
323
+
324
+ // send a modal with a dropdown that says "Public Note" or "Private Note" and a text area to add the note.
325
+
326
+ const alertStates: Array<AlertState> =
327
+ await AlertStateService.getAllAlertStates({
328
+ projectId: data.slackRequest.projectId!,
329
+ props: {
330
+ isRoot: true,
331
+ },
332
+ });
333
+
334
+ logger.debug("Alert States: ");
335
+ logger.debug(alertStates);
336
+
337
+ const dropdownOptions: Array<DropdownOption> = alertStates
338
+ .map((state: AlertState) => {
339
+ return {
340
+ label: state.name || "",
341
+ value: state._id?.toString() || "",
342
+ };
343
+ })
344
+ .filter((option: DropdownOption) => {
345
+ return option.label !== "" || option.value !== "";
346
+ });
347
+
348
+ logger.debug("Dropdown Options: ");
349
+ logger.debug(dropdownOptions);
350
+
351
+ const statePickerDropdown: WorkspaceDropdownBlock = {
352
+ _type: "WorkspaceDropdownBlock",
353
+ label: "Alert State",
354
+ blockId: "alertState",
355
+ placeholder: "Select Alert State",
356
+ options: dropdownOptions,
357
+ };
358
+
359
+ const modalBlock: WorkspaceModalBlock = {
360
+ _type: "WorkspaceModalBlock",
361
+ title: "Change Alert State",
362
+ submitButtonTitle: "Submit",
363
+ cancelButtonTitle: "Cancel",
364
+ actionId: SlackActionType.SubmitChangeAlertState,
365
+ actionValue: actionValue,
366
+ blocks: [statePickerDropdown],
367
+ };
368
+
369
+ await SlackUtil.showModalToUser({
370
+ authToken: data.slackRequest.projectAuthToken!,
371
+ modalBlock: modalBlock,
372
+ triggerId: data.slackRequest.triggerId!,
373
+ });
374
+ }
375
+
376
+ public static async submitChangeAlertState(data: {
377
+ slackRequest: SlackRequest;
378
+ action: SlackAction;
379
+ req: ExpressRequest;
380
+ res: ExpressResponse;
381
+ }): Promise<void> {
382
+ const { req, res } = data;
383
+ const { actionValue } = data.action;
384
+
385
+ if (!actionValue) {
386
+ return Response.sendErrorResponse(
387
+ req,
388
+ res,
389
+ new BadDataException("Invalid Alert ID"),
390
+ );
391
+ }
392
+
393
+ // We send this early let slack know we're ok. We'll do the rest in the background.
394
+ Response.sendJsonObjectResponse(req, res, {
395
+ response_action: "clear",
396
+ });
397
+
398
+ // const alertId: ObjectID = new ObjectID(actionValue);
399
+
400
+ // send a modal with a dropdown that says "Public Note" or "Private Note" and a text area to add the note.
401
+
402
+ if (
403
+ !data.slackRequest.viewValues ||
404
+ !data.slackRequest.viewValues["alertState"]
405
+ ) {
406
+ return Response.sendErrorResponse(
407
+ req,
408
+ res,
409
+ new BadDataException("Invalid View Values"),
410
+ );
411
+ }
412
+
413
+ const alertId: ObjectID = new ObjectID(actionValue);
414
+ const stateString: string =
415
+ data.slackRequest.viewValues["alertState"].toString();
416
+
417
+ const stateId: ObjectID = new ObjectID(stateString);
418
+
419
+ await AlertService.updateOneById({
420
+ id: alertId,
421
+ data: {
422
+ currentAlertStateId: stateId,
423
+ },
424
+ props:
425
+ await AccessTokenService.getDatabaseCommonInteractionPropsByUserAndProject(
426
+ {
427
+ userId: data.slackRequest.userId!,
428
+ projectId: data.slackRequest.projectId!,
429
+ },
430
+ ),
431
+ });
432
+ }
433
+
434
+ public static async executeOnCallPolicy(data: {
435
+ slackRequest: SlackRequest;
436
+ action: SlackAction;
437
+ req: ExpressRequest;
438
+ res: ExpressResponse;
439
+ }): Promise<void> {
440
+ const { slackRequest, req, res } = data;
441
+ const { botUserId, userId, projectAuthToken, slackUsername } = slackRequest;
442
+
443
+ const { actionValue } = data.action;
444
+
445
+ if (!actionValue) {
446
+ return Response.sendErrorResponse(
447
+ req,
448
+ res,
449
+ new BadDataException("Invalid Alert ID"),
450
+ );
451
+ }
452
+
453
+ if (!userId) {
454
+ return Response.sendErrorResponse(
455
+ req,
456
+ res,
457
+ new BadDataException("Invalid User ID"),
458
+ );
459
+ }
460
+
461
+ if (!projectAuthToken) {
462
+ return Response.sendErrorResponse(
463
+ req,
464
+ res,
465
+ new BadDataException("Invalid Project Auth Token"),
466
+ );
467
+ }
468
+
469
+ if (!botUserId) {
470
+ return Response.sendErrorResponse(
471
+ req,
472
+ res,
473
+ new BadDataException("Invalid Bot User ID"),
474
+ );
475
+ }
476
+
477
+ if (
478
+ data.action.actionType === SlackActionType.SubmitExecuteAlertOnCallPolicy
479
+ ) {
480
+ const alertId: ObjectID = new ObjectID(actionValue);
481
+
482
+ // We send this early let slack know we're ok. We'll do the rest in the background.
483
+ Response.sendJsonObjectResponse(req, res, {
484
+ response_action: "clear",
485
+ });
486
+
487
+ const isAlreadyResolved: boolean = await AlertService.isAlertResolved({
488
+ alertId: alertId,
489
+ });
490
+
491
+ if (isAlreadyResolved) {
492
+ const alertNumber: number | null = await AlertService.getAlertNumber({
493
+ alertId: alertId,
494
+ });
495
+ // send a message to the channel visible to user, that the alert has already been Resolved.
496
+ const markdwonPayload: WorkspacePayloadMarkdown = {
497
+ _type: "WorkspacePayloadMarkdown",
498
+ text: `@${slackUsername}, unfortunately you cannot execute the on call policy for **[Alert ${alertNumber?.toString()}](${await AlertService.getAlertLinkInDashboard(slackRequest.projectId!, alertId)})**. It has already been resolved.`,
499
+ };
500
+
501
+ await SlackUtil.sendDirectMessageToUser({
502
+ messageBlocks: [markdwonPayload],
503
+ authToken: projectAuthToken,
504
+ workspaceUserId: slackRequest.slackUserId!,
505
+ });
506
+
507
+ return;
508
+ }
509
+
510
+ if (
511
+ !data.slackRequest.viewValues ||
512
+ !data.slackRequest.viewValues["onCallPolicy"]
513
+ ) {
514
+ return Response.sendErrorResponse(
515
+ req,
516
+ res,
517
+ new BadDataException("Invalid View Values"),
518
+ );
519
+ }
520
+
521
+ const onCallPolicyString: string =
522
+ data.slackRequest.viewValues["onCallPolicy"].toString();
523
+
524
+ // get the on call policy id.
525
+ const onCallPolicyId: ObjectID = new ObjectID(onCallPolicyString);
526
+
527
+ await OnCallDutyPolicyService.executePolicy(onCallPolicyId, {
528
+ triggeredByAlertId: alertId,
529
+ userNotificationEventType: UserNotificationEventType.AlertCreated,
530
+ });
531
+ }
532
+ }
533
+
534
+ public static async submitAlertNote(data: {
535
+ slackRequest: SlackRequest;
536
+ action: SlackAction;
537
+ req: ExpressRequest;
538
+ res: ExpressResponse;
539
+ }): Promise<void> {
540
+ const { req, res } = data;
541
+ const { actionValue } = data.action;
542
+
543
+ if (!actionValue) {
544
+ return Response.sendErrorResponse(
545
+ req,
546
+ res,
547
+ new BadDataException("Invalid Alert ID"),
548
+ );
549
+ }
550
+
551
+ // const alertId: ObjectID = new ObjectID(actionValue);
552
+
553
+ // send a modal with a dropdown that says "Public Note" or "Private Note" and a text area to add the note.
554
+
555
+ // if view values is empty, then return error.
556
+
557
+ if (!data.slackRequest.viewValues) {
558
+ return Response.sendErrorResponse(
559
+ req,
560
+ res,
561
+ new BadDataException("Invalid View Values"),
562
+ );
563
+ }
564
+
565
+ if (!data.slackRequest.viewValues["note"]) {
566
+ // return error.
567
+ return Response.sendErrorResponse(
568
+ req,
569
+ res,
570
+ new BadDataException("Invalid Note"),
571
+ );
572
+ }
573
+
574
+ const alertId: ObjectID = new ObjectID(actionValue);
575
+ const note: string = data.slackRequest.viewValues["note"].toString();
576
+
577
+ // send empty response.
578
+ Response.sendJsonObjectResponse(req, res, {
579
+ response_action: "clear",
580
+ });
581
+
582
+ await AlertInternalNoteService.addNote({
583
+ alertId: alertId!,
584
+ note: note || "",
585
+ projectId: data.slackRequest.projectId!,
586
+ userId: data.slackRequest.userId!,
587
+ });
588
+ }
589
+
590
+ public static async viewAddAlertNote(data: {
591
+ slackRequest: SlackRequest;
592
+ action: SlackAction;
593
+ req: ExpressRequest;
594
+ res: ExpressResponse;
595
+ }): Promise<void> {
596
+ const { req, res } = data;
597
+ const { actionValue } = data.action;
598
+
599
+ if (!actionValue) {
600
+ return Response.sendErrorResponse(
601
+ req,
602
+ res,
603
+ new BadDataException("Invalid Alert ID"),
604
+ );
605
+ }
606
+
607
+ // We send this early let slack know we're ok. We'll do the rest in the background.
608
+ Response.sendJsonObjectResponse(req, res, {
609
+ response_action: "clear",
610
+ });
611
+
612
+ // const alertId: ObjectID = new ObjectID(actionValue);
613
+
614
+ // send a modal with a dropdown that says "Public Note" or "Private Note" and a text area to add the note.
615
+
616
+ const noteTextArea: WorkspaceTextAreaBlock = {
617
+ _type: "WorkspaceTextAreaBlock",
618
+ label: "Note",
619
+ blockId: "note",
620
+ placeholder: "Note",
621
+ description: "Please type in plain text or markdown.",
622
+ };
623
+
624
+ const modalBlock: WorkspaceModalBlock = {
625
+ _type: "WorkspaceModalBlock",
626
+ title: "Add Note",
627
+ submitButtonTitle: "Submit",
628
+ cancelButtonTitle: "Cancel",
629
+ actionId: SlackActionType.SubmitAlertNote,
630
+ actionValue: actionValue,
631
+ blocks: [noteTextArea],
632
+ };
633
+
634
+ await SlackUtil.showModalToUser({
635
+ authToken: data.slackRequest.projectAuthToken!,
636
+ modalBlock: modalBlock,
637
+ triggerId: data.slackRequest.triggerId!,
638
+ });
639
+ }
640
+
641
+ public static async handleAlertAction(data: {
642
+ slackRequest: SlackRequest;
643
+ action: SlackAction;
644
+ req: ExpressRequest;
645
+ res: ExpressResponse;
646
+ }): Promise<void> {
647
+ // now we should be all set, project is authorized and user is authorized. Lets perform some actions based on the action type.
648
+ const actionType: SlackActionType | undefined = data.action.actionType;
649
+
650
+ if (actionType === SlackActionType.AcknowledgeAlert) {
651
+ return await this.acknowledgeAlert(data);
652
+ }
653
+
654
+ if (actionType === SlackActionType.ResolveAlert) {
655
+ return await this.resolveAlert(data);
656
+ }
657
+
658
+ if (actionType === SlackActionType.ViewAddAlertNote) {
659
+ return await this.viewAddAlertNote(data);
660
+ }
661
+
662
+ if (actionType === SlackActionType.SubmitAlertNote) {
663
+ return await this.submitAlertNote(data);
664
+ }
665
+
666
+ if (actionType === SlackActionType.ViewExecuteAlertOnCallPolicy) {
667
+ return await this.viewExecuteOnCallPolicy(data);
668
+ }
669
+
670
+ if (actionType === SlackActionType.SubmitExecuteAlertOnCallPolicy) {
671
+ return await this.executeOnCallPolicy(data);
672
+ }
673
+
674
+ if (actionType === SlackActionType.ViewChangeAlertState) {
675
+ return await this.viewChangeAlertState(data);
676
+ }
677
+
678
+ if (actionType === SlackActionType.SubmitChangeAlertState) {
679
+ return await this.submitChangeAlertState(data);
680
+ }
681
+
682
+ if (actionType === SlackActionType.ViewAlert) {
683
+ // do nothing. This is just a view alert action.
684
+ // clear response.
685
+ return Response.sendJsonObjectResponse(data.req, data.res, {
686
+ response_action: "clear",
687
+ });
688
+ }
689
+
690
+ // invalid action type.
691
+ return Response.sendErrorResponse(
692
+ data.req,
693
+ data.res,
694
+ new BadDataException("Invalid Action Type"),
695
+ );
696
+ }
697
+ }