@oneuptime/common 12.0.17 → 12.0.19

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 (220) hide show
  1. package/Models/DatabaseModels/EnterpriseLicense.ts +23 -0
  2. package/Models/DatabaseModels/Index.ts +4 -2
  3. package/Models/DatabaseModels/Monitor.ts +39 -9
  4. package/Models/DatabaseModels/UserMicrosoftTeams.ts +344 -0
  5. package/Models/DatabaseModels/UserNotificationRule.ts +144 -8
  6. package/Models/DatabaseModels/UserNotificationSetting.ts +34 -0
  7. package/Models/DatabaseModels/UserOnCallLogTimeline.ts +95 -0
  8. package/Models/DatabaseModels/UserSlack.ts +341 -0
  9. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +9 -0
  10. package/Server/API/UserMicrosoftTeamsAPI.ts +127 -0
  11. package/Server/API/UserSlackAPI.ts +125 -0
  12. package/Server/EnvironmentConfig.ts +12 -107
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.ts +33 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.ts +51 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.ts +117 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.ts +197 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  18. package/Server/Infrastructure/Queue.ts +7 -0
  19. package/Server/Services/BillingService.ts +8 -0
  20. package/Server/Services/EnterpriseLicenseService.ts +60 -0
  21. package/Server/Services/Index.ts +6 -2
  22. package/Server/Services/LlmLogService.ts +25 -9
  23. package/Server/Services/OnCallReadinessService.ts +86 -2
  24. package/Server/Services/ProjectService.ts +67 -0
  25. package/Server/Services/UserMicrosoftTeamsService.ts +208 -0
  26. package/Server/Services/UserNotificationMethodAdminService.ts +167 -5
  27. package/Server/Services/UserNotificationRuleAdminService.ts +40 -6
  28. package/Server/Services/UserNotificationRuleService.ts +589 -11
  29. package/Server/Services/UserNotificationSettingService.ts +138 -0
  30. package/Server/Services/UserService.ts +28 -0
  31. package/Server/Services/UserSlackService.ts +218 -0
  32. package/Server/Services/WorkspaceProjectAuthTokenService.ts +67 -1
  33. package/Server/Services/WorkspaceUserAuthTokenService.ts +73 -0
  34. package/Server/Services/WorkspaceUserNotificationService.ts +190 -0
  35. package/Server/Utils/Marketing/MarketingEventUtil.ts +145 -0
  36. package/Server/Utils/Marketing/MarketingEventWebhook.ts +114 -0
  37. package/Server/Utils/Monitor/MonitorLogUtil.ts +14 -1
  38. package/Server/Utils/Monitor/MonitorPayloadRedaction.ts +321 -0
  39. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +191 -4
  40. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +22 -14
  41. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +22 -11
  42. package/Tests/App/Dashboard/OnCallPreventionGuards.test.tsx +37 -1
  43. package/Tests/App/Dashboard/OnCallRulesTable.test.tsx +18 -10
  44. package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +17 -0
  45. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +27 -1
  46. package/Tests/Models/DatabaseModels/MonitorSecretKeyColumnAccessControl.test.ts +214 -0
  47. package/Tests/Server/API/OnCallReadinessAPI.test.ts +145 -26
  48. package/Tests/Server/API/UserNotificationMethodAdminAPI.test.ts +2 -2
  49. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +11 -1
  50. package/Tests/Server/Services/AdminRuleEditGuards.test.ts +22 -8
  51. package/Tests/Server/Services/BillingService.test.ts +20 -0
  52. package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +18 -2
  53. package/Tests/Server/Services/EpisodeRuleSeverityRepair.test.ts +5 -1
  54. package/Tests/Server/Services/LlmLogServiceTokenAggregateParams.test.ts +640 -0
  55. package/Tests/Server/Services/NotificationChannelEventCoverage.test.ts +246 -22
  56. package/Tests/Server/Services/NotificationDeletionImpact.test.ts +136 -8
  57. package/Tests/Server/Services/OnCallNotificationFallback.test.ts +191 -8
  58. package/Tests/Server/Services/OnCallReadinessService.test.ts +343 -18
  59. package/Tests/Server/Services/SeverityRuleBackfill.test.ts +5 -1
  60. package/Tests/Server/Services/UserMicrosoftTeamsService.test.ts +343 -0
  61. package/Tests/Server/Services/UserNotificationMethodAdminService.test.ts +209 -8
  62. package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +22 -6
  63. package/Tests/Server/Services/UserNotificationRuleDefaultCreation.test.ts +12 -6
  64. package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +37 -3
  65. package/Tests/Server/Services/UserNotificationRuleWorkspaceDelivery.test.ts +669 -0
  66. package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +410 -0
  67. package/Tests/Server/Services/UserSlackService.test.ts +407 -0
  68. package/Tests/Server/Services/WorkspaceProjectAuthTokenDisconnectCascade.test.ts +224 -0
  69. package/Tests/Server/Services/WorkspaceUserAuthTokenNotificationMethodCascade.test.ts +189 -0
  70. package/Tests/Server/Services/WorkspaceUserNotificationService.test.ts +496 -0
  71. package/Tests/Server/Types/Database/Permissions/AdminNotificationRuleAccess.test.ts +30 -17
  72. package/Tests/Server/Types/Database/Permissions/CreateOwnershipScoping.test.ts +8 -3
  73. package/Tests/Server/Types/Database/Permissions/OwnerOnlyColumns.test.ts +72 -3
  74. package/Tests/Server/Types/Database/Permissions/UserNotificationRuleScoping.test.ts +22 -18
  75. package/Tests/Server/Types/Database/Permissions/WorkspaceMethodStampedColumnCreate.test.ts +178 -0
  76. package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +259 -0
  77. package/Tests/Server/Utils/Marketing/MarketingEventWebhook.test.ts +257 -0
  78. package/Tests/Server/Utils/Monitor/MonitorLogUtilRedaction.test.ts +300 -0
  79. package/Tests/Server/Utils/Monitor/MonitorPayloadRedaction.test.ts +381 -0
  80. package/Tests/Server/Utils/Runbook/RunbookExecutePermission.test.ts +228 -0
  81. package/Tests/Server/Utils/SessionReplay/SessionReplayErasureTombstone.test.ts +189 -0
  82. package/Tests/Server/Utils/SessionReplay/SessionReplayUsage.test.ts +205 -0
  83. package/Tests/Server/Utils/Telemetry/AppMetrics.test.ts +275 -0
  84. package/Tests/Server/Utils/Telemetry/TelemetryContext.test.ts +279 -0
  85. package/Tests/Server/Utils/Workspace/MicrosoftTeamsDirectMessage.test.ts +454 -0
  86. package/Tests/Types/Kubernetes/KubernetesObjectParsers.test.ts +794 -0
  87. package/Tests/Types/Kubernetes/KubernetesRightSizing.test.ts +53 -0
  88. package/Tests/Types/Measurement/MeasurementAggregationType.test.ts +100 -0
  89. package/Tests/Types/Monitor/MonitorStepConfigHelpers.test.ts +114 -0
  90. package/Tests/Types/Workspace/WorkspaceType.test.ts +53 -0
  91. package/Tests/UI/Utils/NotificationMethodUtil.test.ts +137 -9
  92. package/Tests/UI/Utils/PermissionGate.test.ts +105 -0
  93. package/Tests/Utils/Dashboard/Components/DashboardComponentDefaults.test.ts +257 -0
  94. package/Types/Billing/PayAsYouGoPricing.ts +1 -1
  95. package/Types/Marketing/MarketingEvent.ts +97 -0
  96. package/UI/Utils/NotificationMethodUtil.ts +41 -1
  97. package/UI/Utils/PermissionGate.ts +56 -0
  98. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +24 -0
  99. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
  100. package/build/dist/Models/DatabaseModels/Index.js +4 -2
  101. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  102. package/build/dist/Models/DatabaseModels/Monitor.js +39 -9
  103. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  104. package/build/dist/Models/DatabaseModels/UserMicrosoftTeams.js +363 -0
  105. package/build/dist/Models/DatabaseModels/UserMicrosoftTeams.js.map +1 -0
  106. package/build/dist/Models/DatabaseModels/UserNotificationRule.js +145 -8
  107. package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
  108. package/build/dist/Models/DatabaseModels/UserNotificationSetting.js +38 -0
  109. package/build/dist/Models/DatabaseModels/UserNotificationSetting.js.map +1 -1
  110. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +96 -0
  111. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
  112. package/build/dist/Models/DatabaseModels/UserSlack.js +361 -0
  113. package/build/dist/Models/DatabaseModels/UserSlack.js.map +1 -0
  114. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  115. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +82 -0
  116. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -0
  117. package/build/dist/Server/API/UserSlackAPI.js +81 -0
  118. package/build/dist/Server/API/UserSlackAPI.js.map +1 -0
  119. package/build/dist/Server/EnvironmentConfig.js +10 -70
  120. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  121. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.js +26 -0
  122. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.js.map +1 -0
  123. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.js +37 -0
  124. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.js.map +1 -0
  125. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js +106 -0
  126. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js.map +1 -0
  127. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js +78 -0
  128. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js.map +1 -0
  129. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  130. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  131. package/build/dist/Server/Infrastructure/Queue.js +7 -0
  132. package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
  133. package/build/dist/Server/Services/BillingService.js +6 -0
  134. package/build/dist/Server/Services/BillingService.js.map +1 -1
  135. package/build/dist/Server/Services/EnterpriseLicenseService.js +65 -0
  136. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  137. package/build/dist/Server/Services/Index.js +6 -2
  138. package/build/dist/Server/Services/Index.js.map +1 -1
  139. package/build/dist/Server/Services/LlmLogService.js +25 -9
  140. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  141. package/build/dist/Server/Services/OnCallReadinessService.js +74 -2
  142. package/build/dist/Server/Services/OnCallReadinessService.js.map +1 -1
  143. package/build/dist/Server/Services/ProjectService.js +56 -0
  144. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  145. package/build/dist/Server/Services/UserMicrosoftTeamsService.js +183 -0
  146. package/build/dist/Server/Services/UserMicrosoftTeamsService.js.map +1 -0
  147. package/build/dist/Server/Services/UserNotificationMethodAdminService.js +138 -2
  148. package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -1
  149. package/build/dist/Server/Services/UserNotificationRuleAdminService.js +32 -4
  150. package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -1
  151. package/build/dist/Server/Services/UserNotificationRuleService.js +499 -67
  152. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  153. package/build/dist/Server/Services/UserNotificationSettingService.js +118 -0
  154. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  155. package/build/dist/Server/Services/UserService.js +26 -1
  156. package/build/dist/Server/Services/UserService.js.map +1 -1
  157. package/build/dist/Server/Services/UserSlackService.js +195 -0
  158. package/build/dist/Server/Services/UserSlackService.js.map +1 -0
  159. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +64 -1
  160. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
  161. package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js +70 -0
  162. package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js.map +1 -1
  163. package/build/dist/Server/Services/WorkspaceUserNotificationService.js +129 -0
  164. package/build/dist/Server/Services/WorkspaceUserNotificationService.js.map +1 -0
  165. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +94 -0
  166. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -0
  167. package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js +93 -0
  168. package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js.map +1 -0
  169. package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js +12 -1
  170. package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js.map +1 -1
  171. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js +233 -0
  172. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js.map +1 -0
  173. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +141 -4
  174. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  175. package/build/dist/Types/Billing/PayAsYouGoPricing.js +1 -1
  176. package/build/dist/Types/Billing/PayAsYouGoPricing.js.map +1 -1
  177. package/build/dist/Types/Marketing/MarketingEvent.js +43 -0
  178. package/build/dist/Types/Marketing/MarketingEvent.js.map +1 -0
  179. package/build/dist/UI/Utils/NotificationMethodUtil.js +33 -1
  180. package/build/dist/UI/Utils/NotificationMethodUtil.js.map +1 -1
  181. package/build/dist/UI/Utils/PermissionGate.js +32 -0
  182. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  183. package/package.json +1 -1
  184. package/Models/DatabaseModels/MarketingConversion.ts +0 -410
  185. package/Server/Services/MarketingConversionService.ts +0 -10
  186. package/Server/Utils/Marketing/ConversionUploadProvider.ts +0 -215
  187. package/Server/Utils/Marketing/ConversionUploadProviders.ts +0 -22
  188. package/Server/Utils/Marketing/Providers/GoogleAds.ts +0 -333
  189. package/Server/Utils/Marketing/Providers/LinkedIn.ts +0 -185
  190. package/Server/Utils/Marketing/Providers/Meta.ts +0 -182
  191. package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +0 -223
  192. package/Server/Utils/Marketing/Providers/Reddit.ts +0 -208
  193. package/Tests/Server/Utils/Marketing/AdUploadableConversionTypes.test.ts +0 -315
  194. package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +0 -300
  195. package/Tests/Server/Utils/Marketing/GoogleAds.test.ts +0 -592
  196. package/Tests/Server/Utils/Marketing/LinkedIn.test.ts +0 -282
  197. package/Tests/Server/Utils/Marketing/Meta.test.ts +0 -304
  198. package/Tests/Server/Utils/Marketing/MicrosoftAds.test.ts +0 -263
  199. package/Tests/Server/Utils/Marketing/Reddit.test.ts +0 -259
  200. package/Types/Marketing/MarketingConversion.ts +0 -53
  201. package/build/dist/Models/DatabaseModels/MarketingConversion.js +0 -445
  202. package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +0 -1
  203. package/build/dist/Server/Services/MarketingConversionService.js +0 -9
  204. package/build/dist/Server/Services/MarketingConversionService.js.map +0 -1
  205. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +0 -93
  206. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +0 -1
  207. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js +0 -20
  208. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js.map +0 -1
  209. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +0 -221
  210. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +0 -1
  211. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +0 -137
  212. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +0 -1
  213. package/build/dist/Server/Utils/Marketing/Providers/Meta.js +0 -133
  214. package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +0 -1
  215. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +0 -143
  216. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +0 -1
  217. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +0 -145
  218. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +0 -1
  219. package/build/dist/Types/Marketing/MarketingConversion.js +0 -52
  220. package/build/dist/Types/Marketing/MarketingConversion.js.map +0 -1
