@oneuptime/common 9.3.20 → 9.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/IncomingCallLog.ts +521 -0
- package/Models/DatabaseModels/IncomingCallLogItem.ts +463 -0
- package/Models/DatabaseModels/IncomingCallPolicy.ts +811 -0
- package/Models/DatabaseModels/IncomingCallPolicyEscalationRule.ts +597 -0
- package/Models/DatabaseModels/Index.ts +18 -0
- package/Models/DatabaseModels/ProjectSCIMLog.ts +422 -0
- package/Models/DatabaseModels/StatusPageSCIMLog.ts +455 -0
- package/Models/DatabaseModels/User.ts +0 -15
- package/Models/DatabaseModels/UserIncomingCallNumber.ts +296 -0
- package/Server/API/UserIncomingCallNumberAPI.ts +128 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1768583966447-MigrationName.ts +121 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1768647802022-RemoveAlertPhoneNumberFromUser.ts +22 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1768649699509-MigrationName.ts +787 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1768682071562-MigrationName.ts +29 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
- package/Server/Services/IncomingCallLogItemService.ts +10 -0
- package/Server/Services/IncomingCallLogService.ts +10 -0
- package/Server/Services/IncomingCallPolicyEscalationRuleService.ts +267 -0
- package/Server/Services/IncomingCallPolicyService.ts +10 -0
- package/Server/Services/Index.ts +7 -0
- package/Server/Services/ProjectSCIMLogService.ts +11 -0
- package/Server/Services/StatusPageSCIMLogService.ts +11 -0
- package/Server/Services/UserCallService.ts +31 -0
- package/Server/Services/UserIncomingCallNumberService.ts +258 -0
- package/Server/Services/UserSmsService.ts +31 -0
- package/Server/Utils/AnalyticsDatabase/Statement.ts +2 -2
- package/Server/Utils/StartServer.ts +5 -0
- package/Tests/UI/Components/Input.test.tsx +33 -0
- package/Types/Call/CallProvider.ts +99 -0
- package/Types/Call/CallProviderType.ts +6 -0
- package/Types/Date.ts +18 -0
- package/Types/Icon/IconProp.ts +1 -0
- package/Types/IncomingCall/IncomingCallStatus.ts +13 -0
- package/Types/Permission.ts +126 -0
- package/Types/Phone.ts +53 -4
- package/Types/SCIM/SCIMLogStatus.ts +7 -0
- package/UI/Components/Date/StartAndEndDate.tsx +35 -11
- package/UI/Components/Diagram/ConceptCards.tsx +74 -0
- package/UI/Components/Diagram/HorizontalStepChain.tsx +92 -0
- package/UI/Components/Diagram/Index.ts +11 -0
- package/UI/Components/Diagram/NumberedSteps.tsx +77 -0
- package/UI/Components/Diagram/VerticalFlowSteps.tsx +59 -0
- package/UI/Components/Filters/FilterViewer.tsx +7 -0
- package/UI/Components/Icon/Icon.tsx +10 -0
- package/UI/Components/Input/Input.tsx +7 -0
- package/UI/Components/SimpleLogViewer/SimpleLogViewer.tsx +86 -2
- package/build/dist/Models/DatabaseModels/IncomingCallLog.js +565 -0
- package/build/dist/Models/DatabaseModels/IncomingCallLog.js.map +1 -0
- package/build/dist/Models/DatabaseModels/IncomingCallLogItem.js +497 -0
- package/build/dist/Models/DatabaseModels/IncomingCallLogItem.js.map +1 -0
- package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js +840 -0
- package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js.map +1 -0
- package/build/dist/Models/DatabaseModels/IncomingCallPolicyEscalationRule.js +619 -0
- package/build/dist/Models/DatabaseModels/IncomingCallPolicyEscalationRule.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/ProjectSCIMLog.js +455 -0
- package/build/dist/Models/DatabaseModels/ProjectSCIMLog.js.map +1 -0
- package/build/dist/Models/DatabaseModels/StatusPageSCIMLog.js +486 -0
- package/build/dist/Models/DatabaseModels/StatusPageSCIMLog.js.map +1 -0
- package/build/dist/Models/DatabaseModels/User.js +0 -16
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js +315 -0
- package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js.map +1 -0
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js +72 -0
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768583966447-MigrationName.js +48 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768583966447-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768647802022-RemoveAlertPhoneNumberFromUser.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768647802022-RemoveAlertPhoneNumberFromUser.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768649699509-MigrationName.js +270 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768649699509-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768682071562-MigrationName.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768682071562-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/IncomingCallLogItemService.js +9 -0
- package/build/dist/Server/Services/IncomingCallLogItemService.js.map +1 -0
- package/build/dist/Server/Services/IncomingCallLogService.js +9 -0
- package/build/dist/Server/Services/IncomingCallLogService.js.map +1 -0
- package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js +197 -0
- package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js.map +1 -0
- package/build/dist/Server/Services/IncomingCallPolicyService.js +9 -0
- package/build/dist/Server/Services/IncomingCallPolicyService.js.map +1 -0
- package/build/dist/Server/Services/Index.js +6 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/ProjectSCIMLogService.js +10 -0
- package/build/dist/Server/Services/ProjectSCIMLogService.js.map +1 -0
- package/build/dist/Server/Services/StatusPageSCIMLogService.js +10 -0
- package/build/dist/Server/Services/StatusPageSCIMLogService.js.map +1 -0
- package/build/dist/Server/Services/UserCallService.js +21 -0
- package/build/dist/Server/Services/UserCallService.js.map +1 -1
- package/build/dist/Server/Services/UserIncomingCallNumberService.js +225 -0
- package/build/dist/Server/Services/UserIncomingCallNumberService.js.map +1 -0
- package/build/dist/Server/Services/UserSmsService.js +21 -0
- package/build/dist/Server/Services/UserSmsService.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +2 -2
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +5 -0
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Tests/UI/Components/Input.test.js +10 -0
- package/build/dist/Tests/UI/Components/Input.test.js.map +1 -1
- package/build/dist/Types/Call/CallProvider.js +2 -0
- package/build/dist/Types/Call/CallProvider.js.map +1 -0
- package/build/dist/Types/Call/CallProviderType.js +7 -0
- package/build/dist/Types/Call/CallProviderType.js.map +1 -0
- package/build/dist/Types/Date.js +17 -3
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Icon/IconProp.js +1 -0
- package/build/dist/Types/Icon/IconProp.js.map +1 -1
- package/build/dist/Types/IncomingCall/IncomingCallStatus.js +14 -0
- package/build/dist/Types/IncomingCall/IncomingCallStatus.js.map +1 -0
- package/build/dist/Types/Permission.js +104 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Phone.js +47 -3
- package/build/dist/Types/Phone.js.map +1 -1
- package/build/dist/Types/SCIM/SCIMLogStatus.js +8 -0
- package/build/dist/Types/SCIM/SCIMLogStatus.js.map +1 -0
- package/build/dist/UI/Components/Date/StartAndEndDate.js +13 -13
- package/build/dist/UI/Components/Date/StartAndEndDate.js.map +1 -1
- package/build/dist/UI/Components/Diagram/ConceptCards.js +30 -0
- package/build/dist/UI/Components/Diagram/ConceptCards.js.map +1 -0
- package/build/dist/UI/Components/Diagram/HorizontalStepChain.js +30 -0
- package/build/dist/UI/Components/Diagram/HorizontalStepChain.js.map +1 -0
- package/build/dist/UI/Components/Diagram/Index.js +5 -0
- package/build/dist/UI/Components/Diagram/Index.js.map +1 -0
- package/build/dist/UI/Components/Diagram/NumberedSteps.js +18 -0
- package/build/dist/UI/Components/Diagram/NumberedSteps.js.map +1 -0
- package/build/dist/UI/Components/Diagram/VerticalFlowSteps.js +16 -0
- package/build/dist/UI/Components/Diagram/VerticalFlowSteps.js.map +1 -0
- package/build/dist/UI/Components/Filters/FilterViewer.js +6 -5
- package/build/dist/UI/Components/Filters/FilterViewer.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +4 -0
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +4 -1
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/UI/Components/SimpleLogViewer/SimpleLogViewer.js +30 -1
- package/build/dist/UI/Components/SimpleLogViewer/SimpleLogViewer.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { IsBillingEnabled } from "../EnvironmentConfig";
|
|
2
|
+
import CreateBy from "../Types/Database/CreateBy";
|
|
3
|
+
import { OnCreate } from "../Types/Database/Hooks";
|
|
4
|
+
import logger from "../Utils/Logger";
|
|
5
|
+
import DatabaseService from "./DatabaseService";
|
|
6
|
+
import ProjectService from "./ProjectService";
|
|
7
|
+
import SmsService from "./SmsService";
|
|
8
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
9
|
+
import ObjectID from "../../Types/ObjectID";
|
|
10
|
+
import Text from "../../Types/Text";
|
|
11
|
+
import Project from "../../Models/DatabaseModels/Project";
|
|
12
|
+
import Model from "../../Models/DatabaseModels/UserIncomingCallNumber";
|
|
13
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
14
|
+
|
|
15
|
+
export class Service extends DatabaseService<Model> {
|
|
16
|
+
public constructor() {
|
|
17
|
+
super(Model);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@CaptureSpan()
|
|
21
|
+
protected override async onBeforeCreate(
|
|
22
|
+
createBy: CreateBy<Model>,
|
|
23
|
+
): Promise<OnCreate<Model>> {
|
|
24
|
+
// Check if user is trying to set isVerified to true
|
|
25
|
+
if (!createBy.props.isRoot && createBy.data.isVerified) {
|
|
26
|
+
throw new BadDataException("isVerified cannot be set to true");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Check if SMS notifications are enabled for this project
|
|
30
|
+
const project: Project | null = await ProjectService.findOneById({
|
|
31
|
+
id: createBy.data.projectId!,
|
|
32
|
+
props: {
|
|
33
|
+
isRoot: true,
|
|
34
|
+
},
|
|
35
|
+
select: {
|
|
36
|
+
enableSmsNotifications: true,
|
|
37
|
+
smsOrCallCurrentBalanceInUSDCents: true,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (!project) {
|
|
42
|
+
throw new BadDataException("Project not found");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!project.enableSmsNotifications) {
|
|
46
|
+
throw new BadDataException(
|
|
47
|
+
"SMS notifications are disabled for this project. Please enable them in Project Settings > Notification Settings.",
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (
|
|
52
|
+
(project.smsOrCallCurrentBalanceInUSDCents as number) <= 100 &&
|
|
53
|
+
IsBillingEnabled
|
|
54
|
+
) {
|
|
55
|
+
throw new BadDataException(
|
|
56
|
+
"Your SMS balance is low. Please recharge your SMS balance in Project Settings > Notification Settings.",
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Check if user already has a verified phone number for this project
|
|
61
|
+
const existingVerifiedNumber: Model | null = await this.findOneBy({
|
|
62
|
+
query: {
|
|
63
|
+
userId: createBy.data.userId!,
|
|
64
|
+
projectId: createBy.data.projectId!,
|
|
65
|
+
isVerified: true,
|
|
66
|
+
},
|
|
67
|
+
select: {
|
|
68
|
+
_id: true,
|
|
69
|
+
},
|
|
70
|
+
props: {
|
|
71
|
+
isRoot: true,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (existingVerifiedNumber) {
|
|
76
|
+
throw new BadDataException(
|
|
77
|
+
"You already have a verified phone number for this project. Please delete the existing one before adding a new one.",
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return { carryForward: null, createBy };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@CaptureSpan()
|
|
85
|
+
protected override async onCreateSuccess(
|
|
86
|
+
_onCreate: OnCreate<Model>,
|
|
87
|
+
createdItem: Model,
|
|
88
|
+
): Promise<Model> {
|
|
89
|
+
if (!createdItem.isVerified) {
|
|
90
|
+
this.sendVerificationCode(createdItem);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return createdItem;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@CaptureSpan()
|
|
97
|
+
public async resendVerificationCode(itemId: ObjectID): Promise<void> {
|
|
98
|
+
const item: Model | null = await this.findOneById({
|
|
99
|
+
id: itemId,
|
|
100
|
+
props: {
|
|
101
|
+
isRoot: true,
|
|
102
|
+
},
|
|
103
|
+
select: {
|
|
104
|
+
phone: true,
|
|
105
|
+
verificationCode: true,
|
|
106
|
+
isVerified: true,
|
|
107
|
+
projectId: true,
|
|
108
|
+
userId: true,
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
if (!item) {
|
|
113
|
+
throw new BadDataException(
|
|
114
|
+
"Item with ID " + itemId.toString() + " not found",
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (item.isVerified) {
|
|
119
|
+
throw new BadDataException("Phone Number already verified");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Check if SMS notifications are enabled for this project
|
|
123
|
+
const project: Project | null = await ProjectService.findOneById({
|
|
124
|
+
id: item.projectId!,
|
|
125
|
+
props: {
|
|
126
|
+
isRoot: true,
|
|
127
|
+
},
|
|
128
|
+
select: {
|
|
129
|
+
enableSmsNotifications: true,
|
|
130
|
+
smsOrCallCurrentBalanceInUSDCents: true,
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
if (!project) {
|
|
135
|
+
throw new BadDataException("Project not found");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (!project.enableSmsNotifications) {
|
|
139
|
+
throw new BadDataException(
|
|
140
|
+
"SMS notifications are disabled for this project. Please enable them in Project Settings > Notification Settings.",
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (
|
|
145
|
+
(project.smsOrCallCurrentBalanceInUSDCents as number) <= 100 &&
|
|
146
|
+
IsBillingEnabled
|
|
147
|
+
) {
|
|
148
|
+
throw new BadDataException(
|
|
149
|
+
"Your SMS balance is low. Please recharge your SMS balance in Project Settings > Notification Settings.",
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Generate new verification code
|
|
154
|
+
item.verificationCode = Text.generateRandomNumber(6);
|
|
155
|
+
|
|
156
|
+
await this.updateOneById({
|
|
157
|
+
id: item.id!,
|
|
158
|
+
props: {
|
|
159
|
+
isRoot: true,
|
|
160
|
+
},
|
|
161
|
+
data: {
|
|
162
|
+
verificationCode: item.verificationCode,
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
this.sendVerificationCode(item);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
public sendVerificationCode(item: Model): void {
|
|
170
|
+
// Send verification SMS
|
|
171
|
+
SmsService.sendSms(
|
|
172
|
+
{
|
|
173
|
+
to: item.phone!,
|
|
174
|
+
message:
|
|
175
|
+
"This message is from OneUptime. Your verification code for incoming call routing is " +
|
|
176
|
+
item.verificationCode,
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
projectId: item.projectId,
|
|
180
|
+
isSensitive: true,
|
|
181
|
+
userId: item.userId!,
|
|
182
|
+
},
|
|
183
|
+
).catch((err: Error) => {
|
|
184
|
+
logger.error(err);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@CaptureSpan()
|
|
189
|
+
public async verifyPhoneNumber(
|
|
190
|
+
itemId: ObjectID,
|
|
191
|
+
userId: ObjectID,
|
|
192
|
+
code: string,
|
|
193
|
+
): Promise<void> {
|
|
194
|
+
const item: Model | null = await this.findOneById({
|
|
195
|
+
id: itemId,
|
|
196
|
+
props: {
|
|
197
|
+
isRoot: true,
|
|
198
|
+
},
|
|
199
|
+
select: {
|
|
200
|
+
userId: true,
|
|
201
|
+
verificationCode: true,
|
|
202
|
+
isVerified: true,
|
|
203
|
+
projectId: true,
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
if (!item) {
|
|
208
|
+
throw new BadDataException("Item not found");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Check user ID
|
|
212
|
+
if (item.userId?.toString() !== userId.toString()) {
|
|
213
|
+
throw new BadDataException("Invalid user ID");
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (item.isVerified) {
|
|
217
|
+
throw new BadDataException("Phone number is already verified");
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (item.verificationCode !== code) {
|
|
221
|
+
throw new BadDataException("Invalid verification code");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Check if user already has a verified number for this project
|
|
225
|
+
const existingVerifiedNumber: Model | null = await this.findOneBy({
|
|
226
|
+
query: {
|
|
227
|
+
userId: item.userId!,
|
|
228
|
+
projectId: item.projectId!,
|
|
229
|
+
isVerified: true,
|
|
230
|
+
},
|
|
231
|
+
select: {
|
|
232
|
+
_id: true,
|
|
233
|
+
},
|
|
234
|
+
props: {
|
|
235
|
+
isRoot: true,
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
if (existingVerifiedNumber) {
|
|
240
|
+
throw new BadDataException(
|
|
241
|
+
"You already have a verified phone number for this project. Please delete the existing one before verifying a new one.",
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Mark as verified
|
|
246
|
+
await this.updateOneById({
|
|
247
|
+
id: itemId,
|
|
248
|
+
props: {
|
|
249
|
+
isRoot: true,
|
|
250
|
+
},
|
|
251
|
+
data: {
|
|
252
|
+
isVerified: true,
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export default new Service();
|
|
@@ -137,6 +137,37 @@ export class Service extends DatabaseService<Model> {
|
|
|
137
137
|
throw new BadDataException("Phone Number already verified");
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
// Check if SMS notifications are enabled for this project
|
|
141
|
+
const project: Project | null = await ProjectService.findOneById({
|
|
142
|
+
id: item.projectId!,
|
|
143
|
+
props: {
|
|
144
|
+
isRoot: true,
|
|
145
|
+
},
|
|
146
|
+
select: {
|
|
147
|
+
enableSmsNotifications: true,
|
|
148
|
+
smsOrCallCurrentBalanceInUSDCents: true,
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
if (!project) {
|
|
153
|
+
throw new BadDataException("Project not found");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (!project.enableSmsNotifications) {
|
|
157
|
+
throw new BadDataException(
|
|
158
|
+
"SMS notifications are disabled for this project. Please enable them in Project Settings > Notification Settings.",
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (
|
|
163
|
+
(project.smsOrCallCurrentBalanceInUSDCents as number) <= 100 &&
|
|
164
|
+
IsBillingEnabled
|
|
165
|
+
) {
|
|
166
|
+
throw new BadDataException(
|
|
167
|
+
"Your SMS balance is low. Please recharge your SMS balance in Project Settings > Notification Settings.",
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
140
171
|
// generate new verification code
|
|
141
172
|
item.verificationCode = Text.generateRandomNumber(6);
|
|
142
173
|
|
|
@@ -118,7 +118,7 @@ export class Statement implements BaseQueryParams {
|
|
|
118
118
|
finalValue = v.value.values;
|
|
119
119
|
}
|
|
120
120
|
} else if (v.value instanceof Date) {
|
|
121
|
-
finalValue = OneUptimeDate.
|
|
121
|
+
finalValue = OneUptimeDate.toClickhouseDateTime(v.value);
|
|
122
122
|
} else {
|
|
123
123
|
finalValue = v.value;
|
|
124
124
|
}
|
|
@@ -127,7 +127,7 @@ export class Statement implements BaseQueryParams {
|
|
|
127
127
|
|
|
128
128
|
if (typeof v !== "string" && v.type === TableColumnType.Date) {
|
|
129
129
|
finalValue = OneUptimeDate.fromString(finalValue as string);
|
|
130
|
-
finalValue = OneUptimeDate.
|
|
130
|
+
finalValue = OneUptimeDate.toClickhouseDateTime(finalValue);
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
return finalValue;
|
|
@@ -45,6 +45,11 @@ const app: ExpressApplication = Express.getExpressApp();
|
|
|
45
45
|
app.disable("x-powered-by");
|
|
46
46
|
app.set("port", process.env["PORT"]);
|
|
47
47
|
app.set("view engine", "ejs");
|
|
48
|
+
/*
|
|
49
|
+
* Enable trust proxy to correctly interpret X-Forwarded-* headers from reverse proxies
|
|
50
|
+
* This is needed for req.protocol, req.ip to be correct when behind nginx/load balancers
|
|
51
|
+
*/
|
|
52
|
+
app.set("trust proxy", true);
|
|
48
53
|
app.use(CookieParser());
|
|
49
54
|
|
|
50
55
|
const jsonBodyParserMiddleware: RequestHandler = ExpressJson({
|
|
@@ -207,6 +207,39 @@ describe("Input", () => {
|
|
|
207
207
|
);
|
|
208
208
|
});
|
|
209
209
|
|
|
210
|
+
test("sets step attribute to 1 for datetime-local when showSecondsForDateTime is true", () => {
|
|
211
|
+
const dataTestId: string = "testid";
|
|
212
|
+
|
|
213
|
+
render(
|
|
214
|
+
<Input
|
|
215
|
+
type={InputType.DATETIME_LOCAL}
|
|
216
|
+
showSecondsForDateTime={true}
|
|
217
|
+
dataTestId={dataTestId}
|
|
218
|
+
/>,
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
expect(screen.getByTestId<HTMLInputElement>(dataTestId)).toHaveAttribute(
|
|
222
|
+
"step",
|
|
223
|
+
"1",
|
|
224
|
+
);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test("does not set step attribute for datetime-local when showSecondsForDateTime is false", () => {
|
|
228
|
+
const dataTestId: string = "testid";
|
|
229
|
+
|
|
230
|
+
render(
|
|
231
|
+
<Input
|
|
232
|
+
type={InputType.DATETIME_LOCAL}
|
|
233
|
+
showSecondsForDateTime={false}
|
|
234
|
+
dataTestId={dataTestId}
|
|
235
|
+
/>,
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
expect(
|
|
239
|
+
screen.getByTestId<HTMLInputElement>(dataTestId),
|
|
240
|
+
).not.toHaveAttribute("step");
|
|
241
|
+
});
|
|
242
|
+
|
|
210
243
|
test("uses YYYY-MM-DD for date type", () => {
|
|
211
244
|
const date: string = "2023-04-22T00:00:00";
|
|
212
245
|
const dataTestId: string = "testid";
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { JSONObject } from "../JSON";
|
|
2
|
+
|
|
3
|
+
// Phone number from provider search
|
|
4
|
+
export interface AvailablePhoneNumber {
|
|
5
|
+
phoneNumber: string; // "+14155550123"
|
|
6
|
+
friendlyName: string; // "(415) 555-0123"
|
|
7
|
+
locality?: string; // "San Francisco"
|
|
8
|
+
region?: string; // "CA"
|
|
9
|
+
country: string; // "US"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Purchased phone number details
|
|
13
|
+
export interface PurchasedPhoneNumber {
|
|
14
|
+
phoneNumberId: string; // Provider's ID (e.g., Twilio SID)
|
|
15
|
+
phoneNumber: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Owned phone number (already purchased in Twilio account)
|
|
19
|
+
export interface OwnedPhoneNumber {
|
|
20
|
+
phoneNumberId: string; // Provider's ID (e.g., Twilio SID)
|
|
21
|
+
phoneNumber: string; // "+14155550123"
|
|
22
|
+
friendlyName: string; // "(415) 555-0123"
|
|
23
|
+
voiceUrl?: string | undefined; // Current webhook URL configured
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Search options for available numbers
|
|
27
|
+
export interface SearchNumberOptions {
|
|
28
|
+
countryCode: string;
|
|
29
|
+
areaCode?: string;
|
|
30
|
+
contains?: string;
|
|
31
|
+
limit?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Options for dial operation
|
|
35
|
+
export interface DialOptions {
|
|
36
|
+
toPhoneNumber: string;
|
|
37
|
+
fromPhoneNumber: string;
|
|
38
|
+
timeoutSeconds: number;
|
|
39
|
+
statusCallbackUrl: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Parsed incoming call data from webhook
|
|
43
|
+
export interface IncomingCallData {
|
|
44
|
+
callId: string; // Provider's call ID
|
|
45
|
+
callerPhoneNumber: string;
|
|
46
|
+
calledPhoneNumber: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Parsed dial status data from webhook
|
|
50
|
+
export interface DialStatusData {
|
|
51
|
+
callId: string;
|
|
52
|
+
dialStatus: "completed" | "busy" | "no-answer" | "failed" | "canceled";
|
|
53
|
+
dialDurationSeconds?: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Express Request type for webhook parsing
|
|
57
|
+
export interface WebhookRequest {
|
|
58
|
+
body: JSONObject;
|
|
59
|
+
headers: { [key: string]: string | string[] | undefined };
|
|
60
|
+
originalUrl: string;
|
|
61
|
+
url: string;
|
|
62
|
+
protocol: string;
|
|
63
|
+
get: (name: string) => string | undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Call provider interface - all providers must implement this
|
|
67
|
+
export interface ICallProvider {
|
|
68
|
+
// Phone number management
|
|
69
|
+
searchAvailableNumbers(
|
|
70
|
+
options: SearchNumberOptions,
|
|
71
|
+
): Promise<AvailablePhoneNumber[]>;
|
|
72
|
+
listOwnedNumbers(): Promise<OwnedPhoneNumber[]>;
|
|
73
|
+
purchaseNumber(
|
|
74
|
+
phoneNumber: string,
|
|
75
|
+
webhookUrl: string,
|
|
76
|
+
): Promise<PurchasedPhoneNumber>;
|
|
77
|
+
assignExistingNumber(
|
|
78
|
+
phoneNumberId: string,
|
|
79
|
+
webhookUrl: string,
|
|
80
|
+
): Promise<PurchasedPhoneNumber>;
|
|
81
|
+
releaseNumber(phoneNumberId: string): Promise<void>;
|
|
82
|
+
updateWebhookUrl(phoneNumberId: string, webhookUrl: string): Promise<void>;
|
|
83
|
+
|
|
84
|
+
// Voice response generation (provider-specific markup)
|
|
85
|
+
generateGreetingResponse(message: string): string;
|
|
86
|
+
generateDialResponse(options: DialOptions): string;
|
|
87
|
+
generateHangupResponse(message?: string): string;
|
|
88
|
+
generateEscalationResponse(
|
|
89
|
+
message: string,
|
|
90
|
+
nextDialOptions: DialOptions,
|
|
91
|
+
): string;
|
|
92
|
+
|
|
93
|
+
// Webhook parsing
|
|
94
|
+
parseIncomingCallWebhook(request: WebhookRequest): IncomingCallData;
|
|
95
|
+
parseDialStatusWebhook(request: WebhookRequest): DialStatusData;
|
|
96
|
+
|
|
97
|
+
// Webhook signature validation
|
|
98
|
+
validateWebhookSignature(request: WebhookRequest, signature: string): boolean;
|
|
99
|
+
}
|
package/Types/Date.ts
CHANGED
|
@@ -970,11 +970,13 @@ export default class OneUptimeDate {
|
|
|
970
970
|
public static getDateAsUserFriendlyLocalFormattedString(
|
|
971
971
|
date: string | Date,
|
|
972
972
|
onlyShowDate?: boolean,
|
|
973
|
+
showSeconds?: boolean,
|
|
973
974
|
): string {
|
|
974
975
|
return this.getDateAsLocalFormattedString(
|
|
975
976
|
date,
|
|
976
977
|
onlyShowDate,
|
|
977
978
|
this.getUserPrefers12HourFormat(),
|
|
979
|
+
showSeconds,
|
|
978
980
|
);
|
|
979
981
|
}
|
|
980
982
|
|
|
@@ -1363,6 +1365,7 @@ export default class OneUptimeDate {
|
|
|
1363
1365
|
date: string | Date,
|
|
1364
1366
|
onlyShowDate?: boolean,
|
|
1365
1367
|
use12HourFormat?: boolean,
|
|
1368
|
+
showSeconds?: boolean,
|
|
1366
1369
|
): string {
|
|
1367
1370
|
date = this.fromString(date);
|
|
1368
1371
|
|
|
@@ -1372,6 +1375,14 @@ export default class OneUptimeDate {
|
|
|
1372
1375
|
formatstring = "MMM DD YYYY, hh:mm A";
|
|
1373
1376
|
}
|
|
1374
1377
|
|
|
1378
|
+
if (showSeconds) {
|
|
1379
|
+
if (use12HourFormat) {
|
|
1380
|
+
formatstring = "MMM DD YYYY, hh:mm:ss A";
|
|
1381
|
+
} else {
|
|
1382
|
+
formatstring = "MMM DD YYYY, HH:mm:ss";
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1375
1386
|
if (onlyShowDate) {
|
|
1376
1387
|
formatstring = "MMM DD, YYYY";
|
|
1377
1388
|
}
|
|
@@ -1502,6 +1513,13 @@ export default class OneUptimeDate {
|
|
|
1502
1513
|
return moment(date).format("YYYY-MM-DD HH:mm:ss");
|
|
1503
1514
|
}
|
|
1504
1515
|
|
|
1516
|
+
public static resetSecondsAndMilliseconds(date: Date): Date {
|
|
1517
|
+
date = this.fromString(date);
|
|
1518
|
+
date.setSeconds(0);
|
|
1519
|
+
date.setMilliseconds(0);
|
|
1520
|
+
return date;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1505
1523
|
public static toClickhouseDateTime(date: Date | string): string {
|
|
1506
1524
|
const parsedDate: Date = this.fromString(date);
|
|
1507
1525
|
return moment(parsedDate).utc().format("YYYY-MM-DD HH:mm:ss");
|
package/Types/Icon/IconProp.ts
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
enum IncomingCallStatus {
|
|
2
|
+
Initiated = "Initiated",
|
|
3
|
+
Ringing = "Ringing",
|
|
4
|
+
Connected = "Connected",
|
|
5
|
+
Escalated = "Escalated",
|
|
6
|
+
NoAnswer = "NoAnswer",
|
|
7
|
+
Failed = "Failed",
|
|
8
|
+
Completed = "Completed",
|
|
9
|
+
CallerHungUp = "CallerHungUp",
|
|
10
|
+
Busy = "Busy",
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default IncomingCallStatus;
|
package/Types/Permission.ts
CHANGED
|
@@ -164,6 +164,9 @@ enum Permission {
|
|
|
164
164
|
ReadWorkspaceNotificationLog = "ReadWorkspaceNotificationLog",
|
|
165
165
|
ReadLlmLog = "ReadLlmLog",
|
|
166
166
|
|
|
167
|
+
ReadProjectSCIMLog = "ReadProjectSCIMLog",
|
|
168
|
+
ReadStatusPageSCIMLog = "ReadStatusPageSCIMLog",
|
|
169
|
+
|
|
167
170
|
CreateIncidentOwnerTeam = "CreateIncidentOwnerTeam",
|
|
168
171
|
DeleteIncidentOwnerTeam = "DeleteIncidentOwnerTeam",
|
|
169
172
|
EditIncidentOwnerTeam = "EditIncidentOwnerTeam",
|
|
@@ -598,6 +601,24 @@ enum Permission {
|
|
|
598
601
|
DeleteProjectOnCallDutyPolicyEscalationRuleTeam = "DeleteProjectOnCallDutyPolicyEscalationRuleTeam",
|
|
599
602
|
ReadProjectOnCallDutyPolicyEscalationRuleTeam = "ReadProjectOnCallDutyPolicyEscalationRuleTeam",
|
|
600
603
|
|
|
604
|
+
// Incoming Call Policy Permissions
|
|
605
|
+
CreateProjectIncomingCallPolicy = "CreateProjectIncomingCallPolicy",
|
|
606
|
+
EditProjectIncomingCallPolicy = "EditProjectIncomingCallPolicy",
|
|
607
|
+
DeleteProjectIncomingCallPolicy = "DeleteProjectIncomingCallPolicy",
|
|
608
|
+
ReadProjectIncomingCallPolicy = "ReadProjectIncomingCallPolicy",
|
|
609
|
+
|
|
610
|
+
// Incoming Call Policy Escalation Rule Permissions
|
|
611
|
+
CreateProjectIncomingCallPolicyEscalationRule = "CreateProjectIncomingCallPolicyEscalationRule",
|
|
612
|
+
EditProjectIncomingCallPolicyEscalationRule = "EditProjectIncomingCallPolicyEscalationRule",
|
|
613
|
+
DeleteProjectIncomingCallPolicyEscalationRule = "DeleteProjectIncomingCallPolicyEscalationRule",
|
|
614
|
+
ReadProjectIncomingCallPolicyEscalationRule = "ReadProjectIncomingCallPolicyEscalationRule",
|
|
615
|
+
|
|
616
|
+
// Incoming Call Log Permissions
|
|
617
|
+
ReadProjectIncomingCallLog = "ReadProjectIncomingCallLog",
|
|
618
|
+
|
|
619
|
+
// Incoming Call Log Item Permissions
|
|
620
|
+
ReadProjectIncomingCallLogItem = "ReadProjectIncomingCallLogItem",
|
|
621
|
+
|
|
601
622
|
// Project SMTP Config (Team Permission)
|
|
602
623
|
CreateProjectSMTPConfig = "CreateProjectSMTPConfig",
|
|
603
624
|
EditProjectSMTPConfig = "EditProjectSMTPConfig",
|
|
@@ -1373,6 +1394,23 @@ export class PermissionHelper {
|
|
|
1373
1394
|
isAccessControlPermission: false,
|
|
1374
1395
|
},
|
|
1375
1396
|
|
|
1397
|
+
{
|
|
1398
|
+
permission: Permission.ReadProjectSCIMLog,
|
|
1399
|
+
title: "Read Project SCIM Log",
|
|
1400
|
+
description:
|
|
1401
|
+
"This permission can read SCIM provisioning logs of the project.",
|
|
1402
|
+
isAssignableToTenant: true,
|
|
1403
|
+
isAccessControlPermission: false,
|
|
1404
|
+
},
|
|
1405
|
+
{
|
|
1406
|
+
permission: Permission.ReadStatusPageSCIMLog,
|
|
1407
|
+
title: "Read Status Page SCIM Log",
|
|
1408
|
+
description:
|
|
1409
|
+
"This permission can read SCIM provisioning logs of status pages in the project.",
|
|
1410
|
+
isAssignableToTenant: true,
|
|
1411
|
+
isAccessControlPermission: false,
|
|
1412
|
+
},
|
|
1413
|
+
|
|
1376
1414
|
{
|
|
1377
1415
|
permission: Permission.CreateProjectMonitorStatus,
|
|
1378
1416
|
title: "Create Monitor Status",
|
|
@@ -2475,6 +2513,94 @@ export class PermissionHelper {
|
|
|
2475
2513
|
isAccessControlPermission: false,
|
|
2476
2514
|
},
|
|
2477
2515
|
|
|
2516
|
+
// Incoming Call Policy Permissions
|
|
2517
|
+
{
|
|
2518
|
+
permission: Permission.CreateProjectIncomingCallPolicy,
|
|
2519
|
+
title: "Create Incoming Call Policy",
|
|
2520
|
+
description:
|
|
2521
|
+
"This permission can create incoming call policies for this project.",
|
|
2522
|
+
isAssignableToTenant: true,
|
|
2523
|
+
isAccessControlPermission: false,
|
|
2524
|
+
},
|
|
2525
|
+
{
|
|
2526
|
+
permission: Permission.DeleteProjectIncomingCallPolicy,
|
|
2527
|
+
title: "Delete Incoming Call Policy",
|
|
2528
|
+
description:
|
|
2529
|
+
"This permission can delete incoming call policies of this project.",
|
|
2530
|
+
isAssignableToTenant: true,
|
|
2531
|
+
isAccessControlPermission: false,
|
|
2532
|
+
},
|
|
2533
|
+
{
|
|
2534
|
+
permission: Permission.EditProjectIncomingCallPolicy,
|
|
2535
|
+
title: "Edit Incoming Call Policy",
|
|
2536
|
+
description:
|
|
2537
|
+
"This permission can edit incoming call policies of this project.",
|
|
2538
|
+
isAssignableToTenant: true,
|
|
2539
|
+
isAccessControlPermission: false,
|
|
2540
|
+
},
|
|
2541
|
+
{
|
|
2542
|
+
permission: Permission.ReadProjectIncomingCallPolicy,
|
|
2543
|
+
title: "Read Incoming Call Policy",
|
|
2544
|
+
description:
|
|
2545
|
+
"This permission can read incoming call policies of this project.",
|
|
2546
|
+
isAssignableToTenant: true,
|
|
2547
|
+
isAccessControlPermission: false,
|
|
2548
|
+
},
|
|
2549
|
+
|
|
2550
|
+
// Incoming Call Policy Escalation Rule Permissions
|
|
2551
|
+
{
|
|
2552
|
+
permission: Permission.CreateProjectIncomingCallPolicyEscalationRule,
|
|
2553
|
+
title: "Create Incoming Call Policy Escalation Rule",
|
|
2554
|
+
description:
|
|
2555
|
+
"This permission can create incoming call policy escalation rules for this project.",
|
|
2556
|
+
isAssignableToTenant: true,
|
|
2557
|
+
isAccessControlPermission: false,
|
|
2558
|
+
},
|
|
2559
|
+
{
|
|
2560
|
+
permission: Permission.DeleteProjectIncomingCallPolicyEscalationRule,
|
|
2561
|
+
title: "Delete Incoming Call Policy Escalation Rule",
|
|
2562
|
+
description:
|
|
2563
|
+
"This permission can delete incoming call policy escalation rules of this project.",
|
|
2564
|
+
isAssignableToTenant: true,
|
|
2565
|
+
isAccessControlPermission: false,
|
|
2566
|
+
},
|
|
2567
|
+
{
|
|
2568
|
+
permission: Permission.EditProjectIncomingCallPolicyEscalationRule,
|
|
2569
|
+
title: "Edit Incoming Call Policy Escalation Rule",
|
|
2570
|
+
description:
|
|
2571
|
+
"This permission can edit incoming call policy escalation rules of this project.",
|
|
2572
|
+
isAssignableToTenant: true,
|
|
2573
|
+
isAccessControlPermission: false,
|
|
2574
|
+
},
|
|
2575
|
+
{
|
|
2576
|
+
permission: Permission.ReadProjectIncomingCallPolicyEscalationRule,
|
|
2577
|
+
title: "Read Incoming Call Policy Escalation Rule",
|
|
2578
|
+
description:
|
|
2579
|
+
"This permission can read incoming call policy escalation rules of this project.",
|
|
2580
|
+
isAssignableToTenant: true,
|
|
2581
|
+
isAccessControlPermission: false,
|
|
2582
|
+
},
|
|
2583
|
+
|
|
2584
|
+
// Incoming Call Log Permissions
|
|
2585
|
+
{
|
|
2586
|
+
permission: Permission.ReadProjectIncomingCallLog,
|
|
2587
|
+
title: "Read Incoming Call Log",
|
|
2588
|
+
description:
|
|
2589
|
+
"This permission can read incoming call logs of this project.",
|
|
2590
|
+
isAssignableToTenant: true,
|
|
2591
|
+
isAccessControlPermission: false,
|
|
2592
|
+
},
|
|
2593
|
+
|
|
2594
|
+
// Incoming Call Log Item Permissions
|
|
2595
|
+
{
|
|
2596
|
+
permission: Permission.ReadProjectIncomingCallLogItem,
|
|
2597
|
+
title: "Read Incoming Call Log Item",
|
|
2598
|
+
description:
|
|
2599
|
+
"This permission can read incoming call log items of this project.",
|
|
2600
|
+
isAssignableToTenant: true,
|
|
2601
|
+
isAccessControlPermission: false,
|
|
2602
|
+
},
|
|
2603
|
+
|
|
2478
2604
|
{
|
|
2479
2605
|
permission:
|
|
2480
2606
|
Permission.CreateProjectOnCallDutyPolicyEscalationRuleSchedule,
|