@oneuptime/common 7.0.3717 → 7.0.3786

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 (203) hide show
  1. package/Models/DatabaseModels/Alert.ts +3 -2
  2. package/Models/DatabaseModels/Incident.ts +3 -2
  3. package/Models/DatabaseModels/Index.ts +3 -0
  4. package/Models/DatabaseModels/ProjectUser.ts +335 -0
  5. package/Models/DatabaseModels/ScheduledMaintenance.ts +3 -2
  6. package/Server/API/SlackAPI.ts +65 -97
  7. package/Server/API/UserOnCallLogTimelineAPI.ts +2 -9
  8. package/Server/Infrastructure/Postgres/SchemaMigrations/1740597525803-MigrationName.ts +17 -0
  9. package/Server/Infrastructure/Postgres/SchemaMigrations/1740598793630-MigrationName.ts +17 -0
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/1741031019972-MigrationName.ts +17 -0
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/1741209339971-MigrationName.ts +101 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  13. package/Server/Middleware/SlackAuthorization.ts +11 -2
  14. package/Server/Services/AlertFeedService.ts +2 -2
  15. package/Server/Services/AlertInternalNoteService.ts +2 -2
  16. package/Server/Services/AlertOwnerTeamService.ts +4 -4
  17. package/Server/Services/AlertOwnerUserService.ts +3 -3
  18. package/Server/Services/AlertService.ts +62 -20
  19. package/Server/Services/AlertStateTimelineService.ts +8 -18
  20. package/Server/Services/IncidentFeedService.ts +101 -2
  21. package/Server/Services/IncidentInternalNoteService.ts +47 -4
  22. package/Server/Services/IncidentOwnerTeamService.ts +57 -4
  23. package/Server/Services/IncidentOwnerUserService.ts +59 -15
  24. package/Server/Services/IncidentPublicNoteService.ts +41 -4
  25. package/Server/Services/IncidentService.ts +279 -193
  26. package/Server/Services/IncidentStateService.ts +25 -0
  27. package/Server/Services/IncidentStateTimelineService.ts +37 -19
  28. package/Server/Services/MonitorStatusTimelineService.ts +7 -17
  29. package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +2 -0
  30. package/Server/Services/OnCallDutyPolicyExecutionLogService.ts +74 -7
  31. package/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.ts +63 -4
  32. package/Server/Services/OnCallDutyPolicyService.ts +13 -0
  33. package/Server/Services/ProjectUserService.ts +130 -0
  34. package/Server/Services/ScheduledMaintenanceFeedService.ts +2 -2
  35. package/Server/Services/ScheduledMaintenanceInternalNoteService.ts +12 -10
  36. package/Server/Services/ScheduledMaintenanceOwnerTeamService.ts +22 -18
  37. package/Server/Services/ScheduledMaintenanceOwnerUserService.ts +28 -30
  38. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +12 -10
  39. package/Server/Services/ScheduledMaintenanceService.ts +16 -10
  40. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +1 -1
  41. package/Server/Services/StatusPageSubscriberService.ts +3 -0
  42. package/Server/Services/TeamMemberService.ts +20 -0
  43. package/Server/Services/UserNotificationRuleService.ts +74 -0
  44. package/Server/Services/UserOnCallLogService.ts +1 -1
  45. package/Server/Services/UserService.ts +35 -0
  46. package/Server/Services/WorkspaceNotificationRuleService.ts +508 -149
  47. package/Server/Services/WorkspaceUserAuthTokenService.ts +23 -0
  48. package/Server/Utils/Express.ts +1 -1
  49. package/Server/Utils/StartServer.ts +6 -1
  50. package/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.ts +195 -0
  51. package/Server/Utils/Workspace/Slack/Actions/ActionTypes.ts +20 -0
  52. package/Server/Utils/Workspace/Slack/Actions/Auth.ts +266 -0
  53. package/Server/Utils/Workspace/Slack/Actions/Incident.ts +1117 -0
  54. package/Server/Utils/Workspace/Slack/Messages/Incident.ts +116 -0
  55. package/Server/Utils/Workspace/Slack/Slack.ts +555 -18
  56. package/Server/Utils/Workspace/Slack/app-manifest.json +18 -10
  57. package/Server/Utils/Workspace/Workspace.ts +194 -1
  58. package/Server/Utils/Workspace/WorkspaceBase.ts +145 -19
  59. package/Server/Utils/Workspace/WorkspaceMessages/Incident.ts +68 -0
  60. package/Types/Icon/IconProp.ts +1 -0
  61. package/Types/Workspace/NotificationRules/NotificationRuleCondition.ts +2 -1
  62. package/Types/Workspace/NotificationRules/NotificationRuleUtil.ts +251 -121
  63. package/Types/Workspace/NotificationRules/NotificationRuleWorkspaceChannel.ts +6 -0
  64. package/Types/Workspace/WorkspaceMessagePayload.ts +71 -2
  65. package/UI/Components/ComingSoon/ComingSoon.tsx +13 -3
  66. package/UI/Components/Forms/Fields/FormField.tsx +2 -2
  67. package/UI/Components/Icon/Icon.tsx +39 -2
  68. package/UI/Components/ModelTable/BaseModelTable.tsx +16 -0
  69. package/UI/Components/Radio/Radio.tsx +11 -2
  70. package/UI/Components/Table/TableCard.tsx +2 -2
  71. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  72. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  73. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  74. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  75. package/build/dist/Models/DatabaseModels/ProjectUser.js +340 -0
  76. package/build/dist/Models/DatabaseModels/ProjectUser.js.map +1 -0
  77. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  78. package/build/dist/Server/API/SlackAPI.js +39 -79
  79. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  80. package/build/dist/Server/API/UserOnCallLogTimelineAPI.js.map +1 -1
  81. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1740597525803-MigrationName.js +12 -0
  82. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1740597525803-MigrationName.js.map +1 -0
  83. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1740598793630-MigrationName.js +12 -0
  84. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1740598793630-MigrationName.js.map +1 -0
  85. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1741031019972-MigrationName.js +12 -0
  86. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1741031019972-MigrationName.js.map +1 -0
  87. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1741209339971-MigrationName.js +42 -0
  88. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1741209339971-MigrationName.js.map +1 -0
  89. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  90. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  91. package/build/dist/Server/Middleware/SlackAuthorization.js +8 -2
  92. package/build/dist/Server/Middleware/SlackAuthorization.js.map +1 -1
  93. package/build/dist/Server/Services/AlertFeedService.js +2 -2
  94. package/build/dist/Server/Services/AlertFeedService.js.map +1 -1
  95. package/build/dist/Server/Services/AlertInternalNoteService.js +2 -2
  96. package/build/dist/Server/Services/AlertInternalNoteService.js.map +1 -1
  97. package/build/dist/Server/Services/AlertOwnerTeamService.js +4 -4
  98. package/build/dist/Server/Services/AlertOwnerTeamService.js.map +1 -1
  99. package/build/dist/Server/Services/AlertOwnerUserService.js +3 -3
  100. package/build/dist/Server/Services/AlertOwnerUserService.js.map +1 -1
  101. package/build/dist/Server/Services/AlertService.js +44 -19
  102. package/build/dist/Server/Services/AlertService.js.map +1 -1
  103. package/build/dist/Server/Services/AlertStateTimelineService.js +6 -16
  104. package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
  105. package/build/dist/Server/Services/IncidentFeedService.js +62 -2
  106. package/build/dist/Server/Services/IncidentFeedService.js.map +1 -1
  107. package/build/dist/Server/Services/IncidentInternalNoteService.js +35 -4
  108. package/build/dist/Server/Services/IncidentInternalNoteService.js.map +1 -1
  109. package/build/dist/Server/Services/IncidentOwnerTeamService.js +42 -4
  110. package/build/dist/Server/Services/IncidentOwnerTeamService.js.map +1 -1
  111. package/build/dist/Server/Services/IncidentOwnerUserService.js +43 -15
  112. package/build/dist/Server/Services/IncidentOwnerUserService.js.map +1 -1
  113. package/build/dist/Server/Services/IncidentPublicNoteService.js +32 -4
  114. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  115. package/build/dist/Server/Services/IncidentService.js +221 -170
  116. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  117. package/build/dist/Server/Services/IncidentStateService.js +14 -0
  118. package/build/dist/Server/Services/IncidentStateService.js.map +1 -1
  119. package/build/dist/Server/Services/IncidentStateTimelineService.js +31 -17
  120. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  121. package/build/dist/Server/Services/MonitorStatusTimelineService.js +5 -15
  122. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  123. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +1 -0
  124. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
  125. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js +62 -7
  126. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js.map +1 -1
  127. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js +51 -5
  128. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js.map +1 -1
  129. package/build/dist/Server/Services/OnCallDutyPolicyService.js +6 -0
  130. package/build/dist/Server/Services/OnCallDutyPolicyService.js.map +1 -1
  131. package/build/dist/Server/Services/ProjectUserService.js +106 -0
  132. package/build/dist/Server/Services/ProjectUserService.js.map +1 -0
  133. package/build/dist/Server/Services/ScheduledMaintenanceFeedService.js +2 -2
  134. package/build/dist/Server/Services/ScheduledMaintenanceFeedService.js.map +1 -1
  135. package/build/dist/Server/Services/ScheduledMaintenanceInternalNoteService.js +2 -2
  136. package/build/dist/Server/Services/ScheduledMaintenanceInternalNoteService.js.map +1 -1
  137. package/build/dist/Server/Services/ScheduledMaintenanceOwnerTeamService.js +4 -4
  138. package/build/dist/Server/Services/ScheduledMaintenanceOwnerTeamService.js.map +1 -1
  139. package/build/dist/Server/Services/ScheduledMaintenanceOwnerUserService.js +8 -16
  140. package/build/dist/Server/Services/ScheduledMaintenanceOwnerUserService.js.map +1 -1
  141. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +2 -2
  142. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  143. package/build/dist/Server/Services/ScheduledMaintenanceService.js +5 -2
  144. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  145. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +1 -1
  146. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  147. package/build/dist/Server/Services/StatusPageSubscriberService.js +3 -0
  148. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  149. package/build/dist/Server/Services/TeamMemberService.js +17 -0
  150. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  151. package/build/dist/Server/Services/UserNotificationRuleService.js +52 -0
  152. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  153. package/build/dist/Server/Services/UserOnCallLogService.js +1 -1
  154. package/build/dist/Server/Services/UserOnCallLogService.js.map +1 -1
  155. package/build/dist/Server/Services/UserService.js +23 -0
  156. package/build/dist/Server/Services/UserService.js.map +1 -1
  157. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +306 -84
  158. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  159. package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js +18 -0
  160. package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js.map +1 -1
  161. package/build/dist/Server/Utils/StartServer.js +4 -0
  162. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  163. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.js +148 -0
  164. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.js.map +1 -0
  165. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js +19 -0
  166. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js.map +1 -0
  167. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js +167 -0
  168. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js.map +1 -0
  169. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js +727 -0
  170. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js.map +1 -0
  171. package/build/dist/Server/Utils/Workspace/Slack/Messages/Incident.js +82 -0
  172. package/build/dist/Server/Utils/Workspace/Slack/Messages/Incident.js.map +1 -0
  173. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +397 -14
  174. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  175. package/build/dist/Server/Utils/Workspace/Slack/app-manifest.json +18 -10
  176. package/build/dist/Server/Utils/Workspace/Workspace.js +126 -0
  177. package/build/dist/Server/Utils/Workspace/Workspace.js.map +1 -1
  178. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js +69 -11
  179. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
  180. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/Incident.js +47 -0
  181. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/Incident.js.map +1 -0
  182. package/build/dist/Types/Icon/IconProp.js +1 -0
  183. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  184. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js +2 -1
  185. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js.map +1 -1
  186. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleUtil.js +214 -120
  187. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleUtil.js.map +1 -1
  188. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleWorkspaceChannel.js +2 -0
  189. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleWorkspaceChannel.js.map +1 -0
  190. package/build/dist/UI/Components/ComingSoon/ComingSoon.js +3 -2
  191. package/build/dist/UI/Components/ComingSoon/ComingSoon.js.map +1 -1
  192. package/build/dist/UI/Components/Forms/Fields/FormField.js +2 -2
  193. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  194. package/build/dist/UI/Components/Icon/Icon.js +19 -2
  195. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  196. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +11 -0
  197. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  198. package/build/dist/UI/Components/Radio/Radio.js +5 -2
  199. package/build/dist/UI/Components/Radio/Radio.js.map +1 -1
  200. package/build/dist/UI/Components/Table/TableCard.js +2 -2
  201. package/build/dist/UI/Components/Table/TableCard.js.map +1 -1
  202. package/package.json +3 -2
  203. package/Server/Utils/Workspace/Slack/app-manifest.example.json +0 -198
