@oneuptime/common 7.0.3786 → 7.0.3815

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/Server/API/SlackAPI.ts +68 -0
  2. package/Server/Services/AccessTokenService.ts +21 -0
  3. package/Server/Services/AlertFeedService.ts +98 -0
  4. package/Server/Services/AlertInternalNoteService.ts +49 -8
  5. package/Server/Services/AlertOwnerTeamService.ts +50 -2
  6. package/Server/Services/AlertOwnerUserService.ts +52 -2
  7. package/Server/Services/AlertService.ts +236 -37
  8. package/Server/Services/AlertStateService.ts +24 -0
  9. package/Server/Services/AlertStateTimelineService.ts +30 -2
  10. package/Server/Services/IncidentInternalNoteService.ts +6 -6
  11. package/Server/Services/IncidentPublicNoteService.ts +7 -4
  12. package/Server/Services/IncidentStateTimelineService.ts +2 -1
  13. package/Server/Services/ScheduledMaintenanceFeedService.ts +103 -0
  14. package/Server/Services/ScheduledMaintenanceInternalNoteService.ts +50 -6
  15. package/Server/Services/ScheduledMaintenanceOwnerTeamService.ts +37 -0
  16. package/Server/Services/ScheduledMaintenanceOwnerUserService.ts +34 -0
  17. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +49 -7
  18. package/Server/Services/ScheduledMaintenanceService.ts +375 -12
  19. package/Server/Services/ScheduledMaintenanceStateService.ts +122 -34
  20. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +33 -1
  21. package/Server/Services/WorkspaceNotificationRuleService.ts +12 -0
  22. package/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.ts +38 -0
  23. package/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.ts +116 -0
  24. package/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.ts +36 -115
  25. package/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.ts +108 -0
  26. package/Server/Utils/Workspace/Slack/Actions/ActionTypes.ts +20 -2
  27. package/Server/Utils/Workspace/Slack/Actions/Alert.ts +697 -0
  28. package/Server/Utils/Workspace/Slack/Actions/Auth.ts +9 -2
  29. package/Server/Utils/Workspace/Slack/Actions/Incident.ts +9 -3
  30. package/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.ts +956 -0
  31. package/Server/Utils/Workspace/Slack/Messages/Alert.ts +116 -0
  32. package/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.ts +108 -0
  33. package/Server/Utils/Workspace/Slack/Slack.ts +48 -2
  34. package/Server/Utils/Workspace/Slack/app-manifest.json +3 -3
  35. package/Server/Utils/Workspace/WorkspaceBase.ts +14 -0
  36. package/Server/Utils/Workspace/WorkspaceMessages/Alert.ts +69 -0
  37. package/Server/Utils/Workspace/WorkspaceMessages/ScheduledMaintenance.ts +73 -0
  38. package/Types/Date.ts +5 -0
  39. package/Types/Workspace/WorkspaceMessagePayload.ts +9 -0
  40. package/build/dist/Server/API/SlackAPI.js +54 -0
  41. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  42. package/build/dist/Server/Services/AccessTokenService.js +11 -0
  43. package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
  44. package/build/dist/Server/Services/AlertFeedService.js +60 -0
  45. package/build/dist/Server/Services/AlertFeedService.js.map +1 -1
  46. package/build/dist/Server/Services/AlertInternalNoteService.js +39 -8
  47. package/build/dist/Server/Services/AlertInternalNoteService.js.map +1 -1
  48. package/build/dist/Server/Services/AlertOwnerTeamService.js +40 -2
  49. package/build/dist/Server/Services/AlertOwnerTeamService.js.map +1 -1
  50. package/build/dist/Server/Services/AlertOwnerUserService.js +41 -3
  51. package/build/dist/Server/Services/AlertOwnerUserService.js.map +1 -1
  52. package/build/dist/Server/Services/AlertService.js +192 -35
  53. package/build/dist/Server/Services/AlertService.js.map +1 -1
  54. package/build/dist/Server/Services/AlertStateService.js +13 -0
  55. package/build/dist/Server/Services/AlertStateService.js.map +1 -1
  56. package/build/dist/Server/Services/AlertStateTimelineService.js +26 -2
  57. package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
  58. package/build/dist/Server/Services/IncidentInternalNoteService.js +6 -6
  59. package/build/dist/Server/Services/IncidentInternalNoteService.js.map +1 -1
  60. package/build/dist/Server/Services/IncidentPublicNoteService.js +5 -4
  61. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  62. package/build/dist/Server/Services/IncidentStateTimelineService.js +1 -1
  63. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  64. package/build/dist/Server/Services/ScheduledMaintenanceFeedService.js +60 -0
  65. package/build/dist/Server/Services/ScheduledMaintenanceFeedService.js.map +1 -1
  66. package/build/dist/Server/Services/ScheduledMaintenanceInternalNoteService.js +36 -6
  67. package/build/dist/Server/Services/ScheduledMaintenanceInternalNoteService.js.map +1 -1
  68. package/build/dist/Server/Services/ScheduledMaintenanceOwnerTeamService.js +24 -0
  69. package/build/dist/Server/Services/ScheduledMaintenanceOwnerTeamService.js.map +1 -1
  70. package/build/dist/Server/Services/ScheduledMaintenanceOwnerUserService.js +22 -0
  71. package/build/dist/Server/Services/ScheduledMaintenanceOwnerUserService.js.map +1 -1
  72. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +36 -7
  73. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  74. package/build/dist/Server/Services/ScheduledMaintenanceService.js +275 -13
  75. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  76. package/build/dist/Server/Services/ScheduledMaintenanceStateService.js +52 -4
  77. package/build/dist/Server/Services/ScheduledMaintenanceStateService.js.map +1 -1
  78. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +28 -1
  79. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  80. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +10 -0
  81. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  82. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.js +37 -0
  83. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.js.map +1 -0
  84. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.js +82 -0
  85. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.js.map +1 -0
  86. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.js +33 -99
  87. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.js.map +1 -1
  88. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.js +74 -0
  89. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.js.map +1 -0
  90. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js +20 -2
  91. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js.map +1 -1
  92. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js +425 -0
  93. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js.map +1 -0
  94. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js +2 -0
  95. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js.map +1 -1
  96. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js +5 -2
  97. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js.map +1 -1
  98. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js +599 -0
  99. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js.map +1 -0
  100. package/build/dist/Server/Utils/Workspace/Slack/Messages/Alert.js +82 -0
  101. package/build/dist/Server/Utils/Workspace/Slack/Messages/Alert.js.map +1 -0
  102. package/build/dist/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.js +74 -0
  103. package/build/dist/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.js.map +1 -0
  104. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +34 -0
  105. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  106. package/build/dist/Server/Utils/Workspace/Slack/app-manifest.json +3 -3
  107. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js +8 -0
  108. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
  109. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/Alert.js +48 -0
  110. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/Alert.js.map +1 -0
  111. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/ScheduledMaintenance.js +47 -0
  112. package/build/dist/Server/Utils/Workspace/WorkspaceMessages/ScheduledMaintenance.js.map +1 -0
  113. package/build/dist/Types/Date.js +4 -0
  114. package/build/dist/Types/Date.js.map +1 -1
  115. package/package.json +2 -2
