@oneuptime/common 7.0.3822 → 7.0.3826

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.
@@ -25,6 +25,7 @@ import ScheduledMaintenanceStateTimeline from "Common/Models/DatabaseModels/Sche
25
25
  import { IsBillingEnabled } from "../EnvironmentConfig";
26
26
  import ScheduledMaintenanceFeedService from "./ScheduledMaintenanceFeedService";
27
27
  import { ScheduledMaintenanceFeedEventType } from "../../Models/DatabaseModels/ScheduledMaintenanceFeed";
28
+ import logger from "../Utils/Logger";
28
29
 
29
30
  export class Service extends DatabaseService<ScheduledMaintenanceStateTimeline> {
30
31
  public constructor() {
@@ -45,22 +46,55 @@ export class Service extends DatabaseService<ScheduledMaintenanceStateTimeline>
45
46
  createBy.data.startsAt = OneUptimeDate.getCurrentDate();
46
47
  }
47
48
 
48
- const lastScheduledMaintenanceStateTimeline: ScheduledMaintenanceStateTimeline | null =
49
+ const stateBeforeThis: ScheduledMaintenanceStateTimeline | null =
49
50
  await this.findOneBy({
50
51
  query: {
51
52
  scheduledMaintenanceId: createBy.data.scheduledMaintenanceId,
53
+ startsAt: QueryHelper.lessThanEqualTo(createBy.data.startsAt),
52
54
  },
53
55
  sort: {
54
- createdAt: SortOrder.Descending,
56
+ startsAt: SortOrder.Descending,
55
57
  },
56
58
  props: {
57
59
  isRoot: true,
58
60
  },
59
61
  select: {
60
- _id: true,
62
+ scheduledMaintenanceStateId: true,
63
+ startsAt: true,
64
+ endsAt: true,
61
65
  },
62
66
  });
63
67
 
68
+ // If this is the first state, then do not notify the owner.
69
+ if (!stateBeforeThis) {
70
+ // since this is the first status, do not notify the owner.
71
+ createBy.data.isOwnerNotified = true;
72
+ }
73
+
74
+ const stateAfterThis: ScheduledMaintenanceStateTimeline | null =
75
+ await this.findOneBy({
76
+ query: {
77
+ scheduledMaintenanceId: createBy.data.scheduledMaintenanceId,
78
+ startsAt: QueryHelper.greaterThan(createBy.data.startsAt),
79
+ },
80
+ sort: {
81
+ startsAt: SortOrder.Ascending,
82
+ },
83
+ props: {
84
+ isRoot: true,
85
+ },
86
+ select: {
87
+ scheduledMaintenanceStateId: true,
88
+ startsAt: true,
89
+ endsAt: true,
90
+ },
91
+ });
92
+
93
+ // compute ends at. It's the start of the next status.
94
+ if (stateAfterThis && stateAfterThis.startsAt) {
95
+ createBy.data.endsAt = stateAfterThis.startsAt;
96
+ }
97
+
64
98
  const publicNote: string | undefined = (
65
99
  createBy.miscDataProps as JSONObject | undefined
66
100
  )?.["publicNote"] as string | undefined;
@@ -93,8 +127,9 @@ export class Service extends DatabaseService<ScheduledMaintenanceStateTimeline>
93
127
  return {
94
128
  createBy,
95
129
  carryForward: {
96
- lastScheduledMaintenanceStateTimelineId:
97
- lastScheduledMaintenanceStateTimeline?.id || null,
130
+ statusTimelineBeforeThisStatus: stateBeforeThis || null,
131
+ statusTimelineAfterThisStatus: stateAfterThis || null,
132
+ publicNote: publicNote,
98
133
  },
99
134
  };
100
135
  }
@@ -113,30 +148,71 @@ export class Service extends DatabaseService<ScheduledMaintenanceStateTimeline>
113
148
 
114
149
  // update the last status as ended.
115
150
 
