insert call to db when making a call
This commit is contained in:
parent
f628addd80
commit
30d186d37d
@ -1,20 +1,68 @@
|
|||||||
import type { BlitzApiRequest, BlitzApiResponse } from "blitz";
|
import type { BlitzApiRequest, BlitzApiResponse } from "blitz";
|
||||||
import Twilio from "twilio";
|
import { getConfig } from "blitz";
|
||||||
|
import twilio from "twilio";
|
||||||
|
|
||||||
import db from "../../../../db";
|
import type { ApiError } from "../../../_types";
|
||||||
|
import db, { Direction } from "../../../../db";
|
||||||
|
import appLogger from "../../../../integrations/logger";
|
||||||
|
|
||||||
|
const { serverRuntimeConfig } = getConfig();
|
||||||
|
const logger = appLogger.child({ route: "/api/webhook/call" });
|
||||||
|
|
||||||
export default async function incomingCallHandler(req: BlitzApiRequest, res: BlitzApiResponse) {
|
export default async function incomingCallHandler(req: BlitzApiRequest, res: BlitzApiResponse) {
|
||||||
console.log("req.body", req.body);
|
console.log("req.body", req.body);
|
||||||
|
|
||||||
const isOutgoingCall = true;
|
const url = `https://${serverRuntimeConfig.app.baseUrl}/api/webhook/incoming-message`;
|
||||||
|
const twilioSignature = req.headers["X-Twilio-Signature"] || req.headers["x-twilio-signature"];
|
||||||
|
if (!twilioSignature || Array.isArray(twilioSignature)) {
|
||||||
|
const statusCode = 400;
|
||||||
|
const apiError: ApiError = {
|
||||||
|
statusCode,
|
||||||
|
errorMessage: "Invalid header X-Twilio-Signature",
|
||||||
|
};
|
||||||
|
logger.error(apiError);
|
||||||
|
|
||||||
|
res.status(statusCode).send(apiError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isOutgoingCall = req.body.From.startsWith("client:");
|
||||||
if (isOutgoingCall) {
|
if (isOutgoingCall) {
|
||||||
const recipient = req.body.To;
|
const recipient = req.body.To;
|
||||||
const organizationId = req.body.From.slice("client:".length).split("__")[0];
|
const organizationId = req.body.From.slice("client:".length).split("__")[0];
|
||||||
const phoneNumber = await db.phoneNumber.findFirst({
|
const phoneNumber = await db.phoneNumber.findFirst({
|
||||||
where: { organizationId },
|
where: { organizationId },
|
||||||
select: { number: true },
|
include: { organization: true },
|
||||||
});
|
});
|
||||||
const twiml = new Twilio.twiml.VoiceResponse();
|
if (
|
||||||
|
!phoneNumber ||
|
||||||
|
!phoneNumber.organization.twilioAuthToken ||
|
||||||
|
!twilio.validateRequest(phoneNumber.organization.twilioAuthToken, twilioSignature, url, req.body)
|
||||||
|
) {
|
||||||
|
const statusCode = 400;
|
||||||
|
const apiError: ApiError = {
|
||||||
|
statusCode,
|
||||||
|
errorMessage: "Invalid webhook",
|
||||||
|
};
|
||||||
|
logger.error(apiError);
|
||||||
|
|
||||||
|
res.status(statusCode).send(apiError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.phoneCall.create({
|
||||||
|
data: {
|
||||||
|
id: req.body.CallSid,
|
||||||
|
from: phoneNumber.number,
|
||||||
|
to: req.body.To,
|
||||||
|
status: req.body.CallStatus,
|
||||||
|
direction: Direction.Outbound,
|
||||||
|
duration: "", // TODO
|
||||||
|
organizationId: phoneNumber.organization.id,
|
||||||
|
phoneNumberId: phoneNumber.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const twiml = new twilio.twiml.VoiceResponse();
|
||||||
const dial = twiml.dial({
|
const dial = twiml.dial({
|
||||||
answerOnBridge: true,
|
answerOnBridge: true,
|
||||||
callerId: phoneNumber!.number,
|
callerId: phoneNumber!.number,
|
||||||
@ -24,8 +72,42 @@ export default async function incomingCallHandler(req: BlitzApiRequest, res: Bli
|
|||||||
|
|
||||||
res.setHeader("content-type", "text/xml");
|
res.setHeader("content-type", "text/xml");
|
||||||
return res.status(200).send(twiml.toString());
|
return res.status(200).send(twiml.toString());
|
||||||
|
} else {
|
||||||
|
const phoneNumbers = await db.phoneNumber.findMany({
|
||||||
|
where: { number: req.body.To },
|
||||||
|
include: { organization: true },
|
||||||
|
});
|
||||||
|
if (phoneNumbers.length === 0) {
|
||||||
|
// phone number is not registered by any organization
|
||||||
|
res.status(500).end();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const phoneNumber = phoneNumbers.find((phoneNumber) => {
|
||||||
|
// if multiple organizations have the same number
|
||||||
|
// find the organization currently using that phone number
|
||||||
|
// maybe we shouldn't let multiple organizations use the same phone number
|
||||||
|
const authToken = phoneNumber.organization.twilioAuthToken ?? "";
|
||||||
|
return twilio.validateRequest(authToken, twilioSignature, url, req.body);
|
||||||
|
});
|
||||||
|
if (!phoneNumber) {
|
||||||
|
const statusCode = 400;
|
||||||
|
const apiError: ApiError = {
|
||||||
|
statusCode,
|
||||||
|
errorMessage: "Invalid webhook",
|
||||||
|
};
|
||||||
|
logger.error(apiError);
|
||||||
|
|
||||||
|
res.status(statusCode).send(apiError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO send notification
|
||||||
|
// TODO db.phoneCall.create(...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO queue job to update duration when call ends
|
||||||
|
|
||||||
res.status(500).end();
|
res.status(500).end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user