@@ -0,0 +1,125 @@
1
+ import UserMiddleware from "../Middleware/UserAuthorization";
2
+ import UserSlackService, {
3
+ Service as UserSlackServiceType,
4
+ } from "../Services/UserSlackService";
5
+ import WorkspaceUserNotificationService from "../Services/WorkspaceUserNotificationService";
6
+ import {
7
+ ExpressRequest,
8
+ ExpressResponse,
9
+ NextFunction,
10
+ OneUptimeRequest,
11
+ } from "../Utils/Express";
12
+ import Response from "../Utils/Response";
13
+ import BaseAPI from "./BaseAPI";
14
+ import BadDataException from "../../Types/Exception/BadDataException";
15
+ import UserSlack from "../../Models/DatabaseModels/UserSlack";
16
+ import WorkspaceType from "../../Types/Workspace/WorkspaceType";
17
+ import { WorkspacePayloadMarkdown } from "../../Types/Workspace/WorkspaceMessagePayload";
18
+
19
+ export default class UserSlackAPI extends BaseAPI<
20
+ UserSlack,
21
+ UserSlackServiceType
22
+ > {
23
+ public constructor() {
24
+ super(UserSlack, UserSlackService);
25
+
26
+ /*
27
+ * Sends a test direct message to the caller's own linked Slack account,
28
+ * so "will a page actually reach me?" is answerable with one click
29
+ * instead of a real incident.
30
+ */
31
+ this.router.post(
32
+ `${new this.entityType().getCrudApiPath()?.toString()}/test`,
33
+ UserMiddleware.getUserMiddleware,
34
+ async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
35
+ try {
36
+ req = req as OneUptimeRequest;
37
+
38
+ if (!req.body["itemId"]) {
39
+ return Response.sendErrorResponse(
40
+ req,
41
+ res,
42
+ new BadDataException("Invalid item ID"),
43
+ );
44
+ }
45
+
46
+ const item: UserSlack | null = await this.service.findOneById({
47
+ id: req.body["itemId"],
48
+ props: {
49
+ isRoot: true,
50
+ },
51
+ select: {
52
+ userId: true,
53
+ projectId: true,
54
+ slackUserId: true,
55
+ isVerified: true,
56
+ },
57
+ });
58
+
59
+ if (!item) {
60
+ return Response.sendErrorResponse(
61
+ req,
62
+ res,
63
+ new BadDataException("Item not found"),
64
+ );
65
+ }
66
+
67
+ if (
68
+ item.userId?.toString() !==
69
+ (req as OneUptimeRequest)?.userAuthorization?.userId?.toString()
70
+ ) {
71
+ return Response.sendErrorResponse(
72
+ req,
73
+ res,
74
+ new BadDataException("Invalid user ID"),
75
+ );
76
+ }
77
+
78
+ if (!item.slackUserId || !item.isVerified) {
79
+ return Response.sendErrorResponse(
80
+ req,
81
+ res,
82
+ new BadDataException(
83
+ "This Slack account is not verified. Please remove it and add it again.",
84
+ ),
85
+ );
86
+ }
87
+
88
+ const markdownBlock: WorkspacePayloadMarkdown = {
89
+ _type: "WorkspacePayloadMarkdown",
90
+ text: "👋 This is a OneUptime test notification. Your Slack account can receive on-call notifications.",
91
+ };
92
+
93
+ try {
94
+ await WorkspaceUserNotificationService.sendDirectMessageToUser({
95
+ projectId: item.projectId!,
96
+ workspaceType: WorkspaceType.Slack,
97
+ workspaceUserId: item.slackUserId,
98
+ messageBlocks: [markdownBlock],
99
+ messageSummary: "Test notification",
100
+ userId: item.userId!,
101
+ });
102
+ } catch (err) {
103
+ const message: string =
104
+ err instanceof Error && err.message
105
+ ? err.message
106
+ : "Unknown error sending test Slack message.";
107
+
108
+ return Response.sendJsonObjectResponse(req, res, {
109
+ ok: false,
110
+ statusMessage: message,
111
+ });
112
+ }
113
+
114
+ return Response.sendJsonObjectResponse(req, res, {
115
+ ok: true,
116
+ statusMessage:
117
+ "Test message sent. Check your Slack direct messages.",
118
+ });
119
+ } catch (err) {
120
+ return next(err);
121
+ }
122
+ },
123
+ );
124
+ }
125
+ }
@@ -376,116 +376,21 @@ export const AnalyticsHost: string = process.env["ANALYTICS_HOST"] || "";
376
376
  export const CalWebhookSecret: string = process.env["CAL_WEBHOOK_SECRET"] || "";
