@oneuptime/common 7.0.4194 → 7.0.4222

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 (121) hide show
  1. package/Models/AnalyticsModels/AnalyticsBaseModel/CommonModel.ts +4 -0
  2. package/Models/DatabaseModels/Index.ts +4 -0
  3. package/Models/DatabaseModels/OnCallDutyPolicyTimeLog.ts +498 -0
  4. package/Models/DatabaseModels/UserNotificationRule.ts +0 -2
  5. package/Models/DatabaseModels/WorkspaceNotificationRule.ts +2 -2
  6. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +0 -2
  7. package/Models/DatabaseModels/WorkspaceSetting.ts +0 -2
  8. package/Models/DatabaseModels/WorkspaceUserAuthToken.ts +0 -2
  9. package/Server/Infrastructure/Postgres/SchemaMigrations/1747305098533-MigrationName.ts +69 -0
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  11. package/Server/Services/Index.ts +3 -0
  12. package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +25 -0
  13. package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +29 -0
  14. package/Server/Services/OnCallDutyPolicyScheduleService.ts +73 -0
  15. package/Server/Services/OnCallDutyPolicyTimeLogService.ts +175 -0
  16. package/Server/Services/TeamMemberService.ts +10 -0
  17. package/Server/Services/WorkspaceNotificationRuleService.ts +1 -1
  18. package/Server/Types/Database/QueryHelper.ts +15 -0
  19. package/Server/Types/Database/QueryUtil.ts +18 -0
  20. package/Server/Utils/AnalyticsDatabase/Statement.ts +5 -1
  21. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +16 -0
  22. package/Tests/Types/JSON.test.ts +2 -0
  23. package/Types/BaseDatabase/GreaterThan.ts +11 -0
  24. package/Types/BaseDatabase/GreaterThanOrEqual.ts +11 -0
  25. package/Types/BaseDatabase/GreaterThanOrNull.ts +39 -0
  26. package/Types/BaseDatabase/LessThan.ts +11 -0
  27. package/Types/BaseDatabase/LessThanOrEqual.ts +11 -0
  28. package/Types/BaseDatabase/LessThanOrNull.ts +39 -0
  29. package/Types/Date.ts +18 -0
  30. package/Types/JSON.ts +8 -0
  31. package/Types/Permission.ts +11 -0
  32. package/Types/SerializableObjectDictionary.ts +4 -0
  33. package/Types/Time/RangeStartAndEndDateTime.ts +98 -0
  34. package/Types/Time/TimeRange.ts +15 -0
  35. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +3 -3
  36. package/UI/Components/Date/RangeStartAndEndDateEdit.tsx +64 -0
  37. package/UI/Components/Date/RangeStartAndEndDateView.tsx +86 -0
  38. package/UI/Components/Filters/FilterViewer.tsx +5 -5
  39. package/UI/Components/Table/LocalTable.tsx +74 -0
  40. package/UI/Components/Table/Table.tsx +33 -24
  41. package/UI/Components/Table/TableBody.tsx +5 -1
  42. package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/CommonModel.js.map +1 -1
  43. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  44. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  45. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js +522 -0
  46. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js.map +1 -0
  47. package/build/dist/Models/DatabaseModels/UserNotificationRule.js +0 -2
  48. package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
  49. package/build/dist/Models/DatabaseModels/WorkspaceNotificationRule.js +2 -2
  50. package/build/dist/Models/DatabaseModels/WorkspaceNotificationRule.js.map +1 -1
  51. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js +0 -2
  52. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  53. package/build/dist/Models/DatabaseModels/WorkspaceSetting.js +0 -2
  54. package/build/dist/Models/DatabaseModels/WorkspaceSetting.js.map +1 -1
  55. package/build/dist/Models/DatabaseModels/WorkspaceUserAuthToken.js +0 -2
  56. package/build/dist/Models/DatabaseModels/WorkspaceUserAuthToken.js.map +1 -1
  57. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1747305098533-MigrationName.js +30 -0
  58. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1747305098533-MigrationName.js.map +1 -0
  59. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  60. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  61. package/build/dist/Server/Services/Index.js +2 -0
  62. package/build/dist/Server/Services/Index.js.map +1 -1
  63. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +20 -0
  64. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
  65. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +24 -0
  66. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
  67. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +58 -0
  68. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  69. package/build/dist/Server/Services/OnCallDutyPolicyTimeLogService.js +107 -0
  70. package/build/dist/Server/Services/OnCallDutyPolicyTimeLogService.js.map +1 -0
  71. package/build/dist/Server/Services/TeamMemberService.js +9 -0
  72. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  73. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +8 -8
  74. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  75. package/build/dist/Server/Types/Database/QueryHelper.js +21 -7
  76. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  77. package/build/dist/Server/Types/Database/QueryUtil.js +12 -0
  78. package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
  79. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +5 -1
  80. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
  81. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +14 -0
  82. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  83. package/build/dist/Tests/Types/JSON.test.js +2 -0
  84. package/build/dist/Tests/Types/JSON.test.js.map +1 -1
  85. package/build/dist/Types/BaseDatabase/GreaterThan.js +8 -0
  86. package/build/dist/Types/BaseDatabase/GreaterThan.js.map +1 -1
  87. package/build/dist/Types/BaseDatabase/GreaterThanOrEqual.js +8 -0
  88. package/build/dist/Types/BaseDatabase/GreaterThanOrEqual.js.map +1 -1
  89. package/build/dist/Types/BaseDatabase/GreaterThanOrNull.js +29 -0
  90. package/build/dist/Types/BaseDatabase/GreaterThanOrNull.js.map +1 -0
  91. package/build/dist/Types/BaseDatabase/LessThan.js +8 -0
  92. package/build/dist/Types/BaseDatabase/LessThan.js.map +1 -1
  93. package/build/dist/Types/BaseDatabase/LessThanOrEqual.js +8 -0
  94. package/build/dist/Types/BaseDatabase/LessThanOrEqual.js.map +1 -1
  95. package/build/dist/Types/BaseDatabase/LessThanOrNull.js +29 -0
  96. package/build/dist/Types/BaseDatabase/LessThanOrNull.js.map +1 -0
  97. package/build/dist/Types/Date.js +12 -0
  98. package/build/dist/Types/Date.js.map +1 -1
  99. package/build/dist/Types/JSON.js +2 -0
  100. package/build/dist/Types/JSON.js.map +1 -1
  101. package/build/dist/Types/Permission.js +8 -0
  102. package/build/dist/Types/Permission.js.map +1 -1
  103. package/build/dist/Types/SerializableObjectDictionary.js +4 -0
  104. package/build/dist/Types/SerializableObjectDictionary.js.map +1 -1
  105. package/build/dist/Types/Time/RangeStartAndEndDateTime.js +48 -0
  106. package/build/dist/Types/Time/RangeStartAndEndDateTime.js.map +1 -0
  107. package/build/dist/Types/Time/TimeRange.js +16 -0
  108. package/build/dist/Types/Time/TimeRange.js.map +1 -0
  109. package/build/dist/UI/Components/Date/RangeStartAndEndDateEdit.js +32 -0
  110. package/build/dist/UI/Components/Date/RangeStartAndEndDateEdit.js.map +1 -0
  111. package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js +43 -0
  112. package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js.map +1 -0
  113. package/build/dist/UI/Components/Filters/FilterViewer.js +3 -3
  114. package/build/dist/UI/Components/Filters/FilterViewer.js.map +1 -1
  115. package/build/dist/UI/Components/Table/LocalTable.js +32 -0
  116. package/build/dist/UI/Components/Table/LocalTable.js.map +1 -0
  117. package/build/dist/UI/Components/Table/Table.js +19 -8
  118. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  119. package/build/dist/UI/Components/Table/TableBody.js +3 -0
  120. package/build/dist/UI/Components/Table/TableBody.js.map +1 -1
  121. package/package.json +2 -2
