@oneuptime/common 7.0.3517 → 7.0.3538
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/AlertFeed.ts +12 -4
- package/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.ts +2 -0
- package/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.ts +59 -2
- package/Models/DatabaseModels/ScheduledMaintenanceFeed.ts +15 -7
- package/Models/DatabaseModels/UserNotificationRule.ts +50 -0
- package/Models/DatabaseModels/UserOnCallLog.ts +48 -1
- package/Models/DatabaseModels/UserOnCallLogTimeline.ts +49 -2
- package/Server/API/BillingInvoiceAPI.ts +2 -32
- package/Server/API/UserOnCallLogTimelineAPI.ts +32 -8
- package/Server/Infrastructure/Postgres/SchemaMigrations/1737141420441-MigrationName.ts +131 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/AlertFeedService.ts +44 -37
- package/Server/Services/AlertInternalNoteService.ts +73 -0
- package/Server/Services/AlertOwnerTeamService.ts +112 -0
- package/Server/Services/AlertOwnerUserService.ts +114 -0
- package/Server/Services/AlertService.ts +121 -0
- package/Server/Services/AlertStateTimelineService.ts +52 -0
- package/Server/Services/BillingInvoiceService.ts +170 -0
- package/Server/Services/IncidentFeedService.ts +59 -54
- package/Server/Services/IncidentInternalNoteService.ts +46 -1
- package/Server/Services/IncidentPublicNoteService.ts +47 -2
- package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +32 -14
- package/Server/Services/OnCallDutyPolicyExecutionLogService.ts +86 -27
- package/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.ts +30 -12
- package/Server/Services/ScheduledMaintenanceFeedService.ts +51 -40
- package/Server/Services/ScheduledMaintenanceInternalNoteService.ts +75 -0
- package/Server/Services/ScheduledMaintenanceOwnerTeamService.ts +116 -0
- package/Server/Services/ScheduledMaintenanceOwnerUserService.ts +118 -0
- package/Server/Services/ScheduledMaintenancePublicNoteService.ts +74 -1
- package/Server/Services/ScheduledMaintenanceService.ts +68 -0
- package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +30 -0
- package/Server/Services/UserNotificationRuleService.ts +450 -67
- package/Server/Services/UserOnCallLogService.ts +61 -18
- package/Server/Services/UserOnCallLogTimelineService.ts +25 -11
- package/Server/Utils/Logger.ts +14 -0
- package/Types/Email/EmailTemplateType.ts +1 -0
- package/Types/NotificationRule/NotificationRuleType.ts +1 -1
- package/UI/Utils/Project.ts +25 -0
- package/build/dist/Models/DatabaseModels/AlertFeed.js +12 -4
- package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js +2 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.js +60 -2
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceFeed.js +15 -7
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserNotificationRule.js +49 -0
- package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js +48 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +50 -2
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
- package/build/dist/Server/API/BillingInvoiceAPI.js +2 -19
- package/build/dist/Server/API/BillingInvoiceAPI.js.map +1 -1
- package/build/dist/Server/API/UserOnCallLogTimelineAPI.js +10 -2
- package/build/dist/Server/API/UserOnCallLogTimelineAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1737141420441-MigrationName.js +50 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1737141420441-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AlertFeedService.js +43 -35
- package/build/dist/Server/Services/AlertFeedService.js.map +1 -1
- package/build/dist/Server/Services/AlertInternalNoteService.js +56 -0
- package/build/dist/Server/Services/AlertInternalNoteService.js.map +1 -1
- package/build/dist/Server/Services/AlertOwnerTeamService.js +86 -0
- package/build/dist/Server/Services/AlertOwnerTeamService.js.map +1 -1
- package/build/dist/Server/Services/AlertOwnerUserService.js +89 -0
- package/build/dist/Server/Services/AlertOwnerUserService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +107 -3
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/AlertStateTimelineService.js +44 -1
- package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/BillingInvoiceService.js +123 -0
- package/build/dist/Server/Services/BillingInvoiceService.js.map +1 -1
- package/build/dist/Server/Services/IncidentFeedService.js +45 -39
- package/build/dist/Server/Services/IncidentFeedService.js.map +1 -1
- package/build/dist/Server/Services/IncidentInternalNoteService.js +37 -0
- package/build/dist/Server/Services/IncidentInternalNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js +38 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +18 -8
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js +70 -24
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js +26 -11
- package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceFeedService.js +45 -37
- package/build/dist/Server/Services/ScheduledMaintenanceFeedService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceInternalNoteService.js +56 -0
- package/build/dist/Server/Services/ScheduledMaintenanceInternalNoteService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerTeamService.js +86 -0
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerTeamService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerUserService.js +89 -0
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerUserService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +56 -0
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +57 -0
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +24 -0
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +334 -67
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/UserOnCallLogService.js +66 -27
- package/build/dist/Server/Services/UserOnCallLogService.js.map +1 -1
- package/build/dist/Server/Services/UserOnCallLogTimelineService.js +16 -5
- package/build/dist/Server/Services/UserOnCallLogTimelineService.js.map +1 -1
- package/build/dist/Server/Utils/Logger.js +11 -0
- package/build/dist/Server/Utils/Logger.js.map +1 -1
- package/build/dist/Types/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/NotificationRule/NotificationRuleType.js +1 -1
- package/build/dist/Types/NotificationRule/NotificationRuleType.js.map +1 -1
- package/build/dist/UI/Utils/Project.js +11 -0
- package/build/dist/UI/Utils/Project.js.map +1 -1
- package/package.json +2 -2
|
@@ -10,6 +10,11 @@ import Model, {
|
|
|
10
10
|
InvoiceStatus,
|
|
11
11
|
} from "Common/Models/DatabaseModels/BillingInvoice";
|
|
12
12
|
import Project from "Common/Models/DatabaseModels/Project";
|
|
13
|
+
import SubscriptionStatus from "../../Types/Billing/SubscriptionStatus";
|
|
14
|
+
import ObjectID from "../../Types/ObjectID";
|
|
15
|
+
import Semaphore, { SemaphoreMutex } from "../Infrastructure/Semaphore";
|
|
16
|
+
import logger from "../Utils/Logger";
|
|
17
|
+
import OneUptimeDate from "../../Types/Date";
|
|
13
18
|
|
|
14
19
|
export class Service extends DatabaseService<Model> {
|
|
15
20
|
public constructor() {
|
|
@@ -17,6 +22,166 @@ export class Service extends DatabaseService<Model> {
|
|
|
17
22
|
this.setDoNotAllowDelete(true);
|
|
18
23
|
}
|
|
19
24
|
|
|
25
|
+
public async refreshSubscriptionStatus(data: {
|
|
26
|
+
projectId: ObjectID;
|
|
27
|
+
}): Promise<void> {
|
|
28
|
+
let mutex: SemaphoreMutex | null = null;
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
mutex = await Semaphore.lock({
|
|
32
|
+
key: data.projectId.toString(),
|
|
33
|
+
namespace: "BillingInoviceService.refreshSubscriptionStatus",
|
|
34
|
+
lockTimeout: 15000,
|
|
35
|
+
acquireTimeout: 20000,
|
|
36
|
+
});
|
|
37
|
+
logger.debug(
|
|
38
|
+
"Mutex acquired - " +
|
|
39
|
+
data.projectId.toString() +
|
|
40
|
+
" at " +
|
|
41
|
+
OneUptimeDate.getCurrentDateAsFormattedString(),
|
|
42
|
+
);
|
|
43
|
+
} catch (err) {
|
|
44
|
+
logger.debug(
|
|
45
|
+
"Mutex acquire failed - " +
|
|
46
|
+
data.projectId.toString() +
|
|
47
|
+
" at " +
|
|
48
|
+
OneUptimeDate.getCurrentDateAsFormattedString(),
|
|
49
|
+
);
|
|
50
|
+
logger.error(err);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let project: Project | null = await ProjectService.findOneById({
|
|
54
|
+
id: data.projectId,
|
|
55
|
+
props: {
|
|
56
|
+
isRoot: true,
|
|
57
|
+
},
|
|
58
|
+
select: {
|
|
59
|
+
_id: true,
|
|
60
|
+
paymentProviderCustomerId: true,
|
|
61
|
+
paymentProviderSubscriptionId: true,
|
|
62
|
+
paymentProviderMeteredSubscriptionId: true,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// refresh the subscription status. This is a hack to ensure that the subscription status is always up to date.
|
|
67
|
+
// This is because the subscription status can change at any time and we need to ensure that the subscription status is always up to date.
|
|
68
|
+
|
|
69
|
+
if (!project) {
|
|
70
|
+
throw new BadDataException("Project not found");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!project.paymentProviderCustomerId) {
|
|
74
|
+
throw new BadDataException("Payment provider customer id not found.");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let subscriptionState: SubscriptionStatus =
|
|
78
|
+
await BillingService.getSubscriptionStatus(
|
|
79
|
+
project.paymentProviderSubscriptionId as string,
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
let meteredSubscriptionState: SubscriptionStatus =
|
|
83
|
+
await BillingService.getSubscriptionStatus(
|
|
84
|
+
project.paymentProviderMeteredSubscriptionId as string,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// update the project.
|
|
88
|
+
|
|
89
|
+
await ProjectService.updateOneById({
|
|
90
|
+
id: project.id!,
|
|
91
|
+
data: {
|
|
92
|
+
paymentProviderSubscriptionStatus: subscriptionState,
|
|
93
|
+
paymentProviderMeteredSubscriptionStatus: meteredSubscriptionState,
|
|
94
|
+
},
|
|
95
|
+
props: {
|
|
96
|
+
isRoot: true,
|
|
97
|
+
ignoreHooks: true,
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (
|
|
102
|
+
meteredSubscriptionState === SubscriptionStatus.Canceled ||
|
|
103
|
+
subscriptionState === SubscriptionStatus.Canceled
|
|
104
|
+
) {
|
|
105
|
+
// check if all invoices are paid. If yes, then reactivate the subscription.
|
|
106
|
+
|
|
107
|
+
const invoices: Array<Invoice> = await BillingService.getInvoices(
|
|
108
|
+
project.paymentProviderCustomerId,
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
let allInvoicesPaid: boolean = true;
|
|
112
|
+
|
|
113
|
+
for (const invoice of invoices) {
|
|
114
|
+
if (
|
|
115
|
+
invoice.status === InvoiceStatus.Open ||
|
|
116
|
+
invoice.status === InvoiceStatus.Uncollectible
|
|
117
|
+
) {
|
|
118
|
+
allInvoicesPaid = false;
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (allInvoicesPaid) {
|
|
124
|
+
await ProjectService.reactiveSubscription(project.id!);
|
|
125
|
+
project = await ProjectService.findOneById({
|
|
126
|
+
id: data.projectId,
|
|
127
|
+
props: {
|
|
128
|
+
isRoot: true,
|
|
129
|
+
},
|
|
130
|
+
select: {
|
|
131
|
+
_id: true,
|
|
132
|
+
paymentProviderCustomerId: true,
|
|
133
|
+
paymentProviderSubscriptionId: true,
|
|
134
|
+
paymentProviderMeteredSubscriptionId: true,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
if (!project) {
|
|
139
|
+
throw new BadDataException("Project not found");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
subscriptionState = await BillingService.getSubscriptionStatus(
|
|
143
|
+
project.paymentProviderSubscriptionId as string,
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
meteredSubscriptionState = await BillingService.getSubscriptionStatus(
|
|
147
|
+
project.paymentProviderMeteredSubscriptionId as string,
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
await ProjectService.updateOneById({
|
|
151
|
+
id: project.id!,
|
|
152
|
+
data: {
|
|
153
|
+
paymentProviderSubscriptionStatus: subscriptionState,
|
|
154
|
+
paymentProviderMeteredSubscriptionStatus: meteredSubscriptionState,
|
|
155
|
+
},
|
|
156
|
+
props: {
|
|
157
|
+
isRoot: true,
|
|
158
|
+
ignoreHooks: true,
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (mutex) {
|
|
165
|
+
try {
|
|
166
|
+
await Semaphore.release(mutex);
|
|
167
|
+
logger.debug(
|
|
168
|
+
"Mutex released - " +
|
|
169
|
+
data.projectId.toString() +
|
|
170
|
+
" at " +
|
|
171
|
+
OneUptimeDate.getCurrentDateAsFormattedString(),
|
|
172
|
+
);
|
|
173
|
+
} catch (err) {
|
|
174
|
+
logger.debug(
|
|
175
|
+
"Mutex release failed - " +
|
|
176
|
+
data.projectId.toString() +
|
|
177
|
+
" at " +
|
|
178
|
+
OneUptimeDate.getCurrentDateAsFormattedString(),
|
|
179
|
+
);
|
|
180
|
+
logger.error(err);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
20
185
|
protected override async onBeforeFind(
|
|
21
186
|
findBy: FindBy<Model>,
|
|
22
187
|
): Promise<OnFind<Model>> {
|
|
@@ -37,6 +202,11 @@ export class Service extends DatabaseService<Model> {
|
|
|
37
202
|
},
|
|
38
203
|
});
|
|
39
204
|
|
|
205
|
+
// refresh the subscription status. This is a hack to ensure that the subscription status is always up to date.
|
|
206
|
+
// This is because the subscription status can change at any time and we need to ensure that the subscription status is always up to date.
|
|
207
|
+
|
|
208
|
+
await this.refreshSubscriptionStatus({ projectId: findBy.props.tenantId! });
|
|
209
|
+
|
|
40
210
|
if (!project) {
|
|
41
211
|
throw new BadDataException("Project not found");
|
|
42
212
|
}
|
|
@@ -28,61 +28,66 @@ export class Service extends DatabaseService<IncidentFeed> {
|
|
|
28
28
|
displayColor?: Color | undefined;
|
|
29
29
|
userId?: ObjectID | undefined;
|
|
30
30
|
postedAt?: Date | undefined;
|
|
31
|
-
}): Promise<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
data.displayColor
|
|
31
|
+
}): Promise<void> {
|
|
32
|
+
try {
|
|
33
|
+
logger.debug("IncidentFeedService.createIncidentFeed");
|
|
34
|
+
logger.debug(data);
|
|
35
|
+
|
|
36
|
+
const incidentFeed: IncidentFeed = new IncidentFeed();
|
|
37
|
+
|
|
38
|
+
if (!data.incidentId) {
|
|
39
|
+
throw new BadDataException("Incident ID is required");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!data.feedInfoInMarkdown) {
|
|
43
|
+
throw new BadDataException("Log in markdown is required");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!data.incidentFeedEventType) {
|
|
47
|
+
throw new BadDataException("Incident log event is required");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!data.projectId) {
|
|
51
|
+
throw new BadDataException("Project ID is required");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!data.displayColor) {
|
|
55
|
+
data.displayColor = Blue500;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
incidentFeed.displayColor = data.displayColor;
|
|
59
|
+
incidentFeed.incidentId = data.incidentId;
|
|
60
|
+
incidentFeed.feedInfoInMarkdown = data.feedInfoInMarkdown;
|
|
61
|
+
incidentFeed.incidentFeedEventType = data.incidentFeedEventType;
|
|
62
|
+
incidentFeed.projectId = data.projectId;
|
|
63
|
+
|
|
64
|
+
if (!data.postedAt) {
|
|
65
|
+
incidentFeed.postedAt = OneUptimeDate.getCurrentDate();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (data.userId) {
|
|
69
|
+
incidentFeed.userId = data.userId;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (data.moreInformationInMarkdown) {
|
|
73
|
+
incidentFeed.moreInformationInMarkdown = data.moreInformationInMarkdown;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const createdIncidentFeed: IncidentFeed = await this.create({
|
|
77
|
+
data: incidentFeed,
|
|
78
|
+
props: {
|
|
79
|
+
isRoot: true,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
logger.debug("Incident Feed created");
|
|
84
|
+
logger.debug(createdIncidentFeed);
|
|
85
|
+
} catch (e) {
|
|
86
|
+
logger.error("Error in creating incident feed");
|
|
87
|
+
logger.error(e);
|
|
88
|
+
|
|
89
|
+
// we dont throw this error as it is not a critical error
|
|
55
90
|
}
|
|
56
|
-
|
|
57
|
-
incidentFeed.displayColor = data.displayColor;
|
|
58
|
-
incidentFeed.incidentId = data.incidentId;
|
|
59
|
-
incidentFeed.feedInfoInMarkdown = data.feedInfoInMarkdown;
|
|
60
|
-
incidentFeed.incidentFeedEventType = data.incidentFeedEventType;
|
|
61
|
-
incidentFeed.projectId = data.projectId;
|
|
62
|
-
|
|
63
|
-
if (!data.postedAt) {
|
|
64
|
-
incidentFeed.postedAt = OneUptimeDate.getCurrentDate();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (data.userId) {
|
|
68
|
-
incidentFeed.userId = data.userId;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (data.moreInformationInMarkdown) {
|
|
72
|
-
incidentFeed.moreInformationInMarkdown = data.moreInformationInMarkdown;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const createdIncidentFeed: IncidentFeed = await this.create({
|
|
76
|
-
data: incidentFeed,
|
|
77
|
-
props: {
|
|
78
|
-
isRoot: true,
|
|
79
|
-
},
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
logger.debug("Incident Feed created");
|
|
83
|
-
logger.debug(createdIncidentFeed);
|
|
84
|
-
|
|
85
|
-
return createdIncidentFeed;
|
|
86
91
|
}
|
|
87
92
|
}
|
|
88
93
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import ObjectID from "../../Types/ObjectID";
|
|
2
2
|
import DatabaseService from "./DatabaseService";
|
|
3
3
|
import Model from "Common/Models/DatabaseModels/IncidentInternalNote";
|
|
4
|
-
import { OnCreate } from "../Types/Database/Hooks";
|
|
4
|
+
import { OnCreate, OnUpdate } from "../Types/Database/Hooks";
|
|
5
5
|
import IncidentFeedService from "./IncidentFeedService";
|
|
6
6
|
import { IncidentFeedEventType } from "../../Models/DatabaseModels/IncidentFeed";
|
|
7
7
|
import { Blue500 } from "../../Types/BrandColors";
|
|
8
|
+
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
8
9
|
|
|
9
10
|
export class Service extends DatabaseService<Model> {
|
|
10
11
|
public constructor() {
|
|
@@ -33,6 +34,50 @@ ${createdItem.note}
|
|
|
33
34
|
|
|
34
35
|
return createdItem;
|
|
35
36
|
}
|
|
37
|
+
|
|
38
|
+
public override async onUpdateSuccess(
|
|
39
|
+
onUpdate: OnUpdate<Model>,
|
|
40
|
+
_updatedItemIds: Array<ObjectID>,
|
|
41
|
+
): Promise<OnUpdate<Model>> {
|
|
42
|
+
if (onUpdate.updateBy.data.note) {
|
|
43
|
+
const updatedItems: Array<Model> = await this.findBy({
|
|
44
|
+
query: onUpdate.updateBy.query,
|
|
45
|
+
limit: LIMIT_PER_PROJECT,
|
|
46
|
+
skip: 0,
|
|
47
|
+
props: {
|
|
48
|
+
isRoot: true,
|
|
49
|
+
},
|
|
50
|
+
select: {
|
|
51
|
+
incidentId: true,
|
|
52
|
+
projectId: true,
|
|
53
|
+
note: true,
|
|
54
|
+
createdByUserId: true,
|
|
55
|
+
createdByUser: {
|
|
56
|
+
_id: true,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const userId: ObjectID | null | undefined =
|
|
62
|
+
onUpdate.updateBy.props.userId;
|
|
63
|
+
|
|
64
|
+
for (const updatedItem of updatedItems) {
|
|
65
|
+
await IncidentFeedService.createIncidentFeed({
|
|
66
|
+
incidentId: updatedItem.incidentId!,
|
|
67
|
+
projectId: updatedItem.projectId!,
|
|
68
|
+
incidentFeedEventType: IncidentFeedEventType.PrivateNote,
|
|
69
|
+
displayColor: Blue500,
|
|
70
|
+
userId: userId || undefined,
|
|
71
|
+
|
|
72
|
+
feedInfoInMarkdown: `**Updated Internal / Private Note**
|
|
73
|
+
|
|
74
|
+
${updatedItem.note}
|
|
75
|
+
`,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return onUpdate;
|
|
80
|
+
}
|
|
36
81
|
}
|
|
37
82
|
|
|
38
83
|
export default new Service();
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import CreateBy from "../Types/Database/CreateBy";
|
|
2
|
-
import { OnCreate } from "../Types/Database/Hooks";
|
|
2
|
+
import { OnCreate, OnUpdate } from "../Types/Database/Hooks";
|
|
3
3
|
import DatabaseService from "./DatabaseService";
|
|
4
4
|
import OneUptimeDate from "../../Types/Date";
|
|
5
5
|
import Model from "Common/Models/DatabaseModels/IncidentPublicNote";
|
|
6
6
|
import IncidentFeedService from "./IncidentFeedService";
|
|
7
7
|
import { IncidentFeedEventType } from "../../Models/DatabaseModels/IncidentFeed";
|
|
8
|
-
import { Indigo500 } from "../../Types/BrandColors";
|
|
8
|
+
import { Blue500, Indigo500 } from "../../Types/BrandColors";
|
|
9
9
|
import ObjectID from "../../Types/ObjectID";
|
|
10
|
+
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
10
11
|
|
|
11
12
|
export class Service extends DatabaseService<Model> {
|
|
12
13
|
public constructor() {
|
|
@@ -47,6 +48,50 @@ ${createdItem.note}
|
|
|
47
48
|
|
|
48
49
|
return createdItem;
|
|
49
50
|
}
|
|
51
|
+
|
|
52
|
+
public override async onUpdateSuccess(
|
|
53
|
+
onUpdate: OnUpdate<Model>,
|
|
54
|
+
_updatedItemIds: Array<ObjectID>,
|
|
55
|
+
): Promise<OnUpdate<Model>> {
|
|
56
|
+
if (onUpdate.updateBy.data.note) {
|
|
57
|
+
const updatedItems: Array<Model> = await this.findBy({
|
|
58
|
+
query: onUpdate.updateBy.query,
|
|
59
|
+
limit: LIMIT_PER_PROJECT,
|
|
60
|
+
skip: 0,
|
|
61
|
+
props: {
|
|
62
|
+
isRoot: true,
|
|
63
|
+
},
|
|
64
|
+
select: {
|
|
65
|
+
incidentId: true,
|
|
66
|
+
projectId: true,
|
|
67
|
+
note: true,
|
|
68
|
+
createdByUserId: true,
|
|
69
|
+
createdByUser: {
|
|
70
|
+
_id: true,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const userId: ObjectID | null | undefined =
|
|
76
|
+
onUpdate.updateBy.props.userId;
|
|
77
|
+
|
|
78
|
+
for (const updatedItem of updatedItems) {
|
|
79
|
+
await IncidentFeedService.createIncidentFeed({
|
|
80
|
+
incidentId: updatedItem.incidentId!,
|
|
81
|
+
projectId: updatedItem.projectId!,
|
|
82
|
+
incidentFeedEventType: IncidentFeedEventType.PublicNote,
|
|
83
|
+
displayColor: Blue500,
|
|
84
|
+
userId: userId || undefined,
|
|
85
|
+
|
|
86
|
+
feedInfoInMarkdown: `**Updated Public Note**
|
|
87
|
+
|
|
88
|
+
${updatedItem.note}
|
|
89
|
+
`,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return onUpdate;
|
|
94
|
+
}
|
|
50
95
|
}
|
|
51
96
|
|
|
52
97
|
export default new Service();
|
|
@@ -30,6 +30,7 @@ import OnCallDutyPolicyEscalationRuleTeam from "Common/Models/DatabaseModels/OnC
|
|
|
30
30
|
import OnCallDutyPolicyEscalationRuleUser from "Common/Models/DatabaseModels/OnCallDutyPolicyEscalationRuleUser";
|
|
31
31
|
import OnCallDutyPolicyExecutionLogTimeline from "Common/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline";
|
|
32
32
|
import User from "Common/Models/DatabaseModels/User";
|
|
33
|
+
import logger from "../Utils/Logger";
|
|
33
34
|
|
|
34
35
|
export class Service extends DatabaseService<Model> {
|
|
35
36
|
public async startRuleExecution(
|
|
@@ -37,12 +38,13 @@ export class Service extends DatabaseService<Model> {
|
|
|
37
38
|
options: {
|
|
38
39
|
projectId: ObjectID;
|
|
39
40
|
triggeredByIncidentId?: ObjectID | undefined;
|
|
41
|
+
triggeredByAlertId?: ObjectID | undefined;
|
|
40
42
|
userNotificationEventType: UserNotificationEventType;
|
|
41
43
|
onCallPolicyExecutionLogId: ObjectID;
|
|
42
44
|
onCallPolicyId: ObjectID;
|
|
43
45
|
},
|
|
44
46
|
): Promise<void> {
|
|
45
|
-
|
|
47
|
+
logger.debug(`Starting rule execution for ruleId: ${ruleId.toString()}`);
|
|
46
48
|
|
|
47
49
|
const rule: Model | null = await this.findOneById({
|
|
48
50
|
id: ruleId,
|
|
@@ -62,6 +64,8 @@ export class Service extends DatabaseService<Model> {
|
|
|
62
64
|
);
|
|
63
65
|
}
|
|
64
66
|
|
|
67
|
+
logger.debug(`Found rule: ${JSON.stringify(rule)}`);
|
|
68
|
+
|
|
65
69
|
await OnCallDutyPolicyExecutionLogService.updateOneById({
|
|
66
70
|
id: options.onCallPolicyExecutionLogId,
|
|
67
71
|
data: {
|
|
@@ -75,6 +79,8 @@ export class Service extends DatabaseService<Model> {
|
|
|
75
79
|
},
|
|
76
80
|
});
|
|
77
81
|
|
|
82
|
+
logger.debug(`Updated execution log for ruleId: ${ruleId.toString()}`);
|
|
83
|
+
|
|
78
84
|
type GetNewLogFunction = () => OnCallDutyPolicyExecutionLogTimeline;
|
|
79
85
|
|
|
80
86
|
const getNewLog: GetNewLogFunction =
|
|
@@ -92,6 +98,10 @@ export class Service extends DatabaseService<Model> {
|
|
|
92
98
|
log.triggeredByIncidentId = options.triggeredByIncidentId;
|
|
93
99
|
}
|
|
94
100
|
|
|
101
|
+
if (options.triggeredByAlertId) {
|
|
102
|
+
log.triggeredByAlertId = options.triggeredByAlertId;
|
|
103
|
+
}
|
|
104
|
+
|
|
95
105
|
return log;
|
|
96
106
|
};
|
|
97
107
|
|
|
@@ -105,6 +115,16 @@ export class Service extends DatabaseService<Model> {
|
|
|
105
115
|
);
|
|
106
116
|
}
|
|
107
117
|
|
|
118
|
+
if (
|
|
119
|
+
UserNotificationEventType.AlertCreated ===
|
|
120
|
+
options.userNotificationEventType &&
|
|
121
|
+
!options.triggeredByAlertId
|
|
122
|
+
) {
|
|
123
|
+
throw new BadDataException(
|
|
124
|
+
"triggeredByAlertId is required when userNotificationEventType is IncidentCreated",
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
108
128
|
const usersInRule: Array<OnCallDutyPolicyEscalationRuleUser> =
|
|
109
129
|
await OnCallDutyPolicyEscalationRuleUserService.findBy({
|
|
110
130
|
query: {
|
|
@@ -120,6 +140,8 @@ export class Service extends DatabaseService<Model> {
|
|
|
120
140
|
},
|
|
121
141
|
});
|
|
122
142
|
|
|
143
|
+
logger.debug(`Found users in rule: ${JSON.stringify(usersInRule)}`);
|
|
144
|
+
|
|
123
145
|
const teamsInRule: Array<OnCallDutyPolicyEscalationRuleTeam> =
|
|
124
146
|
await OnCallDutyPolicyEscalationRuleTeamService.findBy({
|
|
125
147
|
query: {
|
|
@@ -135,6 +157,8 @@ export class Service extends DatabaseService<Model> {
|
|
|
135
157
|
},
|
|
136
158
|
});
|
|
137
159
|
|
|
160
|
+
logger.debug(`Found teams in rule: ${JSON.stringify(teamsInRule)}`);
|
|
161
|
+
|
|
138
162
|
const schedulesInRule: Array<OnCallDutyPolicyEscalationRuleSchedule> =
|
|
139
163
|
await OnCallDutyPolicyEscalationRuleScheduleService.findBy({
|
|
140
164
|
query: {
|
|
@@ -150,7 +174,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
150
174
|
},
|
|
151
175
|
});
|
|
152
176
|
|
|
153
|
-
|
|
177
|
+
logger.debug(`Found schedules in rule: ${JSON.stringify(schedulesInRule)}`);
|
|
154
178
|
|
|
155
179
|
type StartUserNotificationRuleExecutionFunction = (
|
|
156
180
|
userId: ObjectID,
|
|
@@ -164,7 +188,9 @@ export class Service extends DatabaseService<Model> {
|
|
|
164
188
|
teamId: ObjectID | null,
|
|
165
189
|
scheduleId: ObjectID | null,
|
|
166
190
|
): Promise<void> => {
|
|
167
|
-
|
|
191
|
+
logger.debug(
|
|
192
|
+
`Starting notification rule execution for userId: ${userId.toString()}`,
|
|
193
|
+
);
|
|
168
194
|
let log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
|
169
195
|
log.statusMessage = "Sending notification to user.";
|
|
170
196
|
log.status = OnCallDutyExecutionLogTimelineStatus.Executing;
|
|
@@ -189,6 +215,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
189
215
|
{
|
|
190
216
|
userNotificationEventType: options.userNotificationEventType!,
|
|
191
217
|
triggeredByIncidentId: options.triggeredByIncidentId || undefined,
|
|
218
|
+
triggeredByAlertId: options.triggeredByAlertId || undefined,
|
|
192
219
|
onCallPolicyExecutionLogId: options.onCallPolicyExecutionLogId,
|
|
193
220
|
onCallPolicyId: options.onCallPolicyId,
|
|
194
221
|
onCallPolicyEscalationRuleId: ruleId,
|
|
@@ -220,7 +247,6 @@ export class Service extends DatabaseService<Model> {
|
|
|
220
247
|
null,
|
|
221
248
|
);
|
|
222
249
|
} else {
|
|
223
|
-
// no users in this rule. Skipping.
|
|
224
250
|
const log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
|
225
251
|
log.statusMessage =
|
|
226
252
|
"Skipped because notification sent to this user already.";
|
|
@@ -247,7 +273,6 @@ export class Service extends DatabaseService<Model> {
|
|
|
247
273
|
uniqueUserIds.push(userRule.userId!);
|
|
248
274
|
await startUserNotificationRuleExecution(userRule.userId!, null, null);
|
|
249
275
|
} else {
|
|
250
|
-
// no users in this rule. Skipping.
|
|
251
276
|
const log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
|
252
277
|
log.statusMessage =
|
|
253
278
|
"Skipped because notification sent to this user already.";
|
|
@@ -264,23 +289,16 @@ export class Service extends DatabaseService<Model> {
|
|
|
264
289
|
}
|
|
265
290
|
|
|
266
291
|
for (const scheduleRule of schedulesInRule) {
|
|
267
|
-
// get layers and users in this schedule and find a user to notify.
|
|
268
|
-
|
|
269
292
|
const userIdInSchedule: ObjectID | null =
|
|
270
293
|
await OnCallDutyPolicyScheduleService.getCurrentUserIdInSchedule(
|
|
271
294
|
scheduleRule.onCallDutyPolicyScheduleId!,
|
|
272
295
|
);
|
|
273
296
|
|
|
274
297
|
if (!userIdInSchedule) {
|
|
275
|
-
// no user active in this schedule. Skipping.
|
|
276
|
-
|
|
277
298
|
const log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
|
278
|
-
|
|
279
299
|
log.statusMessage =
|
|
280
300
|
"Skipped because no active users are found in this schedule.";
|
|
281
|
-
|
|
282
301
|
log.status = OnCallDutyExecutionLogTimelineStatus.Skipped;
|
|
283
|
-
|
|
284
302
|
log.onCallDutyScheduleId = scheduleRule.onCallDutyPolicyScheduleId!;
|
|
285
303
|
|
|
286
304
|
await OnCallDutyPolicyExecutionLogTimelineService.create({
|
|
@@ -305,7 +323,6 @@ export class Service extends DatabaseService<Model> {
|
|
|
305
323
|
scheduleRule.onCallDutyPolicyScheduleId!,
|
|
306
324
|
);
|
|
307
325
|
} else {
|
|
308
|
-
// no users in this rule. Skipping.
|
|
309
326
|
const log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
|
310
327
|
log.statusMessage =
|
|
311
328
|
"Skipped because notification sent to this user already.";
|
|
@@ -323,7 +340,6 @@ export class Service extends DatabaseService<Model> {
|
|
|
323
340
|
}
|
|
324
341
|
|
|
325
342
|
if (uniqueUserIds.length === 0) {
|
|
326
|
-
// no users in this rule. Skipping.
|
|
327
343
|
const log: OnCallDutyPolicyExecutionLogTimeline = getNewLog();
|
|
328
344
|
log.statusMessage = "Skipped because no users in this rule.";
|
|
329
345
|
log.status = OnCallDutyExecutionLogTimelineStatus.Skipped;
|
|
@@ -335,6 +351,8 @@ export class Service extends DatabaseService<Model> {
|
|
|
335
351
|
},
|
|
336
352
|
});
|
|
337
353
|
}
|
|
354
|
+
|
|
355
|
+
logger.debug(`Completed rule execution for ruleId: ${ruleId.toString()}`);
|
|
338
356
|
}
|
|
339
357
|
|
|
340
358
|
public constructor() {
|