@oneuptime/common 7.0.4349 → 7.0.4372

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 (64) hide show
  1. package/Models/AnalyticsModels/ExceptionInstance.ts +2 -2
  2. package/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleSchedule.ts +2 -2
  3. package/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleTeam.ts +2 -2
  4. package/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleUser.ts +2 -2
  5. package/Models/DatabaseModels/OnCallDutyPolicyTimeLog.ts +2 -2
  6. package/Models/DatabaseModels/Probe.ts +7 -1
  7. package/Models/DatabaseModels/ServiceCatalog.ts +2 -2
  8. package/Models/DatabaseModels/ServiceCopilotCodeRepository.ts +2 -2
  9. package/Models/DatabaseModels/StatusPage.ts +37 -0
  10. package/Models/DatabaseModels/StatusPageSubscriber.ts +60 -0
  11. package/Server/API/StatusPageAPI.ts +104 -10
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1749065784320-MigrationName.ts +23 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1749133333893-MigrationName.ts +17 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  15. package/Server/Services/ScheduledMaintenanceService.ts +21 -0
  16. package/Server/Services/StatusPageSubscriberService.ts +116 -1
  17. package/Server/Utils/OpenAPI.ts +738 -11
  18. package/Server/Utils/Workspace/Slack/Slack.ts +14 -0
  19. package/Utils/Schema/AnalyticsModelSchema.ts +764 -0
  20. package/Utils/Schema/BaseSchema.ts +450 -0
  21. package/Utils/Schema/ModelSchema.ts +1099 -38
  22. package/build/dist/Models/AnalyticsModels/ExceptionInstance.js +2 -2
  23. package/build/dist/Models/AnalyticsModels/ExceptionInstance.js.map +1 -1
  24. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleSchedule.js +2 -2
  25. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleSchedule.js.map +1 -1
  26. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleTeam.js +2 -2
  27. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleTeam.js.map +1 -1
  28. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleUser.js +2 -2
  29. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleUser.js.map +1 -1
  30. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js +2 -2
  31. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js.map +1 -1
  32. package/build/dist/Models/DatabaseModels/Probe.js +7 -1
  33. package/build/dist/Models/DatabaseModels/Probe.js.map +1 -1
  34. package/build/dist/Models/DatabaseModels/ServiceCatalog.js +2 -2
  35. package/build/dist/Models/DatabaseModels/ServiceCatalog.js.map +1 -1
  36. package/build/dist/Models/DatabaseModels/ServiceCopilotCodeRepository.js +2 -2
  37. package/build/dist/Models/DatabaseModels/ServiceCopilotCodeRepository.js.map +1 -1
  38. package/build/dist/Models/DatabaseModels/StatusPage.js +39 -0
  39. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  40. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +62 -0
  41. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
  42. package/build/dist/Server/API/StatusPageAPI.js +73 -10
  43. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  44. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1749065784320-MigrationName.js +14 -0
  45. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1749065784320-MigrationName.js.map +1 -0
  46. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1749133333893-MigrationName.js +12 -0
  47. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1749133333893-MigrationName.js.map +1 -0
  48. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  49. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  50. package/build/dist/Server/Services/ScheduledMaintenanceService.js +19 -0
  51. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  52. package/build/dist/Server/Services/StatusPageSubscriberService.js +98 -1
  53. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  54. package/build/dist/Server/Utils/OpenAPI.js +578 -11
  55. package/build/dist/Server/Utils/OpenAPI.js.map +1 -1
  56. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +15 -0
  57. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  58. package/build/dist/Utils/Schema/AnalyticsModelSchema.js +636 -0
  59. package/build/dist/Utils/Schema/AnalyticsModelSchema.js.map +1 -0
  60. package/build/dist/Utils/Schema/BaseSchema.js +295 -0
  61. package/build/dist/Utils/Schema/BaseSchema.js.map +1 -0
  62. package/build/dist/Utils/Schema/ModelSchema.js +940 -27
  63. package/build/dist/Utils/Schema/ModelSchema.js.map +1 -1
  64. package/package.json +1 -1
@@ -31,6 +31,7 @@ import Model from "../../Models/DatabaseModels/StatusPageSubscriber";
31
31
  import PositiveNumber from "../../Types/PositiveNumber";
32
32
  import StatusPageEventType from "../../Types/StatusPage/StatusPageEventType";
33
33
  import NumberUtil from "../../Utils/Number";
34
+ import SlackUtil from "../Utils/Workspace/Slack/Slack";
34
35
 
35
36
  export class Service extends DatabaseService<Model> {
36
37
  public constructor() {
@@ -143,6 +144,7 @@ export class Service extends DatabaseService<Model> {
143
144
  ignoreHooks: true,
144
145
  },
145
146
  });
147
+
146
148
  logger.debug(`Found Subscriber by Phone: ${JSON.stringify(subscriber)}`);
147
149
  }
148
150
 