@@ -52,6 +52,10 @@ import { ScheduledMaintenanceFeedEventType } from "../../Models/DatabaseModels/S
52
52
  import { Gray500, Red500 } from "../../Types/BrandColors";
53
53
  import Label from "../../Models/DatabaseModels/Label";
54
54
  import LabelService from "./LabelService";
55
+ import WorkspaceType from "../../Types/Workspace/WorkspaceType";
56
+ import NotificationRuleWorkspaceChannel from "../../Types/Workspace/NotificationRules/NotificationRuleWorkspaceChannel";
57
+ import { MessageBlocksByWorkspaceType } from "./WorkspaceNotificationRuleService";
58
+ import ScheduledMaintenanceWorkspaceMessages from "../Utils/Workspace/WorkspaceMessages/ScheduledMaintenance";
55
59
 
56
60
  export class Service extends DatabaseService<Model> {
57
61
  public constructor() {
@@ -163,7 +167,7 @@ export class Service extends DatabaseService<Model> {
163
167
  }
164
168
 
165
169
  if (!statuspage.showScheduledMaintenanceEventsOnStatusPage) {
166
- continue; // Do not send notification to subscribers if incidents are not visible on status page.
170
+ continue; // Do not send notification to subscribers if scheduledMaintenances are not visible on status page.
167
171
  }
168
172
 
169
173
  const subscribers: Array<StatusPageSubscriber> =
@@ -491,24 +495,111 @@ export class Service extends DatabaseService<Model> {
491
495
  const createdByUserId: ObjectID | undefined | null =
492
496
  createdItem.createdByUserId || createdItem.createdByUser?.id;
493
497
 
498
+ // send message to workspaces - slack, teams, etc.
499
+ const workspaceResult: {
500
+ channelsCreated: Array<NotificationRuleWorkspaceChannel>;
501
+ } | null =
502
+ await ScheduledMaintenanceWorkspaceMessages.createChannelsAndInviteUsersToChannels(
503
+ {
504
+ projectId: createdItem.projectId!,
505
+ scheduledMaintenanceId: createdItem.id!,
506
+ scheduledMaintenanceNumber: createdItem.scheduledMaintenanceNumber!,
507
+ },
508
+ );
509
+
510
+ if (workspaceResult && workspaceResult.channelsCreated?.length > 0) {
511
+ // update scheduledMaintenance with these channels.
512
+ await this.updateOneById({
513
+ id: createdItem.id!,
514
+ data: {
515
+ postUpdatesToWorkspaceChannels: workspaceResult.channelsCreated || [],
516
+ },
517
+ props: {
518
+ isRoot: true,
519
+ },
520
+ });
521
+ }
522
+
523
+ const scheduledMaintenance: Model | null = await this.findOneById({
524
+ id: createdItem.id!,
525
+ select: {
526
+ projectId: true,
527
+ scheduledMaintenanceNumber: true,
528
+ title: true,
529
+ description: true,
530
+ currentScheduledMaintenanceState: {
531
+ name: true,
532
+ },
533
+ startsAt: true,
534
+ endsAt: true,
535
+ monitors: {
536
+ name: true,
537
+ _id: true,
538
+ },
539
+ },
540
+ props: {
541
+ isRoot: true,
542
+ },
543
+ });
544
+
545
+ if (!scheduledMaintenance) {
546
+ throw new BadDataException("Scheduled Maintenance not found");
547
+ }
548
+
549
+ let feedInfoInMarkdown: string = `#### 🕒 Scheduled Maintenance ${createdItem.scheduledMaintenanceNumber?.toString()} Created:
550
+
551
+ **${createdItem.title || "No title provided."}**:
552
+
553
+ ${createdItem.description || "No description provided."}
554
+
555
+ `;
556
+
557
+ // add starts at and ends at.
558
+ if (scheduledMaintenance.startsAt) {
559
+ feedInfoInMarkdown += `**Starts At**: ${OneUptimeDate.getDateAsLocalFormattedString(scheduledMaintenance.startsAt)} \n\n`;
560
+ }
561
+
562
+ if (scheduledMaintenance.endsAt) {
563
+ feedInfoInMarkdown += `**Ends At**: ${OneUptimeDate.getDateAsLocalFormattedString(scheduledMaintenance.endsAt)} \n\n`;
564
+ }
565
+
566
+ if (scheduledMaintenance.currentScheduledMaintenanceState?.name) {
567
+ feedInfoInMarkdown += `⏳ **Scheduled Maintenance State**: ${scheduledMaintenance.currentScheduledMaintenanceState.name} \n\n`;
568
+ }
569
+
570
+ if (
571
+ scheduledMaintenance.monitors &&
572
+ scheduledMaintenance.monitors.length > 0
573
+ ) {
574
+ feedInfoInMarkdown += `🌎 **Resources Affected**:\n`;
575
+
576
+ for (const monitor of scheduledMaintenance.monitors) {
577
+ feedInfoInMarkdown += `- [${monitor.name}](${(await MonitorService.getMonitorLinkInDashboard(createdItem.projectId!, monitor.id!)).toString()})\n`;
578
+ }
579
+
580
+ feedInfoInMarkdown += `\n\n`;
581
+ }
582
+
583
+ const scheduledMaintenanceCreateMessageBlocks: Array<MessageBlocksByWorkspaceType> =
584
+ await ScheduledMaintenanceWorkspaceMessages.getScheduledMaintenanceCreateMessageBlocks(
585
+ {
586
+ scheduledMaintenanceId: createdItem.id!,
587
+ projectId: createdItem.projectId!,
588
+ },
589
+ );
590
+
494
591
  await ScheduledMaintenanceFeedService.createScheduledMaintenanceFeedItem({
495
592
  scheduledMaintenanceId: createdItem.id!,
496
593
  projectId: createdItem.projectId!,
497
594
  scheduledMaintenanceFeedEventType:
498
595
  ScheduledMaintenanceFeedEventType.ScheduledMaintenanceCreated,
499
596
  displayColor: Red500,
500
- feedInfoInMarkdown: `**Scheduled Maintenance #${createdItem.scheduledMaintenanceNumber?.toString()} Created**:
501
-
502
- **Scheduled Maintenance Title**:
503
-
504
- ${createdItem.title || "No title provided."}
505
-
506
- **Description**:
507
-
508
- ${createdItem.description || "No description provided."}
509
-
510
- `,
597
+ feedInfoInMarkdown: feedInfoInMarkdown,
511
598
  userId: createdByUserId || undefined,
599
+ workspaceNotification: {
600
+ appendMessageBlocks: scheduledMaintenanceCreateMessageBlocks,
601
+ sendWorkspaceNotification: true,
602
+ },
512
603
  });
513
604
 
514
605
  const timeline: ScheduledMaintenanceStateTimeline =
@@ -1051,5 +1142,277 @@ ${labels
1051
1142
  },
1052
1143
  });
1053
1144
  }
