@oneuptime/common 9.1.2 → 9.2.0
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 +112 -0
- package/Server/API/IncidentAPI.ts +106 -0
- package/Server/API/MicrosoftTeamsAPI.ts +42 -1
- package/Server/API/StatusPageAPI.ts +134 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1764762146063-MigrationName.ts +45 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1764767371788-MigrationName.ts +23 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.ts +2 -2
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +18 -16
- package/Types/Icon/IconProp.ts +1 -0
- package/UI/Components/EventItem/EventItem.tsx +32 -14
- package/UI/Components/Icon/Icon.tsx +8 -0
- package/build/dist/Models/DatabaseModels/Incident.js +115 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Server/API/IncidentAPI.js +76 -0
- package/build/dist/Server/API/IncidentAPI.js.map +1 -0
- 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 +154 -45
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1764762146063-MigrationName.js +22 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1764762146063-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1764767371788-MigrationName.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1764767371788-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.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/MicrosoftTeams.js +14 -12
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Types/Icon/IconProp.js +1 -0
- package/build/dist/Types/Icon/IconProp.js.map +1 -1
- package/build/dist/UI/Components/EventItem/EventItem.js +10 -6
- package/build/dist/UI/Components/EventItem/EventItem.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +3 -0
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/package.json +1 -1
|
@@ -7,6 +7,7 @@ import OnCallDutyPolicy from "./OnCallDutyPolicy";
|
|
|
7
7
|
import Probe from "./Probe";
|
|
8
8
|
import Project from "./Project";
|
|
9
9
|
import User from "./User";
|
|
10
|
+
import File from "./File";
|
|
10
11
|
import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
|
|
11
12
|
import Route from "../../Types/API/Route";
|
|
12
13
|
import ColumnAccessControl from "../../Types/Database/AccessControl/ColumnAccessControl";
|
|
@@ -996,6 +997,117 @@ export default class Incident extends BaseModel {
|
|
|
996
997
|
})
|
|
997
998
|
public postmortemNote?: string = undefined;
|
|
998
999
|
|
|
1000
|
+
@ColumnAccessControl({
|
|
1001
|
+
create: [
|
|
1002
|
+
Permission.ProjectOwner,
|
|
1003
|
+
Permission.ProjectAdmin,
|
|
1004
|
+
Permission.ProjectMember,
|
|
1005
|
+
Permission.CreateProjectIncident,
|
|
1006
|
+
],
|
|
1007
|
+
read: [
|
|
1008
|
+
Permission.ProjectOwner,
|
|
1009
|
+
Permission.ProjectAdmin,
|
|
1010
|
+
Permission.ProjectMember,
|
|
1011
|
+
Permission.ReadProjectIncident,
|
|
1012
|
+
],
|
|
1013
|
+
update: [
|
|
1014
|
+
Permission.ProjectOwner,
|
|
1015
|
+
Permission.ProjectAdmin,
|
|
1016
|
+
Permission.ProjectMember,
|
|
1017
|
+
Permission.EditProjectIncident,
|
|
1018
|
+
],
|
|
1019
|
+
})
|
|
1020
|
+
@TableColumn({
|
|
1021
|
+
type: TableColumnType.Boolean,
|
|
1022
|
+
title: "Show postmortem on status page?",
|
|
1023
|
+
description:
|
|
1024
|
+
"Should the postmortem note and attachments be visible on the status page once published?",
|
|
1025
|
+
defaultValue: false,
|
|
1026
|
+
isDefaultValueColumn: true,
|
|
1027
|
+
})
|
|
1028
|
+
@Column({
|
|
1029
|
+
type: ColumnType.Boolean,
|
|
1030
|
+
default: false,
|
|
1031
|
+
})
|
|
1032
|
+
public showPostmortemOnStatusPage?: boolean = undefined;
|
|
1033
|
+
|
|
1034
|
+
@ColumnAccessControl({
|
|
1035
|
+
create: [
|
|
1036
|
+
Permission.ProjectOwner,
|
|
1037
|
+
Permission.ProjectAdmin,
|
|
1038
|
+
Permission.ProjectMember,
|
|
1039
|
+
Permission.CreateProjectIncident,
|
|
1040
|
+
],
|
|
1041
|
+
read: [
|
|
1042
|
+
Permission.ProjectOwner,
|
|
1043
|
+
Permission.ProjectAdmin,
|
|
1044
|
+
Permission.ProjectMember,
|
|
1045
|
+
Permission.ReadProjectIncident,
|
|
1046
|
+
],
|
|
1047
|
+
update: [
|
|
1048
|
+
Permission.ProjectOwner,
|
|
1049
|
+
Permission.ProjectAdmin,
|
|
1050
|
+
Permission.ProjectMember,
|
|
1051
|
+
Permission.EditProjectIncident,
|
|
1052
|
+
],
|
|
1053
|
+
})
|
|
1054
|
+
@TableColumn({
|
|
1055
|
+
type: TableColumnType.Date,
|
|
1056
|
+
title: "Postmortem Posted At",
|
|
1057
|
+
description:
|
|
1058
|
+
"Timestamp that will be shown alongside the published postmortem on the status page.",
|
|
1059
|
+
required: false,
|
|
1060
|
+
})
|
|
1061
|
+
@Column({
|
|
1062
|
+
type: ColumnType.Date,
|
|
1063
|
+
nullable: true,
|
|
1064
|
+
})
|
|
1065
|
+
public postmortemPostedAt?: Date = undefined;
|
|
1066
|
+
|
|
1067
|
+
@ColumnAccessControl({
|
|
1068
|
+
create: [
|
|
1069
|
+
Permission.ProjectOwner,
|
|
1070
|
+
Permission.ProjectAdmin,
|
|
1071
|
+
Permission.ProjectMember,
|
|
1072
|
+
Permission.CreateProjectIncident,
|
|
1073
|
+
],
|
|
1074
|
+
read: [
|
|
1075
|
+
Permission.ProjectOwner,
|
|
1076
|
+
Permission.ProjectAdmin,
|
|
1077
|
+
Permission.ProjectMember,
|
|
1078
|
+
Permission.ReadProjectIncident,
|
|
1079
|
+
],
|
|
1080
|
+
update: [
|
|
1081
|
+
Permission.ProjectOwner,
|
|
1082
|
+
Permission.ProjectAdmin,
|
|
1083
|
+
Permission.ProjectMember,
|
|
1084
|
+
Permission.EditProjectIncident,
|
|
1085
|
+
],
|
|
1086
|
+
})
|
|
1087
|
+
@TableColumn({
|
|
1088
|
+
type: TableColumnType.EntityArray,
|
|
1089
|
+
modelType: File,
|
|
1090
|
+
title: "Postmortem Attachments",
|
|
1091
|
+
description:
|
|
1092
|
+
"Files that accompany the postmortem note and can be shared publicly when enabled.",
|
|
1093
|
+
required: false,
|
|
1094
|
+
})
|
|
1095
|
+
@ManyToMany(() => {
|
|
1096
|
+
return File;
|
|
1097
|
+
})
|
|
1098
|
+
@JoinTable({
|
|
1099
|
+
name: "IncidentPostmortemAttachmentFile",
|
|
1100
|
+
joinColumn: {
|
|
1101
|
+
name: "incidentId",
|
|
1102
|
+
referencedColumnName: "_id",
|
|
1103
|
+
},
|
|
1104
|
+
inverseJoinColumn: {
|
|
1105
|
+
name: "fileId",
|
|
1106
|
+
referencedColumnName: "_id",
|
|
1107
|
+
},
|
|
1108
|
+
})
|
|
1109
|
+
public postmortemAttachments?: Array<File> = undefined;
|
|
1110
|
+
|
|
999
1111
|
@ColumnAccessControl({
|
|
1000
1112
|
create: [],
|
|
1001
1113
|
read: [
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import Incident from "../../Models/DatabaseModels/Incident";
|
|
2
|
+
import File from "../../Models/DatabaseModels/File";
|
|
3
|
+
import NotFoundException from "../../Types/Exception/NotFoundException";
|
|
4
|
+
import ObjectID from "../../Types/ObjectID";
|
|
5
|
+
import IncidentService, {
|
|
6
|
+
Service as IncidentServiceType,
|
|
7
|
+
} from "../Services/IncidentService";
|
|
8
|
+
import UserMiddleware from "../Middleware/UserAuthorization";
|
|
9
|
+
import Response from "../Utils/Response";
|
|
10
|
+
import BaseAPI from "./BaseAPI";
|
|
11
|
+
import {
|
|
12
|
+
ExpressRequest,
|
|
13
|
+
ExpressResponse,
|
|
14
|
+
NextFunction,
|
|
15
|
+
} from "../Utils/Express";
|
|
16
|
+
import CommonAPI from "./CommonAPI";
|
|
17
|
+
import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
18
|
+
|
|
19
|
+
export default class IncidentAPI extends BaseAPI<
|
|
20
|
+
Incident,
|
|
21
|
+
IncidentServiceType
|
|
22
|
+
> {
|
|
23
|
+
public constructor() {
|
|
24
|
+
super(Incident, IncidentService);
|
|
25
|
+
|
|
26
|
+
this.router.get(
|
|
27
|
+
`${new this.entityType()
|
|
28
|
+
.getCrudApiPath()
|
|
29
|
+
?.toString()}/postmortem/attachment/:projectId/:incidentId/:fileId`,
|
|
30
|
+
UserMiddleware.getUserMiddleware,
|
|
31
|
+
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
|
32
|
+
try {
|
|
33
|
+
await this.getPostmortemAttachment(req, res);
|
|
34
|
+
} catch (err) {
|
|
35
|
+
next(err);
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private async getPostmortemAttachment(
|
|
42
|
+
req: ExpressRequest,
|
|
43
|
+
res: ExpressResponse,
|
|
44
|
+
): Promise<void> {
|
|
45
|
+
const projectIdParam: string | undefined = req.params["projectId"];
|
|
46
|
+
const incidentIdParam: string | undefined = req.params["incidentId"];
|
|
47
|
+
const fileIdParam: string | undefined = req.params["fileId"];
|
|
48
|
+
|
|
49
|
+
if (!projectIdParam || !incidentIdParam || !fileIdParam) {
|
|
50
|
+
throw new NotFoundException("Attachment not found");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let incidentId: ObjectID;
|
|
54
|
+
let fileId: ObjectID;
|
|
55
|
+
let projectId: ObjectID;
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
incidentId = new ObjectID(incidentIdParam);
|
|
59
|
+
fileId = new ObjectID(fileIdParam);
|
|
60
|
+
projectId = new ObjectID(projectIdParam);
|
|
61
|
+
} catch {
|
|
62
|
+
throw new NotFoundException("Attachment not found");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const props: DatabaseCommonInteractionProps =
|
|
66
|
+
await CommonAPI.getDatabaseCommonInteractionProps(req);
|
|
67
|
+
|
|
68
|
+
const incident: Incident | null = await this.service.findOneBy({
|
|
69
|
+
query: {
|
|
70
|
+
_id: incidentId,
|
|
71
|
+
projectId,
|
|
72
|
+
},
|
|
73
|
+
select: {
|
|
74
|
+
postmortemAttachments: {
|
|
75
|
+
_id: true,
|
|
76
|
+
file: true,
|
|
77
|
+
fileType: true,
|
|
78
|
+
name: true,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
props,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
if (!incident) {
|
|
85
|
+
throw new NotFoundException("Attachment not found");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const attachment: File | undefined = incident.postmortemAttachments?.find(
|
|
89
|
+
(file: File) => {
|
|
90
|
+
const attachmentId: string | null = file._id
|
|
91
|
+
? file._id.toString()
|
|
92
|
+
: file.id
|
|
93
|
+
? file.id.toString()
|
|
94
|
+
: null;
|
|
95
|
+
return attachmentId === fileId.toString();
|
|
96
|
+
},
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
if (!attachment || !attachment.file) {
|
|
100
|
+
throw new NotFoundException("Attachment not found");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
Response.setNoCacheHeaders(res);
|
|
104
|
+
return Response.sendFileResponse(req, res, attachment);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -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"],
|
|
@@ -408,6 +408,20 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
408
408
|
},
|
|
409
409
|
);
|
|
410
410
|
|
|
411
|
+
this.router.get(
|
|
412
|
+
`${new this.entityType()
|
|
413
|
+
.getCrudApiPath()
|
|
414
|
+
?.toString()}/incident/postmortem/attachment/:statusPageId/:incidentId/:fileId`,
|
|
415
|
+
UserMiddleware.getUserMiddleware,
|
|
416
|
+
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
|
417
|
+
try {
|
|
418
|
+
await this.getIncidentPostmortemAttachment(req, res);
|
|
419
|
+
} catch (err) {
|
|
420
|
+
next(err);
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
);
|
|
424
|
+
|
|
411
425
|
this.router.get(
|
|
412
426
|
`${new this.entityType()
|
|
413
427
|
.getCrudApiPath()
|
|
@@ -1422,9 +1436,17 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
1422
1436
|
let select: Select<Incident> = {
|
|
1423
1437
|
createdAt: true,
|
|
1424
1438
|
declaredAt: true,
|
|
1439
|
+
updatedAt: true,
|
|
1425
1440
|
title: true,
|
|
1426
1441
|
description: true,
|
|
1427
1442
|
_id: true,
|
|
1443
|
+
postmortemNote: true,
|
|
1444
|
+
postmortemPostedAt: true,
|
|
1445
|
+
showPostmortemOnStatusPage: true,
|
|
1446
|
+
postmortemAttachments: {
|
|
1447
|
+
_id: true,
|
|
1448
|
+
name: true,
|
|
1449
|
+
},
|
|
1428
1450
|
incidentSeverity: {
|
|
1429
1451
|
name: true,
|
|
1430
1452
|
color: true,
|
|
@@ -3306,9 +3328,17 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
3306
3328
|
let selectIncidents: Select<Incident> = {
|
|
3307
3329
|
createdAt: true,
|
|
3308
3330
|
declaredAt: true,
|
|
3331
|
+
updatedAt: true,
|
|
3309
3332
|
title: true,
|
|
3310
3333
|
description: true,
|
|
3311
3334
|
_id: true,
|
|
3335
|
+
postmortemNote: true,
|
|
3336
|
+
postmortemPostedAt: true,
|
|
3337
|
+
showPostmortemOnStatusPage: true,
|
|
3338
|
+
postmortemAttachments: {
|
|
3339
|
+
_id: true,
|
|
3340
|
+
name: true,
|
|
3341
|
+
},
|
|
3312
3342
|
incidentSeverity: {
|
|
3313
3343
|
name: true,
|
|
3314
3344
|
color: true,
|
|
@@ -3969,6 +3999,110 @@ export default class StatusPageAPI extends BaseAPI<
|
|
|
3969
3999
|
return Response.sendFileResponse(req, res, attachment);
|
|
3970
4000
|
}
|
|
3971
4001
|
|
|
4002
|
+
private async getIncidentPostmortemAttachment(
|
|
4003
|
+
req: ExpressRequest,
|
|
4004
|
+
res: ExpressResponse,
|
|
4005
|
+
): Promise<void> {
|
|
4006
|
+
const statusPageIdParam: string | undefined = req.params["statusPageId"];
|
|
4007
|
+
const incidentIdParam: string | undefined = req.params["incidentId"];
|
|
4008
|
+
const fileIdParam: string | undefined = req.params["fileId"];
|
|
4009
|
+
|
|
4010
|
+
if (!statusPageIdParam || !incidentIdParam || !fileIdParam) {
|
|
4011
|
+
throw new NotFoundException("Attachment not found");
|
|
4012
|
+
}
|
|
4013
|
+
|
|
4014
|
+
let statusPageId: ObjectID;
|
|
4015
|
+
let incidentId: ObjectID;
|
|
4016
|
+
let fileId: ObjectID;
|
|
4017
|
+
|
|
4018
|
+
try {
|
|
4019
|
+
statusPageId = new ObjectID(statusPageIdParam);
|
|
4020
|
+
incidentId = new ObjectID(incidentIdParam);
|
|
4021
|
+
fileId = new ObjectID(fileIdParam);
|
|
4022
|
+
} catch {
|
|
4023
|
+
throw new NotFoundException("Attachment not found");
|
|
4024
|
+
}
|
|
4025
|
+
|
|
4026
|
+
await this.checkHasReadAccess({
|
|
4027
|
+
statusPageId,
|
|
4028
|
+
req,
|
|
4029
|
+
});
|
|
4030
|
+
|
|
4031
|
+
const statusPage: StatusPage | null = await StatusPageService.findOneBy({
|
|
4032
|
+
query: {
|
|
4033
|
+
_id: statusPageId.toString(),
|
|
4034
|
+
},
|
|
4035
|
+
select: {
|
|
4036
|
+
_id: true,
|
|
4037
|
+
projectId: true,
|
|
4038
|
+
showIncidentsOnStatusPage: true,
|
|
4039
|
+
},
|
|
4040
|
+
props: {
|
|
4041
|
+
isRoot: true,
|
|
4042
|
+
},
|
|
4043
|
+
});
|
|
4044
|
+
|
|
4045
|
+
if (
|
|
4046
|
+
!statusPage ||
|
|
4047
|
+
!statusPage.projectId ||
|
|
4048
|
+
!statusPage.showIncidentsOnStatusPage
|
|
4049
|
+
) {
|
|
4050
|
+
throw new NotFoundException("Attachment not found");
|
|
4051
|
+
}
|
|
4052
|
+
|
|
4053
|
+
const { monitorsOnStatusPage } =
|
|
4054
|
+
await StatusPageService.getMonitorIdsOnStatusPage({
|
|
4055
|
+
statusPageId,
|
|
4056
|
+
});
|
|
4057
|
+
|
|
4058
|
+
if (!monitorsOnStatusPage || monitorsOnStatusPage.length === 0) {
|
|
4059
|
+
throw new NotFoundException("Attachment not found");
|
|
4060
|
+
}
|
|
4061
|
+
|
|
4062
|
+
const incident: Incident | null = await IncidentService.findOneBy({
|
|
4063
|
+
query: {
|
|
4064
|
+
_id: incidentId.toString(),
|
|
4065
|
+
projectId: statusPage.projectId!,
|
|
4066
|
+
isVisibleOnStatusPage: true,
|
|
4067
|
+
showPostmortemOnStatusPage: true,
|
|
4068
|
+
monitors: monitorsOnStatusPage as any,
|
|
4069
|
+
},
|
|
4070
|
+
select: {
|
|
4071
|
+
postmortemAttachments: {
|
|
4072
|
+
_id: true,
|
|
4073
|
+
file: true,
|
|
4074
|
+
fileType: true,
|
|
4075
|
+
name: true,
|
|
4076
|
+
},
|
|
4077
|
+
},
|
|
4078
|
+
props: {
|
|
4079
|
+
isRoot: true,
|
|
4080
|
+
},
|
|
4081
|
+
});
|
|
4082
|
+
|
|
4083
|
+
if (!incident) {
|
|
4084
|
+
throw new NotFoundException("Attachment not found");
|
|
4085
|
+
}
|
|
4086
|
+
|
|
4087
|
+
const attachment: File | undefined = incident.postmortemAttachments?.find(
|
|
4088
|
+
(file: File) => {
|
|
4089
|
+
const attachmentId: string | null = file._id
|
|
4090
|
+
? file._id.toString()
|
|
4091
|
+
: file.id
|
|
4092
|
+
? file.id.toString()
|
|
4093
|
+
: null;
|
|
4094
|
+
return attachmentId === fileId.toString();
|
|
4095
|
+
},
|
|
4096
|
+
);
|
|
4097
|
+
|
|
4098
|
+
if (!attachment || !attachment.file) {
|
|
4099
|
+
throw new NotFoundException("Attachment not found");
|
|
4100
|
+
}
|
|
4101
|
+
|
|
4102
|
+
Response.setNoCacheHeaders(res);
|
|
4103
|
+
return Response.sendFileResponse(req, res, attachment);
|
|
4104
|
+
}
|
|
4105
|
+
|
|
3972
4106
|
private async getIncidentPublicNoteAttachment(
|
|
3973
4107
|
req: ExpressRequest,
|
|
3974
4108
|
res: ExpressResponse,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
export class MigrationName1764762146063 implements MigrationInterface {
|
|
4
|
+
public name = "MigrationName1764762146063";
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
await queryRunner.query(
|
|
8
|
+
`CREATE TABLE "IncidentPostmortemAttachmentFile" ("incidentId" uuid NOT NULL, "fileId" uuid NOT NULL, CONSTRAINT "PK_40b17c7d5bcfbde48d7ebab4130" PRIMARY KEY ("incidentId", "fileId"))`,
|
|
9
|
+
);
|
|
10
|
+
await queryRunner.query(
|
|
11
|
+
`CREATE INDEX "IDX_62b9c09c42e05df3f134aa14a4" ON "IncidentPostmortemAttachmentFile" ("incidentId") `,
|
|
12
|
+
);
|
|
13
|
+
await queryRunner.query(
|
|
14
|
+
`CREATE INDEX "IDX_7e09116a3b9672622bba9f8b2e" ON "IncidentPostmortemAttachmentFile" ("fileId") `,
|
|
15
|
+
);
|
|
16
|
+
await queryRunner.query(
|
|
17
|
+
`ALTER TABLE "Incident" ADD "showPostmortemOnStatusPage" boolean NOT NULL DEFAULT false`,
|
|
18
|
+
);
|
|
19
|
+
await queryRunner.query(
|
|
20
|
+
`ALTER TABLE "IncidentPostmortemAttachmentFile" ADD CONSTRAINT "FK_62b9c09c42e05df3f134aa14a46" FOREIGN KEY ("incidentId") REFERENCES "Incident"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
|
|
21
|
+
);
|
|
22
|
+
await queryRunner.query(
|
|
23
|
+
`ALTER TABLE "IncidentPostmortemAttachmentFile" ADD CONSTRAINT "FK_7e09116a3b9672622bba9f8b2e3" FOREIGN KEY ("fileId") REFERENCES "File"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
28
|
+
await queryRunner.query(
|
|
29
|
+
`ALTER TABLE "IncidentPostmortemAttachmentFile" DROP CONSTRAINT "FK_7e09116a3b9672622bba9f8b2e3"`,
|
|
30
|
+
);
|
|
31
|
+
await queryRunner.query(
|
|
32
|
+
`ALTER TABLE "IncidentPostmortemAttachmentFile" DROP CONSTRAINT "FK_62b9c09c42e05df3f134aa14a46"`,
|
|
33
|
+
);
|
|
34
|
+
await queryRunner.query(
|
|
35
|
+
`ALTER TABLE "Incident" DROP COLUMN "showPostmortemOnStatusPage"`,
|
|
36
|
+
);
|
|
37
|
+
await queryRunner.query(
|
|
38
|
+
`DROP INDEX "public"."IDX_7e09116a3b9672622bba9f8b2e"`,
|
|
39
|
+
);
|
|
40
|
+
await queryRunner.query(
|
|
41
|
+
`DROP INDEX "public"."IDX_62b9c09c42e05df3f134aa14a4"`,
|
|
42
|
+
);
|
|
43
|
+
await queryRunner.query(`DROP TABLE "IncidentPostmortemAttachmentFile"`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
export class MigrationName1764767371788 implements MigrationInterface {
|
|
4
|
+
public name = "MigrationName1764767371788";
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
await queryRunner.query(
|
|
8
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
|
|
9
|
+
);
|
|
10
|
+
await queryRunner.query(
|
|
11
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
16
|
+
await queryRunner.query(
|
|
17
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
|
|
18
|
+
);
|
|
19
|
+
await queryRunner.query(
|
|
20
|
+
`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -187,6 +187,8 @@ import { MigrationName1763477560906 } from "./1763477560906-MigrationName";
|
|
|
187
187
|
import { MigrationName1763480947474 } from "./1763480947474-MigrationName";
|
|
188
188
|
import { MigrationName1763643080445 } from "./1763643080445-MigrationName";
|
|
189
189
|
import { MigrationName1764324618043 } from "./1764324618043-MigrationName";
|
|
190
|
+
import { MigrationName1764762146063 } from "./1764762146063-MigrationName";
|
|
191
|
+
import { MigrationName1764767371788 } from "./1764767371788-MigrationName";
|
|
190
192
|
|
|
191
193
|
export default [
|
|
192
194
|
InitialMigration,
|
|
@@ -378,4 +380,6 @@ export default [
|
|
|
378
380
|
MigrationName1763480947474,
|
|
379
381
|
MigrationName1763643080445,
|
|
380
382
|
MigrationName1764324618043,
|
|
383
|
+
MigrationName1764762146063,
|
|
384
|
+
MigrationName1764767371788,
|
|
381
385
|
];
|
|
@@ -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
|
|
|
@@ -1798,14 +1798,19 @@ export default class MicrosoftTeamsUtil extends WorkspaceBase {
|
|
|
1798
1798
|
let responseText: string = "";
|
|
1799
1799
|
|
|
1800
1800
|
try {
|
|
1801
|
+
const isCreateIncidentCommand: boolean =
|
|
1802
|
+
cleanText === "create incident" ||
|
|
1803
|
+
cleanText.startsWith("create incident ");
|
|
1804
|
+
|
|
1805
|
+
const isCreateMaintenanceCommand: boolean =
|
|
1806
|
+
cleanText === "create maintenance" ||
|
|
1807
|
+
cleanText.startsWith("create maintenance ");
|
|
1808
|
+
|
|
1801
1809
|
if (cleanText.includes("help") || cleanText === "") {
|
|
1802
1810
|
responseText = this.getHelpMessage();
|
|
1803
|
-
} else if (
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
) {
|
|
1807
|
-
// Handle /incident slash command
|
|
1808
|
-
logger.debug("Processing /incident command");
|
|
1811
|
+
} else if (isCreateIncidentCommand) {
|
|
1812
|
+
// Handle create incident command (legacy slash command supported)
|
|
1813
|
+
logger.debug("Processing create incident command");
|
|
1809
1814
|
const card: JSONObject =
|
|
1810
1815
|
await MicrosoftTeamsIncidentActions.buildNewIncidentCard(projectId);
|
|
1811
1816
|
await data.turnContext.sendActivity({
|
|
@@ -1818,12 +1823,9 @@ export default class MicrosoftTeamsUtil extends WorkspaceBase {
|
|
|
1818
1823
|
});
|
|
1819
1824
|
logger.debug("New incident card sent successfully");
|
|
1820
1825
|
return;
|
|
1821
|
-
} else if (
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
) {
|
|
1825
|
-
// Handle /maintenance slash command
|
|
1826
|
-
logger.debug("Processing /maintenance command");
|
|
1826
|
+
} else if (isCreateMaintenanceCommand) {
|
|
1827
|
+
// Handle create maintenance command (legacy slash command supported)
|
|
1828
|
+
logger.debug("Processing create maintenance command");
|
|
1827
1829
|
const card: JSONObject =
|
|
1828
1830
|
await MicrosoftTeamsScheduledMaintenanceActions.buildNewScheduledMaintenanceCard(
|
|
1829
1831
|
projectId,
|
|
@@ -1880,8 +1882,8 @@ export default class MicrosoftTeamsUtil extends WorkspaceBase {
|
|
|
1880
1882
|
|
|
1881
1883
|
**Available Commands:**
|
|
1882
1884
|
- **help** — Show this help message
|
|
1883
|
-
-
|
|
1884
|
-
-
|
|
1885
|
+
- **create incident** — Create a new incident
|
|
1886
|
+
- **create maintenance** — Create a new scheduled maintenance event
|
|
1885
1887
|
- **show active incidents** — Display all currently active incidents
|
|
1886
1888
|
- **show scheduled maintenance** — Show upcoming scheduled maintenance events
|
|
1887
1889
|
- **show ongoing maintenance** — Display currently ongoing maintenance events
|
|
@@ -2720,11 +2722,11 @@ All monitoring checks are passing normally.`;
|
|
|
2720
2722
|
value: "Show quick help and useful links",
|
|
2721
2723
|
},
|
|
2722
2724
|
{
|
|
2723
|
-
title: "
|
|
2725
|
+
title: "create incident",
|
|
2724
2726
|
value: "Create a new incident without leaving Teams",
|
|
2725
2727
|
},
|
|
2726
2728
|
{
|
|
2727
|
-
title: "
|
|
2729
|
+
title: "create maintenance",
|
|
2728
2730
|
value: "Schedule or review maintenance windows",
|
|
2729
2731
|
},
|
|
2730
2732
|
{
|