@@ -131,6 +131,7 @@ import { MigrationName1743692467814 } from "./1743692467814-MigrationName";
131
131
  import { MigrationName1743714801105 } from "./1743714801105-MigrationName";
132
132
  import { MigrationName1744804990712 } from "./1744804990712-MigrationName";
133
133
  import { MigrationName1744809770336 } from "./1744809770336-MigrationName";
134
+ import { MigrationName1747305098533 } from "./1747305098533-MigrationName";
134
135
 
135
136
  export default [
136
137
  InitialMigration,
@@ -266,4 +267,5 @@ export default [
266
267
  MigrationName1743714801105,
267
268
  MigrationName1744804990712,
268
269
  MigrationName1744809770336,
270
+ MigrationName1747305098533,
269
271
  ];
@@ -162,7 +162,10 @@ import OnCallDutyPolicyUserOverrideService from "./OnCallDutyPolicyUserOverrideS
162
162
 
163
163
  import MonitorLogService from "./MonitorLogService";
164
164
 
165
+ import OnCallDutyPolicyTimeLogService from "./OnCallDutyPolicyTimeLogService";
166
+
165
167
  const services: Array<BaseService> = [
168
+ OnCallDutyPolicyTimeLogService,
166
169
  AcmeCertificateService,
167
170
  PromoCodeService,
168
171
 
@@ -19,6 +19,8 @@ import OnCallDutyPolicyFeedService from "./OnCallDutyPolicyFeedService";
19
19
  import { OnCallDutyPolicyFeedEventType } from "../../Models/DatabaseModels/OnCallDutyPolicyFeed";
20
20
  import { Gray500, Red500 } from "../../Types/BrandColors";
21
21
  import Team from "../../Models/DatabaseModels/Team";
22
+ import OnCallDutyPolicyTimeLogService from "./OnCallDutyPolicyTimeLogService";
23
+ import OneUptimeDate from "../../Types/Date";
22
24
 
23
25
  export class Service extends DatabaseService<Model> {
24
26
  public constructor() {
@@ -134,6 +136,17 @@ export class Service extends DatabaseService<Model> {
134
136
  eventType:
135
137
  NotificationSettingEventType.SEND_WHEN_USER_IS_ADDED_TO_ON_CALL_POLICY,
136
138
  });
139
+
140
+ // add start log
141
+ OnCallDutyPolicyTimeLogService.startTimeLogForUser({
142
+ userId: sendEmailToUserId,
143
+ onCallDutyPolicyId: createdModel.onCallDutyPolicy!.id!,
144
+ onCallDutyPolicyEscalationRuleId:
145
+ createdModel.onCallDutyPolicyEscalationRule!.id!,
146
+ projectId: createdModel.projectId!,
147
+ teamId: createdModel.teamId!,
148
+ startsAt: new Date(),
149
+ });
137
150
  }
138
151
 
139
152
  // add workspace message.
@@ -304,6 +317,18 @@ export class Service extends DatabaseService<Model> {
304
317
  eventType:
305
318
  NotificationSettingEventType.SEND_WHEN_USER_IS_REMOVED_FROM_ON_CALL_POLICY,
306
319
  });
320
+
321
+ // end time log
322
+ await OnCallDutyPolicyTimeLogService.endTimeLogForUser({
323
+ userId: sendEmailToUserId,
324
+ onCallDutyPolicyId: deletedItem.onCallDutyPolicy!.id!,
325
+ onCallDutyPolicyEscalationRuleId:
326
+ deletedItem.onCallDutyPolicyEscalationRule!.id!,
327
+
328
+ projectId: deletedItem.projectId!,
329
+ teamId: deletedItem.teamId!,
330
+ endsAt: OneUptimeDate.getCurrentDate(),
331
+ });
307
332
  }