1145
+
1146
+ public async isScheduledMaintenanceCompleted(data: {
1147
+ scheduledMaintenanceId: ObjectID;
1148
+ }): Promise<boolean> {
1149
+ const scheduledMaintenance: Model | null = await this.findOneBy({
1150
+ query: {
1151
+ _id: data.scheduledMaintenanceId,
1152
+ },
1153
+ select: {
1154
+ projectId: true,
1155
+ currentScheduledMaintenanceState: {
1156
+ order: true,
1157
+ },
1158
+ },
1159
+ props: {
1160
+ isRoot: true,
1161
+ },
1162
+ });
1163
+
1164
+ if (!scheduledMaintenance) {
1165
+ throw new BadDataException("ScheduledMaintenance not found");
1166
+ }
1167
+
1168
+ if (!scheduledMaintenance.projectId) {
1169
+ throw new BadDataException("Incient Project ID not found");
1170
+ }
1171
+
1172
+ const resolvedScheduledMaintenanceState: ScheduledMaintenanceState =
1173
+ await ScheduledMaintenanceStateService.getCompletedScheduledMaintenanceState(
1174
+ {
1175
+ projectId: scheduledMaintenance.projectId,
1176
+ props: {
1177
+ isRoot: true,
1178
+ },
1179
+ },
1180
+ );
1181
+
1182
+ const currentScheduledMaintenanceStateOrder: number =
1183
+ scheduledMaintenance.currentScheduledMaintenanceState!.order!;
1184
+ const resolvedScheduledMaintenanceStateOrder: number =
1185
+ resolvedScheduledMaintenanceState.order!;
1186
+
1187
+ if (
1188
+ currentScheduledMaintenanceStateOrder >=
1189
+ resolvedScheduledMaintenanceStateOrder
1190
+ ) {
1191
+ return true;
1192
+ }
1193
+
1194
+ return false;
1195
+ }
1196
+
1197
+ public async getScheduledMaintenanceNumber(data: {
1198
+ scheduledMaintenanceId: ObjectID;
1199
+ }): Promise<number | null> {
1200
+ const scheduledMaintenance: Model | null = await this.findOneById({
1201
+ id: data.scheduledMaintenanceId,
1202
+ select: {
1203
+ scheduledMaintenanceNumber: true,
1204
+ },
1205
+ props: {
1206
+ isRoot: true,
1207
+ },
1208
+ });
1209
+
1210
+ if (!scheduledMaintenance) {
1211
+ throw new BadDataException("ScheduledMaintenance not found.");
1212
+ }
1213
+
1214
+ return scheduledMaintenance.scheduledMaintenanceNumber || null;
1215
+ }
1216
+
1217
+ public async isScheduledMaintenanceOngoing(data: {
1218
+ scheduledMaintenanceId: ObjectID;
1219
+ }): Promise<boolean> {
1220
+ const scheduledMaintenance: Model | null = await this.findOneBy({
1221
+ query: {
1222
+ _id: data.scheduledMaintenanceId,
1223
+ },
1224
+ select: {
1225
+ projectId: true,
1226
+ currentScheduledMaintenanceState: {
1227
+ order: true,
1228
+ },
1229
+ },
1230
+ props: {
1231
+ isRoot: true,
1232
+ },
1233
+ });
1234
+
1235
+ if (!scheduledMaintenance) {
1236
+ throw new BadDataException("ScheduledMaintenance not found");
1237
+ }
1238
+
1239
+ if (!scheduledMaintenance.projectId) {
1240
+ throw new BadDataException("Incient Project ID not found");
1241
+ }
1242
+
1243
+ const ackScheduledMaintenanceState: ScheduledMaintenanceState =
1244
+ await ScheduledMaintenanceStateService.getOngoingScheduledMaintenanceState(
1245
+ {
1246
+ projectId: scheduledMaintenance.projectId,
1247
+ props: {
1248
+ isRoot: true,
1249
+ },
1250
+ },
1251
+ );
1252
+
1253
+ const currentScheduledMaintenanceStateOrder: number =
1254
+ scheduledMaintenance.currentScheduledMaintenanceState!.order!;
1255
+ const ackScheduledMaintenanceStateOrder: number =
1256
+ ackScheduledMaintenanceState.order!;
1257
+
1258
+ if (
1259
+ currentScheduledMaintenanceStateOrder >= ackScheduledMaintenanceStateOrder
1260
+ ) {
1261
+ return true;
1262
+ }
1263
+
1264
+ return false;
1265
+ }
1266
+
1267
+ public async markScheduledMaintenanceAsComplete(
1268
+ scheduledMaintenanceId: ObjectID,
1269
+ resolvedByUserId: ObjectID,
1270
+ ): Promise<Model> {
1271
+ const scheduledMaintenance: Model | null = await this.findOneById({
1272
+ id: scheduledMaintenanceId,
1273
+ select: {
1274
+ projectId: true,
1275
+ scheduledMaintenanceNumber: true,
1276
+ },
1277
+ props: {
1278
+ isRoot: true,
1279
+ },
1280
+ });
1281
+
1282
+ if (!scheduledMaintenance || !scheduledMaintenance.projectId) {
1283
+ throw new BadDataException("ScheduledMaintenance not found.");
1284
+ }
1285
+
1286
+ const scheduledMaintenanceState: ScheduledMaintenanceState | null =
1287
+ await ScheduledMaintenanceStateService.findOneBy({
1288
+ query: {
1289
+ projectId: scheduledMaintenance.projectId,
1290
+ isResolvedState: true,
1291
+ },
1292
+ select: {
1293
+ _id: true,
1294
+ },
1295
+ props: {
1296
+ isRoot: true,
1297
+ },
1298
+ });
1299
+
1300
+ if (!scheduledMaintenanceState || !scheduledMaintenanceState.id) {
1301
+ throw new BadDataException(
1302
+ "Acknowledged state not found for this project. Please add acknowledged state from settings.",
1303
+ );
1304
+ }
1305
+
1306
+ const scheduledMaintenanceStateTimeline: ScheduledMaintenanceStateTimeline =
1307
+ new ScheduledMaintenanceStateTimeline();
1308
+ scheduledMaintenanceStateTimeline.projectId =
1309
+ scheduledMaintenance.projectId;
1310
+ scheduledMaintenanceStateTimeline.scheduledMaintenanceId =
1311
+ scheduledMaintenanceId;
1312
+ scheduledMaintenanceStateTimeline.scheduledMaintenanceStateId =
1313
+ scheduledMaintenanceState.id;
1314
+ scheduledMaintenanceStateTimeline.createdByUserId = resolvedByUserId;
1315
+
1316
+ await ScheduledMaintenanceStateTimelineService.create({
1317
+ data: scheduledMaintenanceStateTimeline,
1318
+ props: {
1319
+ isRoot: true,
1320
+ },
1321
+ });
1322
+
1323
+ // store scheduledMaintenance metric
1324
+
1325
+ return scheduledMaintenance;
1326
+ }
1327
+
1328
+ public async markScheduledMaintenanceAsOngoing(
1329
+ scheduledMaintenanceId: ObjectID,
1330
+ markedByUserId: ObjectID,
1331
+ ): Promise<Model> {
1332
+ const scheduledMaintenance: Model | null = await this.findOneById({
1333
+ id: scheduledMaintenanceId,
1334
+ select: {
1335
+ projectId: true,
1336
+ scheduledMaintenanceNumber: true,
1337
+ },
1338
+ props: {
1339
+ isRoot: true,
1340
+ },
1341
+ });
1342
+
1343
+ if (!scheduledMaintenance || !scheduledMaintenance.projectId) {
1344
+ throw new BadDataException("ScheduledMaintenance not found.");
1345
+ }
1346
+
1347
+ const scheduledMaintenanceState: ScheduledMaintenanceState | null =
1348
+ await ScheduledMaintenanceStateService.findOneBy({
1349
+ query: {
1350
+ projectId: scheduledMaintenance.projectId,
1351
+ isOngoingState: true,
1352
+ },
1353
+ select: {
1354
+ _id: true,
1355
+ },
1356
+ props: {
1357
+ isRoot: true,
1358
+ },
1359
+ });
1360
+
1361
+ if (!scheduledMaintenanceState || !scheduledMaintenanceState.id) {
1362
+ throw new BadDataException(
1363
+ "Acknowledged state not found for this project. Please add acknowledged state from settings.",
1364
+ );
1365
+ }
1366
+
1367
+ const scheduledMaintenanceStateTimeline: ScheduledMaintenanceStateTimeline =
1368
+ new ScheduledMaintenanceStateTimeline();
1369
+ scheduledMaintenanceStateTimeline.projectId =
1370
+ scheduledMaintenance.projectId;
1371
+ scheduledMaintenanceStateTimeline.scheduledMaintenanceId =
1372
+ scheduledMaintenanceId;
1373
+ scheduledMaintenanceStateTimeline.scheduledMaintenanceStateId =
1374
+ scheduledMaintenanceState.id;
1375
+ scheduledMaintenanceStateTimeline.createdByUserId = markedByUserId;
1376
+
1377
+ await ScheduledMaintenanceStateTimelineService.create({
1378
+ data: scheduledMaintenanceStateTimeline,
1379
+ props: {
1380
+ isRoot: true,
1381
+ },
1382
+ });
1383
+
1384
+ // store scheduledMaintenance metric
1385
+
1386
+ return scheduledMaintenance;
1387
+ }
1388
+
1389
+ public async getWorkspaceChannelForScheduledMaintenance(data: {
1390
+ scheduledMaintenanceId: ObjectID;
1391
+ workspaceType?: WorkspaceType | null;
1392
+ }): Promise<Array<NotificationRuleWorkspaceChannel>> {
1393
+ const scheduledMaintenance: Model | null = await this.findOneById({
1394
+ id: data.scheduledMaintenanceId,
1395
+ select: {
1396
+ postUpdatesToWorkspaceChannels: true,
1397
+ },
1398
+ props: {
1399
+ isRoot: true,
1400
+ },
1401
+ });
1402
+
1403
+ if (!scheduledMaintenance) {
1404
+ throw new BadDataException("ScheduledMaintenance not found.");
1405
+ }
1406
+
1407
+ return (scheduledMaintenance.postUpdatesToWorkspaceChannels || []).filter(
1408
+ (channel: NotificationRuleWorkspaceChannel) => {
1409
+ if (!data.workspaceType) {
1410
+ return true;
1411
+ }
1412
+
1413
+ return channel.workspaceType === data.workspaceType;
1414
+ },
1415
+ );
1416
+ }
1054
1417
  }
