@oneuptime/common 9.1.0 → 9.1.2
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.
- package/Models/DatabaseModels/BillingPaymentMethod.ts +45 -9
- package/Models/DatabaseModels/Incident.ts +37 -0
- package/Models/DatabaseModels/StatusPageDomain.ts +3 -2
- package/Models/DatabaseModels/User.ts +1 -1
- package/Server/API/BillingPaymentMethodAPI.ts +6 -7
- package/Server/API/StatusPageAPI.ts +6 -1
- package/Server/EnvironmentConfig.ts +11 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1764324618043-MigrationName.ts +30 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/IncidentService.ts +38 -0
- package/Server/Services/MonitorService.ts +49 -31
- package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +18 -0
- package/Server/Services/StatusPageDomainService.ts +17 -10
- package/Server/Services/TeamMemberService.ts +8 -7
- package/Server/Services/TeamService.ts +2 -1
- package/Server/Types/Workflow/Components/Email.ts +10 -1
- package/Server/Utils/Browser.ts +28 -2
- package/Server/Utils/Captcha.ts +98 -0
- package/Server/Utils/Greenlock/Greenlock.ts +10 -3
- package/Server/Utils/Telemetry.ts +10 -2
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +4 -1
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +23 -10
- package/Tests/Server/Services/TeamMemberService.test.ts +119 -0
- package/UI/Components/Captcha/Captcha.tsx +75 -0
- package/UI/Config.ts +3 -0
- package/build/dist/Models/DatabaseModels/BillingPaymentMethod.js +45 -9
- package/build/dist/Models/DatabaseModels/BillingPaymentMethod.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Incident.js +39 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageDomain.js +2 -2
- package/build/dist/Models/DatabaseModels/StatusPageDomain.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +1 -1
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Server/API/BillingPaymentMethodAPI.js +6 -5
- package/build/dist/Server/API/BillingPaymentMethodAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +6 -1
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +6 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1764324618043-MigrationName.js +17 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1764324618043-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +32 -1
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +44 -24
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +12 -0
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageDomainService.js +12 -9
- package/build/dist/Server/Services/StatusPageDomainService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +9 -8
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TeamService.js +2 -1
- package/build/dist/Server/Services/TeamService.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Email.js +8 -1
- package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
- package/build/dist/Server/Utils/Browser.js +24 -2
- package/build/dist/Server/Utils/Browser.js.map +1 -1
- package/build/dist/Server/Utils/Captcha.js +58 -0
- package/build/dist/Server/Utils/Captcha.js.map +1 -0
- package/build/dist/Server/Utils/Greenlock/Greenlock.js +7 -2
- package/build/dist/Server/Utils/Greenlock/Greenlock.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +3 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +19 -11
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Tests/Server/Services/TeamMemberService.test.js +79 -0
- package/build/dist/Tests/Server/Services/TeamMemberService.test.js.map +1 -1
- package/build/dist/UI/Components/Captcha/Captcha.js +37 -0
- package/build/dist/UI/Components/Captcha/Captcha.js.map +1 -0
- package/build/dist/UI/Config.js +2 -0
- package/build/dist/UI/Config.js.map +1 -1
- package/package.json +2 -1
|
@@ -20,7 +20,11 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
|
|
20
20
|
@AllowAccessIfSubscriptionIsUnpaid()
|
|
21
21
|
@TenantColumn("projectId")
|
|
22
22
|
@TableAccessControl({
|
|
23
|
-
create: [
|
|
23
|
+
create: [
|
|
24
|
+
Permission.ProjectOwner,
|
|
25
|
+
Permission.ManageProjectBilling,
|
|
26
|
+
Permission.CreateBillingPaymentMethod,
|
|
27
|
+
],
|
|
24
28
|
read: [
|
|
25
29
|
Permission.ProjectOwner,
|
|
26
30
|
Permission.ProjectUser,
|
|
@@ -28,7 +32,11 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
|
|
28
32
|
Permission.ProjectMember,
|
|
29
33
|
Permission.ReadBillingPaymentMethod,
|
|
30
34
|
],
|
|
31
|
-
delete: [
|
|
35
|
+
delete: [
|
|
36
|
+
Permission.ProjectOwner,
|
|
37
|
+
Permission.ManageProjectBilling,
|
|
38
|
+
Permission.DeleteBillingPaymentMethod,
|
|
39
|
+
],
|
|
32
40
|
update: [],
|
|
33
41
|
})
|
|
34
42
|
@CrudApiEndpoint(new Route("/billing-payment-methods"))
|
|
@@ -45,7 +53,11 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
|
|
45
53
|
})
|
|
46
54
|
export default class BillingPaymentMethod extends BaseModel {
|
|
47
55
|
@ColumnAccessControl({
|
|
48
|
-
create: [
|
|
56
|
+
create: [
|
|
57
|
+
Permission.ProjectOwner,
|
|
58
|
+
Permission.ManageProjectBilling,
|
|
59
|
+
Permission.CreateBillingPaymentMethod,
|
|
60
|
+
],
|
|
49
61
|
read: [
|
|
50
62
|
Permission.ProjectOwner,
|
|
51
63
|
Permission.ProjectUser,
|
|
@@ -77,7 +89,11 @@ export default class BillingPaymentMethod extends BaseModel {
|
|
|
77
89
|
public project?: Project = undefined;
|
|
78
90
|
|
|
79
91
|
@ColumnAccessControl({
|
|
80
|
-
create: [
|
|
92
|
+
create: [
|
|
93
|
+
Permission.ProjectOwner,
|
|
94
|
+
Permission.ManageProjectBilling,
|
|
95
|
+
Permission.CreateBillingPaymentMethod,
|
|
96
|
+
],
|
|
81
97
|
read: [
|
|
82
98
|
Permission.ProjectOwner,
|
|
83
99
|
Permission.ProjectAdmin,
|
|
@@ -103,7 +119,11 @@ export default class BillingPaymentMethod extends BaseModel {
|
|
|
103
119
|
public projectId?: ObjectID = undefined;
|
|
104
120
|
|
|
105
121
|
@ColumnAccessControl({
|
|
106
|
-
create: [
|
|
122
|
+
create: [
|
|
123
|
+
Permission.ProjectOwner,
|
|
124
|
+
Permission.ManageProjectBilling,
|
|
125
|
+
Permission.CreateBillingPaymentMethod,
|
|
126
|
+
],
|
|
107
127
|
read: [
|
|
108
128
|
Permission.ProjectOwner,
|
|
109
129
|
Permission.ProjectAdmin,
|
|
@@ -136,7 +156,11 @@ export default class BillingPaymentMethod extends BaseModel {
|
|
|
136
156
|
public createdByUser?: User = undefined;
|
|
137
157
|
|
|
138
158
|
@ColumnAccessControl({
|
|
139
|
-
create: [
|
|
159
|
+
create: [
|
|
160
|
+
Permission.ProjectOwner,
|
|
161
|
+
Permission.ManageProjectBilling,
|
|
162
|
+
Permission.CreateBillingPaymentMethod,
|
|
163
|
+
],
|
|
140
164
|
read: [
|
|
141
165
|
Permission.ProjectOwner,
|
|
142
166
|
Permission.ProjectAdmin,
|
|
@@ -218,7 +242,11 @@ export default class BillingPaymentMethod extends BaseModel {
|
|
|
218
242
|
public deletedByUserId?: ObjectID = undefined;
|
|
219
243
|
|
|
220
244
|
@ColumnAccessControl({
|
|
221
|
-
create: [
|
|
245
|
+
create: [
|
|
246
|
+
Permission.ProjectOwner,
|
|
247
|
+
Permission.ManageProjectBilling,
|
|
248
|
+
Permission.CreateBillingPaymentMethod,
|
|
249
|
+
],
|
|
222
250
|
read: [
|
|
223
251
|
Permission.ProjectOwner,
|
|
224
252
|
Permission.ProjectAdmin,
|
|
@@ -278,7 +306,11 @@ export default class BillingPaymentMethod extends BaseModel {
|
|
|
278
306
|
public paymentProviderCustomerId?: string = undefined;
|
|
279
307
|
|
|
280
308
|
@ColumnAccessControl({
|
|
281
|
-
create: [
|
|
309
|
+
create: [
|
|
310
|
+
Permission.ProjectOwner,
|
|
311
|
+
Permission.ManageProjectBilling,
|
|
312
|
+
Permission.CreateBillingPaymentMethod,
|
|
313
|
+
],
|
|
282
314
|
read: [
|
|
283
315
|
Permission.ProjectOwner,
|
|
284
316
|
Permission.ProjectAdmin,
|
|
@@ -298,7 +330,11 @@ export default class BillingPaymentMethod extends BaseModel {
|
|
|
298
330
|
public last4Digits?: string = undefined;
|
|
299
331
|
|
|
300
332
|
@ColumnAccessControl({
|
|
301
|
-
create: [
|
|
333
|
+
create: [
|
|
334
|
+
Permission.ProjectOwner,
|
|
335
|
+
Permission.ManageProjectBilling,
|
|
336
|
+
Permission.CreateBillingPaymentMethod,
|
|
337
|
+
],
|
|
302
338
|
read: [
|
|
303
339
|
Permission.ProjectOwner,
|
|
304
340
|
Permission.ProjectAdmin,
|
|
@@ -228,6 +228,43 @@ export default class Incident extends BaseModel {
|
|
|
228
228
|
})
|
|
229
229
|
public description?: string = undefined;
|
|
230
230
|
|
|
231
|
+
@ColumnAccessControl({
|
|
232
|
+
create: [
|
|
233
|
+
Permission.ProjectOwner,
|
|
234
|
+
Permission.ProjectAdmin,
|
|
235
|
+
Permission.ProjectMember,
|
|
236
|
+
Permission.CreateProjectIncident,
|
|
237
|
+
],
|
|
238
|
+
read: [
|
|
239
|
+
Permission.ProjectOwner,
|
|
240
|
+
Permission.ProjectAdmin,
|
|
241
|
+
Permission.ProjectMember,
|
|
242
|
+
Permission.ReadProjectIncident,
|
|
243
|
+
],
|
|
244
|
+
update: [
|
|
245
|
+
Permission.ProjectOwner,
|
|
246
|
+
Permission.ProjectAdmin,
|
|
247
|
+
Permission.ProjectMember,
|
|
248
|
+
Permission.EditProjectIncident,
|
|
249
|
+
],
|
|
250
|
+
})
|
|
251
|
+
@Index()
|
|
252
|
+
@TableColumn({
|
|
253
|
+
required: true,
|
|
254
|
+
type: TableColumnType.Date,
|
|
255
|
+
title: "Declared At",
|
|
256
|
+
description: "Date and time when this incident was declared.",
|
|
257
|
+
isDefaultValueColumn: true,
|
|
258
|
+
})
|
|
259
|
+
@Column({
|
|
260
|
+
type: ColumnType.Date,
|
|
261
|
+
nullable: false,
|
|
262
|
+
default: () => {
|
|
263
|
+
return "now()";
|
|
264
|
+
},
|
|
265
|
+
})
|
|
266
|
+
public declaredAt?: Date = undefined;
|
|
267
|
+
|
|
231
268
|
@Index()
|
|
232
269
|
@ColumnAccessControl({
|
|
233
270
|
create: [],
|
|
@@ -282,8 +282,9 @@ export default class StatusPageDomain extends BaseModel {
|
|
|
282
282
|
@TableColumn({
|
|
283
283
|
required: true,
|
|
284
284
|
type: TableColumnType.ShortText,
|
|
285
|
-
title: "
|
|
286
|
-
description:
|
|
285
|
+
title: "Subdomain",
|
|
286
|
+
description:
|
|
287
|
+
"Subdomain label for your status page such as 'status'. Leave blank or enter @ to use the root domain.",
|
|
287
288
|
})
|
|
288
289
|
@Column({
|
|
289
290
|
nullable: false,
|
|
@@ -30,7 +30,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
|
|
30
30
|
})
|
|
31
31
|
@AllowAccessIfSubscriptionIsUnpaid()
|
|
32
32
|
@TableAccessControl({
|
|
33
|
-
create: [
|
|
33
|
+
create: [],
|
|
34
34
|
read: [Permission.CurrentUser],
|
|
35
35
|
delete: [Permission.CurrentUser],
|
|
36
36
|
update: [Permission.CurrentUser],
|
|
@@ -42,17 +42,16 @@ export default class UserAPI extends BaseAPI<
|
|
|
42
42
|
const userPermissions: Array<UserPermission> = (
|
|
43
43
|
await this.getPermissionsForTenant(req)
|
|
44
44
|
).filter((permission: UserPermission) => {
|
|
45
|
-
return
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
);
|
|
45
|
+
return [
|
|
46
|
+
Permission.ProjectOwner,
|
|
47
|
+
Permission.ManageProjectBilling,
|
|
48
|
+
Permission.CreateBillingPaymentMethod,
|
|
49
|
+
].includes(permission.permission);
|
|
51
50
|
});
|
|
52
51
|
|
|
53
52
|
if (userPermissions.length === 0) {
|
|
54
53
|
throw new BadDataException(
|
|
55
|
-
"Only
|
|
54
|
+
"Only project owners or members with Manage Billing access can add payment methods.",
|
|
56
55
|
);
|
|
57
56
|
}
|
|
58
57
|
|
|
@@ -1421,6 +1421,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
1421
1421
|
if (monitorsOnStatusPage.length > 0) {
|
|
1422
1422
|
let select: Select<Incident> = {
|
|
1423
1423
|
createdAt: true,
|
|
1424
|
+
declaredAt: true,
|
|
1424
1425
|
title: true,
|
|
1425
1426
|
description: true,
|
|
1426
1427
|
_id: true,
|
|
@@ -1474,6 +1475,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
1474
1475
|
},
|
|
1475
1476
|
select: select,
|
|
1476
1477
|
sort: {
|
|
1478
|
+
declaredAt: SortOrder.Descending,
|
|
1477
1479
|
createdAt: SortOrder.Descending,
|
|
1478
1480
|
},
|
|
1479
1481
|
|
|
@@ -2809,7 +2811,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
2809
2811
|
manageSubscriptionUrl: manageUrlink,
|
|
2810
2812
|
},
|
|
2811
2813
|
subject:
|
|
2812
|
-
"Manage your Subscription for" +
|
|
2814
|
+
"Manage your Subscription for " +
|
|
2813
2815
|
(statusPage.name || "Status Page"),
|
|
2814
2816
|
},
|
|
2815
2817
|
{
|
|
@@ -3303,6 +3305,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
3303
3305
|
|
|
3304
3306
|
let selectIncidents: Select<Incident> = {
|
|
3305
3307
|
createdAt: true,
|
|
3308
|
+
declaredAt: true,
|
|
3306
3309
|
title: true,
|
|
3307
3310
|
description: true,
|
|
3308
3311
|
_id: true,
|
|
@@ -3336,6 +3339,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
3336
3339
|
query: incidentQuery,
|
|
3337
3340
|
select: selectIncidents,
|
|
3338
3341
|
sort: {
|
|
3342
|
+
declaredAt: SortOrder.Descending,
|
|
3339
3343
|
createdAt: SortOrder.Descending,
|
|
3340
3344
|
},
|
|
3341
3345
|
skip: 0,
|
|
@@ -3373,6 +3377,7 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
3373
3377
|
},
|
|
3374
3378
|
select: selectIncidents,
|
|
3375
3379
|
sort: {
|
|
3380
|
+
declaredAt: SortOrder.Descending,
|
|
3376
3381
|
createdAt: SortOrder.Descending,
|
|
3377
3382
|
},
|
|
3378
3383
|
|
|
@@ -44,6 +44,8 @@ const FRONTEND_ENV_ALLOW_LIST: Array<string> = [
|
|
|
44
44
|
"DISABLE_TELEMETRY",
|
|
45
45
|
"SLACK_APP_CLIENT_ID",
|
|
46
46
|
"MICROSOFT_TEAMS_APP_CLIENT_ID",
|
|
47
|
+
"CAPTCHA_ENABLED",
|
|
48
|
+
"CAPTCHA_SITE_KEY",
|
|
47
49
|
];
|
|
48
50
|
|
|
49
51
|
const FRONTEND_ENV_ALLOW_PREFIXES: Array<string> = [
|
|
@@ -324,6 +326,13 @@ export const Host: string = process.env["HOST"] || "";
|
|
|
324
326
|
|
|
325
327
|
export const ProvisionSsl: boolean = process.env["PROVISION_SSL"] === "true";
|
|
326
328
|
|
|
329
|
+
export const CaptchaEnabled: boolean =
|
|
330
|
+
process.env["CAPTCHA_ENABLED"] === "true";
|
|
331
|
+
|
|
332
|
+
export const CaptchaSecretKey: string = process.env["CAPTCHA_SECRET_KEY"] || "";
|
|
333
|
+
|
|
334
|
+
export const CaptchaSiteKey: string = process.env["CAPTCHA_SITE_KEY"] || "";
|
|
335
|
+
|
|
327
336
|
export const WorkflowScriptTimeoutInMS: number = process.env[
|
|
328
337
|
"WORKFLOW_SCRIPT_TIMEOUT_IN_MS"
|
|
329
338
|
]
|
|
@@ -446,6 +455,8 @@ export const MicrosoftTeamsAppClientId: string | null =
|
|
|
446
455
|
process.env["MICROSOFT_TEAMS_APP_CLIENT_ID"] || null;
|
|
447
456
|
export const MicrosoftTeamsAppClientSecret: string | null =
|
|
448
457
|
process.env["MICROSOFT_TEAMS_APP_CLIENT_SECRET"] || null;
|
|
458
|
+
export const MicrosoftTeamsAppTenantId: string | null =
|
|
459
|
+
process.env["MICROSOFT_TEAMS_APP_TENANT_ID"] || null;
|
|
449
460
|
|
|
450
461
|
// VAPID Configuration for Web Push Notifications
|
|
451
462
|
export const VapidPublicKey: string | undefined =
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
export class MigrationName1764324618043 implements MigrationInterface {
|
|
4
|
+
public name = "MigrationName1764324618043";
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
await queryRunner.query(
|
|
8
|
+
`ALTER TABLE "Incident" ADD "declaredAt" TIMESTAMP WITH TIME ZONE`,
|
|
9
|
+
);
|
|
10
|
+
await queryRunner.query(
|
|
11
|
+
`UPDATE "Incident" SET "declaredAt" = "createdAt" WHERE "declaredAt" IS NULL`,
|
|
12
|
+
);
|
|
13
|
+
await queryRunner.query(
|
|
14
|
+
`ALTER TABLE "Incident" ALTER COLUMN "declaredAt" SET DEFAULT now()`,
|
|
15
|
+
);
|
|
16
|
+
await queryRunner.query(
|
|
17
|
+
`ALTER TABLE "Incident" ALTER COLUMN "declaredAt" SET NOT NULL`,
|
|
18
|
+
);
|
|
19
|
+
await queryRunner.query(
|
|
20
|
+
`CREATE INDEX "IDX_b26979b9f119310661734465a4" ON "Incident" ("declaredAt") `,
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
25
|
+
await queryRunner.query(
|
|
26
|
+
`DROP INDEX "public"."IDX_b26979b9f119310661734465a4"`,
|
|
27
|
+
);
|
|
28
|
+
await queryRunner.query(`ALTER TABLE "Incident" DROP COLUMN "declaredAt"`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -186,6 +186,7 @@ import { MigrationName1763471659817 } from "./1763471659817-MigrationName";
|
|
|
186
186
|
import { MigrationName1763477560906 } from "./1763477560906-MigrationName";
|
|
187
187
|
import { MigrationName1763480947474 } from "./1763480947474-MigrationName";
|
|
188
188
|
import { MigrationName1763643080445 } from "./1763643080445-MigrationName";
|
|
189
|
+
import { MigrationName1764324618043 } from "./1764324618043-MigrationName";
|
|
189
190
|
|
|
190
191
|
export default [
|
|
191
192
|
InitialMigration,
|
|
@@ -376,4 +377,5 @@ export default [
|
|
|
376
377
|
MigrationName1763477560906,
|
|
377
378
|
MigrationName1763480947474,
|
|
378
379
|
MigrationName1763643080445,
|
|
380
|
+
MigrationName1764324618043,
|
|
379
381
|
];
|
|
@@ -480,6 +480,14 @@ export class Service extends DatabaseService<Model> {
|
|
|
480
480
|
const projectId: ObjectID =
|
|
481
481
|
createBy.props.tenantId || createBy.data.projectId!;
|
|
482
482
|
|
|
483
|
+
if (!createBy.data.declaredAt) {
|
|
484
|
+
createBy.data.declaredAt = OneUptimeDate.getCurrentDate();
|
|
485
|
+
} else {
|
|
486
|
+
createBy.data.declaredAt = OneUptimeDate.fromString(
|
|
487
|
+
createBy.data.declaredAt as Date,
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
|
|
483
491
|
// Determine the initial incident state
|
|
484
492
|
let initialIncidentStateId: ObjectID | undefined = undefined;
|
|
485
493
|
|
|
@@ -975,6 +983,7 @@ ${incident.remediationNotes || "No remediation notes provided."}
|
|
|
975
983
|
notifyOwners: false,
|
|
976
984
|
rootCause: createdItem.rootCause,
|
|
977
985
|
stateChangeLog: createdItem.createdStateLog,
|
|
986
|
+
timelineStartsAt: createdItem.declaredAt,
|
|
978
987
|
props: {
|
|
979
988
|
isRoot: true,
|
|
980
989
|
},
|
|
@@ -1790,6 +1799,7 @@ ${incidentSeverity.name}
|
|
|
1790
1799
|
limit: LIMIT_MAX,
|
|
1791
1800
|
skip: 0,
|
|
1792
1801
|
select: {
|
|
1802
|
+
_id: true,
|
|
1793
1803
|
projectId: true,
|
|
1794
1804
|
monitors: {
|
|
1795
1805
|
_id: true,
|
|
@@ -1821,6 +1831,18 @@ ${incidentSeverity.name}
|
|
|
1821
1831
|
incident.monitors,
|
|
1822
1832
|
);
|
|
1823
1833
|
}
|
|
1834
|
+
|
|
1835
|
+
if (incident.projectId && incident.id) {
|
|
1836
|
+
await MetricService.deleteBy({
|
|
1837
|
+
query: {
|
|
1838
|
+
projectId: incident.projectId,
|
|
1839
|
+
serviceId: incident.id,
|
|
1840
|
+
},
|
|
1841
|
+
props: {
|
|
1842
|
+
isRoot: true,
|
|
1843
|
+
},
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1824
1846
|
}
|
|
1825
1847
|
}
|
|
1826
1848
|
|
|
@@ -1838,6 +1860,7 @@ ${incidentSeverity.name}
|
|
|
1838
1860
|
rootCause: string | undefined;
|
|
1839
1861
|
stateChangeLog: JSONObject | undefined;
|
|
1840
1862
|
props: DatabaseCommonInteractionProps | undefined;
|
|
1863
|
+
timelineStartsAt?: Date | string | undefined;
|
|
1841
1864
|
}): Promise<void> {
|
|
1842
1865
|
const {
|
|
1843
1866
|
projectId,
|
|
@@ -1849,8 +1872,13 @@ ${incidentSeverity.name}
|
|
|
1849
1872
|
rootCause,
|
|
1850
1873
|
stateChangeLog,
|
|
1851
1874
|
props,
|
|
1875
|
+
timelineStartsAt,
|
|
1852
1876
|
} = data;
|
|
1853
1877
|
|
|
1878
|
+
const declaredTimelineStart: Date | undefined = timelineStartsAt
|
|
1879
|
+
? OneUptimeDate.fromString(timelineStartsAt as Date)
|
|
1880
|
+
: undefined;
|
|
1881
|
+
|
|
1854
1882
|
// get last monitor status timeline.
|
|
1855
1883
|
const lastIncidentStatusTimeline: IncidentStateTimeline | null =
|
|
1856
1884
|
await IncidentStateTimelineService.findOneBy({
|
|
@@ -1888,6 +1916,10 @@ ${incidentSeverity.name}
|
|
|
1888
1916
|
statusTimeline.shouldStatusPageSubscribersBeNotified =
|
|
1889
1917
|
shouldNotifyStatusPageSubscribers;
|
|
1890
1918
|
|
|
1919
|
+
if (!lastIncidentStatusTimeline && declaredTimelineStart) {
|
|
1920
|
+
statusTimeline.startsAt = declaredTimelineStart;
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1891
1923
|
// Map boolean to enum value
|
|
1892
1924
|
statusTimeline.subscriberNotificationStatus = isSubscribersNotified
|
|
1893
1925
|
? StatusPageSubscriberNotificationStatus.Success
|
|
@@ -1914,6 +1946,7 @@ ${incidentSeverity.name}
|
|
|
1914
1946
|
id: data.incidentId,
|
|
1915
1947
|
select: {
|
|
1916
1948
|
projectId: true,
|
|
1949
|
+
declaredAt: true,
|
|
1917
1950
|
monitors: {
|
|
1918
1951
|
_id: true,
|
|
1919
1952
|
name: true,
|
|
@@ -1970,6 +2003,7 @@ ${incidentSeverity.name}
|
|
|
1970
2003
|
|
|
1971
2004
|
await MetricService.deleteBy({
|
|
1972
2005
|
query: {
|
|
2006
|
+
projectId: incident.projectId,
|
|
1973
2007
|
serviceId: data.incidentId,
|
|
1974
2008
|
},
|
|
1975
2009
|
props: {
|
|
@@ -1983,6 +2017,7 @@ ${incidentSeverity.name}
|
|
|
1983
2017
|
|
|
1984
2018
|
const incidentStartsAt: Date =
|
|
1985
2019
|
firstIncidentStateTimeline?.startsAt ||
|
|
2020
|
+
incident.declaredAt ||
|
|
1986
2021
|
incident.createdAt ||
|
|
1987
2022
|
OneUptimeDate.getCurrentDate();
|
|
1988
2023
|
|
|
@@ -2075,6 +2110,7 @@ ${incidentSeverity.name}
|
|
|
2075
2110
|
|
|
2076
2111
|
timeToAcknowledgeMetric.time =
|
|
2077
2112
|
ackIncidentStateTimeline?.startsAt ||
|
|
2113
|
+
incident.declaredAt ||
|
|
2078
2114
|
incident.createdAt ||
|
|
2079
2115
|
OneUptimeDate.getCurrentDate();
|
|
2080
2116
|
timeToAcknowledgeMetric.timeUnixNano = OneUptimeDate.toUnixNano(
|
|
@@ -2140,6 +2176,7 @@ ${incidentSeverity.name}
|
|
|
2140
2176
|
|
|
2141
2177
|
timeToResolveMetric.time =
|
|
2142
2178
|
resolvedIncidentStateTimeline?.startsAt ||
|
|
2179
|
+
incident.declaredAt ||
|
|
2143
2180
|
incident.createdAt ||
|
|
2144
2181
|
OneUptimeDate.getCurrentDate();
|
|
2145
2182
|
timeToResolveMetric.timeUnixNano = OneUptimeDate.toUnixNano(
|
|
@@ -2200,6 +2237,7 @@ ${incidentSeverity.name}
|
|
|
2200
2237
|
|
|
2201
2238
|
incidentDurationMetric.time =
|
|
2202
2239
|
lastIncidentStateTimeline?.startsAt ||
|
|
2240
|
+
incident.declaredAt ||
|
|
2203
2241
|
incident.createdAt ||
|
|
2204
2242
|
OneUptimeDate.getCurrentDate();
|
|
2205
2243
|
incidentDurationMetric.timeUnixNano = OneUptimeDate.toUnixNano(
|
|
@@ -63,14 +63,13 @@ import MonitorFeedService from "./MonitorFeedService";
|
|
|
63
63
|
import { MonitorFeedEventType } from "../../Models/DatabaseModels/MonitorFeed";
|
|
64
64
|
import { Gray500, Green500 } from "../../Types/BrandColors";
|
|
65
65
|
import LabelService from "./LabelService";
|
|
66
|
-
import QueryOperator from "../../Types/BaseDatabase/QueryOperator";
|
|
67
|
-
import { FindWhere } from "../../Types/BaseDatabase/Query";
|
|
68
66
|
import logger from "../Utils/Logger";
|
|
69
67
|
import PushNotificationUtil from "../Utils/PushNotificationUtil";
|
|
70
68
|
import ExceptionMessages from "../../Types/Exception/ExceptionMessages";
|
|
71
69
|
import Project from "../../Models/DatabaseModels/Project";
|
|
72
70
|
import { createWhatsAppMessageFromTemplate } from "../Utils/WhatsAppTemplateUtil";
|
|
73
71
|
import { WhatsAppMessagePayload } from "../../Types/WhatsApp/WhatsAppMessage";
|
|
72
|
+
import MetricService from "./MetricService";
|
|
74
73
|
|
|
75
74
|
export class Service extends DatabaseService<Model> {
|
|
76
75
|
public constructor() {
|
|
@@ -136,12 +135,26 @@ export class Service extends DatabaseService<Model> {
|
|
|
136
135
|
protected override async onBeforeDelete(
|
|
137
136
|
deleteBy: DeleteBy<Model>,
|
|
138
137
|
): Promise<OnDelete<Model>> {
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
const monitorsPendingDeletion: Array<Model> = await this.findBy({
|
|
139
|
+
query: deleteBy.query,
|
|
140
|
+
limit: LIMIT_MAX,
|
|
141
|
+
skip: 0,
|
|
142
|
+
select: {
|
|
143
|
+
_id: true,
|
|
144
|
+
projectId: true,
|
|
145
|
+
},
|
|
146
|
+
props: deleteBy.props,
|
|
147
|
+
});
|
|
141
148
|
|
|
149
|
+
for (const monitor of monitorsPendingDeletion) {
|
|
150
|
+
if (!monitor.id) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// delete all the status page resources for this monitor.
|
|
142
155
|
await StatusPageResourceService.deleteBy({
|
|
143
156
|
query: {
|
|
144
|
-
monitorId:
|
|
157
|
+
monitorId: monitor.id,
|
|
145
158
|
},
|
|
146
159
|
limit: LIMIT_MAX,
|
|
147
160
|
skip: 0,
|
|
@@ -150,37 +163,19 @@ export class Service extends DatabaseService<Model> {
|
|
|
150
163
|
},
|
|
151
164
|
});
|
|
152
165
|
|
|
153
|
-
|
|
154
|
-
|
|
166
|
+
const projectId: ObjectID | undefined = monitor.projectId as
|
|
167
|
+
| ObjectID
|
|
168
|
+
| undefined;
|
|
155
169
|
|
|
156
170
|
if (!projectId) {
|
|
157
|
-
|
|
158
|
-
const monitor: Model | null = await this.findOneById({
|
|
159
|
-
id: new ObjectID(deleteBy.query._id as string) as ObjectID,
|
|
160
|
-
select: {
|
|
161
|
-
projectId: true,
|
|
162
|
-
},
|
|
163
|
-
props: {
|
|
164
|
-
isRoot: true,
|
|
165
|
-
},
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
if (!monitor) {
|
|
169
|
-
throw new BadDataException(ExceptionMessages.MonitorNotFound);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (!monitor.id) {
|
|
173
|
-
throw new BadDataException(ExceptionMessages.MonitorNotFound);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
projectId = monitor.projectId!;
|
|
171
|
+
continue;
|
|
177
172
|
}
|
|
178
173
|
|
|
179
174
|
try {
|
|
180
175
|
await WorkspaceNotificationRuleService.archiveWorkspaceChannels({
|
|
181
|
-
projectId: projectId
|
|
176
|
+
projectId: projectId,
|
|
182
177
|
notificationFor: {
|
|
183
|
-
monitorId:
|
|
178
|
+
monitorId: monitor.id,
|
|
184
179
|
},
|
|
185
180
|
sendMessageBeforeArchiving: {
|
|
186
181
|
_type: "WorkspacePayloadMarkdown",
|
|
@@ -189,12 +184,17 @@ export class Service extends DatabaseService<Model> {
|
|
|
189
184
|
});
|
|
190
185
|
} catch (error) {
|
|
191
186
|
logger.error(
|
|
192
|
-
`Error while archiving workspace channels for monitor ${
|
|
187
|
+
`Error while archiving workspace channels for monitor ${monitor.id?.toString()}: ${error}`,
|
|
193
188
|
);
|
|
194
189
|
}
|
|
195
190
|
}
|
|
196
191
|
|
|
197
|
-
return {
|
|
192
|
+
return {
|
|
193
|
+
deleteBy,
|
|
194
|
+
carryForward: {
|
|
195
|
+
monitors: monitorsPendingDeletion,
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
@CaptureSpan()
|
|
@@ -208,6 +208,24 @@ export class Service extends DatabaseService<Model> {
|
|
|
208
208
|
);
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
if (onDelete.carryForward && onDelete.carryForward.monitors) {
|
|
212
|
+
for (const monitor of onDelete.carryForward.monitors as Array<Model>) {
|
|
213
|
+
if (!monitor.projectId || !monitor.id) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
await MetricService.deleteBy({
|
|
218
|
+
query: {
|
|
219
|
+
projectId: monitor.projectId,
|
|
220
|
+
serviceId: monitor.id,
|
|
221
|
+
},
|
|
222
|
+
props: {
|
|
223
|
+
isRoot: true,
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
211
229
|
return onDelete;
|
|
212
230
|
}
|
|
213
231
|
|
|
@@ -510,12 +510,30 @@ export class Service extends DatabaseService<ScheduledMaintenanceStateTimeline>
|
|
|
510
510
|
monitors: {
|
|
511
511
|
_id: true,
|
|
512
512
|
},
|
|
513
|
+
nextSubscriberNotificationBeforeTheEventAt: true,
|
|
513
514
|
},
|
|
514
515
|
props: {
|
|
515
516
|
isRoot: true,
|
|
516
517
|
},
|
|
517
518
|
});
|
|
518
519
|
|
|
520
|
+
const hasProgressedBeyondScheduledState: boolean = Boolean(
|
|
521
|
+
scheduledMaintenanceState && !scheduledMaintenanceState.isScheduledState,
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
if (
|
|
525
|
+
hasProgressedBeyondScheduledState &&
|
|
526
|
+
scheduledMaintenanceEvent?.nextSubscriberNotificationBeforeTheEventAt
|
|
527
|
+
) {
|
|
528
|
+
await ScheduledMaintenanceService.updateOneById({
|
|
529
|
+
id: createdItem.scheduledMaintenanceId!,
|
|
530
|
+
data: {
|
|
531
|
+
nextSubscriberNotificationBeforeTheEventAt: null,
|
|
532
|
+
},
|
|
533
|
+
props: onCreate.createBy.props,
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
|
|
519
537
|
if (isOngoingState) {
|
|
520
538
|
if (
|
|
521
539
|
scheduledMaintenanceEvent &&
|
|
@@ -48,19 +48,26 @@ export class Service extends DatabaseService<StatusPageDomain> {
|
|
|
48
48
|
);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
let normalizedSubdomain: string =
|
|
52
|
+
createBy.data.subdomain?.trim().toLowerCase() || "";
|
|
53
|
+
|
|
54
|
+
if (normalizedSubdomain === "@") {
|
|
55
|
+
normalizedSubdomain = "";
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
createBy.data.subdomain = normalizedSubdomain;
|
|
59
|
+
|
|
56
60
|
if (domain) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
const baseDomain: string =
|
|
62
|
+
domain.domain?.toString().toLowerCase().trim() || "";
|
|
63
|
+
|
|
64
|
+
if (!baseDomain) {
|
|
65
|
+
throw new BadDataException("Please select a valid domain.");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
createBy.data.fullDomain = normalizedSubdomain
|
|
69
|
+
? `${normalizedSubdomain}.${baseDomain}`
|
|
70
|
+
: baseDomain;
|
|
64
71
|
}
|
|
65
72
|
|
|
66
73
|
createBy.data.cnameVerificationToken = ObjectID.generate().toString();
|