@oneuptime/common 9.5.8 → 9.5.10
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/API/OpenSourceDeploymentAPI.ts +8 -0
- 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/Middleware/UserAuthorization.ts +8 -3
- 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/MonitorService.ts +8 -0
- package/Server/Services/WorkspaceNotificationRuleService.ts +31 -2
- package/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.ts +183 -0
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +13 -0
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +37 -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/MicrosoftTeams/MicrosoftTeams.ts +11 -7
- 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 +64 -12
- 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/Tests/Server/Middleware/UserAuthorization.test.ts +10 -2
- package/Types/Monitor/CriteriaFilter.ts +20 -3
- package/Types/Monitor/DnsMonitor/DnsMonitorResponse.ts +16 -0
- package/Types/Monitor/DnsMonitor/DnsRecordType.ts +14 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +67 -0
- package/Types/Monitor/MonitorStep.ts +30 -0
- package/Types/Monitor/MonitorStepDnsMonitor.ts +46 -0
- package/Types/Monitor/MonitorType.ts +15 -2
- package/Types/Permission.ts +641 -0
- package/Types/Probe/ProbeMonitorResponse.ts +2 -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/Utils/Monitor/MonitorMetricType.ts +2 -1
- 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/API/OpenSourceDeploymentAPI.js +5 -0
- package/build/dist/Server/API/OpenSourceDeploymentAPI.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/Middleware/UserAuthorization.js +2 -3
- package/build/dist/Server/Middleware/UserAuthorization.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/MonitorService.js +8 -1
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +26 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.js +138 -0
- package/build/dist/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +10 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +24 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.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/MicrosoftTeams/MicrosoftTeams.js +10 -7
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.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 +55 -11
- 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/Tests/Server/Middleware/UserAuthorization.test.js +4 -2
- package/build/dist/Tests/Server/Middleware/UserAuthorization.test.js.map +1 -1
- package/build/dist/Types/Monitor/CriteriaFilter.js +15 -3
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/Monitor/DnsMonitor/DnsMonitorResponse.js +2 -0
- package/build/dist/Types/Monitor/DnsMonitor/DnsMonitorResponse.js.map +1 -0
- package/build/dist/Types/Monitor/DnsMonitor/DnsRecordType.js +15 -0
- package/build/dist/Types/Monitor/DnsMonitor/DnsRecordType.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +62 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +22 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepDnsMonitor.js +34 -0
- package/build/dist/Types/Monitor/MonitorStepDnsMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorType.js +13 -2
- package/build/dist/Types/Monitor/MonitorType.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/build/dist/Utils/Monitor/MonitorMetricType.js +2 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/package.json +1 -1
|
@@ -33,6 +33,8 @@ import User from "../../Models/DatabaseModels/User";
|
|
|
33
33
|
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
34
34
|
import NotificationRuleWorkspaceChannel from "../../Types/Workspace/NotificationRules/NotificationRuleWorkspaceChannel";
|
|
35
35
|
import WorkspaceType from "../../Types/Workspace/WorkspaceType";
|
|
36
|
+
import IncidentEpisodeWorkspaceMessages from "../Utils/Workspace/WorkspaceMessages/IncidentEpisode";
|
|
37
|
+
import { MessageBlocksByWorkspaceType } from "./WorkspaceNotificationRuleService";
|
|
36
38
|
import IncidentService from "./IncidentService";
|
|
37
39
|
import OnCallDutyPolicyService from "./OnCallDutyPolicyService";
|
|
38
40
|
import OnCallDutyPolicy from "../../Models/DatabaseModels/OnCallDutyPolicy";
|
|
@@ -147,6 +149,17 @@ export class Service extends DatabaseService<Model> {
|
|
|
147
149
|
|
|
148
150
|
// Create initial state timeline entry
|
|
149
151
|
Promise.resolve()
|
|
152
|
+
.then(async () => {
|
|
153
|
+
try {
|
|
154
|
+
if (createdItem.projectId && createdItem.id) {
|
|
155
|
+
await this.handleEpisodeWorkspaceOperationsAsync(createdItem);
|
|
156
|
+
}
|
|
157
|
+
} catch (error) {
|
|
158
|
+
logger.error(
|
|
159
|
+
`Workspace operations failed in IncidentEpisodeService.onCreateSuccess: ${error}`,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
})
|
|
150
163
|
.then(async () => {
|
|
151
164
|
try {
|
|
152
165
|
await this.changeEpisodeState({
|
|
@@ -193,6 +206,51 @@ export class Service extends DatabaseService<Model> {
|
|
|
193
206
|
return createdItem;
|
|
194
207
|
}
|
|
195
208
|
|
|
209
|
+
@CaptureSpan()
|
|
210
|
+
private async handleEpisodeWorkspaceOperationsAsync(
|
|
211
|
+
createdItem: Model,
|
|
212
|
+
): Promise<void> {
|
|
213
|
+
try {
|
|
214
|
+
if (!createdItem.projectId || !createdItem.id) {
|
|
215
|
+
throw new BadDataException(
|
|
216
|
+
"projectId and id are required for workspace operations",
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const workspaceResult: {
|
|
221
|
+
channelsCreated: Array<NotificationRuleWorkspaceChannel>;
|
|
222
|
+
} | null =
|
|
223
|
+
await IncidentEpisodeWorkspaceMessages.createChannelsAndInviteUsersToChannels(
|
|
224
|
+
{
|
|
225
|
+
projectId: createdItem.projectId,
|
|
226
|
+
incidentEpisodeId: createdItem.id,
|
|
227
|
+
episodeNumber: createdItem.episodeNumber || 0,
|
|
228
|
+
...(createdItem.episodeNumberWithPrefix
|
|
229
|
+
? {
|
|
230
|
+
episodeNumberWithPrefix: createdItem.episodeNumberWithPrefix,
|
|
231
|
+
}
|
|
232
|
+
: {}),
|
|
233
|
+
},
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
if (workspaceResult && workspaceResult.channelsCreated?.length > 0) {
|
|
237
|
+
await this.updateOneById({
|
|
238
|
+
id: createdItem.id,
|
|
239
|
+
data: {
|
|
240
|
+
postUpdatesToWorkspaceChannels:
|
|
241
|
+
workspaceResult.channelsCreated || [],
|
|
242
|
+
},
|
|
243
|
+
props: {
|
|
244
|
+
isRoot: true,
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
} catch (error) {
|
|
249
|
+
logger.error(`Error in handleEpisodeWorkspaceOperationsAsync: ${error}`);
|
|
250
|
+
throw error;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
196
254
|
@CaptureSpan()
|
|
197
255
|
private async createEpisodeCreatedFeed(episode: Model): Promise<void> {
|
|
198
256
|
if (!episode.id || !episode.projectId) {
|
|
@@ -213,6 +271,14 @@ export class Service extends DatabaseService<Model> {
|
|
|
213
271
|
feedInfoInMarkdown += `This episode was manually created.\n\n`;
|
|
214
272
|
}
|
|
215
273
|
|
|
274
|
+
const episodeCreateMessageBlocks: Array<MessageBlocksByWorkspaceType> =
|
|
275
|
+
await IncidentEpisodeWorkspaceMessages.getIncidentEpisodeCreateMessageBlocks(
|
|
276
|
+
{
|
|
277
|
+
incidentEpisodeId: episode.id,
|
|
278
|
+
projectId: episode.projectId,
|
|
279
|
+
},
|
|
280
|
+
);
|
|
281
|
+
|
|
216
282
|
await IncidentEpisodeFeedService.createIncidentEpisodeFeedItem({
|
|
217
283
|
incidentEpisodeId: episode.id,
|
|
218
284
|
projectId: episode.projectId,
|
|
@@ -220,6 +286,10 @@ export class Service extends DatabaseService<Model> {
|
|
|
220
286
|
displayColor: Red500,
|
|
221
287
|
feedInfoInMarkdown: feedInfoInMarkdown,
|
|
222
288
|
userId: episode.createdByUserId || undefined,
|
|
289
|
+
workspaceNotification: {
|
|
290
|
+
appendMessageBlocks: episodeCreateMessageBlocks,
|
|
291
|
+
sendWorkspaceNotification: true,
|
|
292
|
+
},
|
|
223
293
|
});
|
|
224
294
|
}
|
|
225
295
|
|
|
@@ -952,21 +1022,30 @@ export class Service extends DatabaseService<Model> {
|
|
|
952
1022
|
}
|
|
953
1023
|
|
|
954
1024
|
@CaptureSpan()
|
|
955
|
-
public getWorkspaceChannelForEpisode(
|
|
956
|
-
|
|
957
|
-
workspaceType
|
|
958
|
-
): Array<NotificationRuleWorkspaceChannel
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1025
|
+
public async getWorkspaceChannelForEpisode(data: {
|
|
1026
|
+
episodeId: ObjectID;
|
|
1027
|
+
workspaceType?: WorkspaceType | null;
|
|
1028
|
+
}): Promise<Array<NotificationRuleWorkspaceChannel>> {
|
|
1029
|
+
const episode: Model | null = await this.findOneById({
|
|
1030
|
+
id: data.episodeId,
|
|
1031
|
+
select: {
|
|
1032
|
+
postUpdatesToWorkspaceChannels: true,
|
|
1033
|
+
},
|
|
1034
|
+
props: {
|
|
1035
|
+
isRoot: true,
|
|
1036
|
+
},
|
|
1037
|
+
});
|
|
1038
|
+
|
|
1039
|
+
if (!episode) {
|
|
1040
|
+
throw new BadDataException("Incident Episode not found.");
|
|
965
1041
|
}
|
|
966
1042
|
|
|
967
|
-
return episode.postUpdatesToWorkspaceChannels.filter(
|
|
1043
|
+
return (episode.postUpdatesToWorkspaceChannels || []).filter(
|
|
968
1044
|
(channel: NotificationRuleWorkspaceChannel) => {
|
|
969
|
-
|
|
1045
|
+
if (!data.workspaceType) {
|
|
1046
|
+
return true;
|
|
1047
|
+
}
|
|
1048
|
+
return channel.workspaceType === data.workspaceType;
|
|
970
1049
|
},
|
|
971
1050
|
);
|
|
972
1051
|
}
|
|
@@ -383,6 +383,11 @@ export class Service extends DatabaseService<IncidentEpisodeStateTimeline> {
|
|
|
383
383
|
? `**Cause:** \n${createdItem.rootCause}`
|
|
384
384
|
: undefined,
|
|
385
385
|
userId: createdItem.createdByUserId || onCreate.createBy.props.userId,
|
|
386
|
+
workspaceNotification: {
|
|
387
|
+
sendWorkspaceNotification: true,
|
|
388
|
+
notifyUserId:
|
|
389
|
+
createdItem.createdByUserId || onCreate.createBy.props.userId,
|
|
390
|
+
},
|
|
386
391
|
});
|
|
387
392
|
|
|
388
393
|
return createdItem;
|
|
@@ -843,6 +843,11 @@ export class Service extends DatabaseService<Model> {
|
|
|
843
843
|
projectId: createdItem.projectId,
|
|
844
844
|
incidentId: createdItem.id,
|
|
845
845
|
incidentNumber: createdItem.incidentNumber!,
|
|
846
|
+
...(createdItem.incidentNumberWithPrefix
|
|
847
|
+
? {
|
|
848
|
+
incidentNumberWithPrefix: createdItem.incidentNumberWithPrefix,
|
|
849
|
+
}
|
|
850
|
+
: {}),
|
|
846
851
|
});
|
|
847
852
|
|
|
848
853
|
if (workspaceResult && workspaceResult.channelsCreated?.length > 0) {
|
|
@@ -127,6 +127,14 @@ export class Service extends DatabaseService<Model> {
|
|
|
127
127
|
monitorDestination = `${monitorDestination}:${port}`;
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
|
+
|
|
131
|
+
// For DNS monitors, use the queryName from dnsMonitor config
|
|
132
|
+
if (monitorType === MonitorType.DNS && firstStep?.data?.dnsMonitor) {
|
|
133
|
+
monitorDestination = firstStep.data.dnsMonitor.queryName || "";
|
|
134
|
+
if (firstStep.data.dnsMonitor.hostname) {
|
|
135
|
+
monitorDestination = `${monitorDestination} @${firstStep.data.dnsMonitor.hostname}`;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
130
138
|
}
|
|
131
139
|
}
|
|
132
140
|
|
|
@@ -52,6 +52,7 @@ import WorkspaceNotificationActionType from "../../Types/Workspace/WorkspaceNoti
|
|
|
52
52
|
import ExceptionMessages from "../../Types/Exception/ExceptionMessages";
|
|
53
53
|
import IncidentEpisode from "../../Models/DatabaseModels/IncidentEpisode";
|
|
54
54
|
import IncidentEpisodeService from "./IncidentEpisodeService";
|
|
55
|
+
import AlertEpisodeService from "./AlertEpisodeService";
|
|
55
56
|
|
|
56
57
|
export interface MessageBlocksByWorkspaceType {
|
|
57
58
|
workspaceType: WorkspaceType;
|
|
@@ -735,6 +736,25 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
735
736
|
);
|
|
736
737
|
}
|
|
737
738
|
|
|
739
|
+
// incident episodes
|
|
740
|
+
if (data.notificationFor.incidentEpisodeId) {
|
|
741
|
+
monitorChannels =
|
|
742
|
+
await IncidentEpisodeService.getWorkspaceChannelForEpisode({
|
|
743
|
+
episodeId: data.notificationFor.incidentEpisodeId,
|
|
744
|
+
workspaceType: data.workspaceType,
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// alert episodes
|
|
749
|
+
if (data.notificationFor.alertEpisodeId) {
|
|
750
|
+
monitorChannels = await AlertEpisodeService.getWorkspaceChannelForEpisode(
|
|
751
|
+
{
|
|
752
|
+
episodeId: data.notificationFor.alertEpisodeId,
|
|
753
|
+
workspaceType: data.workspaceType,
|
|
754
|
+
},
|
|
755
|
+
);
|
|
756
|
+
}
|
|
757
|
+
|
|
738
758
|
logger.debug("Workspace channels found:");
|
|
739
759
|
logger.debug(monitorChannels);
|
|
740
760
|
|
|
@@ -1785,9 +1805,18 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
1785
1805
|
logger.debug("New channel template name:");
|
|
1786
1806
|
logger.debug(notificationChannels);
|
|
1787
1807
|
|
|
1808
|
+
/*
|
|
1809
|
+
* Sanitize the suffix for workspace channel names.
|
|
1810
|
+
* When no custom prefix is set, the default "#" prefix (e.g. "#42") produces
|
|
1811
|
+
* invalid Slack channel names (e.g. "oneuptime-alert-#42"). Strip characters
|
|
1812
|
+
* that are not valid in Slack/Teams channel names.
|
|
1813
|
+
*/
|
|
1814
|
+
const sanitizedSuffix: string = data.channelNameSiffix
|
|
1815
|
+
.toLowerCase()
|
|
1816
|
+
.replace(/[^a-z0-9\-_]/g, "");
|
|
1817
|
+
|
|
1788
1818
|
// add suffix and then check if it is already added or not.
|
|
1789
|
-
const channelName: string =
|
|
1790
|
-
notificationChannels + data.channelNameSiffix;
|
|
1819
|
+
const channelName: string = notificationChannels + sanitizedSuffix;
|
|
1791
1820
|
|
|
1792
1821
|
logger.debug("Final channel name with suffix:");
|
|
1793
1822
|
logger.debug(channelName);
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import DataToProcess from "../DataToProcess";
|
|
2
|
+
import CompareCriteria from "./CompareCriteria";
|
|
3
|
+
import {
|
|
4
|
+
CheckOn,
|
|
5
|
+
CriteriaFilter,
|
|
6
|
+
FilterType,
|
|
7
|
+
} from "../../../../Types/Monitor/CriteriaFilter";
|
|
8
|
+
import DnsMonitorResponse from "../../../../Types/Monitor/DnsMonitor/DnsMonitorResponse";
|
|
9
|
+
import ProbeMonitorResponse from "../../../../Types/Probe/ProbeMonitorResponse";
|
|
10
|
+
import EvaluateOverTime from "./EvaluateOverTime";
|
|
11
|
+
import CaptureSpan from "../../Telemetry/CaptureSpan";
|
|
12
|
+
import logger from "../../Logger";
|
|
13
|
+
|
|
14
|
+
export default class DnsMonitorCriteria {
|
|
15
|
+
@CaptureSpan()
|
|
16
|
+
public static async isMonitorInstanceCriteriaFilterMet(input: {
|
|
17
|
+
dataToProcess: DataToProcess;
|
|
18
|
+
criteriaFilter: CriteriaFilter;
|
|
19
|
+
}): Promise<string | null> {
|
|
20
|
+
let threshold: number | string | undefined | null =
|
|
21
|
+
input.criteriaFilter.value;
|
|
22
|
+
|
|
23
|
+
const dataToProcess: ProbeMonitorResponse =
|
|
24
|
+
input.dataToProcess as ProbeMonitorResponse;
|
|
25
|
+
|
|
26
|
+
const dnsResponse: DnsMonitorResponse | undefined =
|
|
27
|
+
dataToProcess.dnsResponse;
|
|
28
|
+
|
|
29
|
+
let overTimeValue: Array<number | boolean> | number | boolean | undefined =
|
|
30
|
+
undefined;
|
|
31
|
+
|
|
32
|
+
if (
|
|
33
|
+
input.criteriaFilter.evaluateOverTime &&
|
|
34
|
+
input.criteriaFilter.evaluateOverTimeOptions
|
|
35
|
+
) {
|
|
36
|
+
try {
|
|
37
|
+
overTimeValue = await EvaluateOverTime.getValueOverTime({
|
|
38
|
+
projectId: (input.dataToProcess as ProbeMonitorResponse).projectId,
|
|
39
|
+
monitorId: input.dataToProcess.monitorId!,
|
|
40
|
+
evaluateOverTimeOptions: input.criteriaFilter.evaluateOverTimeOptions,
|
|
41
|
+
metricType: input.criteriaFilter.checkOn,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (Array.isArray(overTimeValue) && overTimeValue.length === 0) {
|
|
45
|
+
overTimeValue = undefined;
|
|
46
|
+
}
|
|
47
|
+
} catch (err) {
|
|
48
|
+
logger.error(
|
|
49
|
+
`Error in getting over time value for ${input.criteriaFilter.checkOn}`,
|
|
50
|
+
);
|
|
51
|
+
logger.error(err);
|
|
52
|
+
overTimeValue = undefined;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Check if DNS is online
|
|
57
|
+
if (input.criteriaFilter.checkOn === CheckOn.DnsIsOnline) {
|
|
58
|
+
const currentIsOnline: boolean | Array<boolean> =
|
|
59
|
+
(overTimeValue as Array<boolean>) ||
|
|
60
|
+
(input.dataToProcess as ProbeMonitorResponse).isOnline;
|
|
61
|
+
|
|
62
|
+
return CompareCriteria.compareCriteriaBoolean({
|
|
63
|
+
value: currentIsOnline,
|
|
64
|
+
criteriaFilter: input.criteriaFilter,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Check DNS response time
|
|
69
|
+
if (input.criteriaFilter.checkOn === CheckOn.DnsResponseTime) {
|
|
70
|
+
threshold = CompareCriteria.convertToNumber(threshold);
|
|
71
|
+
|
|
72
|
+
if (threshold === null || threshold === undefined) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const currentResponseTime: number | Array<number> =
|
|
77
|
+
(overTimeValue as Array<number>) ||
|
|
78
|
+
dnsResponse?.responseTimeInMs ||
|
|
79
|
+
(input.dataToProcess as ProbeMonitorResponse).responseTimeInMs;
|
|
80
|
+
|
|
81
|
+
if (currentResponseTime === null || currentResponseTime === undefined) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return CompareCriteria.compareCriteriaNumbers({
|
|
86
|
+
value: currentResponseTime,
|
|
87
|
+
threshold: threshold as number,
|
|
88
|
+
criteriaFilter: input.criteriaFilter,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Check if DNS record exists
|
|
93
|
+
if (input.criteriaFilter.checkOn === CheckOn.DnsRecordExists) {
|
|
94
|
+
const exists: boolean = Boolean(
|
|
95
|
+
dnsResponse?.records && dnsResponse.records.length > 0,
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const isTrue: boolean =
|
|
99
|
+
input.criteriaFilter.filterType === FilterType.True;
|
|
100
|
+
const isFalse: boolean =
|
|
101
|
+
input.criteriaFilter.filterType === FilterType.False;
|
|
102
|
+
|
|
103
|
+
if (exists && isTrue) {
|
|
104
|
+
return `DNS records exist for the query.`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!exists && isFalse) {
|
|
108
|
+
return `No DNS records found for the query.`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Check DNSSEC validity
|
|
115
|
+
if (input.criteriaFilter.checkOn === CheckOn.DnssecIsValid) {
|
|
116
|
+
const isTrue: boolean =
|
|
117
|
+
input.criteriaFilter.filterType === FilterType.True;
|
|
118
|
+
const isFalse: boolean =
|
|
119
|
+
input.criteriaFilter.filterType === FilterType.False;
|
|
120
|
+
|
|
121
|
+
if (dnsResponse?.isDnssecValid === undefined) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (dnsResponse.isDnssecValid && isTrue) {
|
|
126
|
+
return `DNSSEC is valid.`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!dnsResponse.isDnssecValid && isFalse) {
|
|
130
|
+
return `DNSSEC is not valid.`;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Check DNS record value
|
|
137
|
+
if (input.criteriaFilter.checkOn === CheckOn.DnsRecordValue) {
|
|
138
|
+
if (!dnsResponse?.records || dnsResponse.records.length === 0) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Check if any record value matches the criteria
|
|
143
|
+
for (const record of dnsResponse.records) {
|
|
144
|
+
const recordValue: string = record.value;
|
|
145
|
+
|
|
146
|
+
// Try numeric comparison first
|
|
147
|
+
if (
|
|
148
|
+
typeof threshold === "number" ||
|
|
149
|
+
(typeof threshold === "string" && !isNaN(Number(threshold)))
|
|
150
|
+
) {
|
|
151
|
+
const numericThreshold: number | null =
|
|
152
|
+
CompareCriteria.convertToNumber(threshold);
|
|
153
|
+
|
|
154
|
+
if (numericThreshold !== null && !isNaN(Number(recordValue))) {
|
|
155
|
+
const result: string | null =
|
|
156
|
+
CompareCriteria.compareCriteriaNumbers({
|
|
157
|
+
value: Number(recordValue),
|
|
158
|
+
threshold: numericThreshold,
|
|
159
|
+
criteriaFilter: input.criteriaFilter,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
if (result) {
|
|
163
|
+
return `DNS record (${record.type}): ${result}`;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// String comparison
|
|
169
|
+
const result: string | null = CompareCriteria.compareCriteriaStrings({
|
|
170
|
+
value: recordValue,
|
|
171
|
+
threshold: String(threshold),
|
|
172
|
+
criteriaFilter: input.criteriaFilter,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
if (result) {
|
|
176
|
+
return `DNS record (${record.type}): ${result}`;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -12,6 +12,7 @@ import MetricMonitorCriteria from "./Criteria/MetricMonitorCriteria";
|
|
|
12
12
|
import TraceMonitorCriteria from "./Criteria/TraceMonitorCriteria";
|
|
13
13
|
import ExceptionMonitorCriteria from "./Criteria/ExceptionMonitorCriteria";
|
|
14
14
|
import SnmpMonitorCriteria from "./Criteria/SnmpMonitorCriteria";
|
|
15
|
+
import DnsMonitorCriteria from "./Criteria/DnsMonitorCriteria";
|
|
15
16
|
import MonitorCriteriaMessageBuilder from "./MonitorCriteriaMessageBuilder";
|
|
16
17
|
import MonitorCriteriaDataExtractor from "./MonitorCriteriaDataExtractor";
|
|
17
18
|
import MonitorCriteriaMessageFormatter from "./MonitorCriteriaMessageFormatter";
|
|
@@ -493,6 +494,18 @@ ${contextBlock}
|
|
|
493
494
|
}
|
|
494
495
|
}
|
|
495
496
|
|
|
497
|
+
if (input.monitor.monitorType === MonitorType.DNS) {
|
|
498
|
+
const dnsMonitorResult: string | null =
|
|
499
|
+
await DnsMonitorCriteria.isMonitorInstanceCriteriaFilterMet({
|
|
500
|
+
dataToProcess: input.dataToProcess,
|
|
501
|
+
criteriaFilter: input.criteriaFilter,
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
if (dnsMonitorResult) {
|
|
505
|
+
return dnsMonitorResult;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
496
509
|
return null;
|
|
497
510
|
}
|
|
498
511
|
|
|
@@ -14,6 +14,9 @@ import SyntheticMonitorResponse from "../../../Types/Monitor/SyntheticMonitors/S
|
|
|
14
14
|
import SnmpMonitorResponse, {
|
|
15
15
|
SnmpOidResponse,
|
|
16
16
|
} from "../../../Types/Monitor/SnmpMonitor/SnmpMonitorResponse";
|
|
17
|
+
import DnsMonitorResponse, {
|
|
18
|
+
DnsRecordResponse,
|
|
19
|
+
} from "../../../Types/Monitor/DnsMonitor/DnsMonitorResponse";
|
|
17
20
|
import Typeof from "../../../Types/Typeof";
|
|
18
21
|
import VMUtil from "../VM/VMAPI";
|
|
19
22
|
import DataToProcess from "./DataToProcess";
|
|
@@ -240,6 +243,40 @@ export default class MonitorTemplateUtil {
|
|
|
240
243
|
}
|
|
241
244
|
}
|
|
242
245
|
}
|
|
246
|
+
|
|
247
|
+
if (data.monitorType === MonitorType.DNS) {
|
|
248
|
+
const dnsResponse: DnsMonitorResponse | undefined = (
|
|
249
|
+
data.dataToProcess as ProbeMonitorResponse
|
|
250
|
+
).dnsResponse;
|
|
251
|
+
|
|
252
|
+
storageMap = {
|
|
253
|
+
isOnline: (data.dataToProcess as ProbeMonitorResponse).isOnline,
|
|
254
|
+
responseTimeInMs: dnsResponse?.responseTimeInMs,
|
|
255
|
+
failureCause: dnsResponse?.failureCause,
|
|
256
|
+
isTimeout: dnsResponse?.isTimeout,
|
|
257
|
+
isDnssecValid: dnsResponse?.isDnssecValid,
|
|
258
|
+
} as JSONObject;
|
|
259
|
+
|
|
260
|
+
// Add DNS records
|
|
261
|
+
if (dnsResponse?.records) {
|
|
262
|
+
storageMap["records"] = dnsResponse.records.map(
|
|
263
|
+
(record: DnsRecordResponse) => {
|
|
264
|
+
return {
|
|
265
|
+
type: record.type,
|
|
266
|
+
value: record.value,
|
|
267
|
+
ttl: record.ttl,
|
|
268
|
+
};
|
|
269
|
+
},
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
// Add record values as a flat array for easier templating
|
|
273
|
+
storageMap["recordValues"] = dnsResponse.records.map(
|
|
274
|
+
(record: DnsRecordResponse) => {
|
|
275
|
+
return record.value;
|
|
276
|
+
},
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
243
280
|
} catch (err) {
|
|
244
281
|
logger.error(err);
|
|
245
282
|
}
|
|
@@ -361,7 +361,7 @@ export default class MicrosoftTeamsAlertActions {
|
|
|
361
361
|
await this.buildExecuteAlertOnCallPolicyCard(actionValue, projectId);
|
|
362
362
|
if (!card) {
|
|
363
363
|
await turnContext.sendActivity(
|
|
364
|
-
"No on-call policies
|
|
364
|
+
"No on-call policies have been configured for this project yet. Please add an on-call policy in the OneUptime Dashboard under On-Call Duty > Policies to use this feature.",
|
|
365
365
|
);
|
|
366
366
|
return;
|
|
367
367
|
}
|
|
@@ -391,7 +391,7 @@ export default class MicrosoftTeamsAlertEpisodeActions {
|
|
|
391
391
|
);
|
|
392
392
|
if (!card) {
|
|
393
393
|
await turnContext.sendActivity(
|
|
394
|
-
"No on-call policies
|
|
394
|
+
"No on-call policies have been configured for this project yet. Please add an on-call policy in the OneUptime Dashboard under On-Call Duty > Policies to use this feature.",
|
|
395
395
|
);
|
|
396
396
|
return;
|
|
397
397
|
}
|
|
@@ -495,11 +495,12 @@ export default class MicrosoftTeamsAlertEpisodeActions {
|
|
|
495
495
|
// Update the state
|
|
496
496
|
const episodeId: ObjectID = new ObjectID(actionValue);
|
|
497
497
|
|
|
498
|
-
await AlertEpisodeService.
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
498
|
+
await AlertEpisodeService.changeEpisodeState({
|
|
499
|
+
projectId: projectId,
|
|
500
|
+
episodeId: episodeId,
|
|
501
|
+
alertStateId: new ObjectID(alertStateId.toString()),
|
|
502
|
+
notifyOwners: true,
|
|
503
|
+
rootCause: "State changed via Microsoft Teams.",
|
|
503
504
|
props: {
|
|
504
505
|
isRoot: true,
|
|
505
506
|
},
|
|
@@ -424,7 +424,7 @@ export default class MicrosoftTeamsIncidentActions {
|
|
|
424
424
|
);
|
|
425
425
|
if (!card) {
|
|
426
426
|
await turnContext.sendActivity(
|
|
427
|
-
"No on-call policies
|
|
427
|
+
"No on-call policies have been configured for this project yet. Please add an on-call policy in the OneUptime Dashboard under On-Call Duty > Policies to use this feature.",
|
|
428
428
|
);
|
|
429
429
|
return;
|
|
430
430
|
}
|
|
@@ -403,7 +403,7 @@ export default class MicrosoftTeamsIncidentEpisodeActions {
|
|
|
403
403
|
);
|
|
404
404
|
if (!card) {
|
|
405
405
|
await turnContext.sendActivity(
|
|
406
|
-
"No on-call policies
|
|
406
|
+
"No on-call policies have been configured for this project yet. Please add an on-call policy in the OneUptime Dashboard under On-Call Duty > Policies to use this feature.",
|
|
407
407
|
);
|
|
408
408
|
return;
|
|
409
409
|
}
|
|
@@ -505,11 +505,12 @@ export default class MicrosoftTeamsIncidentEpisodeActions {
|
|
|
505
505
|
// Update the state
|
|
506
506
|
const episodeId: ObjectID = new ObjectID(actionValue);
|
|
507
507
|
|
|
508
|
-
await IncidentEpisodeService.
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
508
|
+
await IncidentEpisodeService.changeEpisodeState({
|
|
509
|
+
projectId: projectId,
|
|
510
|
+
episodeId: episodeId,
|
|
511
|
+
incidentStateId: new ObjectID(incidentStateId.toString()),
|
|
512
|
+
notifyOwners: true,
|
|
513
|
+
rootCause: "State changed via Microsoft Teams.",
|
|
513
514
|
props: {
|
|
514
515
|
isRoot: true,
|
|
515
516
|
},
|
|
@@ -780,13 +780,14 @@ export default class MicrosoftTeamsUtil extends WorkspaceBase {
|
|
|
780
780
|
|
|
781
781
|
const workspaceChannels: Array<WorkspaceChannel> = [];
|
|
782
782
|
|
|
783
|
-
for (
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
783
|
+
for (const channelName of data.channelNames) {
|
|
784
|
+
/*
|
|
785
|
+
* Normalize channel name: replace spaces with hyphens, then strip
|
|
786
|
+
* characters not valid in Teams channel names (e.g. #, %, &, *, etc.).
|
|
787
|
+
*/
|
|
788
|
+
const normalizedChannelName: string = channelName
|
|
789
|
+
.replace(/\s+/g, "-")
|
|
790
|
+
.replace(/[^a-zA-Z0-9\-_]/g, "");
|
|
790
791
|
|
|
791
792
|
// Check if channel exists
|
|
792
793
|
const existingChannel: WorkspaceChannel | null =
|
|
@@ -839,6 +840,9 @@ export default class MicrosoftTeamsUtil extends WorkspaceBase {
|
|
|
839
840
|
}): Promise<WorkspaceChannel> {
|
|
840
841
|
const teamId: string = data.teamId;
|
|
841
842
|
|
|
843
|
+
// Sanitize channel name: strip characters not valid in Teams channel names.
|
|
844
|
+
data.channelName = data.channelName.replace(/[^a-zA-Z0-9\-_\s]/g, "");
|
|
845
|
+
|
|
842
846
|
// Get valid access token
|
|
843
847
|
const accessToken: string = await this.getValidAccessToken({
|
|
844
848
|
authToken: data.authToken,
|
|
@@ -322,6 +322,23 @@ export default class SlackAlertActions {
|
|
|
322
322
|
return option.label !== "" || option.value !== "";
|
|
323
323
|
});
|
|
324
324
|
|
|
325
|
+
if (dropdownOption.length === 0) {
|
|
326
|
+
if (data.slackRequest.slackChannelId) {
|
|
327
|
+
await SlackUtil.sendEphemeralMessageToChannel({
|
|
328
|
+
messageBlocks: [
|
|
329
|
+
{
|
|
330
|
+
_type: "WorkspacePayloadMarkdown",
|
|
331
|
+
text: "No on-call policies have been configured for this project yet. Please add an on-call policy in the OneUptime Dashboard under On-Call Duty > Policies to use this feature.",
|
|
332
|
+
} as WorkspacePayloadMarkdown,
|
|
333
|
+
],
|
|
334
|
+
authToken: data.slackRequest.projectAuthToken!,
|
|
335
|
+
channelId: data.slackRequest.slackChannelId,
|
|
336
|
+
userId: data.slackRequest.slackUserId!,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
325
342
|
const onCallPolicyDropdown: WorkspaceDropdownBlock = {
|
|
326
343
|
_type: "WorkspaceDropdownBlock",
|
|
327
344
|
label: "On Call Policy",
|