mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
feat: update Twilio configuration to include primary and secondary phone numbers
This commit is contained in:
@@ -72,9 +72,9 @@ const Settings: FunctionComponent = (): ReactElement => {
|
||||
},
|
||||
{
|
||||
field: {
|
||||
twilioPhoneNumber: true,
|
||||
twilioPrimaryPhoneNumber: true,
|
||||
},
|
||||
title: "Twilio Phone Number",
|
||||
title: "Primary Twilio Phone Number",
|
||||
fieldType: FormFieldSchemaType.Phone,
|
||||
required: true,
|
||||
description: "You can find this in your Twilio console.",
|
||||
@@ -83,6 +83,19 @@ const Settings: FunctionComponent = (): ReactElement => {
|
||||
minLength: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: {
|
||||
twilioSecondaryPhoneNumbers: true,
|
||||
},
|
||||
title: "Secondary Twilio Phone Number",
|
||||
fieldType: FormFieldSchemaType.LongText,
|
||||
required: true,
|
||||
description: "If you have bought more phone numbers from Twilio for specific countries, you can add them here.",
|
||||
placeholder: "+1234567890, +4444444444",
|
||||
validation: {
|
||||
minLength: 2,
|
||||
},
|
||||
},
|
||||
]}
|
||||
modelDetailProps={{
|
||||
modelType: GlobalConfig,
|
||||
@@ -97,12 +110,20 @@ const Settings: FunctionComponent = (): ReactElement => {
|
||||
},
|
||||
{
|
||||
field: {
|
||||
twilioPhoneNumber: true,
|
||||
twilioPrimaryPhoneNumber: true,
|
||||
},
|
||||
title: "Twilio Phone Number",
|
||||
title: "Primary Twilio Phone Number",
|
||||
fieldType: FieldType.Phone,
|
||||
placeholder: "None",
|
||||
},
|
||||
{
|
||||
field: {
|
||||
twilioSecondaryPhoneNumbers: true,
|
||||
},
|
||||
title: "Secondary Twilio Phone Numbers",
|
||||
fieldType: FieldType.LongText,
|
||||
placeholder: "None",
|
||||
},
|
||||
],
|
||||
modelId: ObjectID.getZeroObjectID(),
|
||||
}}
|
||||
|
||||
@@ -54,7 +54,8 @@ router.post("/test", async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
_id: true,
|
||||
twilioAccountSID: true,
|
||||
twilioAuthToken: true,
|
||||
twilioPhoneNumber: true,
|
||||
twilioPrimaryPhoneNumber: true,
|
||||
twilioSecondaryPhoneNumbers: true,
|
||||
projectId: true,
|
||||
},
|
||||
});
|
||||
@@ -97,11 +98,11 @@ router.post("/test", async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
);
|
||||
}
|
||||
|
||||
if (!config.twilioPhoneNumber) {
|
||||
if (!config.twilioPrimaryPhoneNumber) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException("twilioPhoneNumber is required"),
|
||||
new BadDataException("twilioPrimaryPhoneNumber is required"),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,8 @@ router.post("/test", async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
_id: true,
|
||||
twilioAccountSID: true,
|
||||
twilioAuthToken: true,
|
||||
twilioPhoneNumber: true,
|
||||
twilioPrimaryPhoneNumber: true,
|
||||
twilioSecondaryPhoneNumbers: true,
|
||||
projectId: true,
|
||||
},
|
||||
});
|
||||
@@ -96,11 +97,11 @@ router.post("/test", async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
);
|
||||
}
|
||||
|
||||
if (!config.twilioPhoneNumber) {
|
||||
if (!config.twilioPrimaryPhoneNumber) {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new BadDataException("twilioPhoneNumber is required"),
|
||||
new BadDataException("twilioPrimaryPhoneNumber is required"),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import GlobalConfigService from "Common/Server/Services/GlobalConfigService";
|
||||
import GlobalConfig, {
|
||||
EmailServerType,
|
||||
} from "Common/Models/DatabaseModels/GlobalConfig";
|
||||
import Phone from "Common/Types/Phone";
|
||||
|
||||
export const InternalSmtpPassword: string =
|
||||
process.env["INTERNAL_SMTP_PASSWORD"] || "";
|
||||
@@ -196,7 +197,8 @@ export const getTwilioConfig: GetTwilioConfigFunction =
|
||||
select: {
|
||||
twilioAccountSID: true,
|
||||
twilioAuthToken: true,
|
||||
twilioPhoneNumber: true,
|
||||
twilioPrimaryPhoneNumber: true,
|
||||
twilioSecondaryPhoneNumbers: true,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -207,7 +209,7 @@ export const getTwilioConfig: GetTwilioConfigFunction =
|
||||
if (
|
||||
!globalConfig.twilioAccountSID ||
|
||||
!globalConfig.twilioAuthToken ||
|
||||
!globalConfig.twilioPhoneNumber
|
||||
!globalConfig.twilioPrimaryPhoneNumber
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
@@ -215,7 +217,10 @@ export const getTwilioConfig: GetTwilioConfigFunction =
|
||||
return {
|
||||
accountSid: globalConfig.twilioAccountSID,
|
||||
authToken: globalConfig.twilioAuthToken,
|
||||
phoneNumber: globalConfig.twilioPhoneNumber,
|
||||
primaryPhoneNumber: globalConfig.twilioPrimaryPhoneNumber,
|
||||
secondaryPhoneNumbers: globalConfig.twilioSecondaryPhoneNumbers && globalConfig.twilioSecondaryPhoneNumbers.length > 0 ? globalConfig.twilioSecondaryPhoneNumbers.split(",").map((phoneNumber: string)=>{
|
||||
return new Phone(phoneNumber.trim());
|
||||
}) : [],
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -232,8 +232,8 @@ export default class GlobalConfig extends GlobalConfigModel {
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.Phone,
|
||||
title: "Twilio Phone Number",
|
||||
description: "Phone Number for your Twilio account",
|
||||
title: "Twilio Primary Phone Number",
|
||||
description: "Secondary Phone Number for your Twilio account",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.Phone,
|
||||
@@ -242,7 +242,26 @@ export default class GlobalConfig extends GlobalConfigModel {
|
||||
unique: true,
|
||||
transformer: Phone.getDatabaseTransformer(),
|
||||
})
|
||||
public twilioPhoneNumber?: Phone = undefined;
|
||||
public twilioPrimaryPhoneNumber?: Phone = undefined;
|
||||
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
read: [],
|
||||
update: [],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.LongText,
|
||||
title: "Twilio Secondary Phone Numbers",
|
||||
description: "Secondary Phone Number for your Twilio account",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.LongText,
|
||||
length: ColumnLength.LongText,
|
||||
nullable: true,
|
||||
unique: false,
|
||||
})
|
||||
public twilioSecondaryPhoneNumbers?: string = undefined; // phone numbers seperated by comma
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
|
||||
@@ -426,5 +426,37 @@ export default class ProjectCallSMSConfig extends BaseModel {
|
||||
unique: true,
|
||||
transformer: Phone.getDatabaseTransformer(),
|
||||
})
|
||||
public twilioPhoneNumber?: Phone = undefined;
|
||||
public twilioPrimaryPhoneNumber?: Phone = undefined;
|
||||
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.CreateProjectCallSMSConfig,
|
||||
],
|
||||
read: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.ProjectMember,
|
||||
Permission.ReadProjectCallSMSConfig,
|
||||
],
|
||||
update: [
|
||||
Permission.ProjectOwner,
|
||||
Permission.ProjectAdmin,
|
||||
Permission.EditProjectCallSMSConfig,
|
||||
],
|
||||
})
|
||||
@TableColumn({
|
||||
type: TableColumnType.LongText,
|
||||
title: "Twilio Secondary Phone Numbers",
|
||||
description: "Secondary Phone Number for your Twilio account",
|
||||
})
|
||||
@Column({
|
||||
type: ColumnType.LongText,
|
||||
length: ColumnLength.LongText,
|
||||
nullable: true,
|
||||
unique: false,
|
||||
})
|
||||
public twilioSecondaryPhoneNumbers?: string = undefined; // phone numbers seperated by comma
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import DatabaseService from "./DatabaseService";
|
||||
import TwilioConfig from "../../Types/CallAndSMS/TwilioConfig";
|
||||
import BadDataException from "../../Types/Exception/BadDataException";
|
||||
import Model from "Common/Models/DatabaseModels/ProjectCallSMSConfig";
|
||||
import Phone from "../../Types/Phone";
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor() {
|
||||
@@ -25,7 +26,7 @@ export class Service extends DatabaseService<Model> {
|
||||
);
|
||||
}
|
||||
|
||||
if (!projectCallSmsConfig.twilioPhoneNumber) {
|
||||
if (!projectCallSmsConfig.twilioPrimaryPhoneNumber) {
|
||||
throw new BadDataException(
|
||||
"Project Call and SMS Config twilio phone number is not set",
|
||||
);
|
||||
@@ -40,7 +41,10 @@ export class Service extends DatabaseService<Model> {
|
||||
return {
|
||||
accountSid: projectCallSmsConfig.twilioAccountSID.toString(),
|
||||
authToken: projectCallSmsConfig.twilioAuthToken.toString(),
|
||||
phoneNumber: projectCallSmsConfig.twilioPhoneNumber,
|
||||
primaryPhoneNumber: projectCallSmsConfig.twilioPrimaryPhoneNumber,
|
||||
secondaryPhoneNumbers: projectCallSmsConfig.twilioSecondaryPhoneNumbers && projectCallSmsConfig.twilioSecondaryPhoneNumbers.length > 0 ? projectCallSmsConfig.twilioSecondaryPhoneNumbers.split(",").map((phone: string)=>{
|
||||
return new Phone(phone);
|
||||
}) : [],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +262,9 @@ export class Service extends DatabaseService<Model> {
|
||||
_id: true,
|
||||
twilioAccountSID: true,
|
||||
twilioAuthToken: true,
|
||||
twilioPhoneNumber: true,
|
||||
twilioPrimaryPhoneNumber: true,
|
||||
twilioSecondaryPhoneNumbers: true,
|
||||
|
||||
},
|
||||
},
|
||||
props: {
|
||||
@@ -795,7 +797,8 @@ export class Service extends DatabaseService<Model> {
|
||||
_id: true,
|
||||
twilioAccountSID: true,
|
||||
twilioAuthToken: true,
|
||||
twilioPhoneNumber: true,
|
||||
twilioPrimaryPhoneNumber: true,
|
||||
twilioSecondaryPhoneNumbers: true,
|
||||
},
|
||||
subscriberTimezones: true,
|
||||
reportDataInDays: true,
|
||||
|
||||
@@ -3,5 +3,6 @@ import Phone from "../Phone";
|
||||
export default interface TwilioConfig {
|
||||
accountSid: string;
|
||||
authToken: string;
|
||||
phoneNumber: Phone;
|
||||
primaryPhoneNumber: Phone;
|
||||
secondaryPhoneNumbers: Phone[];
|
||||
}
|
||||
|
||||
@@ -170,9 +170,9 @@ const CustomCallSMSTable: FunctionComponent = (): ReactElement => {
|
||||
},
|
||||
{
|
||||
field: {
|
||||
twilioPhoneNumber: true,
|
||||
twilioPrimaryPhoneNumber: true,
|
||||
},
|
||||
title: "Twilio Phone Number",
|
||||
title: "Twilio Primary Phone Number",
|
||||
stepId: "twilio-info",
|
||||
fieldType: FormFieldSchemaType.Phone,
|
||||
required: true,
|
||||
@@ -182,6 +182,23 @@ const CustomCallSMSTable: FunctionComponent = (): ReactElement => {
|
||||
minLength: 2,
|
||||
},
|
||||
},
|
||||
|
||||
// add twilioSecondaryPhoneNumbers
|
||||
{
|
||||
field: {
|
||||
twilioSecondaryPhoneNumbers: true,
|
||||
},
|
||||
title: "Twilio Secondary Phone Numbers",
|
||||
stepId: "twilio-info",
|
||||
fieldType: FormFieldSchemaType.LongText,
|
||||
required: false,
|
||||
description:
|
||||
"If you have multiple phone numbers, add them here. These numbers will be used to send SMS and make calls if the country code matches instead of primary phone number. If the country code does not match, then primary phone number will be used.",
|
||||
placeholder: "+441234567890, +461234567890",
|
||||
validation: {
|
||||
minLength: 2,
|
||||
},
|
||||
},
|
||||
]}
|
||||
showRefreshButton={true}
|
||||
viewPageRoute={Navigation.getCurrentRoute()}
|
||||
@@ -208,10 +225,17 @@ const CustomCallSMSTable: FunctionComponent = (): ReactElement => {
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Twilio Phone Number",
|
||||
title: "Twilio Primary Phone Number",
|
||||
type: FieldType.Phone,
|
||||
field: {
|
||||
twilioPhoneNumber: true,
|
||||
twilioPrimaryPhoneNumber: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Twilio Secondary Primary Phone Numbers",
|
||||
type: FieldType.LongText,
|
||||
field: {
|
||||
twilioSecondaryPhoneNumbers: true,
|
||||
},
|
||||
},
|
||||
]}
|
||||
@@ -240,11 +264,18 @@ const CustomCallSMSTable: FunctionComponent = (): ReactElement => {
|
||||
},
|
||||
{
|
||||
field: {
|
||||
twilioPhoneNumber: true,
|
||||
twilioPrimaryPhoneNumber: true,
|
||||
},
|
||||
title: "Twilio Phone Number",
|
||||
type: FieldType.Phone,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
twilioSecondaryPhoneNumbers: true,
|
||||
},
|
||||
title: "Twilio Phone Number",
|
||||
type: FieldType.LongText,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -284,19 +315,19 @@ const CustomCallSMSTable: FunctionComponent = (): ReactElement => {
|
||||
const response:
|
||||
| HTTPResponse<EmptyResponseData>
|
||||
| HTTPErrorResponse = await API.post(
|
||||
URL.fromString(NOTIFICATION_URL.toString()).addRoute(
|
||||
`/sms/test`,
|
||||
),
|
||||
URL.fromString(NOTIFICATION_URL.toString()).addRoute(
|
||||
`/sms/test`,
|
||||
),
|
||||
|
||||
{
|
||||
toPhone: values["toPhone"],
|
||||
callSMSConfigId: new ObjectID(
|
||||
currentCallSMSTestConfig["_id"]
|
||||
? currentCallSMSTestConfig["_id"].toString()
|
||||
: "",
|
||||
).toString(),
|
||||
},
|
||||
);
|
||||
{
|
||||
toPhone: values["toPhone"],
|
||||
callSMSConfigId: new ObjectID(
|
||||
currentCallSMSTestConfig["_id"]
|
||||
? currentCallSMSTestConfig["_id"].toString()
|
||||
: "",
|
||||
).toString(),
|
||||
},
|
||||
);
|
||||
if (response.isSuccess()) {
|
||||
setIsCallSMSTestLoading(false);
|
||||
setShowSMSTestModal(false);
|
||||
@@ -321,7 +352,7 @@ const CustomCallSMSTable: FunctionComponent = (): ReactElement => {
|
||||
title={`SMS Sent`}
|
||||
error={
|
||||
error ===
|
||||
"Error connecting to server. Please try again in few minutes."
|
||||
"Error connecting to server. Please try again in few minutes."
|
||||
? "Request timed out. Please check your twilio credentials and make sure they are correct."
|
||||
: error
|
||||
}
|
||||
@@ -373,19 +404,19 @@ const CustomCallSMSTable: FunctionComponent = (): ReactElement => {
|
||||
const response:
|
||||
| HTTPResponse<EmptyResponseData>
|
||||
| HTTPErrorResponse = await API.post(
|
||||
URL.fromString(NOTIFICATION_URL.toString()).addRoute(
|
||||
`/call/test`,
|
||||
),
|
||||
URL.fromString(NOTIFICATION_URL.toString()).addRoute(
|
||||
`/call/test`,
|
||||
),
|
||||
|
||||
{
|
||||
toPhone: values["toPhone"],
|
||||
callSMSConfigId: new ObjectID(
|
||||
currentCallSMSTestConfig["_id"]
|
||||
? currentCallSMSTestConfig["_id"].toString()
|
||||
: "",
|
||||
).toString(),
|
||||
},
|
||||
);
|
||||
{
|
||||
toPhone: values["toPhone"],
|
||||
callSMSConfigId: new ObjectID(
|
||||
currentCallSMSTestConfig["_id"]
|
||||
? currentCallSMSTestConfig["_id"].toString()
|
||||
: "",
|
||||
).toString(),
|
||||
},
|
||||
);
|
||||
if (response.isSuccess()) {
|
||||
setIsCallSMSTestLoading(false);
|
||||
setShowCallTestModal(false);
|
||||
@@ -410,7 +441,7 @@ const CustomCallSMSTable: FunctionComponent = (): ReactElement => {
|
||||
title={`Call Sent`}
|
||||
error={
|
||||
error ===
|
||||
"Error connecting to server. Please try again in few minutes."
|
||||
"Error connecting to server. Please try again in few minutes."
|
||||
? "Request timed out. Please check your twilio credentials and make sure they are correct."
|
||||
: error
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ export default class UpdateGlobalConfigFromEnv extends DataMigrationBase {
|
||||
|
||||
twilioAccountSID: process.env["TWILIO_ACCOUNT_SID"] || "",
|
||||
twilioAuthToken: process.env["TWILIO_AUTH_TOKEN"] || "",
|
||||
twilioPhoneNumber: process.env["TWILIO_PHONE_NUMBER"] || "",
|
||||
twilioPrimaryPhoneNumber: process.env["TWILIO_PHONE_NUMBER"] || "",
|
||||
|
||||
// Update SMTP
|
||||
smtpUsername: process.env["SMTP_USERNAME"] || "",
|
||||
|
||||
Reference in New Issue
Block a user