116
- if (onCreate.carryForward.lastScheduledMaintenanceStateTimelineId) {
151
+ logger.debug("Status Timeline Before this");
152
+ logger.debug(onCreate.carryForward.statusTimelineBeforeThisStatus);
153
+
154
+ logger.debug("Status Timeline After this");
155
+ logger.debug(onCreate.carryForward.statusTimelineAfterThisStatus);
156
+
157
+ logger.debug("Created Item");
158
+ logger.debug(createdItem);
159
+
160
+ // now there are three cases.
161
+ // 1. This is the first status OR there's no status after this.
162
+ if (!onCreate.carryForward.statusTimelineBeforeThisStatus) {
163
+ // This is the first status, no need to update previous status.
164
+ logger.debug("This is the first status.");
165
+ } else if (!onCreate.carryForward.statusTimelineAfterThisStatus) {
166
+ // 2. This is the last status.
167
+ // Update the previous status to end at the start of this status.
168
+ await this.updateOneById({
169
+ id: onCreate.carryForward.statusTimelineBeforeThisStatus.id!,
170
+ data: {
171
+ endsAt: createdItem.startsAt!,
172
+ },
173
+ props: {
174
+ isRoot: true,
175
+ },
176
+ });
177
+ logger.debug("This is the last status.");
178
+ } else {
179
+ // 3. This is in the middle.
180
+ // Update the previous status to end at the start of this status.
117
181
  await this.updateOneById({
118
- id: onCreate.carryForward.lastScheduledMaintenanceStateTimelineId!,
182
+ id: onCreate.carryForward.statusTimelineBeforeThisStatus.id!,
119
183
  data: {
120
- endsAt: createdItem.createdAt || OneUptimeDate.getCurrentDate(),
184
+ endsAt: createdItem.startsAt!,
121
185
  },
122
186
  props: {
123
187
  isRoot: true,
124
188
  },
125
189
  });
190
+
191
+ // Update the next status to start at the end of this status.
192
+ await this.updateOneById({
193
+ id: onCreate.carryForward.statusTimelineAfterThisStatus.id!,
194
+ data: {
195
+ startsAt: createdItem.endsAt!,
196
+ },
197
+ props: {
198
+ isRoot: true,
199
+ },
200
+ });
201
+ logger.debug("This status is in the middle.");
126
202
  }
127
203
 
128
- await ScheduledMaintenanceService.updateOneBy({
129
- query: {
130
- _id: createdItem.scheduledMaintenanceId?.toString(),
131
- },
132
- data: {
133
- currentScheduledMaintenanceStateId:
134
- createdItem.scheduledMaintenanceStateId,
135
- },
136
- props: {
137
- isRoot: true,
138
- },
139
- });
204
+ if (!createdItem.endsAt) {
205
+ await ScheduledMaintenanceService.updateOneBy({
206
+ query: {
207
+ _id: createdItem.scheduledMaintenanceId?.toString(),
208
+ },
209
+ data: {
210
+ currentScheduledMaintenanceStateId:
211
+ createdItem.scheduledMaintenanceStateId,
212
+ },
213
+ props: onCreate.createBy.props,
214
+ });
215
+ }
140
216
 
141
217
  const scheduledMaintenanceState: ScheduledMaintenanceState | null =
142
218
  await ScheduledMaintenanceStateService.findOneBy({
@@ -148,23 +224,18 @@ export class Service extends DatabaseService<ScheduledMaintenanceStateTimeline>
148
224
  },
149
225
  select: {
150
226
  _id: true,
151
- color: true,
152
- name: true,
153
227
  isResolvedState: true,
154
228
  isOngoingState: true,
155
229
  isScheduledState: true,
230
+ color: true,
231
+ name: true,
156
232
  },
157
233
  });
158
234
 
159
235
  const stateName: string = scheduledMaintenanceState?.name || "";
160
-
161
- const scheduledMaintenanceNumber: number | null =
162
- await ScheduledMaintenanceService.getScheduledMaintenanceNumber({
163
- scheduledMaintenanceId: createdItem.scheduledMaintenanceId,
164
- });
236
+ let stateEmoji: string = "➡️";
165
237
 
166
238
  // if resolved state then change emoji to ✅.
167
- let stateEmoji: string = "➡️";
168
239
 