377
377
 
378
378
  /*
379
- * Google Ads offline conversion uploads (MarketingConversions worker job).
380
- * Server-only secrets — must never be added to FRONTEND_ENV_ALLOW_LIST.
381
- */
382
- export const GoogleAdsDeveloperToken: string =
383
- process.env["GOOGLE_ADS_DEVELOPER_TOKEN"] || "";
384
- export const GoogleAdsOAuthClientId: string =
385
- process.env["GOOGLE_ADS_OAUTH_CLIENT_ID"] || "";
386
- export const GoogleAdsOAuthClientSecret: string =
387
- process.env["GOOGLE_ADS_OAUTH_CLIENT_SECRET"] || "";
388
- export const GoogleAdsOAuthRefreshToken: string =
389
- process.env["GOOGLE_ADS_OAUTH_REFRESH_TOKEN"] || "";
390
- // Digits only, no dashes (e.g. 1234567890).
391
- export const GoogleAdsCustomerId: string =
392
- process.env["GOOGLE_ADS_CUSTOMER_ID"] || "";
393
- // Manager (MCC) account id when the OAuth user accesses the account via a manager.
394
- export const GoogleAdsLoginCustomerId: string =
395
- process.env["GOOGLE_ADS_LOGIN_CUSTOMER_ID"] || "";
396
- /*
397
- * Google sunsets Ads API versions roughly yearly (v20 died 2026-06-10) —
398
- * keep this default on a currently supported version and prefer setting
399
- * GOOGLE_ADS_API_VERSION explicitly in production.
400
- */
401
- export const GoogleAdsApiVersion: string =
402
- process.env["GOOGLE_ADS_API_VERSION"] || "v23";
403
- /*
404
- * Numeric conversion action ids from Google Ads (Goals -> Conversions). One
405
- * per conversion type: the provider maps types to actions exhaustively, and an
406
- * empty value leaves that type pending rather than uploading it under some
407
- * other type's action.
408
- */
409
- export const GoogleAdsSignUpConversionActionId: string =
410
- process.env["GOOGLE_ADS_SIGNUP_CONVERSION_ACTION_ID"] || "";
411
- export const GoogleAdsPaidSubscriptionConversionActionId: string =
412
- process.env["GOOGLE_ADS_PAID_SUBSCRIPTION_CONVERSION_ACTION_ID"] || "";
413
- export const GoogleAdsMeetingBookedConversionActionId: string =
414
- process.env["GOOGLE_ADS_MEETING_BOOKED_CONVERSION_ACTION_ID"] || "";
415
-
416
- /*
417
- * Enhanced conversions for leads: upload a conversion identified ONLY by a
418
- * hashed email, with no gclid at all.
379
+ * Outbound marketing conversion webhooks.
419
380
  *
420
- * This is the mechanism that makes a sales-led funnel measurable — a demo
421
- * booked in June and a licence signed in October share an email and nothing
422
- * else. It is off by default because it is not purely a OneUptime-side switch:
423
- * the Google Ads account must have enhanced conversions for leads turned on
424
- * and the conversion action configured for it, and uploading email-only
425
- * conversions to an account without that returns a per-conversion rejection.
381
+ * OneUptime does not store conversions. Signups, booked meetings and plan
382
+ * upgrades/downgrades are POSTed to this endpoint as they happen and kept
383
+ * nowhere afterwards, so an unset URL means those moments are simply not
384
+ * measured nothing accumulates waiting for one to be configured.
426
385
  *
427
- * Hashing the email ALONGSIDE a click id needs no flag and is always sent — it
428
- * only improves the match rate of a conversion that was uploadable anyway.
429
- */
430
- export const GoogleAdsEnhancedConversionsForLeadsEnabled: boolean =
431
- process.env["GOOGLE_ADS_ENHANCED_CONVERSIONS_FOR_LEADS_ENABLED"] === "true";
432
-
433
- // Meta (Facebook) Conversions API. Server-only secrets.
434
- export const MetaConversionsPixelId: string =
435
- process.env["META_CONVERSIONS_PIXEL_ID"] || "";
436
- export const MetaConversionsAccessToken: string =
437
- process.env["META_CONVERSIONS_ACCESS_TOKEN"] || "";
438
- export const MetaGraphApiVersion: string =
439
- process.env["META_GRAPH_API_VERSION"] || "v22.0";
440
-
441
- // Microsoft Advertising (Bing Ads) offline conversions. Server-only secrets.
442
- export const MicrosoftAdsDeveloperToken: string =
443
- process.env["MICROSOFT_ADS_DEVELOPER_TOKEN"] || "";
444
- export const MicrosoftAdsOAuthClientId: string =
445
- process.env["MICROSOFT_ADS_OAUTH_CLIENT_ID"] || "";
446
- export const MicrosoftAdsOAuthClientSecret: string =
447
- process.env["MICROSOFT_ADS_OAUTH_CLIENT_SECRET"] || "";
448
- export const MicrosoftAdsOAuthRefreshToken: string =
449
- process.env["MICROSOFT_ADS_OAUTH_REFRESH_TOKEN"] || "";
450
- export const MicrosoftAdsCustomerId: string =
451
- process.env["MICROSOFT_ADS_CUSTOMER_ID"] || "";
452
- export const MicrosoftAdsAccountId: string =
453
- process.env["MICROSOFT_ADS_ACCOUNT_ID"] || "";
454
- // Offline conversion goals are matched by NAME in Microsoft Advertising.
455
- export const MicrosoftAdsSignUpConversionName: string =
456
- process.env["MICROSOFT_ADS_SIGNUP_CONVERSION_NAME"] || "";
457
- export const MicrosoftAdsPaidSubscriptionConversionName: string =
458
- process.env["MICROSOFT_ADS_PAID_SUBSCRIPTION_CONVERSION_NAME"] || "";
459
- export const MicrosoftAdsMeetingBookedConversionName: string =
460
- process.env["MICROSOFT_ADS_MEETING_BOOKED_CONVERSION_NAME"] || "";
461
-
462
- // LinkedIn Conversions API. Server-only secrets.
463
- export const LinkedInConversionsAccessToken: string =
464
- process.env["LINKEDIN_CONVERSIONS_ACCESS_TOKEN"] || "";
465
- /*
466
- * LinkedIn publishes a new Marketing API version monthly and supports each
467
- * for ~12 months — keep this default recent and prefer setting
468
- * LINKEDIN_API_VERSION explicitly in production.
386
+ * Both are required. The payload carries email addresses and campaign data,
387
+ * so a URL set without a secret is refused rather than sent unsigned. The
388
+ * secret is server-only and must never reach FRONTEND_ENV_ALLOW_LIST.
469
389
  */