1055
1418
  export default new Service();
@@ -8,22 +8,27 @@ import SortOrder from "../../Types/BaseDatabase/SortOrder";
8
8
  import LIMIT_MAX from "../../Types/Database/LimitMax";
9
9
  import BadDataException from "../../Types/Exception/BadDataException";
10
10
  import ObjectID from "../../Types/ObjectID";
11
- import Model from "Common/Models/DatabaseModels/ScheduledMaintenanceState";
11
+ import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
12
+ import ScheduledMaintenanceState from "Common/Models/DatabaseModels/ScheduledMaintenanceState";
12
13
 
13
- export class Service extends DatabaseService<Model> {
14
+ export class Service extends DatabaseService<ScheduledMaintenanceState> {
14
15
  public constructor() {
15
- super(Model);
16
+ super(ScheduledMaintenanceState);
16
17
  }
17
18
 
18
19
  protected override async onBeforeCreate(
19
- createBy: CreateBy<Model>,
20
- ): Promise<OnCreate<Model>> {
20
+ createBy: CreateBy<ScheduledMaintenanceState>,
21
+ ): Promise<OnCreate<ScheduledMaintenanceState>> {
21
22
  if (!createBy.data.order) {
22
- throw new BadDataException("Incident State order is required");
23
+ throw new BadDataException(
24
+ "ScheduledMaintenance State order is required",
25
+ );
23
26
  }
24
27
 
25
28
  if (!createBy.data.projectId) {
26
- throw new BadDataException("Incident State projectId is required");
29
+ throw new BadDataException(
30
+ "ScheduledMaintenance State projectId is required",
31
+ );
27
32
  }
28
33
 
29
34
  await this.rearrangeOrder(
@@ -39,15 +44,15 @@ export class Service extends DatabaseService<Model> {
39
44
  }
40
45
 
41
46
  protected override async onBeforeDelete(
42
- deleteBy: DeleteBy<Model>,
43
- ): Promise<OnDelete<Model>> {
47
+ deleteBy: DeleteBy<ScheduledMaintenanceState>,
48
+ ): Promise<OnDelete<ScheduledMaintenanceState>> {
44
49
  if (!deleteBy.query._id && !deleteBy.props.isRoot) {
45
50
  throw new BadDataException(
46
51
  "_id should be present when deleting scheduled maintenance states. Please try the delete with objectId",
47
52
  );
48
53
  }
49
54
 
50
- let scheduledMaintenanceState: Model | null = null;
55
+ let scheduledMaintenanceState: ScheduledMaintenanceState | null = null;
51
56
 
52
57
  if (!deleteBy.props.isRoot) {
53
58
  scheduledMaintenanceState = await this.findOneBy({
@@ -69,11 +74,12 @@ export class Service extends DatabaseService<Model> {
69
74
  }
70
75
 
71
76
  protected override async onDeleteSuccess(
72
- onDelete: OnDelete<Model>,
77
+ onDelete: OnDelete<ScheduledMaintenanceState>,
73
78
  _itemIdsBeforeDelete: ObjectID[],
74
- ): Promise<OnDelete<Model>> {
75
- const deleteBy: DeleteBy<Model> = onDelete.deleteBy;
76
- const scheduledMaintenanceState: Model | null = onDelete.carryForward;
79
+ ): Promise<OnDelete<ScheduledMaintenanceState>> {
80
+ const deleteBy: DeleteBy<ScheduledMaintenanceState> = onDelete.deleteBy;
81
+ const scheduledMaintenanceState: ScheduledMaintenanceState | null =
82
+ onDelete.carryForward;
77
83
 
78
84
  if (!deleteBy.props.isRoot && scheduledMaintenanceState) {
79
85
  if (
@@ -96,8 +102,8 @@ export class Service extends DatabaseService<Model> {
96
102
  }
97
103
 
98
104
  protected override async onBeforeUpdate(
99
- updateBy: UpdateBy<Model>,
100
- ): Promise<OnUpdate<Model>> {
105
+ updateBy: UpdateBy<ScheduledMaintenanceState>,
106
+ ): Promise<OnUpdate<ScheduledMaintenanceState>> {
101
107
  if (updateBy.data.order && !updateBy.props.isRoot) {
102
108
  throw new BadDataException(
103
109
  "Scheduled Maintenance State order should not be updated. Delete this scheduled maintenance state and create a new state with the right order.",
@@ -113,24 +119,25 @@ export class Service extends DatabaseService<Model> {
113
119
  increaseOrder: boolean = true,
114
120
  ): Promise<void> {
115
121
  // get scheduledMaintenance with this order.
116
- const scheduledMaintenanceStates: Array<Model> = await this.findBy({
117
- query: {
118
- order: QueryHelper.greaterThanEqualTo(currentOrder),
119
- projectId: projectId,
120
- },
121
- limit: LIMIT_MAX,
122
- skip: 0,
123
- props: {
124
- isRoot: true,
125
- },
126
- select: {
127
- _id: true,
128
- order: true,
129
- },
130
- sort: {
131
- order: SortOrder.Ascending,
132
- },
133
- });
122
+ const scheduledMaintenanceStates: Array<ScheduledMaintenanceState> =
123
+ await this.findBy({
124
+ query: {
125
+ order: QueryHelper.greaterThanEqualTo(currentOrder),
126
+ projectId: projectId,
127
+ },
128
+ limit: LIMIT_MAX,
129
+ skip: 0,
130
+ props: {
131
+ isRoot: true,
132
+ },
133
+ select: {
134
+ _id: true,
135
+ order: true,
136
+ },
137
+ sort: {
138
+ order: SortOrder.Ascending,
139
+ },
140
+ });
134
141
 
135
142
  let newOrder: number = currentOrder;
136
143
 
@@ -154,5 +161,86 @@ export class Service extends DatabaseService<Model> {
154
161
  });
155
162
  }
156
163
  }
164
+
165
+ public async getCompletedScheduledMaintenanceState(data: {
166
+ projectId: ObjectID;
167
+ props: DatabaseCommonInteractionProps;
168
+ }): Promise<ScheduledMaintenanceState> {
169
+ const scheduledMaintenanceStates: Array<ScheduledMaintenanceState> =
170
+ await this.getAllScheduledMaintenanceStates({
171
+ projectId: data.projectId,
172
+ props: data.props,
173
+ });
174
+
175
+ const resolvedScheduledMaintenanceState:
176
+ | ScheduledMaintenanceState
177
+ | undefined = scheduledMaintenanceStates.find(
178
+ (scheduledMaintenanceState: ScheduledMaintenanceState) => {
179
+ return scheduledMaintenanceState?.isResolvedState;
180
+ },
181
+ );
182
+
183
+ if (!resolvedScheduledMaintenanceState) {
184
+ throw new BadDataException(
185
+ "Completed ScheduledMaintenance State not found for this project",
186
+ );
187
+ }
188
+
189
+ return resolvedScheduledMaintenanceState;
190
+ }
191
+
192
+ public async getAllScheduledMaintenanceStates(data: {
193
+ projectId: ObjectID;
194
+ props: DatabaseCommonInteractionProps;
195
+ }): Promise<Array<ScheduledMaintenanceState>> {
196
+ const scheduledMaintenanceStates: Array<ScheduledMaintenanceState> =
197
+ await this.findBy({
198
+ query: {
199
+ projectId: data.projectId,
200
+ },
201
+ skip: 0,
202
+ limit: LIMIT_MAX,
203
+ sort: {
204
+ order: SortOrder.Ascending,
205
+ },
206
+ select: {
207
+ _id: true,
208
+ isResolvedState: true,
209
+ isOngoingState: true,
210
+ isScheduledState: true,
211
+ order: true,
212
+ name: true,
213
+ },
214
+ props: data.props,
215
+ });
216
+
217
+ return scheduledMaintenanceStates;
218
+ }
219
+
220
+ public async getOngoingScheduledMaintenanceState(data: {
221
+ projectId: ObjectID;
222
+ props: DatabaseCommonInteractionProps;
223
+ }): Promise<ScheduledMaintenanceState> {
224
+ const scheduledMaintenanceStates: Array<ScheduledMaintenanceState> =
225
+ await this.getAllScheduledMaintenanceStates({
226
+ projectId: data.projectId,
227
+ props: data.props,
228
+ });
229
+
230
+ const ackScheduledMaintenanceState: ScheduledMaintenanceState | undefined =
231
+ scheduledMaintenanceStates.find(
232
+ (scheduledMaintenanceState: ScheduledMaintenanceState) => {
233
+ return scheduledMaintenanceState?.isOngoingState;
234
+ },
235
+ );
236
+
237
+ if (!ackScheduledMaintenanceState) {
238
+ throw new BadDataException(
239
+ "Ongoing ScheduledMaintenance State not found for this project",
240
+ );
241
+ }
242
+
243
+ return ackScheduledMaintenanceState;
244
+ }
157
245
  }
158
246
  export default new Service();
@@ -150,11 +150,35 @@ export class Service extends DatabaseService<ScheduledMaintenanceStateTimeline>
150
150
  _id: true,
151
151
  color: true,
152
152
  name: true,
153
+ isResolvedState: true,
154
+ isOngoingState: true,
155
+ isScheduledState: true,
153
156
  },
154
157
  });
155
158
 
156
159
  const stateName: string = scheduledMaintenanceState?.name || "";
157
160
 
161
+ const scheduledMaintenanceNumber: number | null =
162
+ await ScheduledMaintenanceService.getScheduledMaintenanceNumber({
163
+ scheduledMaintenanceId: createdItem.scheduledMaintenanceId,
164
+ });
165
+
166
+ // if resolved state then change emoji to ✅.
167
+ let stateEmoji: string = "➡️";
168
+
169
+ if (scheduledMaintenanceState?.isResolvedState) {
170
+ stateEmoji = "✅";
171
+ } else if (scheduledMaintenanceState?.isOngoingState) {
172
+ // eyes emoji for acknowledged state.
173
+ stateEmoji = "⏳";
174
+ } else if (scheduledMaintenanceState?.isScheduledState) {
175
+ stateEmoji = "🕒";
176
+ }
177
+
178
+ const projectId: ObjectID = createdItem.projectId!;
179
+ const scheduledMaintenanceId: ObjectID =
180
+ createdItem.scheduledMaintenanceId!;
181
+
158
182
  await ScheduledMaintenanceFeedService.createScheduledMaintenanceFeedItem({
159
183
  scheduledMaintenanceId: createdItem.scheduledMaintenanceId!,
160
184
  projectId: createdItem.projectId!,
@@ -162,8 +186,16 @@ export class Service extends DatabaseService<ScheduledMaintenanceStateTimeline>
162
186
  ScheduledMaintenanceFeedEventType.ScheduledMaintenanceStateChanged,
163
187
  displayColor: scheduledMaintenanceState?.color,
164
188
  feedInfoInMarkdown:
165
- "**Scheduled Maintenance State** changed to **" + stateName + "**",
189
+ stateEmoji +
190
+ ` Changed **[Scheduled Maintenance ${scheduledMaintenanceNumber}](${(await ScheduledMaintenanceService.getScheduledMaintenanceLinkInDashboard(projectId!, scheduledMaintenanceId!)).toString()}) State** to **` +
191
+ stateName +
192
+ "**",
166
193
  userId: createdItem.createdByUserId || onCreate.createBy.props.userId,
194
+ workspaceNotification: {
195
+ sendWorkspaceNotification: true,
196
+ notifyUserId:
197
+ createdItem.createdByUserId || onCreate.createBy.props.userId,
198
+ },
167
199
  });
168
200
 
169
201
  // TODO: DELETE THIS WHEN WORKFLOW IS IMPLEMENMTED.