@@ -197,12 +199,28 @@ export class Service extends DatabaseService<Model> {
197
199
  if (isEmailSubscriber && !isSubscriptionConfirmed) {
198
200
  data.data.isSubscriptionConfirmed = false;
199
201
  } else {
200
- data.data.isSubscriptionConfirmed = true; // if the subscriber is not email, then set it to true for SMS subscribers.
202
+ data.data.isSubscriptionConfirmed = true; // if the subscriber is not email, then set it to true for SMS subscribers / slack subscribers.
201
203
  }
202
204
  logger.debug(
203
205
  `Final Subscription Confirmed: ${data.data.isSubscriptionConfirmed}`,
204
206
  );
205
207
 
208
+ // if slack incoming webhook is provided, then see if it starts with https://hooks.slack.com/services/
209
+
210
+ if (data.data.slackIncomingWebhookUrl) {
211
+ logger.debug(
212
+ `Slack Incoming Webhook URL: ${data.data.slackIncomingWebhookUrl}`,
213
+ );
214
+ if (
215
+ !SlackUtil.isValidSlackIncomingWebhookUrl(
216
+ data.data.slackIncomingWebhookUrl,
217
+ )
218
+ ) {
219
+ logger.debug("Invalid Slack Incoming Webhook URL.");
220
+ throw new BadDataException("Invalid Slack Incoming Webhook URL.");
221
+ }
222
+ }
223
+
206
224
  data.data.subscriptionConfirmationToken = NumberUtil.getRandomNumber(
207
225
  100000,
208
226
  999999,
@@ -331,6 +349,38 @@ export class Service extends DatabaseService<Model> {
331
349
  }
332
350
  }
333
351
 
352
+ // if slack incoming webhook is provided, then send a message to the slack channel.
353
+ if (createdItem.slackIncomingWebhookUrl) {
354
+ logger.debug("Sending Slack notification for new subscriber.");
355
+ const slackMessage: string = `## 📢 New Subscription to ${statusPageName}
356
+
357
+ **You have successfully subscribed to receive status updates!**
358
+
359
+ 🔗 **Status Page:** [${statusPageName}](${statusPageURL})
360
+ 📧 **Manage Subscription:** [Update preferences or unsubscribe](${unsubscribeLink})
361
+
362
+ You will receive real-time notifications for:
363
+ • Incidents and outages
364
+ • Scheduled maintenance events
365
+ • Service announcements
366
+ • Status updates
367
+
368
+ Stay informed about service availability! 🚀`;
369
+
370
+ logger.debug(`Slack Message: ${slackMessage}`);
371
+
372
+ try {
373
+ await SlackUtil.sendMessageToChannelViaIncomingWebhook({
374
+ url: URL.fromString(createdItem.slackIncomingWebhookUrl.toString()),
375
+ text: SlackUtil.convertMarkdownToSlackRichText(slackMessage),
376
+ });
377
+ logger.debug("Slack notification sent successfully.");
378
+ } catch (error) {
379
+ logger.error("Error sending Slack notification:");
380
+ logger.error(error);
381
+ }
382
+ }
383
+
334
384
  logger.debug("onCreateSuccess completed.");
335
385
  return createdItem;
336
386
  }
@@ -637,6 +687,7 @@ export class Service extends DatabaseService<Model> {
637
687
  subscriberEmail: true,
638
688
  subscriberPhone: true,
639
689
  subscriberWebhook: true,
690
+ slackIncomingWebhookUrl: true,
640
691
  isSubscribedToAllResources: true,
641
692
  statusPageResources: true,
642
693
  isSubscribedToAllEventTypes: true,
@@ -820,5 +871,69 @@ export class Service extends DatabaseService<Model> {
820
871
 
821
872
  return statusPages;
822
873
  }
874
+
875
+ @CaptureSpan()
876
+ public async testSlackWebhook(data: {
877
+ webhookUrl: string;
878
+ statusPageId: ObjectID;
879
+ }): Promise<void> {
880
+ // Validate the webhook URL
881
+ if (!data.webhookUrl.startsWith("https://hooks.slack.com/services/")) {
882
+ throw new BadDataException("Invalid Slack webhook URL");
883
+ }
884
+
885
+ // Get status page info
886
+ const statusPage: StatusPage | null = await StatusPageService.findOneById({
887
+ id: data.statusPageId,
888
+ props: {
889
+ isRoot: true,
890
+ },
891
+ select: {
892
+ name: true,
893
+ pageTitle: true,
894
+ projectId: true,
895
+ _id: true,
896
+ },
897
+ });
898
+
899
+ if (!statusPage) {
900
+ throw new BadDataException("Status page not found");
901
+ }
902
+
903
+ // Create test notification message
904
+ const statusPageName: string =
905
+ statusPage.pageTitle || statusPage.name || "Status Page";
906
+ const statusPageURL: string = await StatusPageService.getStatusPageURL(
907
+ statusPage.id!,
908
+ );
909
+
910
+ // Create markdown message for Slack
911
+ const markdownMessage: string = `## Test Notification - ${statusPageName}
912
+
913
+ **This is a test notification from OneUptime.**
914
+
915
+ You have successfully configured Slack notifications for this status page.
916
+
917
+ You will receive real-time notifications for:
918
+ - Incidents
919
+ - Scheduled Maintenance Events
920
+ - Status Updates
921
+ - Announcements
922
+
923
+ [View Status Page](${statusPageURL})`;
924
+
925
+ // Send the test notification
926
+ try {
927
+ await SlackUtil.sendMessageToChannelViaIncomingWebhook({
928
+ url: URL.fromString(data.webhookUrl),
929
+ text: SlackUtil.convertMarkdownToSlackRichText(markdownMessage),
930
+ });
931
+ } catch (error) {
932
+ logger.error("Error sending test Slack notification:");
933
+ logger.error(error);
934
+ throw error;
935
+ }
936
+ }
823
937
  }
938
+
824
939
  export default new Service();