@oneuptime/common 9.1.1 → 9.1.3
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/Incident.ts +37 -0
- package/Server/API/MicrosoftTeamsAPI.ts +42 -1
- package/Server/API/StatusPageAPI.ts +5 -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/TeamMemberService.ts +8 -7
- package/Server/Services/TeamService.ts +2 -1
- package/Server/Utils/Browser.ts +28 -2
- package/Server/Utils/Telemetry.ts +10 -2
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.ts +2 -2
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +4 -1
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +25 -19
- package/Tests/Server/Services/TeamMemberService.test.ts +119 -0
- package/build/dist/Models/DatabaseModels/Incident.js +39 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js +35 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +5 -0
- package/build/dist/Server/API/StatusPageAPI.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/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/Utils/Browser.js +24 -2
- package/build/dist/Server/Utils/Browser.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.js +2 -2
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.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 +20 -15
- 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/package.json +2 -2
|
@@ -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: [],
|
|
@@ -101,7 +101,48 @@ export default class MicrosoftTeamsAPI {
|
|
|
101
101
|
supportsCalling: false,
|
|
102
102
|
supportsVideo: false,
|
|
103
103
|
// Provide basic command lists to improve client compatibility (esp. mobile)
|
|
104
|
-
commandLists: [
|
|
104
|
+
commandLists: [
|
|
105
|
+
{
|
|
106
|
+
scopes: ["team", "groupChat", "personal"],
|
|
107
|
+
commands: [
|
|
108
|
+
{
|
|
109
|
+
title: "help",
|
|
110
|
+
description:
|
|
111
|
+
"Show instructions for interacting with the OneUptime bot.",
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
title: "create incident",
|
|
115
|
+
description:
|
|
116
|
+
"Launch the adaptive card to declare a new incident in OneUptime.",
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
title: "create maintenance",
|
|
120
|
+
description:
|
|
121
|
+
"Open the workflow to schedule maintenance directly from Teams.",
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
title: "show active incidents",
|
|
125
|
+
description:
|
|
126
|
+
"List all ongoing incidents with severity and state context.",
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
title: "show scheduled maintenance",
|
|
130
|
+
description:
|
|
131
|
+
"Display upcoming scheduled maintenance events for the workspace.",
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
title: "show ongoing maintenance",
|
|
135
|
+
description:
|
|
136
|
+
"Surface maintenance windows that are currently in progress.",
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
title: "show active alerts",
|
|
140
|
+
description:
|
|
141
|
+
"Provide a summary of alerts that still require attention.",
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
},
|
|
145
|
+
],
|
|
105
146
|
},
|
|
106
147
|
],
|
|
107
148
|
permissions: ["identity", "messageTeamMembers"],
|
|
@@ -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
|
|
|
@@ -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
|
|
|
@@ -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 &&
|
|
@@ -44,10 +44,11 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
@CaptureSpan()
|
|
47
|
-
private async
|
|
47
|
+
private async isSCIMPushGroupsEnabled(projectId: ObjectID): Promise<boolean> {
|
|
48
48
|
const count: PositiveNumber = await ProjectSCIMService.countBy({
|
|
49
49
|
query: {
|
|
50
50
|
projectId: projectId,
|
|
51
|
+
enablePushGroups: true,
|
|
51
52
|
},
|
|
52
53
|
props: {
|
|
53
54
|
isRoot: true,
|
|
@@ -63,12 +64,12 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
|
|
|
63
64
|
// Check if SCIM is enabled for the project
|
|
64
65
|
if (
|
|
65
66
|
!createBy.props.isRoot &&
|
|
66
|
-
(await this.
|
|
67
|
+
(await this.isSCIMPushGroupsEnabled(
|
|
67
68
|
createBy.data.projectId! || createBy.props.tenantId,
|
|
68
69
|
))
|
|
69
70
|
) {
|
|
70
71
|
throw new BadDataException(
|
|
71
|
-
"Cannot invite team members
|
|
72
|
+
"Cannot invite team members while SCIM Push Groups is enabled for this project. Disable Push Groups to manage members from OneUptime.",
|
|
72
73
|
);
|
|
73
74
|
}
|
|
74
75
|
|
|
@@ -311,10 +312,10 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
|
|
|
311
312
|
!deleteBy.props.isRoot &&
|
|
312
313
|
members.length > 0 &&
|
|
313
314
|
members[0]?.projectId &&
|
|
314
|
-
(await this.
|
|
315
|
+
(await this.isSCIMPushGroupsEnabled(members[0].projectId))
|
|
315
316
|
) {
|
|
316
317
|
throw new BadDataException(
|
|
317
|
-
"Cannot delete team members
|
|
318
|
+
"Cannot delete team members while SCIM Push Groups is enabled for this project. Disable Push Groups to manage members from OneUptime.",
|
|
318
319
|
);
|
|
319
320
|
}
|
|
320
321
|
|
|
@@ -346,11 +347,11 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
|
|
|
346
347
|
});
|
|
347
348
|
|
|
348
349
|
// Skip the one-member guard when SCIM manages membership for the project.
|
|
349
|
-
const
|
|
350
|
+
const isPushGroupsManaged: boolean = await this.isSCIMPushGroupsEnabled(
|
|
350
351
|
member.projectId!,
|
|
351
352
|
);
|
|
352
353
|
|
|
353
|
-
if (!
|
|
354
|
+
if (!isPushGroupsManaged && membersInTeam.toNumber() <= 1) {
|
|
354
355
|
throw new BadDataException(
|
|
355
356
|
Errors.TeamMemberService.ONE_MEMBER_REQUIRED,
|
|
356
357
|
);
|
|
@@ -71,6 +71,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
71
71
|
const scimCount: PositiveNumber = await ProjectSCIMService.countBy({
|
|
72
72
|
query: {
|
|
73
73
|
projectId: projectId,
|
|
74
|
+
enablePushGroups: true,
|
|
74
75
|
},
|
|
75
76
|
skip: new PositiveNumber(0),
|
|
76
77
|
limit: new PositiveNumber(1),
|
|
@@ -82,7 +83,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
82
83
|
|
|
83
84
|
if (scimCount.toNumber() > 0) {
|
|
84
85
|
throw new BadDataException(
|
|
85
|
-
`Cannot ${data.action} teams
|
|
86
|
+
`Cannot ${data.action} teams while SCIM Push Groups is enabled for this project. Disable Push Groups to manage teams from OneUptime.`,
|
|
86
87
|
);
|
|
87
88
|
}
|
|
88
89
|
}
|
package/Server/Utils/Browser.ts
CHANGED
|
@@ -166,7 +166,20 @@ export default class BrowserUtil {
|
|
|
166
166
|
throw new BadDataException("Chrome executable path not found.");
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
|
|
169
|
+
const chromeExecutableCandidates: Array<string> = [
|
|
170
|
+
`/root/.cache/ms-playwright/${chromeInstallationName}/chrome-linux/chrome`,
|
|
171
|
+
`/root/.cache/ms-playwright/${chromeInstallationName}/chrome-linux64/chrome`,
|
|
172
|
+
`/root/.cache/ms-playwright/${chromeInstallationName}/chrome64/chrome`,
|
|
173
|
+
`/root/.cache/ms-playwright/${chromeInstallationName}/chrome/chrome`,
|
|
174
|
+
];
|
|
175
|
+
|
|
176
|
+
for (const executablePath of chromeExecutableCandidates) {
|
|
177
|
+
if (await LocalFile.doesFileExist(executablePath)) {
|
|
178
|
+
return executablePath;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
throw new BadDataException("Chrome executable path not found.");
|
|
170
183
|
}
|
|
171
184
|
|
|
172
185
|
@CaptureSpan()
|
|
@@ -197,6 +210,19 @@ export default class BrowserUtil {
|
|
|
197
210
|
throw new BadDataException("Firefox executable path not found.");
|
|
198
211
|
}
|
|
199
212
|
|
|
200
|
-
|
|
213
|
+
const firefoxExecutableCandidates: Array<string> = [
|
|
214
|
+
`/root/.cache/ms-playwright/${firefoxInstallationName}/firefox/firefox`,
|
|
215
|
+
`/root/.cache/ms-playwright/${firefoxInstallationName}/firefox-linux64/firefox`,
|
|
216
|
+
`/root/.cache/ms-playwright/${firefoxInstallationName}/firefox64/firefox`,
|
|
217
|
+
`/root/.cache/ms-playwright/${firefoxInstallationName}/firefox-64/firefox`,
|
|
218
|
+
];
|
|
219
|
+
|
|
220
|
+
for (const executablePath of firefoxExecutableCandidates) {
|
|
221
|
+
if (await LocalFile.doesFileExist(executablePath)) {
|
|
222
|
+
return executablePath;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
throw new BadDataException("Firefox executable path not found.");
|
|
201
227
|
}
|
|
202
228
|
}
|
|
@@ -226,7 +226,11 @@ export default class Telemetry {
|
|
|
226
226
|
};
|
|
227
227
|
|
|
228
228
|
if (logRecordProcessors.length > 0) {
|
|
229
|
-
|
|
229
|
+
(
|
|
230
|
+
loggerProviderConfig as LoggerProviderConfig & {
|
|
231
|
+
processors?: Array<LogRecordProcessor>;
|
|
232
|
+
}
|
|
233
|
+
).processors = logRecordProcessors;
|
|
230
234
|
}
|
|
231
235
|
|
|
232
236
|
this.loggerProvider = new LoggerProvider(loggerProviderConfig);
|
|
@@ -254,7 +258,11 @@ export default class Telemetry {
|
|
|
254
258
|
*/
|
|
255
259
|
|
|
256
260
|
if (logRecordProcessors.length > 0) {
|
|
257
|
-
|
|
261
|
+
(
|
|
262
|
+
nodeSdkConfiguration as opentelemetry.NodeSDKConfiguration & {
|
|
263
|
+
logRecordProcessors?: Array<LogRecordProcessor>;
|
|
264
|
+
}
|
|
265
|
+
).logRecordProcessors = logRecordProcessors;
|
|
258
266
|
}
|
|
259
267
|
|
|
260
268
|
const sdk: opentelemetry.NodeSDK = new opentelemetry.NodeSDK(
|
|
@@ -16,7 +16,7 @@ export enum MicrosoftTeamsIncidentActionType {
|
|
|
16
16
|
SubmitExecuteIncidentOnCallPolicy = "SubmitExecuteIncidentOnCallPolicy",
|
|
17
17
|
ViewChangeIncidentState = "ViewChangeIncidentState",
|
|
18
18
|
SubmitChangeIncidentState = "SubmitChangeIncidentState",
|
|
19
|
-
NewIncident = "
|
|
19
|
+
NewIncident = "CreateIncident",
|
|
20
20
|
SubmitNewIncident = "SubmitNewIncident",
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -57,7 +57,7 @@ export enum MicrosoftTeamsScheduledMaintenanceActionType {
|
|
|
57
57
|
SubmitScheduledMaintenanceNote = "SubmitScheduledMaintenanceNote",
|
|
58
58
|
ViewChangeScheduledMaintenanceState = "ViewChangeScheduledMaintenanceState",
|
|
59
59
|
SubmitChangeScheduledMaintenanceState = "SubmitChangeScheduledMaintenanceState",
|
|
60
|
-
NewScheduledMaintenance = "
|
|
60
|
+
NewScheduledMaintenance = "CreateMaintenance",
|
|
61
61
|
SubmitNewScheduledMaintenance = "SubmitNewScheduledMaintenance",
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -320,6 +320,7 @@ export default class MicrosoftTeamsIncidentActions {
|
|
|
320
320
|
name: true,
|
|
321
321
|
},
|
|
322
322
|
createdAt: true,
|
|
323
|
+
declaredAt: true,
|
|
323
324
|
},
|
|
324
325
|
props: {
|
|
325
326
|
isRoot: true,
|
|
@@ -331,7 +332,9 @@ export default class MicrosoftTeamsIncidentActions {
|
|
|
331
332
|
return;
|
|
332
333
|
}
|
|
333
334
|
|
|
334
|
-
const
|
|
335
|
+
const declaredAt: Date | undefined =
|
|
336
|
+
incident.declaredAt || incident.createdAt || undefined;
|
|
337
|
+
const message: string = `**Incident Details**\n\n**Title:** ${incident.title}\n**Description:** ${incident.description || "No description"}\n**State:** ${incident.currentIncidentState?.name || "Unknown"}\n**Severity:** ${incident.incidentSeverity?.name || "Unknown"}\n**Declared At:** ${declaredAt ? new Date(declaredAt).toLocaleString() : "Unknown"}`;
|
|
335
338
|
|
|
336
339
|
await turnContext.sendActivity(message);
|
|
337
340
|
return;
|