@@ -4,17 +4,150 @@ import URL from "Common/Types/API/URL";
4
4
  import { JSONObject } from "Common/Types/JSON";
5
5
  import API from "Common/Utils/API";
6
6
  import WorkspaceMessagePayload, {
7
+ WorkspaceCheckboxBlock,
8
+ WorkspaceDropdownBlock,
9
+ WorkspaceMessageBlock,
7
10
  WorkspaceMessagePayloadButton,
11
+ WorkspaceModalBlock,
12
+ WorkspacePayloadButtons,
8
13
  WorkspacePayloadHeader,
14
+ WorkspacePayloadImage,
9
15
  WorkspacePayloadMarkdown,
16
+ WorkspaceTextAreaBlock,
17
+ WorkspaceTextBoxBlock,
10
18
  } from "../../../../Types/Workspace/WorkspaceMessagePayload";
11
19
  import logger from "../../Logger";
12
20
  import Dictionary from "../../../../Types/Dictionary";
13
21
  import BadRequestException from "../../../../Types/Exception/BadRequestException";
14
- import WorkspaceBase, { WorkspaceChannel } from "../WorkspaceBase";
22
+ import WorkspaceBase, {
23
+ WorkspaceChannel,
24
+ WorkspaceSendMessageResponse,
25
+ WorkspaceThread,
26
+ } from "../WorkspaceBase";
15
27
  import WorkspaceType from "../../../../Types/Workspace/WorkspaceType";
