@oneuptime/common 9.3.22 → 9.4.1
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/StatusPageDomain.ts +2 -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/1768825402472-MigrationName.ts +317 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Services/DatabaseService.ts +23 -1
- package/Server/Services/DomainService.ts +26 -15
- 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/MonitorProbeService.ts +96 -1
- 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/StartServer.ts +5 -0
- package/Types/Call/CallProvider.ts +99 -0
- package/Types/Call/CallProviderType.ts +6 -0
- package/Types/Domain.ts +23 -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/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/Icon/Icon.tsx +10 -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/StatusPageDomain.js +2 -0
- package/build/dist/Models/DatabaseModels/StatusPageDomain.js.map +1 -1
- 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/1768825402472-MigrationName.js +116 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768825402472-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +12 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DomainService.js +19 -8
- package/build/dist/Server/Services/DomainService.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/MonitorProbeService.js +77 -0
- package/build/dist/Server/Services/MonitorProbeService.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/StartServer.js +5 -0
- package/build/dist/Server/Utils/StartServer.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/Domain.js +23 -1
- package/build/dist/Types/Domain.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/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/Icon/Icon.js +4 -0
- package/build/dist/UI/Components/Icon/Icon.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
|
|
|
@@ -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({
|
|
@@ -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/Domain.ts
CHANGED
|
@@ -5,6 +5,29 @@ import { FindOperator } from "typeorm/find-options/FindOperator";
|
|
|
5
5
|
import Zod, { ZodSchema } from "../Utils/Schema/Zod";
|
|
6
6
|
|
|
7
7
|
export default class Domain extends DatabaseProperty {
|
|
8
|
+
/*
|
|
9
|
+
* Reserved TLDs for testing and documentation (per IANA)
|
|
10
|
+
* These domains can never have real DNS records, so they're safe for testing
|
|
11
|
+
*/
|
|
12
|
+
public static readonly TEST_DOMAIN_SUFFIXES: string[] = [
|
|
13
|
+
".example.com",
|
|
14
|
+
".example.org",
|
|
15
|
+
".example.net",
|
|
16
|
+
".test",
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Checks if a domain is a test/reserved domain that can skip DNS verification.
|
|
21
|
+
* Test domains include .example.com, .example.org, .example.net, and .test TLDs.
|
|
22
|
+
* These are reserved by IANA for documentation and testing purposes.
|
|
23
|
+
*/
|
|
24
|
+
public static isTestDomain(domain: string): boolean {
|
|
25
|
+
const domainLower: string = domain.toLowerCase().trim();
|
|
26
|
+
return Domain.TEST_DOMAIN_SUFFIXES.some((suffix: string) => {
|
|
27
|
+
return domainLower.endsWith(suffix);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
8
31
|
private _domain: string = "";
|
|
9
32
|
public get domain(): string {
|
|
10
33
|
return this._domain;
|
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,
|