@oneuptime/common 9.4.12 → 9.4.13
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 +77 -0
- package/Models/DatabaseModels/IncidentEpisode.ts +1223 -0
- package/Models/DatabaseModels/IncidentEpisodeFeed.ts +533 -0
- package/Models/DatabaseModels/IncidentEpisodeInternalNote.ts +456 -0
- package/Models/DatabaseModels/IncidentEpisodeMember.ts +587 -0
- package/Models/DatabaseModels/IncidentEpisodeOwnerTeam.ts +421 -0
- package/Models/DatabaseModels/IncidentEpisodeOwnerUser.ts +419 -0
- package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +524 -0
- package/Models/DatabaseModels/IncidentGroupingRule.ts +1430 -0
- package/Models/DatabaseModels/Index.ts +18 -0
- package/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.ts +70 -0
- package/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.ts +59 -0
- package/Models/DatabaseModels/UserOnCallLog.ts +48 -0
- package/Models/DatabaseModels/UserOnCallLogTimeline.ts +49 -0
- package/Models/DatabaseModels/WorkspaceNotificationLog.ts +57 -0
- package/Server/API/IncidentEpisodeAPI.ts +150 -0
- package/Server/API/SlackAPI.ts +23 -0
- package/Server/API/UserOnCallLogTimelineAPI.ts +24 -4
- package/Server/Infrastructure/Postgres/SchemaMigrations/1769626069479-MigrationName.ts +729 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1769629928240-MigrationName.ts +261 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1769676117342-RenameEvaluateOverTimeInCriteriaFilter.ts +28 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Services/BillingService.ts +1 -3
- package/Server/Services/CallService.ts +1 -0
- package/Server/Services/IncidentEpisodeFeedService.ts +94 -0
- package/Server/Services/IncidentEpisodeInternalNoteService.ts +71 -0
- package/Server/Services/IncidentEpisodeMemberService.ts +321 -0
- package/Server/Services/IncidentEpisodeOwnerTeamService.ts +10 -0
- package/Server/Services/IncidentEpisodeOwnerUserService.ts +10 -0
- package/Server/Services/IncidentEpisodeService.ts +1045 -0
- package/Server/Services/IncidentEpisodeStateTimelineService.ts +566 -0
- package/Server/Services/IncidentGroupingEngineService.ts +1047 -0
- package/Server/Services/IncidentGroupingRuleService.ts +14 -0
- package/Server/Services/IncidentService.ts +11 -0
- package/Server/Services/Index.ts +18 -0
- package/Server/Services/MailService.ts +1 -0
- package/Server/Services/MonitorService.ts +9 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +18 -0
- package/Server/Services/OnCallDutyPolicyExecutionLogService.ts +64 -2
- package/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.ts +26 -1
- package/Server/Services/OnCallDutyPolicyService.ts +15 -0
- package/Server/Services/SmsService.ts +1 -0
- package/Server/Services/UserNotificationRuleService.ts +48 -2
- package/Server/Services/UserNotificationSettingService.ts +23 -0
- package/Server/Services/UserOnCallLogService.ts +41 -4
- package/Server/Services/WhatsAppService.ts +1 -0
- package/Server/Services/WorkspaceNotificationLogService.ts +16 -0
- package/Server/Services/WorkspaceNotificationRuleService.ts +116 -0
- package/Server/Utils/AI/IncidentEpisodeAIContextBuilder.ts +490 -0
- package/Server/Utils/Monitor/Criteria/APIRequestCriteria.ts +1 -1
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +1 -1
- package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +1 -1
- package/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.ts +1 -1
- package/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.ts +2 -2
- package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +182 -0
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +13 -0
- package/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.ts +1 -1
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +37 -0
- package/Server/Utils/PushNotificationUtil.ts +31 -0
- package/Server/Utils/WhatsAppTemplateUtil.ts +14 -0
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.ts +18 -0
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +702 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +20 -0
- package/Server/Utils/Workspace/Slack/Actions/ActionTypes.ts +11 -0
- package/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.ts +918 -0
- package/Server/Utils/Workspace/Slack/Messages/IncidentEpisode.ts +120 -0
- package/Server/Utils/Workspace/WorkspaceMessages/IncidentEpisode.ts +74 -0
- package/Types/Email/EmailTemplateType.ts +6 -0
- package/Types/Monitor/CriteriaFilter.ts +24 -4
- package/Types/Monitor/MonitorCriteriaInstance.ts +67 -0
- package/Types/Monitor/MonitorStep.ts +37 -0
- package/Types/Monitor/MonitorStepSnmpMonitor.ts +102 -0
- package/Types/Monitor/MonitorType.ts +15 -2
- package/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.ts +8 -0
- package/Types/Monitor/SnmpMonitor/SnmpDataType.ts +21 -0
- package/Types/Monitor/SnmpMonitor/SnmpMonitorResponse.ts +16 -0
- package/Types/Monitor/SnmpMonitor/SnmpOid.ts +60 -0
- package/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.ts +7 -0
- package/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.ts +7 -0
- package/Types/Monitor/SnmpMonitor/SnmpV3Auth.ts +12 -0
- package/Types/Monitor/SnmpMonitor/SnmpVersion.ts +7 -0
- package/Types/NotificationSetting/NotificationSettingEventType.ts +7 -0
- package/Types/Permission.ts +311 -0
- package/Types/Probe/ProbeMonitorResponse.ts +2 -0
- package/Types/UserNotification/UserNotificationEventType.ts +1 -0
- package/Types/WhatsApp/WhatsAppTemplates.ts +24 -0
- package/Types/Workspace/NotificationRules/EventType.ts +1 -0
- package/Types/Workspace/NotificationRules/NotificationRuleCondition.ts +38 -1
- package/Utils/Monitor/MonitorMetricType.ts +2 -1
- package/build/dist/Models/DatabaseModels/Incident.js +78 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js +1250 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeFeed.js +555 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeInternalNote.js +467 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeInternalNote.js.map +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js +607 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js.map +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeOwnerTeam.js +437 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeOwnerUser.js +436 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +546 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -0
- package/build/dist/Models/DatabaseModels/IncidentGroupingRule.js +1437 -0
- package/build/dist/Models/DatabaseModels/IncidentGroupingRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Index.js +16 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js +69 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.js +58 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js +47 -0
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +48 -0
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkspaceNotificationLog.js +58 -0
- package/build/dist/Models/DatabaseModels/WorkspaceNotificationLog.js.map +1 -1
- package/build/dist/Server/API/IncidentEpisodeAPI.js +97 -0
- package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -0
- package/build/dist/Server/API/SlackAPI.js +18 -0
- package/build/dist/Server/API/SlackAPI.js.map +1 -1
- package/build/dist/Server/API/UserOnCallLogTimelineAPI.js +30 -10
- package/build/dist/Server/API/UserOnCallLogTimelineAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769626069479-MigrationName.js +256 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769626069479-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769629928240-MigrationName.js +96 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769629928240-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769676117342-RenameEvaluateOverTimeInCriteriaFilter.js +25 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1769676117342-RenameEvaluateOverTimeInCriteriaFilter.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/BillingService.js +1 -2
- package/build/dist/Server/Services/BillingService.js.map +1 -1
- package/build/dist/Server/Services/CallService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeFeedService.js +83 -0
- package/build/dist/Server/Services/IncidentEpisodeFeedService.js.map +1 -0
- package/build/dist/Server/Services/IncidentEpisodeInternalNoteService.js +70 -0
- package/build/dist/Server/Services/IncidentEpisodeInternalNoteService.js.map +1 -0
- package/build/dist/Server/Services/IncidentEpisodeMemberService.js +298 -0
- package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -0
- package/build/dist/Server/Services/IncidentEpisodeOwnerTeamService.js +9 -0
- package/build/dist/Server/Services/IncidentEpisodeOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/IncidentEpisodeOwnerUserService.js +9 -0
- package/build/dist/Server/Services/IncidentEpisodeOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/IncidentEpisodeService.js +933 -0
- package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -0
- package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +498 -0
- package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -0
- package/build/dist/Server/Services/IncidentGroupingEngineService.js +799 -0
- package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -0
- package/build/dist/Server/Services/IncidentGroupingRuleService.js +13 -0
- package/build/dist/Server/Services/IncidentGroupingRuleService.js.map +1 -0
- package/build/dist/Server/Services/IncidentService.js +10 -0
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +16 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MailService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +9 -1
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +10 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js +48 -2
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js +20 -1
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyService.js +8 -0
- package/build/dist/Server/Services/OnCallDutyPolicyService.js.map +1 -1
- package/build/dist/Server/Services/SmsService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +39 -2
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js +9 -0
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Server/Services/UserOnCallLogService.js +35 -3
- package/build/dist/Server/Services/UserOnCallLogService.js.map +1 -1
- package/build/dist/Server/Services/WhatsAppService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationLogService.js +12 -0
- package/build/dist/Server/Services/WorkspaceNotificationLogService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +95 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Utils/AI/IncidentEpisodeAIContextBuilder.js +402 -0
- package/build/dist/Server/Utils/AI/IncidentEpisodeAIContextBuilder.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.js +2 -2
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +135 -0
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.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/MonitorCriteriaExpectationBuilder.js +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +26 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/PushNotificationUtil.js +20 -0
- package/build/dist/Server/Utils/PushNotificationUtil.js.map +1 -1
- package/build/dist/Server/Utils/WhatsAppTemplateUtil.js +8 -0
- package/build/dist/Server/Utils/WhatsAppTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.js +17 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +547 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +15 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js +10 -0
- package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.js +651 -0
- package/build/dist/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/Slack/Messages/IncidentEpisode.js +100 -0
- package/build/dist/Server/Utils/Workspace/Slack/Messages/IncidentEpisode.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/WorkspaceMessages/IncidentEpisode.js +70 -0
- package/build/dist/Server/Utils/Workspace/WorkspaceMessages/IncidentEpisode.js.map +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js +5 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/Monitor/CriteriaFilter.js +16 -3
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- 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 +26 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepSnmpMonitor.js +77 -0
- package/build/dist/Types/Monitor/MonitorStepSnmpMonitor.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/Monitor/SnmpMonitor/SnmpAuthProtocol.js +9 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpDataType.js +22 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpDataType.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpMonitorResponse.js +2 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpMonitorResponse.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpOid.js +55 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpOid.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.js +8 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.js +8 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpV3Auth.js +2 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpV3Auth.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpVersion.js +8 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpVersion.js.map +1 -0
- package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js +5 -0
- package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js.map +1 -1
- package/build/dist/Types/Permission.js +264 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/UserNotification/UserNotificationEventType.js +1 -0
- package/build/dist/Types/UserNotification/UserNotificationEventType.js.map +1 -1
- package/build/dist/Types/WhatsApp/WhatsAppTemplates.js +15 -0
- package/build/dist/Types/WhatsApp/WhatsAppTemplates.js.map +1 -1
- package/build/dist/Types/Workspace/NotificationRules/EventType.js +1 -0
- package/build/dist/Types/Workspace/NotificationRules/EventType.js.map +1 -1
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js +33 -1
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.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
|
@@ -0,0 +1,933 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import DatabaseService from "./DatabaseService";
|
|
11
|
+
import IncidentStateService from "./IncidentStateService";
|
|
12
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
13
|
+
import ObjectID from "../../Types/ObjectID";
|
|
14
|
+
import Model from "../../Models/DatabaseModels/IncidentEpisode";
|
|
15
|
+
import SortOrder from "../../Types/BaseDatabase/SortOrder";
|
|
16
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
17
|
+
import logger from "../Utils/Logger";
|
|
18
|
+
import IncidentEpisodeStateTimeline from "../../Models/DatabaseModels/IncidentEpisodeStateTimeline";
|
|
19
|
+
import IncidentEpisodeStateTimelineService from "./IncidentEpisodeStateTimelineService";
|
|
20
|
+
import { IsBillingEnabled } from "../EnvironmentConfig";
|
|
21
|
+
import OneUptimeDate from "../../Types/Date";
|
|
22
|
+
import IncidentEpisodeFeedService from "./IncidentEpisodeFeedService";
|
|
23
|
+
import { IncidentEpisodeFeedEventType } from "../../Models/DatabaseModels/IncidentEpisodeFeed";
|
|
24
|
+
import { Red500, Yellow500, Purple500 } from "../../Types/BrandColors";
|
|
25
|
+
import URL from "../../Types/API/URL";
|
|
26
|
+
import DatabaseConfig from "../DatabaseConfig";
|
|
27
|
+
import IncidentSeverityService from "./IncidentSeverityService";
|
|
28
|
+
import IncidentEpisodeMemberService from "./IncidentEpisodeMemberService";
|
|
29
|
+
import IncidentEpisodeOwnerUserService from "./IncidentEpisodeOwnerUserService";
|
|
30
|
+
import IncidentEpisodeOwnerTeamService from "./IncidentEpisodeOwnerTeamService";
|
|
31
|
+
import TeamMemberService from "./TeamMemberService";
|
|
32
|
+
import IncidentEpisodeOwnerUser from "../../Models/DatabaseModels/IncidentEpisodeOwnerUser";
|
|
33
|
+
import IncidentEpisodeOwnerTeam from "../../Models/DatabaseModels/IncidentEpisodeOwnerTeam";
|
|
34
|
+
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
35
|
+
import WorkspaceType from "../../Types/Workspace/WorkspaceType";
|
|
36
|
+
import IncidentService from "./IncidentService";
|
|
37
|
+
import Semaphore from "../Infrastructure/Semaphore";
|
|
38
|
+
import OnCallDutyPolicyService from "./OnCallDutyPolicyService";
|
|
39
|
+
import UserNotificationEventType from "../../Types/UserNotification/UserNotificationEventType";
|
|
40
|
+
export class Service extends DatabaseService {
|
|
41
|
+
constructor() {
|
|
42
|
+
super(Model);
|
|
43
|
+
if (IsBillingEnabled) {
|
|
44
|
+
this.hardDeleteItemsOlderThanInDays("createdAt", 3 * 365); // 3 years
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async getExistingEpisodeNumberForProject(data) {
|
|
48
|
+
const lastEpisode = await this.findOneBy({
|
|
49
|
+
query: {
|
|
50
|
+
projectId: data.projectId,
|
|
51
|
+
},
|
|
52
|
+
select: {
|
|
53
|
+
episodeNumber: true,
|
|
54
|
+
},
|
|
55
|
+
sort: {
|
|
56
|
+
episodeNumber: SortOrder.Descending,
|
|
57
|
+
},
|
|
58
|
+
props: {
|
|
59
|
+
isRoot: true,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
if (!lastEpisode) {
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
return lastEpisode.episodeNumber ? Number(lastEpisode.episodeNumber) : 0;
|
|
66
|
+
}
|
|
67
|
+
async onBeforeCreate(createBy) {
|
|
68
|
+
if (!createBy.props.tenantId && !createBy.props.isRoot) {
|
|
69
|
+
throw new BadDataException("ProjectId required to create incident episode.");
|
|
70
|
+
}
|
|
71
|
+
const projectId = createBy.props.tenantId || createBy.data.projectId;
|
|
72
|
+
let mutex = null;
|
|
73
|
+
try {
|
|
74
|
+
// Acquire mutex to prevent race conditions when generating episode numbers
|
|
75
|
+
try {
|
|
76
|
+
mutex = await Semaphore.lock({
|
|
77
|
+
key: projectId.toString(),
|
|
78
|
+
namespace: "IncidentEpisode.create",
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
logger.error(err);
|
|
83
|
+
}
|
|
84
|
+
// Get the created state for episodes
|
|
85
|
+
const incidentState = await IncidentStateService.findOneBy({
|
|
86
|
+
query: {
|
|
87
|
+
projectId: projectId,
|
|
88
|
+
isCreatedState: true,
|
|
89
|
+
},
|
|
90
|
+
select: {
|
|
91
|
+
_id: true,
|
|
92
|
+
},
|
|
93
|
+
props: {
|
|
94
|
+
isRoot: true,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
if (!incidentState || !incidentState.id) {
|
|
98
|
+
throw new BadDataException("Created incident state not found for this project. Please add created incident state from settings.");
|
|
99
|
+
}
|
|
100
|
+
createBy.data.currentIncidentStateId = incidentState.id;
|
|
101
|
+
// Auto-generate episode number
|
|
102
|
+
const episodeNumberForThisEpisode = (await this.getExistingEpisodeNumberForProject({
|
|
103
|
+
projectId: projectId,
|
|
104
|
+
})) + 1;
|
|
105
|
+
createBy.data.episodeNumber = episodeNumberForThisEpisode;
|
|
106
|
+
// Set initial lastIncidentAddedAt
|
|
107
|
+
if (!createBy.data.lastIncidentAddedAt) {
|
|
108
|
+
createBy.data.lastIncidentAddedAt = OneUptimeDate.getCurrentDate();
|
|
109
|
+
}
|
|
110
|
+
return { createBy, carryForward: { mutex } };
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
// Release the mutex if it was acquired and an error occurred
|
|
114
|
+
if (mutex) {
|
|
115
|
+
try {
|
|
116
|
+
await Semaphore.release(mutex);
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
logger.error(err);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async onCreateSuccess(onCreate, createdItem) {
|
|
126
|
+
var _a;
|
|
127
|
+
// Release the mutex acquired in onBeforeCreate
|
|
128
|
+
const mutex = ((_a = onCreate.carryForward) === null || _a === void 0 ? void 0 : _a.mutex) || null;
|
|
129
|
+
if (mutex) {
|
|
130
|
+
try {
|
|
131
|
+
await Semaphore.release(mutex);
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
logger.error(err);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (!createdItem.projectId) {
|
|
138
|
+
throw new BadDataException("projectId is required");
|
|
139
|
+
}
|
|
140
|
+
if (!createdItem.id) {
|
|
141
|
+
throw new BadDataException("id is required");
|
|
142
|
+
}
|
|
143
|
+
if (!createdItem.currentIncidentStateId) {
|
|
144
|
+
throw new BadDataException("currentIncidentStateId is required");
|
|
145
|
+
}
|
|
146
|
+
// Create initial state timeline entry
|
|
147
|
+
Promise.resolve()
|
|
148
|
+
.then(async () => {
|
|
149
|
+
try {
|
|
150
|
+
await this.changeEpisodeState({
|
|
151
|
+
projectId: createdItem.projectId,
|
|
152
|
+
episodeId: createdItem.id,
|
|
153
|
+
incidentStateId: createdItem.currentIncidentStateId,
|
|
154
|
+
notifyOwners: false,
|
|
155
|
+
rootCause: undefined,
|
|
156
|
+
props: {
|
|
157
|
+
isRoot: true,
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
logger.error(`Handle episode state change failed in IncidentEpisodeService.onCreateSuccess: ${error}`);
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
.then(async () => {
|
|
166
|
+
try {
|
|
167
|
+
await this.createEpisodeCreatedFeed(createdItem);
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
logger.error(`Create episode feed failed in IncidentEpisodeService.onCreateSuccess: ${error}`);
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
.then(async () => {
|
|
174
|
+
// Execute on-call duty policies
|
|
175
|
+
try {
|
|
176
|
+
await this.executeEpisodeOnCallDutyPoliciesAsync(createdItem);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
logger.error(`On-call duty policy execution failed in IncidentEpisodeService.onCreateSuccess: ${error}`);
|
|
180
|
+
}
|
|
181
|
+
})
|
|
182
|
+
.catch((error) => {
|
|
183
|
+
logger.error(`Critical error in IncidentEpisodeService.onCreateSuccess: ${error}`);
|
|
184
|
+
});
|
|
185
|
+
return createdItem;
|
|
186
|
+
}
|
|
187
|
+
async createEpisodeCreatedFeed(episode) {
|
|
188
|
+
var _a;
|
|
189
|
+
if (!episode.id || !episode.projectId) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
let feedInfoInMarkdown = `#### Episode ${(_a = episode.episodeNumber) === null || _a === void 0 ? void 0 : _a.toString()} Created
|
|
193
|
+
|
|
194
|
+
**${episode.title || "No title provided."}**
|
|
195
|
+
|
|
196
|
+
`;
|
|
197
|
+
if (episode.description) {
|
|
198
|
+
feedInfoInMarkdown += `${episode.description}\n\n`;
|
|
199
|
+
}
|
|
200
|
+
if (episode.isManuallyCreated) {
|
|
201
|
+
feedInfoInMarkdown += `This episode was manually created.\n\n`;
|
|
202
|
+
}
|
|
203
|
+
await IncidentEpisodeFeedService.createIncidentEpisodeFeedItem({
|
|
204
|
+
incidentEpisodeId: episode.id,
|
|
205
|
+
projectId: episode.projectId,
|
|
206
|
+
incidentEpisodeFeedEventType: IncidentEpisodeFeedEventType.EpisodeCreated,
|
|
207
|
+
displayColor: Red500,
|
|
208
|
+
feedInfoInMarkdown: feedInfoInMarkdown,
|
|
209
|
+
userId: episode.createdByUserId || undefined,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
async executeEpisodeOnCallDutyPoliciesAsync(createdItem) {
|
|
213
|
+
var _a;
|
|
214
|
+
if (!createdItem.id || !createdItem.projectId) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
// Fetch the episode with on-call duty policies since they may not be loaded
|
|
219
|
+
const episodeWithPolicies = await this.findOneById({
|
|
220
|
+
id: createdItem.id,
|
|
221
|
+
select: {
|
|
222
|
+
onCallDutyPolicies: {
|
|
223
|
+
_id: true,
|
|
224
|
+
name: true,
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
props: {
|
|
228
|
+
isRoot: true,
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
if (!((_a = episodeWithPolicies === null || episodeWithPolicies === void 0 ? void 0 : episodeWithPolicies.onCallDutyPolicies) === null || _a === void 0 ? void 0 : _a.length) ||
|
|
232
|
+
episodeWithPolicies.onCallDutyPolicies.length === 0) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
// Execute all on-call policies in parallel
|
|
236
|
+
const policyPromises = episodeWithPolicies.onCallDutyPolicies.map((policy) => {
|
|
237
|
+
return OnCallDutyPolicyService.executePolicy(new ObjectID(policy._id), {
|
|
238
|
+
triggeredByIncidentEpisodeId: createdItem.id,
|
|
239
|
+
userNotificationEventType: UserNotificationEventType.IncidentCreated,
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
await Promise.allSettled(policyPromises);
|
|
243
|
+
// Update the flag to indicate on-call policy has been executed
|
|
244
|
+
await this.updateOneById({
|
|
245
|
+
id: createdItem.id,
|
|
246
|
+
data: {
|
|
247
|
+
isOnCallPolicyExecuted: true,
|
|
248
|
+
},
|
|
249
|
+
props: {
|
|
250
|
+
isRoot: true,
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
// Create feed entry for on-call policy execution
|
|
254
|
+
const policyNames = episodeWithPolicies.onCallDutyPolicies
|
|
255
|
+
.map((policy) => {
|
|
256
|
+
return policy.name || "Unnamed Policy";
|
|
257
|
+
})
|
|
258
|
+
.filter((name) => {
|
|
259
|
+
return Boolean(name);
|
|
260
|
+
});
|
|
261
|
+
let feedInfoInMarkdown = `#### On-Call Policy Executed\n\n`;
|
|
262
|
+
feedInfoInMarkdown += `The following on-call ${policyNames.length === 1 ? "policy has" : "policies have"} been executed for this episode:\n\n`;
|
|
263
|
+
for (const policyName of policyNames) {
|
|
264
|
+
feedInfoInMarkdown += `- ${policyName}\n`;
|
|
265
|
+
}
|
|
266
|
+
await IncidentEpisodeFeedService.createIncidentEpisodeFeedItem({
|
|
267
|
+
incidentEpisodeId: createdItem.id,
|
|
268
|
+
projectId: createdItem.projectId,
|
|
269
|
+
incidentEpisodeFeedEventType: IncidentEpisodeFeedEventType.OnCallPolicy,
|
|
270
|
+
displayColor: Purple500,
|
|
271
|
+
feedInfoInMarkdown: feedInfoInMarkdown,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
logger.error(`Error in executeEpisodeOnCallDutyPoliciesAsync: ${error}`);
|
|
276
|
+
throw error;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
async changeEpisodeState(data) {
|
|
280
|
+
const { projectId, episodeId, incidentStateId, notifyOwners, rootCause, props, cascadeToIncidents, } = data;
|
|
281
|
+
// Get last episode state timeline
|
|
282
|
+
const lastEpisodeStateTimeline = await IncidentEpisodeStateTimelineService.findOneBy({
|
|
283
|
+
query: {
|
|
284
|
+
incidentEpisodeId: episodeId,
|
|
285
|
+
projectId: projectId,
|
|
286
|
+
},
|
|
287
|
+
select: {
|
|
288
|
+
_id: true,
|
|
289
|
+
incidentStateId: true,
|
|
290
|
+
},
|
|
291
|
+
sort: {
|
|
292
|
+
createdAt: SortOrder.Descending,
|
|
293
|
+
},
|
|
294
|
+
props: {
|
|
295
|
+
isRoot: true,
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
if (lastEpisodeStateTimeline &&
|
|
299
|
+
lastEpisodeStateTimeline.incidentStateId &&
|
|
300
|
+
lastEpisodeStateTimeline.incidentStateId.toString() ===
|
|
301
|
+
incidentStateId.toString()) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const stateTimeline = new IncidentEpisodeStateTimeline();
|
|
305
|
+
stateTimeline.incidentEpisodeId = episodeId;
|
|
306
|
+
stateTimeline.incidentStateId = incidentStateId;
|
|
307
|
+
stateTimeline.projectId = projectId;
|
|
308
|
+
stateTimeline.isOwnerNotified = !notifyOwners;
|
|
309
|
+
if (rootCause) {
|
|
310
|
+
stateTimeline.rootCause = rootCause;
|
|
311
|
+
}
|
|
312
|
+
await IncidentEpisodeStateTimelineService.create({
|
|
313
|
+
data: stateTimeline,
|
|
314
|
+
props: props || {},
|
|
315
|
+
});
|
|
316
|
+
/*
|
|
317
|
+
* Note: resolvedAt is updated by IncidentEpisodeStateTimelineService.onCreateSuccess()
|
|
318
|
+
* to avoid duplicate updates.
|
|
319
|
+
*/
|
|
320
|
+
// Cascade state change to all member incidents if requested
|
|
321
|
+
if (cascadeToIncidents) {
|
|
322
|
+
await this.cascadeStateToMemberIncidents({
|
|
323
|
+
projectId,
|
|
324
|
+
episodeId,
|
|
325
|
+
incidentStateId,
|
|
326
|
+
props,
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
async cascadeStateToMemberIncidents(data) {
|
|
331
|
+
const { projectId, episodeId, incidentStateId, props } = data;
|
|
332
|
+
// Get all member incidents for this episode
|
|
333
|
+
const members = await IncidentEpisodeMemberService.findBy({
|
|
334
|
+
query: {
|
|
335
|
+
incidentEpisodeId: episodeId,
|
|
336
|
+
projectId: projectId,
|
|
337
|
+
},
|
|
338
|
+
select: {
|
|
339
|
+
incidentId: true,
|
|
340
|
+
},
|
|
341
|
+
props: {
|
|
342
|
+
isRoot: true,
|
|
343
|
+
},
|
|
344
|
+
limit: LIMIT_PER_PROJECT,
|
|
345
|
+
skip: 0,
|
|
346
|
+
});
|
|
347
|
+
if (members.length === 0) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
// Update state for each member incident
|
|
351
|
+
for (const member of members) {
|
|
352
|
+
if (!member.incidentId) {
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
try {
|
|
356
|
+
await IncidentService.changeIncidentState({
|
|
357
|
+
projectId: projectId,
|
|
358
|
+
incidentId: member.incidentId,
|
|
359
|
+
incidentStateId: incidentStateId,
|
|
360
|
+
shouldNotifyStatusPageSubscribers: false,
|
|
361
|
+
isSubscribersNotified: false,
|
|
362
|
+
notifyOwners: false, // Don't send notifications for cascaded state changes
|
|
363
|
+
rootCause: "State changed by episode state cascade.",
|
|
364
|
+
stateChangeLog: undefined,
|
|
365
|
+
props: props,
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
catch (error) {
|
|
369
|
+
logger.error(`Failed to cascade state change to incident ${member.incidentId.toString()}: ${error}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
async acknowledgeEpisode(episodeId, acknowledgedByUserId, cascadeToIncidents = true) {
|
|
374
|
+
const episode = await this.findOneById({
|
|
375
|
+
id: episodeId,
|
|
376
|
+
select: {
|
|
377
|
+
projectId: true,
|
|
378
|
+
},
|
|
379
|
+
props: {
|
|
380
|
+
isRoot: true,
|
|
381
|
+
},
|
|
382
|
+
});
|
|
383
|
+
if (!episode || !episode.projectId) {
|
|
384
|
+
throw new BadDataException("Episode not found.");
|
|
385
|
+
}
|
|
386
|
+
const incidentState = await IncidentStateService.findOneBy({
|
|
387
|
+
query: {
|
|
388
|
+
projectId: episode.projectId,
|
|
389
|
+
isAcknowledgedState: true,
|
|
390
|
+
},
|
|
391
|
+
select: {
|
|
392
|
+
_id: true,
|
|
393
|
+
},
|
|
394
|
+
props: {
|
|
395
|
+
isRoot: true,
|
|
396
|
+
},
|
|
397
|
+
});
|
|
398
|
+
if (!incidentState || !incidentState.id) {
|
|
399
|
+
throw new BadDataException("Acknowledged incident state not found for this project.");
|
|
400
|
+
}
|
|
401
|
+
await this.changeEpisodeState({
|
|
402
|
+
projectId: episode.projectId,
|
|
403
|
+
episodeId: episodeId,
|
|
404
|
+
incidentStateId: incidentState.id,
|
|
405
|
+
notifyOwners: false,
|
|
406
|
+
rootCause: acknowledgedByUserId
|
|
407
|
+
? `Acknowledged by user.`
|
|
408
|
+
: "Acknowledged via API.",
|
|
409
|
+
props: {
|
|
410
|
+
isRoot: true,
|
|
411
|
+
userId: acknowledgedByUserId,
|
|
412
|
+
},
|
|
413
|
+
cascadeToIncidents: cascadeToIncidents,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
async resolveEpisode(episodeId, resolvedByUserId, cascadeToIncidents = true) {
|
|
417
|
+
const episode = await this.findOneById({
|
|
418
|
+
id: episodeId,
|
|
419
|
+
select: {
|
|
420
|
+
projectId: true,
|
|
421
|
+
},
|
|
422
|
+
props: {
|
|
423
|
+
isRoot: true,
|
|
424
|
+
},
|
|
425
|
+
});
|
|
426
|
+
if (!episode || !episode.projectId) {
|
|
427
|
+
throw new BadDataException("Episode not found.");
|
|
428
|
+
}
|
|
429
|
+
const incidentState = await IncidentStateService.findOneBy({
|
|
430
|
+
query: {
|
|
431
|
+
projectId: episode.projectId,
|
|
432
|
+
isResolvedState: true,
|
|
433
|
+
},
|
|
434
|
+
select: {
|
|
435
|
+
_id: true,
|
|
436
|
+
},
|
|
437
|
+
props: {
|
|
438
|
+
isRoot: true,
|
|
439
|
+
},
|
|
440
|
+
});
|
|
441
|
+
if (!incidentState || !incidentState.id) {
|
|
442
|
+
throw new BadDataException("Resolved incident state not found for this project.");
|
|
443
|
+
}
|
|
444
|
+
await this.changeEpisodeState({
|
|
445
|
+
projectId: episode.projectId,
|
|
446
|
+
episodeId: episodeId,
|
|
447
|
+
incidentStateId: incidentState.id,
|
|
448
|
+
notifyOwners: false,
|
|
449
|
+
rootCause: resolvedByUserId ? `Resolved by user.` : "Resolved via API.",
|
|
450
|
+
props: {
|
|
451
|
+
isRoot: true,
|
|
452
|
+
userId: resolvedByUserId,
|
|
453
|
+
},
|
|
454
|
+
cascadeToIncidents: cascadeToIncidents,
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
async reopenEpisode(episodeId, reopenedByUserId, cascadeToIncidents = true) {
|
|
458
|
+
const episode = await this.findOneById({
|
|
459
|
+
id: episodeId,
|
|
460
|
+
select: {
|
|
461
|
+
projectId: true,
|
|
462
|
+
},
|
|
463
|
+
props: {
|
|
464
|
+
isRoot: true,
|
|
465
|
+
},
|
|
466
|
+
});
|
|
467
|
+
if (!episode || !episode.projectId) {
|
|
468
|
+
throw new BadDataException("Episode not found.");
|
|
469
|
+
}
|
|
470
|
+
const incidentState = await IncidentStateService.findOneBy({
|
|
471
|
+
query: {
|
|
472
|
+
projectId: episode.projectId,
|
|
473
|
+
isCreatedState: true,
|
|
474
|
+
},
|
|
475
|
+
select: {
|
|
476
|
+
_id: true,
|
|
477
|
+
},
|
|
478
|
+
props: {
|
|
479
|
+
isRoot: true,
|
|
480
|
+
},
|
|
481
|
+
});
|
|
482
|
+
if (!incidentState || !incidentState.id) {
|
|
483
|
+
throw new BadDataException("Created incident state not found for this project.");
|
|
484
|
+
}
|
|
485
|
+
await this.changeEpisodeState({
|
|
486
|
+
projectId: episode.projectId,
|
|
487
|
+
episodeId: episodeId,
|
|
488
|
+
incidentStateId: incidentState.id,
|
|
489
|
+
notifyOwners: false,
|
|
490
|
+
rootCause: reopenedByUserId ? `Reopened by user.` : "Reopened via API.",
|
|
491
|
+
props: {
|
|
492
|
+
isRoot: true,
|
|
493
|
+
userId: reopenedByUserId,
|
|
494
|
+
},
|
|
495
|
+
cascadeToIncidents: cascadeToIncidents,
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
async updateEpisodeSeverity(episodeId, severityId, onlyIfHigher = false) {
|
|
499
|
+
const episode = await this.findOneById({
|
|
500
|
+
id: episodeId,
|
|
501
|
+
select: {
|
|
502
|
+
projectId: true,
|
|
503
|
+
incidentSeverityId: true,
|
|
504
|
+
},
|
|
505
|
+
props: {
|
|
506
|
+
isRoot: true,
|
|
507
|
+
},
|
|
508
|
+
});
|
|
509
|
+
if (!episode || !episode.projectId) {
|
|
510
|
+
throw new BadDataException("Episode not found.");
|
|
511
|
+
}
|
|
512
|
+
// If onlyIfHigher is true, check if the new severity is higher than the current
|
|
513
|
+
if (onlyIfHigher && episode.incidentSeverityId) {
|
|
514
|
+
const currentSeverity = await IncidentSeverityService.findOneById({
|
|
515
|
+
id: episode.incidentSeverityId,
|
|
516
|
+
select: {
|
|
517
|
+
order: true,
|
|
518
|
+
},
|
|
519
|
+
props: {
|
|
520
|
+
isRoot: true,
|
|
521
|
+
},
|
|
522
|
+
});
|
|
523
|
+
const newSeverity = await IncidentSeverityService.findOneById({
|
|
524
|
+
id: severityId,
|
|
525
|
+
select: {
|
|
526
|
+
order: true,
|
|
527
|
+
},
|
|
528
|
+
props: {
|
|
529
|
+
isRoot: true,
|
|
530
|
+
},
|
|
531
|
+
});
|
|
532
|
+
// Lower order number means higher severity
|
|
533
|
+
if ((currentSeverity === null || currentSeverity === void 0 ? void 0 : currentSeverity.order) !== undefined &&
|
|
534
|
+
(newSeverity === null || newSeverity === void 0 ? void 0 : newSeverity.order) !== undefined &&
|
|
535
|
+
newSeverity.order >= currentSeverity.order) {
|
|
536
|
+
return; // New severity is not higher, don't update
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
await this.updateOneById({
|
|
540
|
+
id: episodeId,
|
|
541
|
+
data: {
|
|
542
|
+
incidentSeverityId: severityId,
|
|
543
|
+
},
|
|
544
|
+
props: {
|
|
545
|
+
isRoot: true,
|
|
546
|
+
},
|
|
547
|
+
});
|
|
548
|
+
// Create feed entry for severity change
|
|
549
|
+
const newSeverity = await IncidentSeverityService.findOneById({
|
|
550
|
+
id: severityId,
|
|
551
|
+
select: {
|
|
552
|
+
name: true,
|
|
553
|
+
color: true,
|
|
554
|
+
},
|
|
555
|
+
props: {
|
|
556
|
+
isRoot: true,
|
|
557
|
+
},
|
|
558
|
+
});
|
|
559
|
+
if (newSeverity && episode.projectId) {
|
|
560
|
+
await IncidentEpisodeFeedService.createIncidentEpisodeFeedItem({
|
|
561
|
+
incidentEpisodeId: episodeId,
|
|
562
|
+
projectId: episode.projectId,
|
|
563
|
+
incidentEpisodeFeedEventType: IncidentEpisodeFeedEventType.SeverityChanged,
|
|
564
|
+
displayColor: newSeverity.color || Yellow500,
|
|
565
|
+
feedInfoInMarkdown: `Episode severity changed to **${newSeverity.name || "Unknown"}**`,
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
async updateIncidentCount(episodeId) {
|
|
570
|
+
const count = await IncidentEpisodeMemberService.countBy({
|
|
571
|
+
query: {
|
|
572
|
+
incidentEpisodeId: episodeId,
|
|
573
|
+
},
|
|
574
|
+
props: {
|
|
575
|
+
isRoot: true,
|
|
576
|
+
},
|
|
577
|
+
});
|
|
578
|
+
await this.updateOneById({
|
|
579
|
+
id: episodeId,
|
|
580
|
+
data: {
|
|
581
|
+
incidentCount: count.toNumber(),
|
|
582
|
+
},
|
|
583
|
+
props: {
|
|
584
|
+
isRoot: true,
|
|
585
|
+
},
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
async updateLastIncidentAddedAt(episodeId) {
|
|
589
|
+
await this.updateOneById({
|
|
590
|
+
id: episodeId,
|
|
591
|
+
data: {
|
|
592
|
+
lastIncidentAddedAt: OneUptimeDate.getCurrentDate(),
|
|
593
|
+
},
|
|
594
|
+
props: {
|
|
595
|
+
isRoot: true,
|
|
596
|
+
},
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
async findOwners(episodeId) {
|
|
600
|
+
// Get direct user owners
|
|
601
|
+
const userOwners = await IncidentEpisodeOwnerUserService.findBy({
|
|
602
|
+
query: {
|
|
603
|
+
incidentEpisodeId: episodeId,
|
|
604
|
+
},
|
|
605
|
+
select: {
|
|
606
|
+
userId: true,
|
|
607
|
+
user: {
|
|
608
|
+
_id: true,
|
|
609
|
+
email: true,
|
|
610
|
+
name: true,
|
|
611
|
+
},
|
|
612
|
+
},
|
|
613
|
+
props: {
|
|
614
|
+
isRoot: true,
|
|
615
|
+
},
|
|
616
|
+
limit: LIMIT_PER_PROJECT,
|
|
617
|
+
skip: 0,
|
|
618
|
+
});
|
|
619
|
+
// Get team owners
|
|
620
|
+
const teamOwners = await IncidentEpisodeOwnerTeamService.findBy({
|
|
621
|
+
query: {
|
|
622
|
+
incidentEpisodeId: episodeId,
|
|
623
|
+
},
|
|
624
|
+
select: {
|
|
625
|
+
teamId: true,
|
|
626
|
+
},
|
|
627
|
+
props: {
|
|
628
|
+
isRoot: true,
|
|
629
|
+
},
|
|
630
|
+
limit: LIMIT_PER_PROJECT,
|
|
631
|
+
skip: 0,
|
|
632
|
+
});
|
|
633
|
+
// Collect all unique users
|
|
634
|
+
const usersMap = new Map();
|
|
635
|
+
// Add direct user owners
|
|
636
|
+
for (const owner of userOwners) {
|
|
637
|
+
if (owner.user && owner.userId) {
|
|
638
|
+
usersMap.set(owner.userId.toString(), owner.user);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
// Add users from teams
|
|
642
|
+
for (const teamOwner of teamOwners) {
|
|
643
|
+
if (teamOwner.teamId) {
|
|
644
|
+
const teamMembers = await TeamMemberService.getUsersInTeam(teamOwner.teamId);
|
|
645
|
+
for (const user of teamMembers) {
|
|
646
|
+
if (user.id) {
|
|
647
|
+
usersMap.set(user.id.toString(), user);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
return Array.from(usersMap.values());
|
|
653
|
+
}
|
|
654
|
+
async addOwners(data) {
|
|
655
|
+
const { episodeId, projectId, userIds, teamIds, createdByUserId } = data;
|
|
656
|
+
// Add user owners
|
|
657
|
+
if (userIds && userIds.length > 0) {
|
|
658
|
+
for (const userId of userIds) {
|
|
659
|
+
// Check if already exists
|
|
660
|
+
const existing = await IncidentEpisodeOwnerUserService.findOneBy({
|
|
661
|
+
query: {
|
|
662
|
+
incidentEpisodeId: episodeId,
|
|
663
|
+
userId: userId,
|
|
664
|
+
},
|
|
665
|
+
props: {
|
|
666
|
+
isRoot: true,
|
|
667
|
+
},
|
|
668
|
+
select: {
|
|
669
|
+
_id: true,
|
|
670
|
+
},
|
|
671
|
+
});
|
|
672
|
+
if (!existing) {
|
|
673
|
+
const ownerUser = new IncidentEpisodeOwnerUser();
|
|
674
|
+
ownerUser.incidentEpisodeId = episodeId;
|
|
675
|
+
ownerUser.userId = userId;
|
|
676
|
+
ownerUser.projectId = projectId;
|
|
677
|
+
if (createdByUserId) {
|
|
678
|
+
ownerUser.createdByUserId = createdByUserId;
|
|
679
|
+
}
|
|
680
|
+
await IncidentEpisodeOwnerUserService.create({
|
|
681
|
+
data: ownerUser,
|
|
682
|
+
props: {
|
|
683
|
+
isRoot: true,
|
|
684
|
+
},
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
// Add team owners
|
|
690
|
+
if (teamIds && teamIds.length > 0) {
|
|
691
|
+
for (const teamId of teamIds) {
|
|
692
|
+
// Check if already exists
|
|
693
|
+
const existing = await IncidentEpisodeOwnerTeamService.findOneBy({
|
|
694
|
+
query: {
|
|
695
|
+
incidentEpisodeId: episodeId,
|
|
696
|
+
teamId: teamId,
|
|
697
|
+
},
|
|
698
|
+
props: {
|
|
699
|
+
isRoot: true,
|
|
700
|
+
},
|
|
701
|
+
select: {
|
|
702
|
+
_id: true,
|
|
703
|
+
},
|
|
704
|
+
});
|
|
705
|
+
if (!existing) {
|
|
706
|
+
const ownerTeam = new IncidentEpisodeOwnerTeam();
|
|
707
|
+
ownerTeam.incidentEpisodeId = episodeId;
|
|
708
|
+
ownerTeam.teamId = teamId;
|
|
709
|
+
ownerTeam.projectId = projectId;
|
|
710
|
+
if (createdByUserId) {
|
|
711
|
+
ownerTeam.createdByUserId = createdByUserId;
|
|
712
|
+
}
|
|
713
|
+
await IncidentEpisodeOwnerTeamService.create({
|
|
714
|
+
data: ownerTeam,
|
|
715
|
+
props: {
|
|
716
|
+
isRoot: true,
|
|
717
|
+
},
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
getWorkspaceChannelForEpisode(episode, workspaceType) {
|
|
724
|
+
if (!episode.postUpdatesToWorkspaceChannels ||
|
|
725
|
+
!Array.isArray(episode.postUpdatesToWorkspaceChannels) ||
|
|
726
|
+
episode.postUpdatesToWorkspaceChannels.length === 0) {
|
|
727
|
+
return [];
|
|
728
|
+
}
|
|
729
|
+
return episode.postUpdatesToWorkspaceChannels.filter((channel) => {
|
|
730
|
+
return channel.workspaceType === workspaceType;
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
async isEpisodeResolved(episodeId) {
|
|
734
|
+
var _a;
|
|
735
|
+
const episode = await this.findOneById({
|
|
736
|
+
id: episodeId,
|
|
737
|
+
select: {
|
|
738
|
+
projectId: true,
|
|
739
|
+
currentIncidentState: {
|
|
740
|
+
order: true,
|
|
741
|
+
},
|
|
742
|
+
},
|
|
743
|
+
props: {
|
|
744
|
+
isRoot: true,
|
|
745
|
+
},
|
|
746
|
+
});
|
|
747
|
+
if (!episode || !episode.projectId) {
|
|
748
|
+
throw new BadDataException("Episode not found.");
|
|
749
|
+
}
|
|
750
|
+
const resolvedState = await IncidentStateService.getResolvedIncidentState({
|
|
751
|
+
projectId: episode.projectId,
|
|
752
|
+
props: {
|
|
753
|
+
isRoot: true,
|
|
754
|
+
},
|
|
755
|
+
});
|
|
756
|
+
const currentOrder = ((_a = episode.currentIncidentState) === null || _a === void 0 ? void 0 : _a.order) || 0;
|
|
757
|
+
const resolvedOrder = resolvedState.order || 0;
|
|
758
|
+
return currentOrder >= resolvedOrder;
|
|
759
|
+
}
|
|
760
|
+
async isEpisodeAcknowledged(data) {
|
|
761
|
+
var _a;
|
|
762
|
+
const episode = await this.findOneById({
|
|
763
|
+
id: data.episodeId,
|
|
764
|
+
select: {
|
|
765
|
+
projectId: true,
|
|
766
|
+
currentIncidentState: {
|
|
767
|
+
order: true,
|
|
768
|
+
},
|
|
769
|
+
},
|
|
770
|
+
props: {
|
|
771
|
+
isRoot: true,
|
|
772
|
+
},
|
|
773
|
+
});
|
|
774
|
+
if (!episode || !episode.projectId) {
|
|
775
|
+
throw new BadDataException("Episode not found.");
|
|
776
|
+
}
|
|
777
|
+
const acknowledgedState = await IncidentStateService.getAcknowledgedIncidentState({
|
|
778
|
+
projectId: episode.projectId,
|
|
779
|
+
props: {
|
|
780
|
+
isRoot: true,
|
|
781
|
+
},
|
|
782
|
+
});
|
|
783
|
+
const currentOrder = ((_a = episode.currentIncidentState) === null || _a === void 0 ? void 0 : _a.order) || 0;
|
|
784
|
+
const acknowledgedOrder = acknowledgedState.order || 0;
|
|
785
|
+
return currentOrder >= acknowledgedOrder;
|
|
786
|
+
}
|
|
787
|
+
async getEpisodeLinkInDashboard(projectId, episodeId) {
|
|
788
|
+
const dashboardUrl = await DatabaseConfig.getDashboardUrl();
|
|
789
|
+
return URL.fromString(dashboardUrl.toString()).addRoute(`/${projectId.toString()}/incidents/episodes/${episodeId.toString()}`);
|
|
790
|
+
}
|
|
791
|
+
async getEpisodeNumber(data) {
|
|
792
|
+
const episode = await this.findOneById({
|
|
793
|
+
id: data.episodeId,
|
|
794
|
+
select: {
|
|
795
|
+
episodeNumber: true,
|
|
796
|
+
},
|
|
797
|
+
props: {
|
|
798
|
+
isRoot: true,
|
|
799
|
+
},
|
|
800
|
+
});
|
|
801
|
+
if (!episode) {
|
|
802
|
+
throw new BadDataException("Episode not found.");
|
|
803
|
+
}
|
|
804
|
+
return episode.episodeNumber ? Number(episode.episodeNumber) : null;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
__decorate([
|
|
808
|
+
CaptureSpan(),
|
|
809
|
+
__metadata("design:type", Function),
|
|
810
|
+
__metadata("design:paramtypes", [Object]),
|
|
811
|
+
__metadata("design:returntype", Promise)
|
|
812
|
+
], Service.prototype, "getExistingEpisodeNumberForProject", null);
|
|
813
|
+
__decorate([
|
|
814
|
+
CaptureSpan(),
|
|
815
|
+
__metadata("design:type", Function),
|
|
816
|
+
__metadata("design:paramtypes", [Object]),
|
|
817
|
+
__metadata("design:returntype", Promise)
|
|
818
|
+
], Service.prototype, "onBeforeCreate", null);
|
|
819
|
+
__decorate([
|
|
820
|
+
CaptureSpan(),
|
|
821
|
+
__metadata("design:type", Function),
|
|
822
|
+
__metadata("design:paramtypes", [Object, Model]),
|
|
823
|
+
__metadata("design:returntype", Promise)
|
|
824
|
+
], Service.prototype, "onCreateSuccess", null);
|
|
825
|
+
__decorate([
|
|
826
|
+
CaptureSpan(),
|
|
827
|
+
__metadata("design:type", Function),
|
|
828
|
+
__metadata("design:paramtypes", [Model]),
|
|
829
|
+
__metadata("design:returntype", Promise)
|
|
830
|
+
], Service.prototype, "createEpisodeCreatedFeed", null);
|
|
831
|
+
__decorate([
|
|
832
|
+
CaptureSpan(),
|
|
833
|
+
__metadata("design:type", Function),
|
|
834
|
+
__metadata("design:paramtypes", [Model]),
|
|
835
|
+
__metadata("design:returntype", Promise)
|
|
836
|
+
], Service.prototype, "executeEpisodeOnCallDutyPoliciesAsync", null);
|
|
837
|
+
__decorate([
|
|
838
|
+
CaptureSpan(),
|
|
839
|
+
__metadata("design:type", Function),
|
|
840
|
+
__metadata("design:paramtypes", [Object]),
|
|
841
|
+
__metadata("design:returntype", Promise)
|
|
842
|
+
], Service.prototype, "changeEpisodeState", null);
|
|
843
|
+
__decorate([
|
|
844
|
+
CaptureSpan(),
|
|
845
|
+
__metadata("design:type", Function),
|
|
846
|
+
__metadata("design:paramtypes", [Object]),
|
|
847
|
+
__metadata("design:returntype", Promise)
|
|
848
|
+
], Service.prototype, "cascadeStateToMemberIncidents", null);
|
|
849
|
+
__decorate([
|
|
850
|
+
CaptureSpan(),
|
|
851
|
+
__metadata("design:type", Function),
|
|
852
|
+
__metadata("design:paramtypes", [ObjectID,
|
|
853
|
+
ObjectID, Boolean]),
|
|
854
|
+
__metadata("design:returntype", Promise)
|
|
855
|
+
], Service.prototype, "acknowledgeEpisode", null);
|
|
856
|
+
__decorate([
|
|
857
|
+
CaptureSpan(),
|
|
858
|
+
__metadata("design:type", Function),
|
|
859
|
+
__metadata("design:paramtypes", [ObjectID,
|
|
860
|
+
ObjectID, Boolean]),
|
|
861
|
+
__metadata("design:returntype", Promise)
|
|
862
|
+
], Service.prototype, "resolveEpisode", null);
|
|
863
|
+
__decorate([
|
|
864
|
+
CaptureSpan(),
|
|
865
|
+
__metadata("design:type", Function),
|
|
866
|
+
__metadata("design:paramtypes", [ObjectID,
|
|
867
|
+
ObjectID, Boolean]),
|
|
868
|
+
__metadata("design:returntype", Promise)
|
|
869
|
+
], Service.prototype, "reopenEpisode", null);
|
|
870
|
+
__decorate([
|
|
871
|
+
CaptureSpan(),
|
|
872
|
+
__metadata("design:type", Function),
|
|
873
|
+
__metadata("design:paramtypes", [ObjectID,
|
|
874
|
+
ObjectID, Boolean]),
|
|
875
|
+
__metadata("design:returntype", Promise)
|
|
876
|
+
], Service.prototype, "updateEpisodeSeverity", null);
|
|
877
|
+
__decorate([
|
|
878
|
+
CaptureSpan(),
|
|
879
|
+
__metadata("design:type", Function),
|
|
880
|
+
__metadata("design:paramtypes", [ObjectID]),
|
|
881
|
+
__metadata("design:returntype", Promise)
|
|
882
|
+
], Service.prototype, "updateIncidentCount", null);
|
|
883
|
+
__decorate([
|
|
884
|
+
CaptureSpan(),
|
|
885
|
+
__metadata("design:type", Function),
|
|
886
|
+
__metadata("design:paramtypes", [ObjectID]),
|
|
887
|
+
__metadata("design:returntype", Promise)
|
|
888
|
+
], Service.prototype, "updateLastIncidentAddedAt", null);
|
|
889
|
+
__decorate([
|
|
890
|
+
CaptureSpan(),
|
|
891
|
+
__metadata("design:type", Function),
|
|
892
|
+
__metadata("design:paramtypes", [ObjectID]),
|
|
893
|
+
__metadata("design:returntype", Promise)
|
|
894
|
+
], Service.prototype, "findOwners", null);
|
|
895
|
+
__decorate([
|
|
896
|
+
CaptureSpan(),
|
|
897
|
+
__metadata("design:type", Function),
|
|
898
|
+
__metadata("design:paramtypes", [Object]),
|
|
899
|
+
__metadata("design:returntype", Promise)
|
|
900
|
+
], Service.prototype, "addOwners", null);
|
|
901
|
+
__decorate([
|
|
902
|
+
CaptureSpan(),
|
|
903
|
+
__metadata("design:type", Function),
|
|
904
|
+
__metadata("design:paramtypes", [Model, String]),
|
|
905
|
+
__metadata("design:returntype", Array)
|
|
906
|
+
], Service.prototype, "getWorkspaceChannelForEpisode", null);
|
|
907
|
+
__decorate([
|
|
908
|
+
CaptureSpan(),
|
|
909
|
+
__metadata("design:type", Function),
|
|
910
|
+
__metadata("design:paramtypes", [ObjectID]),
|
|
911
|
+
__metadata("design:returntype", Promise)
|
|
912
|
+
], Service.prototype, "isEpisodeResolved", null);
|
|
913
|
+
__decorate([
|
|
914
|
+
CaptureSpan(),
|
|
915
|
+
__metadata("design:type", Function),
|
|
916
|
+
__metadata("design:paramtypes", [Object]),
|
|
917
|
+
__metadata("design:returntype", Promise)
|
|
918
|
+
], Service.prototype, "isEpisodeAcknowledged", null);
|
|
919
|
+
__decorate([
|
|
920
|
+
CaptureSpan(),
|
|
921
|
+
__metadata("design:type", Function),
|
|
922
|
+
__metadata("design:paramtypes", [ObjectID,
|
|
923
|
+
ObjectID]),
|
|
924
|
+
__metadata("design:returntype", Promise)
|
|
925
|
+
], Service.prototype, "getEpisodeLinkInDashboard", null);
|
|
926
|
+
__decorate([
|
|
927
|
+
CaptureSpan(),
|
|
928
|
+
__metadata("design:type", Function),
|
|
929
|
+
__metadata("design:paramtypes", [Object]),
|
|
930
|
+
__metadata("design:returntype", Promise)
|
|
931
|
+
], Service.prototype, "getEpisodeNumber", null);
|
|
932
|
+
export default new Service();
|
|
933
|
+
//# sourceMappingURL=IncidentEpisodeService.js.map
|