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