169
240
  if (scheduledMaintenanceState?.isResolvedState) {
170
241
  stateEmoji = "✅";
@@ -175,6 +246,11 @@ export class Service extends DatabaseService<ScheduledMaintenanceStateTimeline>
175
246
  stateEmoji = "🕒";
176
247
  }
177
248
 
249
+ const scheduledMaintenanceNumber: number | null =
250
+ await ScheduledMaintenanceService.getScheduledMaintenanceNumber({
251
+ scheduledMaintenanceId: createdItem.scheduledMaintenanceId,
252
+ });
253
+
178
254
  const projectId: ObjectID = createdItem.projectId!;
179
255
  const scheduledMaintenanceId: ObjectID =
180
256
  createdItem.scheduledMaintenanceId!;
@@ -198,9 +274,6 @@ export class Service extends DatabaseService<ScheduledMaintenanceStateTimeline>
198
274
  },
199
275
  });
200
276
 
201
- // TODO: DELETE THIS WHEN WORKFLOW IS IMPLEMENMTED.
202
- // check if this is resolved state, and if it is then resolve all the monitors.
203
-
204
277
  const isResolvedState: ScheduledMaintenanceState | null =
205
278
  await ScheduledMaintenanceStateService.findOneBy({
206
279
  query: {
@@ -405,6 +478,7 @@ export class Service extends DatabaseService<ScheduledMaintenanceStateTimeline>
405
478
  select: {
406
479
  scheduledMaintenanceId: true,
407
480
  startsAt: true,
481
+ endsAt: true,
408
482
  },
409
483
  props: {
410
484
  isRoot: true,
@@ -425,80 +499,106 @@ export class Service extends DatabaseService<ScheduledMaintenanceStateTimeline>
425
499
  },
426
500
  });
427
501
 
502
+ if (!scheduledMaintenanceStateTimelineToBeDeleted) {
503
+ throw new BadDataException(
504
+ "Scheduled maintenance state timeline not found.",
505
+ );
506
+ }
507
+
428
508
  if (scheduledMaintenanceStateTimeline.isOne()) {
429
509
  throw new BadDataException(
430
510
  "Cannot delete the only state timeline. Scheduled Maintenance should have at least one state in its timeline.",
431
511
  );
432
512
  }
433
513
 
434
- if (scheduledMaintenanceStateTimelineToBeDeleted?.startsAt) {
435
- const beforeState: ScheduledMaintenanceStateTimeline | null =
436
- await this.findOneBy({
437
- query: {
438
- scheduledMaintenanceId: scheduledMaintenanceId,
439
- startsAt: QueryHelper.lessThan(
440
- scheduledMaintenanceStateTimelineToBeDeleted?.startsAt,
441
- ),
442
- },
443
- sort: {
444
- createdAt: SortOrder.Descending,
445
- },
446
- props: {
447
- isRoot: true,
448
- },
449
- select: {
450
- _id: true,
451
- startsAt: true,
452
- },
453
- });
454
-
455
- if (beforeState) {
456
- const afterState: ScheduledMaintenanceStateTimeline | null =
457
- await this.findOneBy({
458
- query: {
459
- scheduledMaintenanceId: scheduledMaintenanceId,
460
- startsAt: QueryHelper.greaterThan(
461
- scheduledMaintenanceStateTimelineToBeDeleted?.startsAt,
462
- ),
463
- },
464
- sort: {
465
- createdAt: SortOrder.Ascending,
466
- },
467
- props: {
468
- isRoot: true,
469
- },
470
- select: {
471
- _id: true,
472
- startsAt: true,
473
- },
474
- });
475
-
476
- if (!afterState) {
477
- // if there's nothing after then end date of before state is null.
478
-
479
- await this.updateOneById({
480
- id: beforeState.id!,
481
- data: {
482
- endsAt: null as any,
483
- },
484
- props: {
485
- isRoot: true,
486
- },
487
- });
488
- } else {
489
- // if there's something after then end date of before state is start date of after state.
490
-
491
- await this.updateOneById({
492
- id: beforeState.id!,
493
- data: {
494
- endsAt: afterState.startsAt!,
495
- },
496
- props: {
497
- isRoot: true,
498
- },
499
- });
500
- }
501
- }
514
+ // There are three cases.
515
+ // 1. This is the first state.
516
+ // 2. This is the last state.
517
+ // 3. This is in the middle.
518
+
519
+ const stateBeforeThis: ScheduledMaintenanceStateTimeline | null =
520
+ await this.findOneBy({
521
+ query: {
522
+ _id: QueryHelper.notEquals(deleteBy.query._id as string),
523
+ scheduledMaintenanceId: scheduledMaintenanceId,
524
+ startsAt: QueryHelper.lessThanEqualTo(
525
+ scheduledMaintenanceStateTimelineToBeDeleted.startsAt!,
526
+ ),
527
+ },
528
+ sort: {
529
+ startsAt: SortOrder.Descending,
530
+ },
531
+ props: {
532
+ isRoot: true,
533
+ },
534
+ select: {
535
+ scheduledMaintenanceStateId: true,
536
+ startsAt: true,
537
+ endsAt: true,
538
+ },
539
+ });
540
+
541
+ const stateAfterThis: ScheduledMaintenanceStateTimeline | null =
542
+ await this.findOneBy({
543
+ query: {
544
+ scheduledMaintenanceId: scheduledMaintenanceId,
545
+ startsAt: QueryHelper.greaterThan(
546
+ scheduledMaintenanceStateTimelineToBeDeleted.startsAt!,
547
+ ),
548
+ },
549
+ sort: {
550
+ startsAt: SortOrder.Ascending,
551
+ },
552
+ props: {
553
+ isRoot: true,
554
+ },
555
+ select: {
556
+ scheduledMaintenanceStateId: true,
557
+ startsAt: true,
558
+ endsAt: true,
559
+ },
560
+ });
561
+
562
+ if (!stateBeforeThis) {
563
+ // This is the first state, no need to update previous state.
564
+ logger.debug("This is the first state.");
565
+ } else if (!stateAfterThis) {
566
+ // This is the last state.
567
+ // Update the previous state to end at the end of this state.
568
+ await this.updateOneById({
569
+ id: stateBeforeThis.id!,
570
+ data: {
571
+ endsAt: scheduledMaintenanceStateTimelineToBeDeleted.endsAt!,
572
+ },
573
+ props: {
574
+ isRoot: true,
575
+ },
576
+ });
577
+ logger.debug("This is the last state.");
578
+ } else {
579
+ // This state is in the middle.
580
+ // Update the previous state to end at the start of the next state.
581
+ await this.updateOneById({
582
+ id: stateBeforeThis.id!,
583
+ data: {
584
+ endsAt: stateAfterThis.startsAt!,
585
+ },
586
+ props: {
587
+ isRoot: true,
588
+ },
589
+ });
590
+
591
+ // Update the next state to start at the start of this state.
592
+ await this.updateOneById({
593
+ id: stateAfterThis.id!,
594
+ data: {
595
+ startsAt: scheduledMaintenanceStateTimelineToBeDeleted.startsAt!,
596
+ },
597
+ props: {
598
+ isRoot: true,
599
+ },
600
+ });
601
+ logger.debug("This state is in the middle.");
502
602
  }
503
603
  }
504
604
 
@@ -517,14 +617,14 @@ export class Service extends DatabaseService<ScheduledMaintenanceStateTimeline>
517
617
  const scheduledMaintenanceId: ObjectID =
518
618
  onDelete.carryForward as ObjectID;
519
619
 
520
- // get last status of this monitor.
620
+ // get last status of this scheduled maintenance.
521
621
  const scheduledMaintenanceStateTimeline: ScheduledMaintenanceStateTimeline | null =
522
622
  await this.findOneBy({
523
623
  query: {
524
624
  scheduledMaintenanceId: scheduledMaintenanceId,
525
625
  },
526
626
  sort: {
527
- createdAt: SortOrder.Descending,
627
+ startsAt: SortOrder.Descending,
528
628
  },
529
629
  props: {
530
630
  isRoot: true,