@oneuptime/common 9.5.8 → 9.5.9
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/Alert.ts +8 -9
- package/Models/DatabaseModels/Incident.ts +5 -5
- package/Models/DatabaseModels/IncidentTemplate.ts +4 -3
- package/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.ts +1 -1
- package/Models/DatabaseModels/UserOnCallLog.ts +1 -1
- package/Server/Infrastructure/Postgres/SchemaMigrations/1770833704656-MigrationName.ts +156 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1770834237090-MigrationName.ts +119 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Services/AlertEpisodeFeedService.ts +50 -0
- package/Server/Services/AlertEpisodeInternalNoteService.ts +162 -0
- package/Server/Services/AlertEpisodeMemberService.ts +7 -0
- package/Server/Services/AlertEpisodeOwnerTeamService.ts +186 -0
- package/Server/Services/AlertEpisodeOwnerUserService.ts +180 -0
- package/Server/Services/AlertEpisodeService.ts +68 -0
- package/Server/Services/AlertEpisodeStateTimelineService.ts +5 -0
- package/Server/Services/AlertService.ts +3 -0
- package/Server/Services/IncidentEpisodeFeedService.ts +50 -0
- package/Server/Services/IncidentEpisodeInternalNoteService.ts +163 -0
- package/Server/Services/IncidentEpisodeMemberService.ts +7 -0
- package/Server/Services/IncidentEpisodeOwnerTeamService.ts +189 -0
- package/Server/Services/IncidentEpisodeOwnerUserService.ts +183 -0
- package/Server/Services/IncidentEpisodePublicNoteService.ts +8 -0
- package/Server/Services/IncidentEpisodeService.ts +91 -12
- package/Server/Services/IncidentEpisodeStateTimelineService.ts +5 -0
- package/Server/Services/IncidentService.ts +5 -0
- package/Server/Services/WorkspaceNotificationRuleService.ts +20 -0
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +1 -1
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.ts +7 -6
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +1 -1
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +7 -6
- package/Server/Utils/Workspace/Slack/Actions/Alert.ts +17 -0
- package/Server/Utils/Workspace/Slack/Actions/AlertEpisode.ts +27 -12
- package/Server/Utils/Workspace/Slack/Actions/Incident.ts +17 -0
- package/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.ts +86 -28
- package/Server/Utils/Workspace/Slack/Messages/IncidentEpisode.ts +6 -6
- package/Server/Utils/Workspace/Slack/Slack.ts +49 -0
- package/Server/Utils/Workspace/WorkspaceMessages/Alert.ts +2 -1
- package/Server/Utils/Workspace/WorkspaceMessages/AlertEpisode.ts +3 -1
- package/Server/Utils/Workspace/WorkspaceMessages/Incident.ts +2 -1
- package/Server/Utils/Workspace/WorkspaceMessages/IncidentEpisode.ts +3 -1
- package/Types/Permission.ts +641 -0
- package/UI/Components/Detail/Detail.tsx +13 -4
- package/UI/Components/Detail/Field.ts +2 -2
- package/UI/Components/Dropdown/Dropdown.tsx +38 -7
- package/UI/Components/Forms/BasicForm.tsx +35 -5
- package/UI/Components/Forms/Fields/PermissionPicker.tsx +261 -0
- package/UI/Components/Forms/Types/Field.ts +5 -3
- package/UI/Utils/Permission.ts +29 -6
- package/build/dist/Models/DatabaseModels/Alert.js +8 -8
- package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Incident.js +5 -5
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js +3 -3
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1770833704656-MigrationName.js +63 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1770833704656-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1770834237090-MigrationName.js +46 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1770834237090-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/Services/AlertEpisodeFeedService.js +33 -0
- package/build/dist/Server/Services/AlertEpisodeFeedService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeInternalNoteService.js +132 -0
- package/build/dist/Server/Services/AlertEpisodeInternalNoteService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeMemberService.js +7 -0
- package/build/dist/Server/Services/AlertEpisodeMemberService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeOwnerTeamService.js +163 -0
- package/build/dist/Server/Services/AlertEpisodeOwnerTeamService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeOwnerUserService.js +156 -0
- package/build/dist/Server/Services/AlertEpisodeOwnerUserService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeService.js +53 -0
- package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeStateTimelineService.js +4 -0
- package/build/dist/Server/Services/AlertEpisodeStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +3 -5
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeFeedService.js +33 -0
- package/build/dist/Server/Services/IncidentEpisodeFeedService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeInternalNoteService.js +132 -0
- package/build/dist/Server/Services/IncidentEpisodeInternalNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeMemberService.js +7 -0
- package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeOwnerTeamService.js +163 -0
- package/build/dist/Server/Services/IncidentEpisodeOwnerTeamService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeOwnerUserService.js +156 -0
- package/build/dist/Server/Services/IncidentEpisodeOwnerUserService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +8 -0
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js +72 -10
- package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +4 -0
- package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +5 -5
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +16 -0
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js +7 -6
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +7 -6
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js +16 -0
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/AlertEpisode.js +25 -9
- package/build/dist/Server/Utils/Workspace/Slack/Actions/AlertEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js +16 -0
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.js +71 -25
- package/build/dist/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Messages/IncidentEpisode.js +6 -6
- package/build/dist/Server/Utils/Workspace/Slack/Messages/IncidentEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +40 -0
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/WorkspaceMessages/Alert.js +1 -1
- package/build/dist/Server/Utils/Workspace/WorkspaceMessages/Alert.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/WorkspaceMessages/AlertEpisode.js +1 -1
- package/build/dist/Server/Utils/Workspace/WorkspaceMessages/AlertEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/WorkspaceMessages/Incident.js +1 -1
- package/build/dist/Server/Utils/Workspace/WorkspaceMessages/Incident.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/WorkspaceMessages/IncidentEpisode.js +1 -1
- package/build/dist/Server/Utils/Workspace/WorkspaceMessages/IncidentEpisode.js.map +1 -1
- package/build/dist/Types/Permission.js +637 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/UI/Components/Detail/Detail.js +7 -1
- package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js +17 -2
- package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +17 -3
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/PermissionPicker.js +129 -0
- package/build/dist/UI/Components/Forms/Fields/PermissionPicker.js.map +1 -0
- package/build/dist/UI/Utils/Permission.js +17 -4
- package/build/dist/UI/Utils/Permission.js.map +1 -1
- package/package.json +1 -1
|
@@ -139,6 +139,10 @@ export class Service extends DatabaseService<Model> {
|
|
|
139
139
|
displayColor: Yellow500,
|
|
140
140
|
feedInfoInMarkdown: `**Alert ${alert?.alertNumberWithPrefix || "#" + (alert?.alertNumber || "N/A")}** added to episode: ${alert?.title || "No title"}`,
|
|
141
141
|
userId: createdItem.addedByUserId || undefined,
|
|
142
|
+
workspaceNotification: {
|
|
143
|
+
sendWorkspaceNotification: true,
|
|
144
|
+
notifyUserId: createdItem.addedByUserId || undefined,
|
|
145
|
+
},
|
|
142
146
|
});
|
|
143
147
|
|
|
144
148
|
// Create feed item on alert
|
|
@@ -235,6 +239,9 @@ export class Service extends DatabaseService<Model> {
|
|
|
235
239
|
alertEpisodeFeedEventType: AlertEpisodeFeedEventType.AlertRemoved,
|
|
236
240
|
displayColor: Green500,
|
|
237
241
|
feedInfoInMarkdown: `**Alert #${alert?.alertNumber || "N/A"}** removed from episode: ${alert?.title || "No title"}`,
|
|
242
|
+
workspaceNotification: {
|
|
243
|
+
sendWorkspaceNotification: true,
|
|
244
|
+
},
|
|
238
245
|
});
|
|
239
246
|
|
|
240
247
|
// Create feed item on alert
|
|
@@ -1,10 +1,196 @@
|
|
|
1
|
+
import ObjectID from "../../Types/ObjectID";
|
|
2
|
+
import { OnCreate, OnDelete } from "../Types/Database/Hooks";
|
|
1
3
|
import DatabaseService from "./DatabaseService";
|
|
2
4
|
import Model from "../../Models/DatabaseModels/AlertEpisodeOwnerTeam";
|
|
5
|
+
import AlertEpisodeFeedService from "./AlertEpisodeFeedService";
|
|
6
|
+
import { AlertEpisodeFeedEventType } from "../../Models/DatabaseModels/AlertEpisodeFeed";
|
|
7
|
+
import { Gray500, Red500 } from "../../Types/BrandColors";
|
|
8
|
+
import TeamService from "./TeamService";
|
|
9
|
+
import Team from "../../Models/DatabaseModels/Team";
|
|
10
|
+
import DeleteBy from "../Types/Database/DeleteBy";
|
|
11
|
+
import AlertEpisodeService from "./AlertEpisodeService";
|
|
12
|
+
import AlertEpisode from "../../Models/DatabaseModels/AlertEpisode";
|
|
13
|
+
import WorkspaceNotificationRuleService from "./WorkspaceNotificationRuleService";
|
|
14
|
+
import NotificationRuleEventType from "../../Types/Workspace/NotificationRules/EventType";
|
|
15
|
+
import WorkspaceNotificationRule from "../../Models/DatabaseModels/WorkspaceNotificationRule";
|
|
16
|
+
import logger from "../Utils/Logger";
|
|
17
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
3
18
|
|
|
4
19
|
export class Service extends DatabaseService<Model> {
|
|
5
20
|
public constructor() {
|
|
6
21
|
super(Model);
|
|
7
22
|
}
|
|
23
|
+
|
|
24
|
+
@CaptureSpan()
|
|
25
|
+
protected override async onBeforeDelete(
|
|
26
|
+
deleteBy: DeleteBy<Model>,
|
|
27
|
+
): Promise<OnDelete<Model>> {
|
|
28
|
+
const itemsToDelete: Model[] = await this.findBy({
|
|
29
|
+
query: deleteBy.query,
|
|
30
|
+
limit: deleteBy.limit,
|
|
31
|
+
skip: deleteBy.skip,
|
|
32
|
+
props: {
|
|
33
|
+
isRoot: true,
|
|
34
|
+
},
|
|
35
|
+
select: {
|
|
36
|
+
alertEpisodeId: true,
|
|
37
|
+
projectId: true,
|
|
38
|
+
teamId: true,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
carryForward: {
|
|
44
|
+
itemsToDelete: itemsToDelete,
|
|
45
|
+
},
|
|
46
|
+
deleteBy: deleteBy,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@CaptureSpan()
|
|
51
|
+
protected override async onDeleteSuccess(
|
|
52
|
+
onDelete: OnDelete<Model>,
|
|
53
|
+
_itemIdsBeforeDelete: Array<ObjectID>,
|
|
54
|
+
): Promise<OnDelete<Model>> {
|
|
55
|
+
const deleteByUserId: ObjectID | undefined =
|
|
56
|
+
onDelete.deleteBy.deletedByUser?.id || onDelete.deleteBy.props.userId;
|
|
57
|
+
|
|
58
|
+
const itemsToDelete: Model[] = onDelete.carryForward.itemsToDelete;
|
|
59
|
+
|
|
60
|
+
for (const item of itemsToDelete) {
|
|
61
|
+
const alertEpisodeId: ObjectID | undefined = item.alertEpisodeId;
|
|
62
|
+
const projectId: ObjectID | undefined = item.projectId;
|
|
63
|
+
const teamId: ObjectID | undefined = item.teamId;
|
|
64
|
+
|
|
65
|
+
if (alertEpisodeId && teamId && projectId) {
|
|
66
|
+
const team: Team | null = await TeamService.findOneById({
|
|
67
|
+
id: teamId,
|
|
68
|
+
select: {
|
|
69
|
+
name: true,
|
|
70
|
+
},
|
|
71
|
+
props: {
|
|
72
|
+
isRoot: true,
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const episodeNumberResult: {
|
|
77
|
+
number: number | null;
|
|
78
|
+
numberWithPrefix: string | null;
|
|
79
|
+
} = await AlertEpisodeService.getEpisodeNumber({
|
|
80
|
+
episodeId: alertEpisodeId,
|
|
81
|
+
});
|
|
82
|
+
const episodeNumberDisplay: string =
|
|
83
|
+
episodeNumberResult.numberWithPrefix ||
|
|
84
|
+
"#" + episodeNumberResult.number;
|
|
85
|
+
|
|
86
|
+
if (team && team.name) {
|
|
87
|
+
await AlertEpisodeFeedService.createAlertEpisodeFeedItem({
|
|
88
|
+
alertEpisodeId: alertEpisodeId,
|
|
89
|
+
projectId: projectId,
|
|
90
|
+
alertEpisodeFeedEventType:
|
|
91
|
+
AlertEpisodeFeedEventType.OwnerTeamRemoved,
|
|
92
|
+
displayColor: Red500,
|
|
93
|
+
feedInfoInMarkdown: `👨🏻👩🏻👦🏻 Removed team **${team.name}** from the [Episode ${episodeNumberDisplay}](${(await AlertEpisodeService.getEpisodeLinkInDashboard(projectId!, alertEpisodeId!)).toString()}) as the owner.`,
|
|
94
|
+
userId: deleteByUserId || undefined,
|
|
95
|
+
workspaceNotification: {
|
|
96
|
+
sendWorkspaceNotification: true,
|
|
97
|
+
notifyUserId: deleteByUserId || undefined,
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return onDelete;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@CaptureSpan()
|
|
108
|
+
public override async onCreateSuccess(
|
|
109
|
+
onCreate: OnCreate<Model>,
|
|
110
|
+
createdItem: Model,
|
|
111
|
+
): Promise<Model> {
|
|
112
|
+
const alertEpisodeId: ObjectID | undefined = createdItem.alertEpisodeId;
|
|
113
|
+
const projectId: ObjectID | undefined = createdItem.projectId;
|
|
114
|
+
const teamId: ObjectID | undefined = createdItem.teamId;
|
|
115
|
+
const createdByUserId: ObjectID | undefined =
|
|
116
|
+
createdItem.createdByUserId || onCreate.createBy.props.userId;
|
|
117
|
+
|
|
118
|
+
if (alertEpisodeId && teamId && projectId) {
|
|
119
|
+
const team: Team | null = await TeamService.findOneById({
|
|
120
|
+
id: teamId,
|
|
121
|
+
select: {
|
|
122
|
+
name: true,
|
|
123
|
+
},
|
|
124
|
+
props: {
|
|
125
|
+
isRoot: true,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
if (team && team.name) {
|
|
130
|
+
const episodeNumberResult: {
|
|
131
|
+
number: number | null;
|
|
132
|
+
numberWithPrefix: string | null;
|
|
133
|
+
} = await AlertEpisodeService.getEpisodeNumber({
|
|
134
|
+
episodeId: alertEpisodeId,
|
|
135
|
+
});
|
|
136
|
+
const episodeNumberDisplay: string =
|
|
137
|
+
episodeNumberResult.numberWithPrefix ||
|
|
138
|
+
"#" + episodeNumberResult.number;
|
|
139
|
+
|
|
140
|
+
await AlertEpisodeFeedService.createAlertEpisodeFeedItem({
|
|
141
|
+
alertEpisodeId: alertEpisodeId,
|
|
142
|
+
projectId: projectId,
|
|
143
|
+
alertEpisodeFeedEventType: AlertEpisodeFeedEventType.OwnerTeamAdded,
|
|
144
|
+
displayColor: Gray500,
|
|
145
|
+
feedInfoInMarkdown: `👨🏻👩🏻👦🏻 Added team **${team.name}** to the [Episode ${episodeNumberDisplay}](${(await AlertEpisodeService.getEpisodeLinkInDashboard(projectId!, alertEpisodeId!)).toString()}) as the owner.`,
|
|
146
|
+
userId: createdByUserId || undefined,
|
|
147
|
+
workspaceNotification: {
|
|
148
|
+
sendWorkspaceNotification: true,
|
|
149
|
+
notifyUserId: createdByUserId || undefined,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// get notification rule where inviteOwners is true.
|
|
155
|
+
const notificationRules: Array<WorkspaceNotificationRule> =
|
|
156
|
+
await WorkspaceNotificationRuleService.getNotificationRulesWhereInviteOwnersIsTrue(
|
|
157
|
+
{
|
|
158
|
+
projectId: projectId,
|
|
159
|
+
notificationFor: {
|
|
160
|
+
alertEpisodeId: alertEpisodeId,
|
|
161
|
+
},
|
|
162
|
+
notificationRuleEventType: NotificationRuleEventType.AlertEpisode,
|
|
163
|
+
},
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// Fetch episode to get workspace channels
|
|
167
|
+
const episode: AlertEpisode | null =
|
|
168
|
+
await AlertEpisodeService.findOneById({
|
|
169
|
+
id: alertEpisodeId,
|
|
170
|
+
select: {
|
|
171
|
+
postUpdatesToWorkspaceChannels: true,
|
|
172
|
+
},
|
|
173
|
+
props: {
|
|
174
|
+
isRoot: true,
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
if (episode) {
|
|
179
|
+
WorkspaceNotificationRuleService.inviteTeamsBasedOnRulesAndWorkspaceChannels(
|
|
180
|
+
{
|
|
181
|
+
notificationRules: notificationRules,
|
|
182
|
+
projectId: projectId,
|
|
183
|
+
workspaceChannels: episode.postUpdatesToWorkspaceChannels || [],
|
|
184
|
+
teamIds: [teamId],
|
|
185
|
+
},
|
|
186
|
+
).catch((error: Error) => {
|
|
187
|
+
logger.error(error);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return createdItem;
|
|
193
|
+
}
|
|
8
194
|
}
|
|
9
195
|
|
|
10
196
|
export default new Service();
|
|
@@ -1,10 +1,190 @@
|
|
|
1
|
+
import ObjectID from "../../Types/ObjectID";
|
|
1
2
|
import DatabaseService from "./DatabaseService";
|
|
2
3
|
import Model from "../../Models/DatabaseModels/AlertEpisodeOwnerUser";
|
|
4
|
+
import AlertEpisodeFeedService from "./AlertEpisodeFeedService";
|
|
5
|
+
import { AlertEpisodeFeedEventType } from "../../Models/DatabaseModels/AlertEpisodeFeed";
|
|
6
|
+
import { Gray500, Red500 } from "../../Types/BrandColors";
|
|
7
|
+
import User from "../../Models/DatabaseModels/User";
|
|
8
|
+
import UserService from "./UserService";
|
|
9
|
+
import { OnCreate, OnDelete } from "../Types/Database/Hooks";
|
|
10
|
+
import DeleteBy from "../Types/Database/DeleteBy";
|
|
11
|
+
import AlertEpisodeService from "./AlertEpisodeService";
|
|
12
|
+
import AlertEpisode from "../../Models/DatabaseModels/AlertEpisode";
|
|
13
|
+
import WorkspaceNotificationRuleService from "./WorkspaceNotificationRuleService";
|
|
14
|
+
import NotificationRuleEventType from "../../Types/Workspace/NotificationRules/EventType";
|
|
15
|
+
import WorkspaceNotificationRule from "../../Models/DatabaseModels/WorkspaceNotificationRule";
|
|
16
|
+
import logger from "../Utils/Logger";
|
|
17
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
3
18
|
|
|
4
19
|
export class Service extends DatabaseService<Model> {
|
|
5
20
|
public constructor() {
|
|
6
21
|
super(Model);
|
|
7
22
|
}
|
|
23
|
+
|
|
24
|
+
@CaptureSpan()
|
|
25
|
+
protected override async onBeforeDelete(
|
|
26
|
+
deleteBy: DeleteBy<Model>,
|
|
27
|
+
): Promise<OnDelete<Model>> {
|
|
28
|
+
const itemsToDelete: Model[] = await this.findBy({
|
|
29
|
+
query: deleteBy.query,
|
|
30
|
+
limit: deleteBy.limit,
|
|
31
|
+
skip: deleteBy.skip,
|
|
32
|
+
props: {
|
|
33
|
+
isRoot: true,
|
|
34
|
+
},
|
|
35
|
+
select: {
|
|
36
|
+
alertEpisodeId: true,
|
|
37
|
+
projectId: true,
|
|
38
|
+
userId: true,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
carryForward: {
|
|
44
|
+
itemsToDelete: itemsToDelete,
|
|
45
|
+
},
|
|
46
|
+
deleteBy: deleteBy,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@CaptureSpan()
|
|
51
|
+
protected override async onDeleteSuccess(
|
|
52
|
+
onDelete: OnDelete<Model>,
|
|
53
|
+
_itemIdsBeforeDelete: Array<ObjectID>,
|
|
54
|
+
): Promise<OnDelete<Model>> {
|
|
55
|
+
const deleteByUserId: ObjectID | undefined =
|
|
56
|
+
onDelete.deleteBy.deletedByUser?.id || onDelete.deleteBy.props.userId;
|
|
57
|
+
|
|
58
|
+
const itemsToDelete: Model[] = onDelete.carryForward.itemsToDelete;
|
|
59
|
+
|
|
60
|
+
for (const item of itemsToDelete) {
|
|
61
|
+
const alertEpisodeId: ObjectID | undefined = item.alertEpisodeId;
|
|
62
|
+
const projectId: ObjectID | undefined = item.projectId;
|
|
63
|
+
const userId: ObjectID | undefined = item.userId;
|
|
64
|
+
|
|
65
|
+
if (alertEpisodeId && userId && projectId) {
|
|
66
|
+
const user: User | null = await UserService.findOneById({
|
|
67
|
+
id: userId,
|
|
68
|
+
select: {
|
|
69
|
+
name: true,
|
|
70
|
+
email: true,
|
|
71
|
+
},
|
|
72
|
+
props: {
|
|
73
|
+
isRoot: true,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const episodeNumberResult: {
|
|
78
|
+
number: number | null;
|
|
79
|
+
numberWithPrefix: string | null;
|
|
80
|
+
} = await AlertEpisodeService.getEpisodeNumber({
|
|
81
|
+
episodeId: alertEpisodeId,
|
|
82
|
+
});
|
|
83
|
+
const episodeNumberDisplay: string =
|
|
84
|
+
episodeNumberResult.numberWithPrefix ||
|
|
85
|
+
"#" + episodeNumberResult.number;
|
|
86
|
+
|
|
87
|
+
if (user && user.name) {
|
|
88
|
+
await AlertEpisodeFeedService.createAlertEpisodeFeedItem({
|
|
89
|
+
alertEpisodeId: alertEpisodeId,
|
|
90
|
+
projectId: projectId,
|
|
91
|
+
alertEpisodeFeedEventType:
|
|
92
|
+
AlertEpisodeFeedEventType.OwnerUserRemoved,
|
|
93
|
+
displayColor: Red500,
|
|
94
|
+
feedInfoInMarkdown: `👨🏻💻 Removed **${user.name.toString()}** (${user.email?.toString()}) from the [Episode ${episodeNumberDisplay}](${(await AlertEpisodeService.getEpisodeLinkInDashboard(projectId!, alertEpisodeId!)).toString()}) as the owner.`,
|
|
95
|
+
userId: deleteByUserId || undefined,
|
|
96
|
+
workspaceNotification: {
|
|
97
|
+
sendWorkspaceNotification: true,
|
|
98
|
+
notifyUserId: userId || undefined,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return onDelete;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@CaptureSpan()
|
|
109
|
+
public override async onCreateSuccess(
|
|
110
|
+
onCreate: OnCreate<Model>,
|
|
111
|
+
createdItem: Model,
|
|
112
|
+
): Promise<Model> {
|
|
113
|
+
const alertEpisodeId: ObjectID | undefined = createdItem.alertEpisodeId;
|
|
114
|
+
const projectId: ObjectID | undefined = createdItem.projectId;
|
|
115
|
+
const userId: ObjectID | undefined = createdItem.userId;
|
|
116
|
+
const createdByUserId: ObjectID | undefined =
|
|
117
|
+
createdItem.createdByUserId || onCreate.createBy.props.userId;
|
|
118
|
+
|
|
119
|
+
if (alertEpisodeId && userId && projectId) {
|
|
120
|
+
const episodeNumberResult: {
|
|
121
|
+
number: number | null;
|
|
122
|
+
numberWithPrefix: string | null;
|
|
123
|
+
} = await AlertEpisodeService.getEpisodeNumber({
|
|
124
|
+
episodeId: alertEpisodeId,
|
|
125
|
+
});
|
|
126
|
+
const episodeNumberDisplay: string =
|
|
127
|
+
episodeNumberResult.numberWithPrefix ||
|
|
128
|
+
"#" + episodeNumberResult.number;
|
|
129
|
+
|
|
130
|
+
await AlertEpisodeFeedService.createAlertEpisodeFeedItem({
|
|
131
|
+
alertEpisodeId: alertEpisodeId,
|
|
132
|
+
projectId: projectId,
|
|
133
|
+
alertEpisodeFeedEventType: AlertEpisodeFeedEventType.OwnerUserAdded,
|
|
134
|
+
displayColor: Gray500,
|
|
135
|
+
feedInfoInMarkdown: `👨🏻💻 Added **${await UserService.getUserMarkdownString(
|
|
136
|
+
{
|
|
137
|
+
userId: userId,
|
|
138
|
+
projectId: projectId,
|
|
139
|
+
},
|
|
140
|
+
)}** to the [Episode ${episodeNumberDisplay}](${(await AlertEpisodeService.getEpisodeLinkInDashboard(projectId!, alertEpisodeId!)).toString()}) as the owner.`,
|
|
141
|
+
userId: createdByUserId || undefined,
|
|
142
|
+
workspaceNotification: {
|
|
143
|
+
sendWorkspaceNotification: true,
|
|
144
|
+
notifyUserId: userId || undefined,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// get notification rule where inviteOwners is true.
|
|
149
|
+
const notificationRules: Array<WorkspaceNotificationRule> =
|
|
150
|
+
await WorkspaceNotificationRuleService.getNotificationRulesWhereInviteOwnersIsTrue(
|
|
151
|
+
{
|
|
152
|
+
projectId: projectId,
|
|
153
|
+
notificationFor: {
|
|
154
|
+
alertEpisodeId: alertEpisodeId,
|
|
155
|
+
},
|
|
156
|
+
notificationRuleEventType: NotificationRuleEventType.AlertEpisode,
|
|
157
|
+
},
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
// Fetch episode to get workspace channels
|
|
161
|
+
const episode: AlertEpisode | null =
|
|
162
|
+
await AlertEpisodeService.findOneById({
|
|
163
|
+
id: alertEpisodeId,
|
|
164
|
+
select: {
|
|
165
|
+
postUpdatesToWorkspaceChannels: true,
|
|
166
|
+
},
|
|
167
|
+
props: {
|
|
168
|
+
isRoot: true,
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
if (episode) {
|
|
173
|
+
WorkspaceNotificationRuleService.inviteUsersBasedOnRulesAndWorkspaceChannels(
|
|
174
|
+
{
|
|
175
|
+
notificationRules: notificationRules,
|
|
176
|
+
projectId: projectId,
|
|
177
|
+
workspaceChannels: episode.postUpdatesToWorkspaceChannels || [],
|
|
178
|
+
userIds: [userId],
|
|
179
|
+
},
|
|
180
|
+
).catch((error: Error) => {
|
|
181
|
+
logger.error(error);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return createdItem;
|
|
187
|
+
}
|
|
8
188
|
}
|
|
9
189
|
|
|
10
190
|
export default new Service();
|
|
@@ -38,6 +38,8 @@ import User from "../../Models/DatabaseModels/User";
|
|
|
38
38
|
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
39
39
|
import NotificationRuleWorkspaceChannel from "../../Types/Workspace/NotificationRules/NotificationRuleWorkspaceChannel";
|
|
40
40
|
import WorkspaceType from "../../Types/Workspace/WorkspaceType";
|
|
41
|
+
import AlertEpisodeWorkspaceMessages from "../Utils/Workspace/WorkspaceMessages/AlertEpisode";
|
|
42
|
+
import { MessageBlocksByWorkspaceType } from "./WorkspaceNotificationRuleService";
|
|
41
43
|
import Typeof from "../../Types/Typeof";
|
|
42
44
|
import AlertService from "./AlertService";
|
|
43
45
|
import OnCallDutyPolicyService from "./OnCallDutyPolicyService";
|
|
@@ -124,6 +126,17 @@ export class Service extends DatabaseService<Model> {
|
|
|
124
126
|
|
|
125
127
|
// Create initial state timeline entry
|
|
126
128
|
Promise.resolve()
|
|
129
|
+
.then(async () => {
|
|
130
|
+
try {
|
|
131
|
+
if (createdItem.projectId && createdItem.id) {
|
|
132
|
+
await this.handleEpisodeWorkspaceOperationsAsync(createdItem);
|
|
133
|
+
}
|
|
134
|
+
} catch (error) {
|
|
135
|
+
logger.error(
|
|
136
|
+
`Workspace operations failed in AlertEpisodeService.onCreateSuccess: ${error}`,
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
})
|
|
127
140
|
.then(async () => {
|
|
128
141
|
try {
|
|
129
142
|
await this.changeEpisodeState({
|
|
@@ -170,6 +183,51 @@ export class Service extends DatabaseService<Model> {
|
|
|
170
183
|
return createdItem;
|
|
171
184
|
}
|
|
172
185
|
|
|
186
|
+
@CaptureSpan()
|
|
187
|
+
private async handleEpisodeWorkspaceOperationsAsync(
|
|
188
|
+
createdItem: Model,
|
|
189
|
+
): Promise<void> {
|
|
190
|
+
try {
|
|
191
|
+
if (!createdItem.projectId || !createdItem.id) {
|
|
192
|
+
throw new BadDataException(
|
|
193
|
+
"projectId and id are required for workspace operations",
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const workspaceResult: {
|
|
198
|
+
channelsCreated: Array<NotificationRuleWorkspaceChannel>;
|
|
199
|
+
} | null =
|
|
200
|
+
await AlertEpisodeWorkspaceMessages.createChannelsAndInviteUsersToChannels(
|
|
201
|
+
{
|
|
202
|
+
projectId: createdItem.projectId,
|
|
203
|
+
alertEpisodeId: createdItem.id,
|
|
204
|
+
episodeNumber: createdItem.episodeNumber || 0,
|
|
205
|
+
...(createdItem.episodeNumberWithPrefix
|
|
206
|
+
? {
|
|
207
|
+
episodeNumberWithPrefix: createdItem.episodeNumberWithPrefix,
|
|
208
|
+
}
|
|
209
|
+
: {}),
|
|
210
|
+
},
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
if (workspaceResult && workspaceResult.channelsCreated?.length > 0) {
|
|
214
|
+
await this.updateOneById({
|
|
215
|
+
id: createdItem.id,
|
|
216
|
+
data: {
|
|
217
|
+
postUpdatesToWorkspaceChannels:
|
|
218
|
+
workspaceResult.channelsCreated || [],
|
|
219
|
+
},
|
|
220
|
+
props: {
|
|
221
|
+
isRoot: true,
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
} catch (error) {
|
|
226
|
+
logger.error(`Error in handleEpisodeWorkspaceOperationsAsync: ${error}`);
|
|
227
|
+
throw error;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
173
231
|
@CaptureSpan()
|
|
174
232
|
private async createEpisodeCreatedFeed(episode: Model): Promise<void> {
|
|
175
233
|
if (!episode.id || !episode.projectId) {
|
|
@@ -190,6 +248,12 @@ export class Service extends DatabaseService<Model> {
|
|
|
190
248
|
feedInfoInMarkdown += `This episode was manually created.\n\n`;
|
|
191
249
|
}
|
|
192
250
|
|
|
251
|
+
const episodeCreateMessageBlocks: Array<MessageBlocksByWorkspaceType> =
|
|
252
|
+
await AlertEpisodeWorkspaceMessages.getAlertEpisodeCreateMessageBlocks({
|
|
253
|
+
alertEpisodeId: episode.id,
|
|
254
|
+
projectId: episode.projectId,
|
|
255
|
+
});
|
|
256
|
+
|
|
193
257
|
await AlertEpisodeFeedService.createAlertEpisodeFeedItem({
|
|
194
258
|
alertEpisodeId: episode.id,
|
|
195
259
|
projectId: episode.projectId,
|
|
@@ -197,6 +261,10 @@ export class Service extends DatabaseService<Model> {
|
|
|
197
261
|
displayColor: Red500,
|
|
198
262
|
feedInfoInMarkdown: feedInfoInMarkdown,
|
|
199
263
|
userId: episode.createdByUserId || undefined,
|
|
264
|
+
workspaceNotification: {
|
|
265
|
+
appendMessageBlocks: episodeCreateMessageBlocks,
|
|
266
|
+
sendWorkspaceNotification: true,
|
|
267
|
+
},
|
|
200
268
|
});
|
|
201
269
|
}
|
|
202
270
|
|
|
@@ -374,6 +374,11 @@ export class Service extends DatabaseService<AlertEpisodeStateTimeline> {
|
|
|
374
374
|
? `**Cause:** \n${createdItem.rootCause}`
|
|
375
375
|
: undefined,
|
|
376
376
|
userId: createdItem.createdByUserId || onCreate.createBy.props.userId,
|
|
377
|
+
workspaceNotification: {
|
|
378
|
+
sendWorkspaceNotification: true,
|
|
379
|
+
notifyUserId:
|
|
380
|
+
createdItem.createdByUserId || onCreate.createBy.props.userId,
|
|
381
|
+
},
|
|
377
382
|
});
|
|
378
383
|
|
|
379
384
|
return createdItem;
|
|
@@ -368,6 +368,9 @@ export class Service extends DatabaseService<Model> {
|
|
|
368
368
|
projectId: createdItem.projectId,
|
|
369
369
|
alertId: createdItem.id,
|
|
370
370
|
alertNumber: createdItem.alertNumber!,
|
|
371
|
+
...(createdItem.alertNumberWithPrefix
|
|
372
|
+
? { alertNumberWithPrefix: createdItem.alertNumberWithPrefix }
|
|
373
|
+
: {}),
|
|
371
374
|
});
|
|
372
375
|
|
|
373
376
|
logger.debug("Alert created. Workspace result:");
|
|
@@ -9,6 +9,9 @@ import DatabaseService from "./DatabaseService";
|
|
|
9
9
|
import Model, {
|
|
10
10
|
IncidentEpisodeFeedEventType,
|
|
11
11
|
} from "../../Models/DatabaseModels/IncidentEpisodeFeed";
|
|
12
|
+
import WorkspaceNotificationRuleService, {
|
|
13
|
+
MessageBlocksByWorkspaceType,
|
|
14
|
+
} from "./WorkspaceNotificationRuleService";
|
|
12
15
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
13
16
|
|
|
14
17
|
export class Service extends DatabaseService<Model> {
|
|
@@ -30,6 +33,13 @@ export class Service extends DatabaseService<Model> {
|
|
|
30
33
|
displayColor?: Color | undefined;
|
|
31
34
|
userId?: ObjectID | undefined;
|
|
32
35
|
postedAt?: Date | undefined;
|
|
36
|
+
workspaceNotification?:
|
|
37
|
+
| {
|
|
38
|
+
notifyUserId?: ObjectID | undefined;
|
|
39
|
+
sendWorkspaceNotification: boolean;
|
|
40
|
+
appendMessageBlocks?: Array<MessageBlocksByWorkspaceType> | undefined;
|
|
41
|
+
}
|
|
42
|
+
| undefined;
|
|
33
43
|
}): Promise<void> {
|
|
34
44
|
try {
|
|
35
45
|
if (!data.incidentEpisodeId) {
|
|
@@ -83,12 +93,52 @@ export class Service extends DatabaseService<Model> {
|
|
|
83
93
|
isRoot: true,
|
|
84
94
|
},
|
|
85
95
|
});
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
if (
|
|
99
|
+
data.workspaceNotification &&
|
|
100
|
+
data.workspaceNotification?.sendWorkspaceNotification
|
|
101
|
+
) {
|
|
102
|
+
await this.sendWorkspaceNotification({
|
|
103
|
+
projectId: data.projectId,
|
|
104
|
+
incidentEpisodeId: data.incidentEpisodeId,
|
|
105
|
+
feedInfoInMarkdown: data.feedInfoInMarkdown,
|
|
106
|
+
workspaceNotification: data.workspaceNotification,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
} catch (e) {
|
|
110
|
+
logger.error("Error in sending notification to slack and teams");
|
|
111
|
+
logger.error(e);
|
|
112
|
+
}
|
|
86
113
|
} catch (error) {
|
|
87
114
|
logger.error("IncidentEpisodeFeedService.createIncidentEpisodeFeedItem");
|
|
88
115
|
logger.error(error);
|
|
89
116
|
// we dont want to throw the error here, as this is a non-critical operation
|
|
90
117
|
}
|
|
91
118
|
}
|
|
119
|
+
|
|
120
|
+
@CaptureSpan()
|
|
121
|
+
public async sendWorkspaceNotification(data: {
|
|
122
|
+
projectId: ObjectID;
|
|
123
|
+
incidentEpisodeId: ObjectID;
|
|
124
|
+
feedInfoInMarkdown: string;
|
|
125
|
+
workspaceNotification: {
|
|
126
|
+
notifyUserId?: ObjectID | undefined;
|
|
127
|
+
sendWorkspaceNotification: boolean;
|
|
128
|
+
appendMessageBlocks?: Array<MessageBlocksByWorkspaceType> | undefined;
|
|
129
|
+
};
|
|
130
|
+
}): Promise<void> {
|
|
131
|
+
return await WorkspaceNotificationRuleService.sendWorkspaceMarkdownNotification(
|
|
132
|
+
{
|
|
133
|
+
projectId: data.projectId,
|
|
134
|
+
notificationFor: {
|
|
135
|
+
incidentEpisodeId: data.incidentEpisodeId,
|
|
136
|
+
},
|
|
137
|
+
feedInfoInMarkdown: data.feedInfoInMarkdown,
|
|
138
|
+
workspaceNotification: data.workspaceNotification,
|
|
139
|
+
},
|
|
140
|
+
);
|
|
141
|
+
}
|
|
92
142
|
}
|
|
93
143
|
|
|
94
144
|
export default new Service();
|