28
+ import SlackifyMarkdown from "slackify-markdown";
29
+ import { DropdownOption } from "../../../../UI/Components/Dropdown/Dropdown";
16
30
 
17
31
  export default class SlackUtil extends WorkspaceBase {
32
+ public static override async getUsernameFromUserId(data: {
33
+ authToken: string;
34
+ userId: string;
35
+ }): Promise<string> {
36
+ logger.debug("Getting username from user ID with data:");
37
+ logger.debug(data);
38
+
39
+ const response: HTTPErrorResponse | HTTPResponse<JSONObject> =
40
+ await API.post<JSONObject>(
41
+ URL.fromString("https://slack.com/api/users.info"),
42
+ {
43
+ user: data.userId,
44
+ },
45
+ {
46
+ Authorization: `Bearer ${data.authToken}`,
47
+ ["Content-Type"]: "application/x-www-form-urlencoded",
48
+ },
49
+ );
50
+
51
+ logger.debug("Response from Slack API for getting user info:");
52
+ logger.debug(response);
53
+
54
+ if (response instanceof HTTPErrorResponse) {
55
+ logger.error("Error response from Slack API:");
56
+ logger.error(response);
57
+ throw response;
58
+ }
59
+
60
+ // check for ok response
61
+ if ((response.jsonData as JSONObject)?.["ok"] !== true) {
62
+ logger.error("Invalid response from Slack API:");
63
+ logger.error(response.jsonData);
64
+ throw new BadRequestException("Invalid response");
65
+ }
66
+
67
+ if (
68
+ !((response.jsonData as JSONObject)?.["user"] as JSONObject)?.["name"]
69
+ ) {
70
+ logger.error("Invalid response from Slack API:");
71
+ logger.error(response.jsonData);
72
+ throw new Error("Invalid response");
73
+ }
74
+
75
+ const username: string = (
76
+ (response.jsonData as JSONObject)["user"] as JSONObject
77
+ )["name"] as string;
78
+
79
+ logger.debug("Username obtained:");
80
+ logger.debug(username);
81
+ return username;
82
+ }
83
+
84
+ public static override async showModalToUser(data: {
85
+ authToken: string;
86
+ triggerId: string;
87
+ modalBlock: WorkspaceModalBlock;
88
+ }): Promise<void> {
89
+ logger.debug("Showing modal to user with data:");
90
+ logger.debug(data);
91
+
92
+ const modalJson: JSONObject = this.getModalBlock({
93
+ payloadModalBlock: data.modalBlock,
94
+ });
95
+
96
+ logger.debug("Modal JSON generated:");
97
+ logger.debug(JSON.stringify(modalJson, null, 2));
98
+
99
+ // use view.open API to show modal
100
+ const result: HTTPErrorResponse | HTTPResponse<JSONObject> = await API.post(
101
+ URL.fromString("https://slack.com/api/views.open"),
102
+ {
103
+ trigger_id: data.triggerId,
104
+ view: modalJson,
105
+ },
106
+ {
107
+ Authorization: `Bearer ${data.authToken}`,
108
+ ["Content-Type"]: "application/json",
109
+ },
110
+ );
111
+
112
+ if (result instanceof HTTPErrorResponse) {
113
+ logger.error("Error response from Slack API:");
114
+ logger.error(result);
115
+ throw result;
116
+ }
117
+
118
+ if ((result.jsonData as JSONObject)?.["ok"] !== true) {
119
+ logger.error("Invalid response from Slack API:");
120
+ logger.error(result.jsonData);
121
+ throw new BadRequestException("Invalid response");
122
+ }
123
+
124
+ logger.debug("Modal shown to user successfully.");
125
+ }
126
+
127
+ public static override async sendDirectMessageToUser(data: {
128
+ authToken: string;
129
+ workspaceUserId: string;
130
+ messageBlocks: Array<WorkspaceMessageBlock>;
131
+ }): Promise<void> {
132
+ // Send direct message to user
133
+
134
+ const blocks: Array<JSONObject> = this.getBlocksFromWorkspaceMessagePayload(
135
+ {
136
+ messageBlocks: data.messageBlocks,
137
+ },
138
+ );
139
+
140
+ await this.sendPayloadBlocksToChannel({
141
+ authToken: data.authToken,
142
+ workspaceChannel: {
143
+ id: data.workspaceUserId,
144
+ name: "",
145
+ workspaceType: WorkspaceType.Slack,
146
+ },
147
+ blocks: blocks,
148
+ });
149
+ }
150
+
18
151
  public static override async joinChannel(data: {
19
152
  authToken: string;
20
153
  channelId: string;
@@ -300,11 +433,64 @@ export default class SlackUtil extends WorkspaceBase {
300
433
  return channels;
301
434
  }
302
435
 
436
+ public static override getDividerBlock(): JSONObject {
437
+ return {
438
+ type: "divider",
439
+ };
440
+ }
441
+
442
+ public static getValuesFromView(data: {
443
+ view: JSONObject;
444
+ }): Dictionary<string | number | Array<string | number>> {
445
+ logger.debug("Getting values from view with data:");
446
+ logger.debug(JSON.stringify(data, null, 2));
447
+
448
+ const slackView: JSONObject = data.view;
449
+ const values: Dictionary<string | number | Array<string | number>> = {};
450
+
451
+ if (!slackView["state"] || !(slackView["state"] as JSONObject)["values"]) {
452
+ return {};
453
+ }
454
+
455
+ for (const valueId in (slackView["state"] as JSONObject)[
456
+ "values"
457
+ ] as JSONObject) {
458
+ for (const blockId in (
459
+ (slackView["state"] as JSONObject)["values"] as JSONObject
460
+ )[valueId] as JSONObject) {
461
+ const valueObject: JSONObject = (
462
+ (slackView["state"] as JSONObject)["values"] as JSONObject
463
+ )[valueId] as JSONObject;
464
+ const value: JSONObject = valueObject[blockId] as JSONObject;
465
+ values[blockId] = value["value"] as string | number;
466
+
467
+ if ((value["selected_option"] as JSONObject)?.["value"]) {
468
+ values[blockId] = (value["selected_option"] as JSONObject)?.[
469
+ "value"
470
+ ] as string;
471
+ }
472
+
473
+ if (Array.isArray(value["selected_options"])) {
474
+ values[blockId] = (
475
+ value["selected_options"] as Array<JSONObject>
476
+ ).map((option: JSONObject) => {
477
+ return option["value"] as string | number;
478
+ });
479
+ }
480
+ }
481
+ }
482
+
483
+ logger.debug("Values obtained from view:");
484
+ logger.debug(values);
485
+
486
+ return values;
487
+ }
488
+
303
489
  public static override async sendMessage(data: {
304
490
  workspaceMessagePayload: WorkspaceMessagePayload;
305
491
  authToken: string; // which auth token should we use to send.
306
492
  userId: string;
307
- }): Promise<void> {
493
+ }): Promise<WorkspaceSendMessageResponse> {
308
494
  logger.debug("Sending message to Slack with data:");
309
495
  logger.debug(data);
310
496
 
@@ -323,7 +509,7 @@ export default class SlackUtil extends WorkspaceBase {
323
509
  logger.debug("Existing workspace channels:");
324
510
  logger.debug(existingWorkspaceChannels);
325
511
 
326
- const channelIdsToPostTo: Array<string> = [];
512
+ const workspaceChannelsToPostTo: Array<WorkspaceChannel> = [];
327
513
 
328
514
  for (let channelName of data.workspaceMessagePayload.channelNames) {
329
515
  if (channelName && channelName.startsWith("#")) {
@@ -338,21 +524,37 @@ export default class SlackUtil extends WorkspaceBase {
338
524
  }
339
525
 
340
526
  if (channel) {
341
- channelIdsToPostTo.push(channel.id);
527
+ workspaceChannelsToPostTo.push(channel);
342
528
  } else {
343
529
  logger.debug(`Channel ${channelName} does not exist.`);
344
530
  }
345
531
  }
346
532
 
533
+ // add channel ids.
534
+ for (const channelId of data.workspaceMessagePayload.channelIds) {
535
+ const channel: WorkspaceChannel = {
536
+ id: channelId,
537
+ name: "",
538
+ workspaceType: WorkspaceType.Slack,
539
+ };
540
+
541
+ workspaceChannelsToPostTo.push(channel);
542
+ }
543
+
347
544
  logger.debug("Channel IDs to post to:");
348
- logger.debug(channelIdsToPostTo);
545
+ logger.debug(workspaceChannelsToPostTo);
349
546
 
350
- for (const channelId of channelIdsToPostTo) {
547
+ const workspaspaceMessageResponse: WorkspaceSendMessageResponse = {
548
+ threads: [],
549
+ workspaceType: WorkspaceType.Slack,
550
+ };
551
+
552
+ for (const channel of workspaceChannelsToPostTo) {
351
553
  try {
352
554
  // check if the user is in the channel.
353
555
  const isUserInChannel: boolean = await this.isUserInChannel({
354
556
  authToken: data.authToken,
355
- channelId: channelId,
557
+ channelId: channel.id,
356
558
  userId: data.userId,
357
559
  });
358
560
 
@@ -360,29 +562,36 @@ export default class SlackUtil extends WorkspaceBase {
360
562
  // add user to the channel
361
563
  await this.joinChannel({
362
564
  authToken: data.authToken,
363
- channelId: channelId,
565
+ channelId: channel.id,
364
566
  });
365
567
  }
366
568
 
367
- await this.sendPayloadBlocksToChannel({
569
+ const thread: WorkspaceThread = await this.sendPayloadBlocksToChannel({
368
570
  authToken: data.authToken,
369
- channelId: channelId,
571
+ workspaceChannel: channel,
370
572
  blocks: blocks,
371
573
  });
372
574
 
373
- logger.debug(`Message sent to channel ID ${channelId} successfully.`);
575
+ workspaspaceMessageResponse.threads.push(thread);
576
+
577
+ logger.debug(`Message sent to channel ID ${channel.id} successfully.`);
374
578
  } catch (e) {
375
- logger.error(`Error sending message to channel ID ${channelId}:`);
579
+ logger.error(`Error sending message to channel ID ${channel.id}:`);
376
580
  logger.error(e);
377
581
  }
378
582
  }
583
+
584
+ logger.debug("Message sent successfully.");
585
+ logger.debug(workspaspaceMessageResponse);
586
+
587
+ return workspaspaceMessageResponse;
379
588
  }
380
589
 
381
590
  public static override async sendPayloadBlocksToChannel(data: {
382
591
  authToken: string;
383
- channelId: string;
592
+ workspaceChannel: WorkspaceChannel;
384
593
  blocks: Array<JSONObject>;
385
- }): Promise<void> {
594
+ }): Promise<WorkspaceThread> {
386
595
  logger.debug("Sending payload blocks to channel with data:");
387
596
  logger.debug(JSON.stringify(data, null, 2));
388
597
 
@@ -390,8 +599,9 @@ export default class SlackUtil extends WorkspaceBase {
390
599
  await API.post(
391
600
  URL.fromString("https://slack.com/api/chat.postMessage"),
392
601
  {
393
- channel: data.channelId,
602
+ channel: data.workspaceChannel.id,
394
603
  blocks: data.blocks,
604
+ unfurl_links: false,
395
605
  },
396
606
  {
397
607
  Authorization: `Bearer ${data.authToken}`,
@@ -415,12 +625,44 @@ export default class SlackUtil extends WorkspaceBase {
415
625
  }
416
626
 
417
627
  logger.debug("Payload blocks sent to channel successfully.");
628
+
629
+ return {
630
+ channel: data.workspaceChannel,
631
+ threadId: (response.jsonData as JSONObject)["ts"] as string,
632
+ };
633
+ }
634
+
635
+ public static override getButtonsBlock(data: {
636
+ payloadButtonsBlock: WorkspacePayloadButtons;
637
+ }): JSONObject {
638
+ logger.debug("Getting buttons block with data:");
639
+ logger.debug(data);
640
+
641
+ const buttonsBlock: JSONObject = {
642
+ type: "actions",
643
+ elements: data.payloadButtonsBlock.buttons.map(
644
+ (button: WorkspaceMessagePayloadButton) => {
645
+ return this.getButtonBlock({ payloadButtonBlock: button });
646
+ },
647
+ ),
648
+ };
649
+
650
+ logger.debug("Buttons block generated:");
651
+ logger.debug(buttonsBlock);
652
+ return buttonsBlock;
418
653
  }
419
654
 
420
655
  public static override async createChannel(data: {
421
656
  authToken: string;
422
657
  channelName: string;
423
658
  }): Promise<WorkspaceChannel> {
659
+ if (data.channelName && data.channelName.startsWith("#")) {
660
+ data.channelName = data.channelName.substring(1);
661
+ }
662
+
663
+ // lower case channel name
664
+ data.channelName = data.channelName.toLowerCase();
665
+
424
666
  logger.debug("Creating channel with data:");
425
667
  logger.debug(data);
426
668
 
@@ -495,6 +737,251 @@ export default class SlackUtil extends WorkspaceBase {
495
737
  return headerBlock;
496
738
  }
497
739
 
740
+ public static override getCheckboxBlock(data: {
741
+ payloadCheckboxBlock: WorkspaceCheckboxBlock;
742
+ }): JSONObject {
743
+ logger.debug("Getting checkbox block with data:");
744
+ logger.debug(data);
745
+
746
+ const checkboxBlock: JSONObject = {
747
+ type: "input",
748
+ element: {
749
+ type: "checkboxes",
750
+ action_id: data.payloadCheckboxBlock.blockId,
751
+ options: [
752
+ {
753
+ text: {
754
+ type: "plain_text",
755
+ text: data.payloadCheckboxBlock.label,
756
+ },
757
+ value: "value",
758
+ },
759
+ ],
760
+ initial_options: data.payloadCheckboxBlock.initialValue
761
+ ? [
762
+ {
763
+ text: {
764
+ type: "plain_text",
765
+ text: data.payloadCheckboxBlock.label,
766
+ },
767
+ value: "value",
768
+ },
769
+ ]
770
+ : undefined,
771
+ },
772
+ label: {
773
+ type: "plain_text",
774
+ text: data.payloadCheckboxBlock.label,
775
+ },
776
+ };
777
+
778
+ // if description then add hint.
779
+
780
+ if (data.payloadCheckboxBlock.description) {
781
+ checkboxBlock["hint"] = {
782
+ type: "plain_text",
783
+ text: data.payloadCheckboxBlock.description,
784
+ };
785
+ }
786
+
787
+ logger.debug("Checkbox block generated:");
788
+ logger.debug(checkboxBlock);
789
+ return checkboxBlock;
790
+ }
791
+
792
+ public static override getTextAreaBlock(data: {
793
+ payloadTextAreaBlock: WorkspaceTextAreaBlock;
794
+ }): JSONObject {
795
+ logger.debug("Getting text area block with data:");
796
+ logger.debug(data);
797
+
798
+ const optional: boolean = data.payloadTextAreaBlock.optional || false;
799
+
800
+ const textAreaBlock: JSONObject = {
801
+ type: "input",
802
+ optional: optional,
803
+ element: {
804
+ type: "plain_text_input",
805
+ multiline: true,
806
+ action_id: data.payloadTextAreaBlock.blockId,
807
+ placeholder: {
808
+ type: "plain_text",
809
+ text: data.payloadTextAreaBlock.placeholder,
810
+ },
811
+ initial_value: data.payloadTextAreaBlock.initialValue,
812
+ },
813
+ label: {
814
+ type: "plain_text",
815
+ text: data.payloadTextAreaBlock.label,
816
+ },
817
+ };
818
+
819
+ // if description then add hint.
820
+
821
+ if (data.payloadTextAreaBlock.description) {
822
+ textAreaBlock["hint"] = {
823
+ type: "plain_text",
824
+ text: data.payloadTextAreaBlock.description,
825
+ };
826
+ }
827
+
828
+ logger.debug("Text area block generated:");
829
+ logger.debug(textAreaBlock);
830
+ return textAreaBlock;
831
+ }
832
+
833
+ public static override getTextBoxBlock(data: {
834
+ payloadTextBoxBlock: WorkspaceTextBoxBlock;
835
+ }): JSONObject {
836
+ logger.debug("Getting text box block with data:");
837
+ logger.debug(data);
838
+
839
+ const optional: boolean = data.payloadTextBoxBlock.optional || false;
840
+
841
+ const textBoxBlock: JSONObject = {
842
+ type: "input",
843
+ optional: optional,
844
+ element: {
845
+ type: "plain_text_input",
846
+ action_id: data.payloadTextBoxBlock.blockId,
847
+ placeholder: {
848
+ type: "plain_text",
849
+ text: data.payloadTextBoxBlock.placeholder,
850
+ },
851
+ initial_value: data.payloadTextBoxBlock.initialValue,
852
+ },
853
+ label: {
854
+ type: "plain_text",
855
+ text: data.payloadTextBoxBlock.label,
856
+ },
857
+ };
858
+
859
+ // if description then add hint.
860
+
861
+ if (data.payloadTextBoxBlock.description) {
862
+ textBoxBlock["hint"] = {
863
+ type: "plain_text",
864
+ text: data.payloadTextBoxBlock.description,
865
+ };
866
+ }
867
+
868
+ logger.debug("Text box block generated:");
869
+ logger.debug(textBoxBlock);
870
+ return textBoxBlock;
871
+ }
872
+
873
+ public static override getImageBlock(data: {
874
+ payloadImageBlock: WorkspacePayloadImage;
875
+ }): JSONObject {
876
+ logger.debug("Getting image block with data:");
877
+ logger.debug(data);
878
+
879
+ const imageBlock: JSONObject = {
880
+ type: "image",
881
+ image_url: data.payloadImageBlock.imageUrl.toString(),
882
+ alt_text: data.payloadImageBlock.altText,
883
+ };
884
+
885
+ logger.debug("Image block generated:");
886
+ logger.debug(imageBlock);
887
+ return imageBlock;
888
+ }
889
+
890
+ public static override getDropdownBlock(data: {
891
+ payloadDropdownBlock: WorkspaceDropdownBlock;
892
+ }): JSONObject {
893
+ logger.debug("Getting dropdown block with data:");
894
+ logger.debug(data);
895
+
896
+ const optional: boolean = data.payloadDropdownBlock.optional || false;
897
+
898
+ const isMiltiSelect: boolean =
899
+ data.payloadDropdownBlock.multiSelect || false;
900
+
901
+ const dropdownBlock: JSONObject = {
902
+ type: "input",
903
+ optional: optional,
904
+ element: {
905
+ type: isMiltiSelect ? "multi_static_select" : "static_select",
906
+ action_id: data.payloadDropdownBlock.blockId,
907
+ placeholder: {
908
+ type: "plain_text",
909
+ text: data.payloadDropdownBlock.placeholder,
910
+ },
911
+ options: data.payloadDropdownBlock.options.map(
912
+ (option: DropdownOption) => {
913
+ return {
914
+ text: {
915
+ type: "plain_text",
916
+ text: option.label,
917
+ },
918
+ value: option.value,
919
+ };
920
+ },
921
+ ),
922
+ initial_option: data.payloadDropdownBlock.initialValue
923
+ ? {
924
+ text: {
925
+ type: "plain_text",
926
+ text: data.payloadDropdownBlock.initialValue,
927
+ },
928
+ value: data.payloadDropdownBlock.initialValue,
929
+ }
930
+ : undefined,
931
+ },
932
+
933
+ label: {
934
+ type: "plain_text",
935
+ text: data.payloadDropdownBlock.label,
936
+ },
937
+ };
938
+
939
+ // if description then add hint.
940
+
941
+ if (data.payloadDropdownBlock.description) {
942
+ dropdownBlock["hint"] = {
943
+ type: "plain_text",
944
+ text: data.payloadDropdownBlock.description,
945
+ };
946
+ }
947
+
948
+ logger.debug("Dropdown block generated:");
949
+ logger.debug(dropdownBlock);
950
+ return dropdownBlock;
951
+ }
952
+
953
+ public static override getModalBlock(data: {
954
+ payloadModalBlock: WorkspaceModalBlock;
955
+ }): JSONObject {
956
+ logger.debug("Getting modal block with data:");
957
+ logger.debug(data);
958
+
959
+ const modalBlock: JSONObject = {
960
+ type: "modal",
961
+ title: {
962
+ type: "plain_text",
963
+ text: data.payloadModalBlock.title,
964
+ },
965
+ callback_id: data.payloadModalBlock.actionId,
966
+ private_metadata: data.payloadModalBlock.actionValue,
967
+ submit: {
968
+ type: "plain_text",
969
+ text: data.payloadModalBlock.submitButtonTitle,
970
+ },
971
+ close: {
972
+ type: "plain_text",
973
+ text: data.payloadModalBlock.cancelButtonTitle,
974
+ },
975
+ blocks: this.getBlocksFromWorkspaceMessagePayload({
976
+ messageBlocks: data.payloadModalBlock.blocks,
977
+ }),
978
+ };
979
+
980
+ logger.debug("Modal block generated:");
981
+ logger.debug(modalBlock);
982
+ return modalBlock;
983
+ }
984
+
498
985
  public static override getMarkdownBlock(data: {
499
986
  payloadMarkdownBlock: WorkspacePayloadMarkdown;
500
987
  }): JSONObject {
@@ -505,7 +992,9 @@ export default class SlackUtil extends WorkspaceBase {
505
992
  type: "section",
506
993
  text: {
507
994
  type: "mrkdwn",
508
- text: data.payloadMarkdownBlock.text,
995
+ text: data.payloadMarkdownBlock.text
996
+ ? SlackifyMarkdown(data.payloadMarkdownBlock.text)
997
+ : "",
509
998
  },
510
999
  };
511
1000
 
@@ -514,6 +1003,50 @@ export default class SlackUtil extends WorkspaceBase {
514
1003
  return markdownBlock;
515
1004
  }
516
1005
 
1006
+ public static override async isUserInDirectMessageChannel(data: {
1007
+ authToken: string;
1008
+ userId: string;
1009
+ directMessageChannelId: string;
1010
+ }): Promise<boolean> {
1011
+ // check of the user id is in the direct message channel id
1012
+ const response: HTTPErrorResponse | HTTPResponse<JSONObject> =
1013
+ await API.post(
1014
+ URL.fromString("https://slack.com/api/conversations.info"),
1015
+ {
1016
+ channel: data.directMessageChannelId,
1017
+ },
1018
+ {
1019
+ Authorization: `Bearer ${data.authToken}`,
1020
+ ["Content-Type"]: "application/x-www-form-urlencoded",
1021
+ },
1022
+ );
1023
+
1024
+ if (response instanceof HTTPErrorResponse) {
1025
+ logger.error("Error response from Slack API:");
1026
+ logger.error(response);
1027
+ throw response;
1028
+ }
1029
+
1030
+ // check for ok response
1031
+
1032
+ if ((response.jsonData as JSONObject)?.["ok"] !== true) {
1033
+ logger.error("Invalid response from Slack API:");
1034
+ logger.error(response.jsonData);
1035
+ throw new BadRequestException("Invalid response");
1036
+ }
1037
+
1038
+ // check if the user is in the channel
1039
+ const user: JSONObject = (
1040
+ (response.jsonData as JSONObject)["channel"] as JSONObject
1041
+ )["user"] as JSONObject;
1042
+
1043
+ if (user?.["user_id"]?.toString() === data.userId.toString()) {
1044
+ return true;
1045
+ }
1046
+
1047
+ return false;
1048
+ }
1049
+
517
1050
  public static override async isUserInChannel(data: {
518
1051
  authToken: string;
519
1052
  channelId: string;
@@ -595,9 +1128,13 @@ export default class SlackUtil extends WorkspaceBase {
595
1128
  text: {
596
1129
  type: "plain_text",
597
1130
  text: data.payloadButtonBlock.title,
1131
+ emoji: true,
598
1132
  },
599
- value: data.payloadButtonBlock.title,
600
- action_id: data.payloadButtonBlock.title,
1133
+ value: data.payloadButtonBlock.value,
1134
+ action_id: data.payloadButtonBlock.actionId,
1135
+ url: data.payloadButtonBlock.url
1136
+ ? data.payloadButtonBlock.url.toString()
1137
+ : undefined,
601
1138
  };
602
1139
 
603
1140
  logger.debug("Button block generated:");