308
333
  }
309
334
 
@@ -18,6 +18,9 @@ import { OnCallDutyPolicyFeedEventType } from "../../Models/DatabaseModels/OnCal
18
18
  import { Gray500, Red500 } from "../../Types/BrandColors";
19
19
  import UserService from "./UserService";
20
20
  import User from "../../Models/DatabaseModels/User";
21
+ import OnCallDutyPolicyTimeLogService from "./OnCallDutyPolicyTimeLogService";
22
+ import OneUptimeDate from "../../Types/Date";
23
+ import logger from "../Utils/Logger";
21
24
 
22
25
  export class Service extends DatabaseService<Model> {
23
26
  public constructor() {
@@ -141,6 +144,20 @@ export class Service extends DatabaseService<Model> {
141
144
  notifyUserId: createdModel.createdByUserId! || undefined,
142
145
  },
143
146
  });
147
+
148
+ // also add on-call duty time log.
149
+ OnCallDutyPolicyTimeLogService.startTimeLogForUser({
150
+ projectId: projectId!,
151
+ onCallDutyPolicyId: onCallDutyPolicyId!,
152
+ onCallDutyPolicyEscalationRuleId:
153
+ createdModel.onCallDutyPolicyEscalationRule!.id!,
154
+ userId: createdModel.user!.id!,
155
+ startsAt: OneUptimeDate.getCurrentDate(),
156
+ }).catch((error: Error) => {
157
+ logger.error(
158
+ `Error starting time log for user ${createdModel.user?.id}: ${error}`,
159
+ );
160
+ });
144
161
  }
145
162
 
146
163
  return createdItem;
@@ -213,6 +230,18 @@ export class Service extends DatabaseService<Model> {
213
230
  notifyUserId: userId || undefined,
214
231
  },
215
232
  });
233
+
234
+ // also remove on-call duty time log.
235
+ OnCallDutyPolicyTimeLogService.endTimeLogForUser({
236
+ projectId: projectId,
237
+ onCallDutyPolicyId: onCallDutyPolicyId,
238
+ onCallDutyPolicyEscalationRuleId:
239
+ item.onCallDutyPolicyEscalationRule!.id!,
240
+ userId: userId,
241
+ endsAt: OneUptimeDate.getCurrentDate(),
242
+ }).catch((error: Error) => {
243
+ logger.error(`Error ending time log for user ${userId}: ${error}`);
244
+ });
216
245
  }
217
246
  }
218
247
  }