470
- export const LinkedInApiVersion: string =
471
- process.env["LINKEDIN_API_VERSION"] || "202606";
472
- // Numeric conversion rule ids (urn:lla:llaPartnerConversion:{id}).
473
- export const LinkedInSignUpConversionId: string =
474
- process.env["LINKEDIN_SIGNUP_CONVERSION_ID"] || "";
475
- export const LinkedInPaidSubscriptionConversionId: string =
476
- process.env["LINKEDIN_PAID_SUBSCRIPTION_CONVERSION_ID"] || "";
477
- export const LinkedInMeetingBookedConversionId: string =
478
- process.env["LINKEDIN_MEETING_BOOKED_CONVERSION_ID"] || "";
479
-
480
- // Reddit Conversions API. Server-only secrets.
481
- export const RedditAdsOAuthClientId: string =
482
- process.env["REDDIT_ADS_OAUTH_CLIENT_ID"] || "";
483
- export const RedditAdsOAuthClientSecret: string =
484
- process.env["REDDIT_ADS_OAUTH_CLIENT_SECRET"] || "";
485
- export const RedditAdsOAuthRefreshToken: string =
486
- process.env["REDDIT_ADS_OAUTH_REFRESH_TOKEN"] || "";
487
- export const RedditAdsAccountId: string =
488
- process.env["REDDIT_ADS_ACCOUNT_ID"] || "";
390
+ export const MarketingWebhookUrl: string =
391
+ process.env["MARKETING_WEBHOOK_URL"] || "";
392
+ export const MarketingWebhookSecret: string =
393
+ process.env["MARKETING_WEBHOOK_SECRET"] || "";
489
394
 
490
395
  export const DisableAutomaticIncidentCreation: boolean =
491
396
  process.env["DISABLE_AUTOMATIC_INCIDENT_CREATION"] === "true";
@@ -0,0 +1,33 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ /*
4
+ * Drop the per-ad-platform upload state from the conversion ledger.
5
+ *
6
+ * OneUptime no longer uploads offline conversions to Google Ads, Meta,
7
+ * Microsoft Advertising, LinkedIn or Reddit. The ledger is now purely
8
+ * OneUptime's own reporting record, so the only column that existed to track
9
+ * delivery to those platforms has nothing left to describe.
10
+ *
11
+ * The down migration restores the column but not its contents: the statuses
12
+ * were per-provider delivery bookkeeping, they are not recoverable from
13
+ * anything else in the schema, and no reporting reads them. Nothing else on
14
+ * the row changes — conversions, their attribution and their chains are
15
+ * untouched.
16
+ */
17
+ export class RemoveMarketingConversionUploadState1788700000000
18
+ implements MigrationInterface
19
+ {
20
+ public name: string = "RemoveMarketingConversionUploadState1788700000000";
21
+
22
+ public async up(queryRunner: QueryRunner): Promise<void> {
23
+ await queryRunner.query(
24
+ `ALTER TABLE "MarketingConversion" DROP COLUMN IF EXISTS "uploadState"`,
25
+ );
26
+ }
27
+
28
+ public async down(queryRunner: QueryRunner): Promise<void> {
29
+ await queryRunner.query(
30
+ `ALTER TABLE "MarketingConversion" ADD "uploadState" jsonb`,
31
+ );
32
+ }
33
+ }
@@ -0,0 +1,51 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ /*
4
+ * Replace the conversion ledger with outbound webhooks, and give an enterprise
5
+ * licence a contact email.
6
+ *
7
+ * TWO CHANGES, ONE MIGRATION, because they are one decision: conversions are
8
+ * no longer stored in OneUptime, they are emitted as they happen and joined by
9
+ * the receiver on email. EnterpriseLicense.email is what makes a sales-led
10
+ * licence joinable to the meeting_booked that produced it, months earlier —
11
+ * without it, dropping the ledger would leave enterprise revenue attributable
12
+ * to nothing at all.
13
+ *
14
+ * The DROP is not reversible in any way that matters. `down` recreates the
15
+ * table's shape so a rollback finds the schema it expects, but every
16
+ * conversion, its attribution and its chain are gone: nothing else in the
17
+ * schema holds them, and nothing writes them any more. Export the table before
18
+ * running this if the history is wanted.
19
+ */
20
+ export class DropMarketingConversionAddEnterpriseLicenseEmail1788800000000
21
+ implements MigrationInterface
22
+ {
23
+ public name: string =
24
+ "DropMarketingConversionAddEnterpriseLicenseEmail1788800000000";
25
+
26
+ public async up(queryRunner: QueryRunner): Promise<void> {
27
+ await queryRunner.query(
28
+ `ALTER TABLE "EnterpriseLicense" ADD "email" character varying(100)`,
29
+ );
30
+ await queryRunner.query(
31
+ `CREATE INDEX "idx_enterprise_license_email" ON "EnterpriseLicense" ("email")`,
32
+ );
33
+ await queryRunner.query(`DROP TABLE IF EXISTS "MarketingConversion"`);
34
+ }
35
+
36
+ public async down(queryRunner: QueryRunner): Promise<void> {
37
+ /*
38
+ * Shape only — deliberately no data. Recreated so a rollback to the
39
+ * previous release starts against the schema it was built for.
40
+ */
41
+ await queryRunner.query(
42
+ `CREATE TABLE IF NOT EXISTS "MarketingConversion" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "conversionType" character varying(100) NOT NULL, "userId" uuid, "projectId" uuid, "email" character varying(100), "clickIds" jsonb NOT NULL, "conversionAt" TIMESTAMP WITH TIME ZONE NOT NULL, "conversionValueInUSDCents" integer, "utmCampaign" character varying(500), "utmSource" character varying(500), "utmMedium" character varying(500), "utmTerm" character varying(500), "utmContent" character varying(500), "utmUrl" character varying(500), "firstTouchAttribution" jsonb, "emailHash" character varying(100), "attributedToConversionId" uuid, CONSTRAINT "PK_MarketingConversion_id" PRIMARY KEY ("_id"))`,
43
+ );
44
+ await queryRunner.query(
45
+ `DROP INDEX IF EXISTS "idx_enterprise_license_email"`,
46
+ );
47
+ await queryRunner.query(
48
+ `ALTER TABLE "EnterpriseLicense" DROP COLUMN IF EXISTS "email"`,
49
+ );
50
+ }
51
+ }
@@ -0,0 +1,117 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ /*
4
+ * Scrub monitor ingest keys out of payloads that were already persisted.
5
+ *
6
+ * https://github.com/OneUptime/oneuptime/issues/3360
7
+ *
8
+ * An Incoming Email monitor's `incomingEmailSecretKey` IS its inbound address:
9
+ * `SendGridInboundProvider.generateMonitorEmailAddress` builds
10
+ * `monitor-{secretKey}@{inboundDomain}`, and `extractSecretKeyFromEmail` reads
11
+ * the key straight back out. Every stored copy of the recipient was therefore a
12
+ * stored copy of a live bearer credential — `emailTo`, the `To:` header, and
13
+ * the `Received:` / `Delivered-To:` headers added in transit.
14
+ *
15
+ * `ProcessProbeIngest.processIncomingEmailFromQueue` now masks the key at the
16
+ * ingest boundary, so nothing written from here on carries it. That fixes the
17
+ * flow and not the stock: rows written before this deploy still hold the key in
18
+ * plaintext, in columns a `Permission.Viewer` can select. Narrowing a read ACL
19
+ * would not have helped either — the same snapshot is copied onto incidents and
20
+ * alerts, which are gated on their own permissions.
21
+ *
22
+ * The four Postgres sinks, all of them jsonb:
23
+ *
24
+ * - `Monitor.incomingEmailMonitorRequest` (the reported leak)
25
+ * - `Monitor.incomingMonitorRequest` (same shape, `incomingRequestSecretKey`)
26
+ * - `Incident.monitorSummary` (via MonitorSummaryCapture)
27
+ * - `Alert.monitorSummary` (via MonitorSummaryCapture)
28
+ *
29
+ * `MonitorLog.logBody` is the fifth sink and is deliberately not touched here:
30
+ * it lives in ClickHouse, not Postgres, and every row carries a `retentionDate`
31
+ * with a `retentionDate DELETE` TTL, so historical rows age out on their own.
32
+ *
33
+ * Matching is case-insensitive (`gi`). A uuid renders lowercase in Postgres,
34
+ * but the key reaches these payloads through relay headers that preserve
35
+ * whatever case the sender used. A uuid is made of hex digits and hyphens, so
36
+ * it needs no regex escaping, and the replacement text contains no backslash,
37
+ * so it needs none either.
38
+ */
39
+ export class RedactStoredMonitorIngestSecrets1788900000000
40
+ implements MigrationInterface
41
+ {
42
+ public name: string = "RedactStoredMonitorIngestSecrets1788900000000";
43
+
44
+ public async up(queryRunner: QueryRunner): Promise<void> {
45
+ /*
46
+ * The monitor's own row: the key and the payload quoting it are on the
47
+ * same row, so this needs no join.
48
+ */
49
+ await queryRunner.query(
50
+ `UPDATE "Monitor"
51
+ SET "incomingEmailMonitorRequest" = regexp_replace(
52
+ "incomingEmailMonitorRequest"::text,
53
+ "incomingEmailSecretKey"::text,
54
+ '[REDACTED]',
55
+ 'gi'
56
+ )::jsonb
57
+ WHERE "incomingEmailSecretKey" IS NOT NULL
58
+ AND "incomingEmailMonitorRequest" IS NOT NULL
59
+ AND "incomingEmailMonitorRequest"::text ILIKE '%' || "incomingEmailSecretKey"::text || '%'`,
60
+ );
61
+
62
+ await queryRunner.query(
63
+ `UPDATE "Monitor"
64
+ SET "incomingMonitorRequest" = regexp_replace(
65
+ "incomingMonitorRequest"::text,
66
+ "incomingRequestSecretKey"::text,
67
+ '[REDACTED]',
68
+ 'gi'
69
+ )::jsonb
70
+ WHERE "incomingRequestSecretKey" IS NOT NULL
71
+ AND "incomingMonitorRequest" IS NOT NULL
72
+ AND "incomingMonitorRequest"::text ILIKE '%' || "incomingRequestSecretKey"::text || '%'`,
73
+ );
74
+
75
+ /*
76
+ * Incident and Alert keep a copy of the snapshot the monitor was evaluated
77
+ * from. The key is not on those rows, so join back to the monitor. The
78
+ * `projectId` equality keeps the join from degenerating into a cross
79
+ * product; the ILIKE is what actually selects the affected rows, and a
80
+ * snapshot describes exactly one monitor, so at most one monitor row can
81
+ * match a given summary.
82
+ */
83
+ for (const table of ["Incident", "Alert"]) {
84
+ for (const secretColumn of [
85
+ "incomingEmailSecretKey",
86
+ "incomingRequestSecretKey",
87
+ ]) {
88
+ await queryRunner.query(
89
+ `UPDATE "${table}" AS t
90
+ SET "monitorSummary" = regexp_replace(
91
+ t."monitorSummary"::text,
92
+ m."${secretColumn}"::text,
93
+ '[REDACTED]',
94
+ 'gi'
95
+ )::jsonb
96
+ FROM "Monitor" AS m
97
+ WHERE m."${secretColumn}" IS NOT NULL
98
+ AND m."projectId" = t."projectId"
99
+ AND t."monitorSummary" IS NOT NULL
100
+ AND t."monitorSummary"::text ILIKE '%' || m."${secretColumn}"::text || '%'`,
101
+ );
102
+ }
103
+ }
104
+ }
105
+
106
+ public async down(): Promise<void> {
107
+ /*
108
+ * Deliberately empty. The whole point of the up migration is that these
109
+ * values are gone; the original text is not recoverable from anything else
110
+ * in the schema, and recovering it would mean re-publishing the leak.
111
+ *
112
+ * Nothing depends on the redacted text either: `IncomingEmailCriteria`
113
+ * re-evaluates against live mail, and the summary cards render whatever
114
+ * string is stored. Rolling the schema back therefore needs no data change.
115
+ */
116
+ }
117
+ }
@@ -0,0 +1,197 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ /*
4
+ * Slack and Microsoft Teams as user notification methods.
5
+ *
6
+ * Two new per-user method tables (UserSlack / UserMicrosoftTeams — pointers at
7
+ * the user's OAuth workspace link, created verified), the notification-rule
8
+ * and on-call timeline foreign keys that let rules route pages to them, and
9
+ * the two per-event toggles on UserNotificationSetting.
10
+ */
11
+ export class AddUserSlackAndMicrosoftTeams1789000000000
12
+ implements MigrationInterface
13
+ {
14
+ public name = "AddUserSlackAndMicrosoftTeams1789000000000";
15
+
16
+ public async up(queryRunner: QueryRunner): Promise<void> {
17
+ await queryRunner.query(
18
+ `CREATE TABLE "UserSlack" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "slackUserId" character varying(100), "slackUserName" character varying(100), "userId" uuid, "createdByUserId" uuid, "deletedByUserId" uuid, "isVerified" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_86de4cd76b41a08811fc403e23a" PRIMARY KEY ("_id"))`,
19
+ );
20
+ await queryRunner.query(
21
+ `CREATE INDEX "IDX_d5dd2503bf422c6a19946216e1" ON "UserSlack" ("projectId") `,
22
+ );
23
+ await queryRunner.query(
24
+ `CREATE INDEX "IDX_abe4265455b18cd43a94bb84ed" ON "UserSlack" ("slackUserId") `,
25
+ );
26
+ await queryRunner.query(
27
+ `CREATE INDEX "IDX_9c8fa391e949f53f670dabe222" ON "UserSlack" ("userId") `,
28
+ );
29
+ await queryRunner.query(
30
+ `CREATE TABLE "UserMicrosoftTeams" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "microsoftTeamsUserId" character varying(100), "microsoftTeamsUserName" character varying(100), "userId" uuid, "createdByUserId" uuid, "deletedByUserId" uuid, "isVerified" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_9e2c27aadbc24a991c68e55c130" PRIMARY KEY ("_id"))`,
31
+ );
32
+ await queryRunner.query(
33
+ `CREATE INDEX "IDX_cebf1edfa5f30a7e597633bddf" ON "UserMicrosoftTeams" ("projectId") `,
34
+ );
35
+ await queryRunner.query(
36
+ `CREATE INDEX "IDX_a746ef4fd29b03ac5abe8f4e4c" ON "UserMicrosoftTeams" ("microsoftTeamsUserId") `,
37
+ );
38
+ await queryRunner.query(
39
+ `CREATE INDEX "IDX_e4405f9dacd3d1e3c363e8dbd3" ON "UserMicrosoftTeams" ("userId") `,
40
+ );
41
+ await queryRunner.query(
42
+ `ALTER TABLE "UserNotificationRule" ADD "userSlackId" uuid`,
43
+ );
44
+ await queryRunner.query(
45
+ `ALTER TABLE "UserNotificationRule" ADD "userMicrosoftTeamsId" uuid`,
46
+ );
47
+ await queryRunner.query(
48
+ `ALTER TABLE "UserOnCallLogTimeline" ADD "userSlackId" uuid`,
49
+ );
50
+ await queryRunner.query(
51
+ `ALTER TABLE "UserOnCallLogTimeline" ADD "userMicrosoftTeamsId" uuid`,
52
+ );
53
+ await queryRunner.query(
54
+ `ALTER TABLE "UserNotificationSetting" ADD "alertBySlack" boolean NOT NULL DEFAULT false`,
55
+ );
56
+ await queryRunner.query(
57
+ `ALTER TABLE "UserNotificationSetting" ADD "alertByMicrosoftTeams" boolean NOT NULL DEFAULT false`,
58
+ );
59
+ await queryRunner.query(
60
+ `CREATE INDEX "IDX_0c24badba9b152d08700f7d8aa" ON "UserNotificationRule" ("userSlackId") `,
61
+ );
62
+ await queryRunner.query(
63
+ `CREATE INDEX "IDX_3dc4e1c367eab9fd36b7983e44" ON "UserNotificationRule" ("userMicrosoftTeamsId") `,
64
+ );
65
+ await queryRunner.query(
66
+ `CREATE INDEX "IDX_d51ef7b2a8b813d37e94890ff7" ON "UserOnCallLogTimeline" ("userSlackId") `,
67
+ );
68
+ await queryRunner.query(
69
+ `CREATE INDEX "IDX_a7206c19df5cdfe02cf3215a64" ON "UserOnCallLogTimeline" ("userMicrosoftTeamsId") `,
70
+ );
71
+ await queryRunner.query(
72
+ `ALTER TABLE "UserSlack" ADD CONSTRAINT "FK_d5dd2503bf422c6a19946216e19" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
73
+ );
74
+ await queryRunner.query(
75
+ `ALTER TABLE "UserSlack" ADD CONSTRAINT "FK_9c8fa391e949f53f670dabe2220" FOREIGN KEY ("userId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
76
+ );
77
+ await queryRunner.query(
78
+ `ALTER TABLE "UserSlack" ADD CONSTRAINT "FK_fd38a9ee050702437ed323f21fb" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
79
+ );
80
+ await queryRunner.query(
81
+ `ALTER TABLE "UserSlack" ADD CONSTRAINT "FK_2f058862227400121f90925d65e" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
82
+ );
83
+ await queryRunner.query(
84
+ `ALTER TABLE "UserMicrosoftTeams" ADD CONSTRAINT "FK_cebf1edfa5f30a7e597633bddf9" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
85
+ );
86
+ await queryRunner.query(
87
+ `ALTER TABLE "UserMicrosoftTeams" ADD CONSTRAINT "FK_e4405f9dacd3d1e3c363e8dbd30" FOREIGN KEY ("userId") REFERENCES "User"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
88
+ );
89
+ await queryRunner.query(
90
+ `ALTER TABLE "UserMicrosoftTeams" ADD CONSTRAINT "FK_81443b1ab79d63b7700f3d16c84" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
91
+ );
92
+ await queryRunner.query(
93
+ `ALTER TABLE "UserMicrosoftTeams" ADD CONSTRAINT "FK_1d7cfdf5a4e314cf4b4cc7873e0" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
94
+ );
95
+ await queryRunner.query(
96
+ `ALTER TABLE "UserNotificationRule" ADD CONSTRAINT "FK_0c24badba9b152d08700f7d8aa8" FOREIGN KEY ("userSlackId") REFERENCES "UserSlack"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
97
+ );
98
+ await queryRunner.query(
99
+ `ALTER TABLE "UserNotificationRule" ADD CONSTRAINT "FK_3dc4e1c367eab9fd36b7983e444" FOREIGN KEY ("userMicrosoftTeamsId") REFERENCES "UserMicrosoftTeams"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
100
+ );
101
+ await queryRunner.query(
102
+ `ALTER TABLE "UserOnCallLogTimeline" ADD CONSTRAINT "FK_d51ef7b2a8b813d37e94890ff77" FOREIGN KEY ("userSlackId") REFERENCES "UserSlack"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
103
+ );
104
+ await queryRunner.query(
105
+ `ALTER TABLE "UserOnCallLogTimeline" ADD CONSTRAINT "FK_a7206c19df5cdfe02cf3215a64c" FOREIGN KEY ("userMicrosoftTeamsId") REFERENCES "UserMicrosoftTeams"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
106
+ );
107
+ }
108
+
109
+ public async down(queryRunner: QueryRunner): Promise<void> {
110
+ await queryRunner.query(
111
+ `ALTER TABLE "UserOnCallLogTimeline" DROP CONSTRAINT "FK_a7206c19df5cdfe02cf3215a64c"`,
112
+ );
113
+ await queryRunner.query(
114
+ `ALTER TABLE "UserOnCallLogTimeline" DROP CONSTRAINT "FK_d51ef7b2a8b813d37e94890ff77"`,
115
+ );
116
+ await queryRunner.query(
117
+ `ALTER TABLE "UserNotificationRule" DROP CONSTRAINT "FK_3dc4e1c367eab9fd36b7983e444"`,
118
+ );
119
+ await queryRunner.query(
120
+ `ALTER TABLE "UserNotificationRule" DROP CONSTRAINT "FK_0c24badba9b152d08700f7d8aa8"`,
121
+ );
122
+ await queryRunner.query(
123
+ `ALTER TABLE "UserMicrosoftTeams" DROP CONSTRAINT "FK_1d7cfdf5a4e314cf4b4cc7873e0"`,
124
+ );
125
+ await queryRunner.query(
126
+ `ALTER TABLE "UserMicrosoftTeams" DROP CONSTRAINT "FK_81443b1ab79d63b7700f3d16c84"`,
127
+ );
128
+ await queryRunner.query(
129
+ `ALTER TABLE "UserMicrosoftTeams" DROP CONSTRAINT "FK_e4405f9dacd3d1e3c363e8dbd30"`,
130
+ );
131
+ await queryRunner.query(
132
+ `ALTER TABLE "UserMicrosoftTeams" DROP CONSTRAINT "FK_cebf1edfa5f30a7e597633bddf9"`,
133
+ );
134
+ await queryRunner.query(
135
+ `ALTER TABLE "UserSlack" DROP CONSTRAINT "FK_2f058862227400121f90925d65e"`,
136
+ );
137
+ await queryRunner.query(
138
+ `ALTER TABLE "UserSlack" DROP CONSTRAINT "FK_fd38a9ee050702437ed323f21fb"`,
139
+ );
140
+ await queryRunner.query(
141
+ `ALTER TABLE "UserSlack" DROP CONSTRAINT "FK_9c8fa391e949f53f670dabe2220"`,
142
+ );
143
+ await queryRunner.query(
144
+ `ALTER TABLE "UserSlack" DROP CONSTRAINT "FK_d5dd2503bf422c6a19946216e19"`,
145
+ );
146
+ await queryRunner.query(
147
+ `DROP INDEX "public"."IDX_a7206c19df5cdfe02cf3215a64"`,
148
+ );
149
+ await queryRunner.query(
150
+ `DROP INDEX "public"."IDX_d51ef7b2a8b813d37e94890ff7"`,
151
+ );
152
+ await queryRunner.query(
153
+ `DROP INDEX "public"."IDX_3dc4e1c367eab9fd36b7983e44"`,
154
+ );
155
+ await queryRunner.query(
156
+ `DROP INDEX "public"."IDX_0c24badba9b152d08700f7d8aa"`,
157
+ );
158
+ await queryRunner.query(
159
+ `ALTER TABLE "UserNotificationSetting" DROP COLUMN "alertByMicrosoftTeams"`,
160
+ );
161
+ await queryRunner.query(
162
+ `ALTER TABLE "UserNotificationSetting" DROP COLUMN "alertBySlack"`,
163
+ );
164
+ await queryRunner.query(
165
+ `ALTER TABLE "UserOnCallLogTimeline" DROP COLUMN "userMicrosoftTeamsId"`,
166
+ );
167
+ await queryRunner.query(
168
+ `ALTER TABLE "UserOnCallLogTimeline" DROP COLUMN "userSlackId"`,
169
+ );
170
+ await queryRunner.query(
171
+ `ALTER TABLE "UserNotificationRule" DROP COLUMN "userMicrosoftTeamsId"`,
172
+ );
173
+ await queryRunner.query(
174
+ `ALTER TABLE "UserNotificationRule" DROP COLUMN "userSlackId"`,
175
+ );
176
+ await queryRunner.query(
177
+ `DROP INDEX "public"."IDX_e4405f9dacd3d1e3c363e8dbd3"`,
178
+ );
179
+ await queryRunner.query(
180
+ `DROP INDEX "public"."IDX_a746ef4fd29b03ac5abe8f4e4c"`,
181
+ );
182
+ await queryRunner.query(
183
+ `DROP INDEX "public"."IDX_cebf1edfa5f30a7e597633bddf"`,
184
+ );
185
+ await queryRunner.query(`DROP TABLE "UserMicrosoftTeams"`);
186
+ await queryRunner.query(
187
+ `DROP INDEX "public"."IDX_9c8fa391e949f53f670dabe222"`,
188
+ );
189
+ await queryRunner.query(
190
+ `DROP INDEX "public"."IDX_abe4265455b18cd43a94bb84ed"`,
191
+ );
192
+ await queryRunner.query(
193
+ `DROP INDEX "public"."IDX_d5dd2503bf422c6a19946216e1"`,
194
+ );
195
+ await queryRunner.query(`DROP TABLE "UserSlack"`);
196
+ }
197
+ }