@@ -31,6 +31,9 @@ import logger from "../Utils/Logger";
31
31
  import OnCallDutyPolicyFeedService from "./OnCallDutyPolicyFeedService";
32
32
  import { OnCallDutyPolicyFeedEventType } from "../../Models/DatabaseModels/OnCallDutyPolicyFeed";
33
33
  import { Green500 } from "../../Types/BrandColors";
34
+ import OnCallDutyPolicyTimeLogService from "./OnCallDutyPolicyTimeLogService";
35
+ import DeleteBy from "../Types/Database/DeleteBy";
36
+ import { OnDelete } from "../Types/Database/Hooks";
34
37
 
35
38
  export class Service extends DatabaseService<OnCallDutyPolicySchedule> {
36
39
  private layerUtil = new LayerUtil();
@@ -39,6 +42,38 @@ export class Service extends DatabaseService<OnCallDutyPolicySchedule> {
39
42
  super(OnCallDutyPolicySchedule);
40
43
  }
41
44
 
45
+ protected override async onBeforeDelete(
46
+ deleteBy: DeleteBy<OnCallDutyPolicySchedule>,
47
+ ): Promise<OnDelete<OnCallDutyPolicySchedule>> {
48
+ const callSchedules: Array<OnCallDutyPolicySchedule> = await this.findBy({
49
+ query: deleteBy.query,
50
+ select: {
51
+ _id: true,
52
+ projectId: true,
53
+ },
54
+ limit: LIMIT_PER_PROJECT,
55
+ skip: 0,
56
+ props: {
57
+ isRoot: true,
58
+ },
59
+ });
60
+
61
+ for (const schedule of callSchedules) {
62
+ OnCallDutyPolicyTimeLogService.endTimeForSchedule({
63
+ projectId: schedule.projectId!,
64
+ onCallDutyPolicyScheduleId: schedule.id!,
65
+ endsAt: OneUptimeDate.getCurrentDate(),
66
+ }).catch((err: Error) => {
67
+ logger.error(err);
68
+ });
69
+ }
70
+
71
+ return {
72
+ deleteBy: deleteBy,
73
+ carryForward: {},
74
+ };
75
+ }
76
+
42
77
  public async getOnCallSchedulesWhereUserIsOnCallDuty(data: {
43
78
  projectId: ObjectID;
44
79
  userId: ObjectID;
@@ -228,6 +263,25 @@ export class Service extends DatabaseService<OnCallDutyPolicySchedule> {
228
263
  NotificationSettingEventType.SEND_WHEN_USER_IS_NO_LONGER_ACTIVE_ON_ON_CALL_ROSTER,
229
264
  });
230
265
 
266
+ // add end log for user.
267
+ OnCallDutyPolicyTimeLogService.endTimeLogForUser({
268
+ userId: sendEmailToUserId,
269
+ onCallDutyPolicyScheduleId: data.scheduleId,
270
+ onCallDutyPolicyEscalationRuleId:
271
+ escalationRule.onCallDutyPolicyEscalationRule!.id!,
272
+ onCallDutyPolicyId: escalationRule.onCallDutyPolicy!.id!,
273
+ projectId: projectId,
274
+ endsAt: OneUptimeDate.getCurrentDate(),
275
+ }).catch((err: Error) => {
276
+ logger.error(
277
+ "Error ending time log for user: " +
278
+ sendEmailToUserId.toString() +
279
+ " for schedule: " +
280
+ data.scheduleId.toString(),
281
+ );
282
+ logger.error(err);
283
+ });
284
+
231
285
  const onCallDutyPolicyId: ObjectID =
232
286
  escalationRule.onCallDutyPolicy!.id!;
233
287
 
@@ -316,6 +370,25 @@ export class Service extends DatabaseService<OnCallDutyPolicySchedule> {
316
370
  NotificationSettingEventType.SEND_WHEN_USER_IS_ON_CALL_ROSTER,
317
371
  });
318
372
 
373
+ // add start log for user.
374
+ OnCallDutyPolicyTimeLogService.startTimeLogForUser({
375
+ userId: sendEmailToUserId,
376
+ onCallDutyPolicyScheduleId: data.scheduleId,
377
+ onCallDutyPolicyEscalationRuleId:
378
+ escalationRule.onCallDutyPolicyEscalationRule!.id!,
379
+ onCallDutyPolicyId: escalationRule.onCallDutyPolicy!.id!,
380
+ projectId: projectId,
381
+ startsAt: OneUptimeDate.getCurrentDate(),
382
+ }).catch((err: Error) => {
383
+ logger.error(
384
+ "Error starting time log for user: " +
385
+ sendEmailToUserId.toString() +
386
+ " for schedule: " +
387
+ data.scheduleId.toString(),
388
+ );
389
+ logger.error(err);
390
+ });
391
+
319
392
  const onCallDutyPolicyId: ObjectID =
320
393
  escalationRule.onCallDutyPolicy!.id!;
321
394
 
@@ -0,0 +1,175 @@
1
+ import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
2
+ import ObjectID from "../../Types/ObjectID";
3
+ import DatabaseService from "./DatabaseService";
4
+ import Model from "Common/Models/DatabaseModels/OnCallDutyPolicyTimeLog";
5
+
6
+ export class Service extends DatabaseService<Model> {
7
+ public constructor() {
8
+ super(Model);
9
+ }
10
+
11
+ public async startTimeLogForUser(data: {
12
+ projectId: ObjectID;
13
+ onCallDutyPolicyId: ObjectID;
14
+ onCallDutyPolicyEscalationRuleId: ObjectID;
15
+ userId: ObjectID;
16
+ teamId?: ObjectID;
17
+ onCallDutyPolicyScheduleId?: ObjectID;
18
+ startsAt: Date;
19
+ }): Promise<Model> {
20
+ const {
21
+ onCallDutyPolicyId,
22
+ userId,
23
+ teamId,
24
+ onCallDutyPolicyScheduleId,
25
+ startsAt,
26
+ } = data;
27
+
28
+ // check if the time log already exists for the user.
29
+
30
+ const existingTimeLog: Model | null = await this.findOneBy({
31
+ query: {
32
+ projectId: data.projectId,
33
+ onCallDutyPolicyId,
34
+ onCallDutyPolicyEscalationRuleId: data.onCallDutyPolicyEscalationRuleId,
35
+ userId,
36
+ ...(teamId && { teamId }),
37
+ ...(onCallDutyPolicyScheduleId && { onCallDutyPolicyScheduleId }),
38
+ },
39
+ props: {
40
+ isRoot: true,
41
+ },
42
+ });
43
+
44
+ if (existingTimeLog) {
45
+ return existingTimeLog;
46
+ }
47
+
48
+ const timeLog: Model = new Model();
49
+ timeLog.onCallDutyPolicyId = onCallDutyPolicyId;
50
+ timeLog.userId = userId;
51
+ if (teamId) {
52
+ timeLog.teamId = teamId;
53
+ }
54
+ timeLog.onCallDutyPolicyEscalationRuleId =
55
+ data.onCallDutyPolicyEscalationRuleId;
56
+ if (onCallDutyPolicyScheduleId) {
57
+ timeLog.onCallDutyPolicyScheduleId = onCallDutyPolicyScheduleId;
58
+ }
59
+ timeLog.projectId = data.projectId;
60
+ timeLog.startsAt = startsAt;
61
+
62
+ return await this.create({
63
+ data: timeLog,
64
+ props: {
65
+ isRoot: true,
66
+ },
67
+ });
68
+ }
69
+
70
+ public async endTimeForSchedule(data: {
71
+ projectId: ObjectID;
72
+ onCallDutyPolicyScheduleId: ObjectID;
73
+ endsAt: Date;
74
+ }): Promise<void> {
75
+ const { endsAt, onCallDutyPolicyScheduleId } = data;
76
+ await this.updateBy({
77
+ query: {
78
+ projectId: data.projectId,
79
+ onCallDutyPolicyScheduleId,
80
+ },
81
+ data: {
82
+ endsAt: endsAt,
83
+ },
84
+ limit: LIMIT_PER_PROJECT,
85
+ skip: 0,
86
+ props: {
87
+ isRoot: true,
88
+ },
89
+ });
90
+ }
91
+
92
+ public async endTimeForTeam(data: {
93
+ projectId: ObjectID;
94
+ teamId: ObjectID;
95
+ endsAt: Date;
96
+ }): Promise<void> {
97
+ const { endsAt, teamId } = data;
98
+ await this.updateBy({
99
+ query: {
100
+ projectId: data.projectId,
101
+ teamId,
102
+ },
103
+
104
+ limit: LIMIT_PER_PROJECT,
105
+ skip: 0,
106
+ data: {
107
+ endsAt: endsAt,
108
+ },
109
+ props: {
110
+ isRoot: true,
111
+ },
112
+ });
113
+ }
114
+
115
+ public async endTimeForUser(data: {
116
+ projectId: ObjectID;
117
+ userId: ObjectID;
118
+ endsAt: Date;
119
+ }): Promise<void> {
120
+ const { endsAt, userId } = data;
121
+ await this.updateBy({
122
+ query: {
123
+ projectId: data.projectId,
124
+ userId,
125
+ },
126
+ limit: LIMIT_PER_PROJECT,
127
+ skip: 0,
128
+ data: {
129
+ endsAt: endsAt,
130
+ },
131
+ props: {
132
+ isRoot: true,
133
+ },
134
+ });
135
+ }
136
+
137
+ public async endTimeLogForUser(data: {
138
+ projectId: ObjectID;
139
+ onCallDutyPolicyId: ObjectID;
140
+ onCallDutyPolicyEscalationRuleId: ObjectID;
141
+ userId: ObjectID;
142
+ teamId?: ObjectID;
143
+ onCallDutyPolicyScheduleId?: ObjectID;
144
+ endsAt: Date;
145
+ }): Promise<void> {
146
+ const {
147
+ onCallDutyPolicyId,
148
+ userId,
149
+ teamId,
150
+ onCallDutyPolicyScheduleId,
151
+ endsAt,
152
+ } = data;
153
+
154
+ await this.updateBy({
155
+ query: {
156
+ projectId: data.projectId,
157
+ onCallDutyPolicyId,
158
+ onCallDutyPolicyEscalationRuleId: data.onCallDutyPolicyEscalationRuleId,
159
+ userId,
160
+ ...(teamId && { teamId }),
161
+ ...(onCallDutyPolicyScheduleId && { onCallDutyPolicyScheduleId }),
162
+ },
163
+ limit: LIMIT_PER_PROJECT,
164
+ skip: 0,
165
+ data: {
166
+ endsAt: endsAt,
167
+ },
168
+ props: {
169
+ isRoot: true,
170
+ },
171
+ });
172
+ }
173
+ }
174
+
175
+ export default new Service();
@@ -34,6 +34,8 @@ import Project from "Common/Models/DatabaseModels/Project";
34
34
  import TeamMember from "Common/Models/DatabaseModels/TeamMember";
35
35
  import User from "Common/Models/DatabaseModels/User";
36
36
  import ProjectUserService from "./ProjectUserService";
37
+ import OnCallDutyPolicyTimeLogService from "./OnCallDutyPolicyTimeLogService";
38
+ import OneUptimeDate from "../../Types/Date";
37
39
 
38
40
  export class TeamMemberService extends DatabaseService<TeamMember> {
39
41
  public constructor() {
@@ -280,6 +282,14 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
280
282
 
281
283
  // check if there's one member in the team.
282
284
  for (const member of members) {
285
+ OnCallDutyPolicyTimeLogService.endTimeForUser({
286
+ projectId: member.projectId!,
287
+ userId: member.userId!,
288
+ endsAt: OneUptimeDate.getCurrentDate(),
289
+ }).catch((err: Error) => {
290
+ logger.error(err);
291
+ });
292
+
283
293
  if (member.team?.shouldHaveAtLeastOneMember) {
284
294
  if (!member.hasAcceptedInvitation) {
285
295
  continue;
@@ -1541,7 +1541,7 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
1541
1541
  [NotificationRuleConditionCheckOn.ScheduledMaintenanceLabels]:
1542
1542
  undefined,
1543
1543
  [NotificationRuleConditionCheckOn.Monitors]: [
1544
- alert.monitor?.id!.toString() || "",
1544
+ alert.monitor!.id!.toString() || "",
1545
1545
  ],
1546
1546
 
1547
1547
  [NotificationRuleConditionCheckOn.OnCallDutyPolicyName]: undefined,
@@ -313,6 +313,21 @@ export default class QueryHelper {
313
313
  ) as FindWhereProperty<T>;
314
314
  }
315
315
 
316
+ @CaptureSpan()
317
+ public static lessThanOrNull<T extends number | Date>(
318
+ value: T,
319
+ ): FindWhereProperty<T> {
320
+ const rid: string = Text.generateRandomText(10);
321
+ return Raw(
322
+ (alias: string) => {
323
+ return `(${alias} < :${rid} or ${alias} IS NULL)`;
324
+ },
325
+ {
326
+ [rid]: value,
327
+ },
328
+ ) as FindWhereProperty<T>;
329
+ }
330
+
316
331
  @CaptureSpan()
317
332
  public static lessThanEqualToOrNull<T extends number | Date>(
318
333
  value: T,
@@ -20,6 +20,8 @@ import Typeof from "Common/Types/Typeof";
20
20
  import { FindOperator } from "typeorm/find-options/FindOperator";
21
21
  import { CompareType } from "../../../Types/Database/CompareBase";
22
22
  import CaptureSpan from "../../Utils/Telemetry/CaptureSpan";
23
+ import LessThanOrNull from "../../../Types/BaseDatabase/LessThanOrNull";
24
+ import GreaterThanOrNull from "../../../Types/BaseDatabase/GreaterThanOrNull";
23
25
 
24
26
  export default class QueryUtil {
25
27
  @CaptureSpan()
@@ -160,6 +162,22 @@ export default class QueryUtil {
160
162
  query[key] = QueryHelper.lessThanEqualTo(
161
163
  (query[key] as LessThanOrEqual<CompareType>).toString() as any,
162
164
  ) as any;
165
+ } else if (
166
+ query[key] &&
167
+ query[key] instanceof LessThanOrNull &&
168
+ tableColumnMetadata
169
+ ) {
170
+ query[key] = QueryHelper.lessThanOrNull(
171
+ (query[key] as LessThanOrNull<CompareType>).toString() as any,
172
+ ) as any;
173
+ } else if (
174
+ query[key] &&
175
+ query[key] instanceof GreaterThanOrNull &&
176
+ tableColumnMetadata
177
+ ) {
178
+ query[key] = QueryHelper.greaterThanOrNull(
179
+ (query[key] as LessThanOrNull<CompareType>).toString() as any,
180
+ ) as any;
163
181
  } else if (
164
182
  query[key] &&
165
183
  Array.isArray(query[key]) &&
@@ -7,6 +7,8 @@ import GreaterThanOrEqual from "Common/Types/BaseDatabase/GreaterThanOrEqual";
7
7
  import Includes from "Common/Types/BaseDatabase/Includes";
8
8
  import LessThan from "Common/Types/BaseDatabase/LessThan";
9
9
  import LessThanOrEqual from "Common/Types/BaseDatabase/LessThanOrEqual";
10
+ import LessThanOrNull from "../../../Types/BaseDatabase/LessThanOrNull";
11
+ import GreaterThanOrNull from "../../../Types/BaseDatabase/GreaterThanOrNull";
10
12
  import Search from "Common/Types/BaseDatabase/Search";
11
13
  import OneUptimeDate from "Common/Types/Date";
12
14
  import Dictionary from "Common/Types/Dictionary";
@@ -99,7 +101,9 @@ export class Statement implements BaseQueryParams {
99
101
  v.value instanceof LessThan ||
100
102
  v.value instanceof LessThanOrEqual ||
101
103
  v.value instanceof GreaterThan ||
102
- v.value instanceof GreaterThanOrEqual
104
+ v.value instanceof GreaterThanOrEqual ||
105
+ v.value instanceof LessThanOrNull ||
106
+ v.value instanceof GreaterThanOrNull
103
107
  ) {
104
108
  finalValue = v.value.value;
105
109
  } else if (v.value instanceof Includes) {
@@ -20,6 +20,8 @@ import Includes from "Common/Types/BaseDatabase/Includes";
20
20
  import IsNull from "Common/Types/BaseDatabase/IsNull";
21
21
  import LessThan from "Common/Types/BaseDatabase/LessThan";
22
22
  import LessThanOrEqual from "Common/Types/BaseDatabase/LessThanOrEqual";
23
+ import GreaterThanOrNull from "../../../Types/BaseDatabase/GreaterThanOrNull";
24
+ import LessThanOrNull from "../../../Types/BaseDatabase/LessThanOrNull";
23
25
  import NotEqual from "Common/Types/BaseDatabase/NotEqual";
24
26
  import Search from "Common/Types/BaseDatabase/Search";
25
27
  import SortOrder from "Common/Types/BaseDatabase/SortOrder";
@@ -382,6 +384,20 @@ export default class StatementGenerator<TBaseModel extends AnalyticsBaseModel> {
382
384
  type: tableColumn.type,
383
385
  }}`,
384
386
  );
387
+ } else if (value instanceof LessThanOrNull) {
388
+ whereStatement.append(
389
+ SQL`AND (${key} <= ${{
390
+ value: value,
391
+ type: tableColumn.type,
392
+ }} OR ${key} IS NULL)`,
393
+ );
394
+ } else if (value instanceof GreaterThanOrNull) {
395
+ whereStatement.append(
396
+ SQL`AND (${key} >= ${{
397
+ value: value,
398
+ type: tableColumn.type,
399
+ }} OR ${key} IS NULL)`,
400
+ );
385
401
  } else if (value instanceof GreaterThanOrEqual) {
386
402
  whereStatement.append(
387
403
  SQL`AND ${key} >= ${{
@@ -19,6 +19,8 @@ describe("ObjectType", () => {
19
19
  "GreaterThanOrEqual",
20
20
  "LessThan",
21
21
  "LessThanOrEqual",
22
+ "LessThanOrNull",
23
+ "GreaterThanOrNull",
22
24
  "Port",
23
25
  "Hostname",
24
26
  "HashedString",
@@ -1,4 +1,5 @@
1
1
  import CompareBase, { CompareType } from "../Database/CompareBase";
2
+ import OneUptimeDate from "../Date";
2
3
  import BadDataException from "../Exception/BadDataException";
3
4
  import { JSONObject, ObjectType } from "../JSON";
4
5
 
@@ -14,6 +15,16 @@ export default class GreaterThan<T extends CompareType> extends CompareBase<T> {
14
15
  };
15
16
  }
16
17
 
18
+ public override toString(): string {
19
+ let value: T = this.value;
20
+
21
+ if (value instanceof Date) {
22
+ value = OneUptimeDate.asDateForDatabaseQuery(value) as T;
23
+ }
24
+
25
+ return value.toString();
26
+ }
27
+
17
28
  public static override fromJSON<T extends CompareType>(
18
29
  json: JSONObject,
19
30
  ): GreaterThan<T> {
@@ -1,4 +1,5 @@
1
1
  import CompareBase, { CompareType } from "../Database/CompareBase";
2
+ import OneUptimeDate from "../Date";
2
3
  import BadDataException from "../Exception/BadDataException";
3
4
  import { JSONObject, ObjectType } from "../JSON";
4
5
 
@@ -16,6 +17,16 @@ export default class GreaterThanOrEqual<
16
17
  };
17
18
  }
18
19
 
20
+ public override toString(): string {
21
+ let value: T = this.value;
22
+
23
+ if (value instanceof Date) {
24
+ value = OneUptimeDate.asDateForDatabaseQuery(value) as T;
25
+ }
26
+
27
+ return value.toString();
28
+ }
29
+
19
30
  public static override fromJSON<T extends CompareType>(
20
31
  json: JSONObject,
21
32
  ): GreaterThanOrEqual<T> {
@@ -0,0 +1,39 @@
1
+ import CompareBase, { CompareType } from "../Database/CompareBase";
2
+ import OneUptimeDate from "../Date";
3
+ import BadDataException from "../Exception/BadDataException";
4
+ import { JSONObject, ObjectType } from "../JSON";
5
+
6
+ export default class GreaterThanOrNull<
7
+ T extends CompareType,
8
+ > extends CompareBase<T> {
9
+ public constructor(value: T) {
10
+ super(value);
11
+ }
12
+
13
+ public override toJSON(): JSONObject {
14
+ return {
15
+ _type: ObjectType.GreaterThanOrNull,
16
+ value: (this as GreaterThanOrNull<T>).toString(),
17
+ };
18
+ }
19
+
20
+ public override toString(): string {
21
+ let value: T = this.value;
22
+
23
+ if (value instanceof Date) {
24
+ value = OneUptimeDate.asDateForDatabaseQuery(value) as T;
25
+ }
26
+
27
+ return value.toString();
28
+ }
29
+
30
+ public static override fromJSON<T extends CompareType>(
31
+ json: JSONObject,
32
+ ): GreaterThanOrNull<T> {
33
+ if (json["_type"] === ObjectType.GreaterThanOrNull) {
34
+ return new GreaterThanOrNull<T>(json["value"] as T);
35
+ }
36
+
37
+ throw new BadDataException("Invalid JSON: " + JSON.stringify(json));
38
+ }
39
+ }
@@ -1,4 +1,5 @@
1
1
  import CompareBase, { CompareType } from "../Database/CompareBase";
2
+ import OneUptimeDate from "../Date";
2
3
  import BadDataException from "../Exception/BadDataException";
3
4
  import { JSONObject, ObjectType } from "../JSON";
4
5
 
@@ -14,6 +15,16 @@ export default class LessThan<T extends CompareType> extends CompareBase<T> {
14
15
  };
15
16
  }
16
17
 
18
+ public override toString(): string {
19
+ let value: T = this.value;
20
+
21
+ if (value instanceof Date) {
22
+ value = OneUptimeDate.asDateForDatabaseQuery(value) as T;
23
+ }
24
+
25
+ return value.toString();
26
+ }
27
+
17
28
  public static override fromJSON<T extends CompareType>(
18
29
  json: JSONObject,
19
30
  ): LessThan<T> {
@@ -1,4 +1,5 @@
1
1
  import CompareBase, { CompareType } from "../Database/CompareBase";
2
+ import OneUptimeDate from "../Date";
2
3
  import BadDataException from "../Exception/BadDataException";
3
4
  import { JSONObject, ObjectType } from "../JSON";
4
5
 
@@ -16,6 +17,16 @@ export default class LessThanOrEqual<
16
17
  };
17
18
  }
18
19
 
20
+ public override toString(): string {
21
+ let value: T = this.value;
22
+
23
+ if (value instanceof Date) {
24
+ value = OneUptimeDate.asDateForDatabaseQuery(value) as T;
25
+ }
26
+
27
+ return value.toString();
28
+ }
29
+
19
30
  public static override fromJSON<T extends CompareType>(
20
31
  json: JSONObject,
21
32
  ): LessThanOrEqual<T> {