use twilio api key/secret instead of authToken
This commit is contained in:
parent
835fcaffcc
commit
6f672bfeb2
@ -1,8 +1,8 @@
|
|||||||
import { Queue } from "quirrel/blitz";
|
import { Queue } from "quirrel/blitz";
|
||||||
import twilio from "twilio";
|
|
||||||
|
|
||||||
import db from "../../../../db";
|
import db from "../../../../db";
|
||||||
import insertMessagesQueue from "./insert-messages";
|
import insertMessagesQueue from "./insert-messages";
|
||||||
|
import getTwilioClient from "../../../../integrations/twilio";
|
||||||
|
|
||||||
type Payload = {
|
type Payload = {
|
||||||
organizationId: string;
|
organizationId: string;
|
||||||
@ -19,13 +19,10 @@ const fetchMessagesQueue = Queue<Payload>("api/queue/fetch-messages", async ({ o
|
|||||||
}
|
}
|
||||||
|
|
||||||
const organization = phoneNumber.organization;
|
const organization = phoneNumber.organization;
|
||||||
if (!organization.twilioAccountSid || !organization.twilioAuthToken) {
|
const twilioClient = getTwilioClient(organization);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [sent, received] = await Promise.all([
|
const [sent, received] = await Promise.all([
|
||||||
twilio(organization.twilioAccountSid, organization.twilioAuthToken).messages.list({ from: phoneNumber.number }),
|
twilioClient.messages.list({ from: phoneNumber.number }),
|
||||||
twilio(organization.twilioAccountSid, organization.twilioAuthToken).messages.list({ to: phoneNumber.number }),
|
twilioClient.messages.list({ to: phoneNumber.number }),
|
||||||
]);
|
]);
|
||||||
const messagesSent = sent.filter((message) => message.direction.startsWith("outbound"));
|
const messagesSent = sent.filter((message) => message.direction.startsWith("outbound"));
|
||||||
const messagesReceived = received.filter((message) => message.direction === "inbound");
|
const messagesReceived = received.filter((message) => message.direction === "inbound");
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { Queue } from "quirrel/blitz";
|
import { Queue } from "quirrel/blitz";
|
||||||
import type { MessageInstance } from "twilio/lib/rest/api/v2010/account/message";
|
import type { MessageInstance } from "twilio/lib/rest/api/v2010/account/message";
|
||||||
import twilio from "twilio";
|
|
||||||
|
|
||||||
import db, { Direction, MessageStatus } from "../../../../db";
|
import db, { Direction, MessageStatus } from "../../../../db";
|
||||||
import { encrypt } from "../../../../db/_encryption";
|
import { encrypt } from "../../../../db/_encryption";
|
||||||
import notifyIncomingMessageQueue from "./notify-incoming-message";
|
import notifyIncomingMessageQueue from "./notify-incoming-message";
|
||||||
|
import getTwilioClient from "../../../../integrations/twilio";
|
||||||
|
|
||||||
type Payload = {
|
type Payload = {
|
||||||
organizationId: string;
|
organizationId: string;
|
||||||
@ -18,13 +18,12 @@ const insertIncomingMessageQueue = Queue<Payload>(
|
|||||||
const organization = await db.organization.findFirst({
|
const organization = await db.organization.findFirst({
|
||||||
where: { id: organizationId },
|
where: { id: organizationId },
|
||||||
});
|
});
|
||||||
if (!organization || !organization.twilioAccountSid || !organization.twilioAuthToken) {
|
if (!organization) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const message = await twilio(organization.twilioAccountSid, organization.twilioAuthToken)
|
const twilioClient = getTwilioClient(organization);
|
||||||
.messages.get(messageSid)
|
const message = await twilioClient.messages.get(messageSid).fetch();
|
||||||
.fetch();
|
|
||||||
await db.message.create({
|
await db.message.create({
|
||||||
data: {
|
data: {
|
||||||
organizationId,
|
organizationId,
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { getConfig } from "blitz";
|
import { getConfig } from "blitz";
|
||||||
import { Queue } from "quirrel/blitz";
|
import { Queue } from "quirrel/blitz";
|
||||||
import type { MessageInstance } from "twilio/lib/rest/api/v2010/account/message";
|
import type { MessageInstance } from "twilio/lib/rest/api/v2010/account/message";
|
||||||
import twilio from "twilio";
|
|
||||||
import webpush, { PushSubscription, WebPushError } from "web-push";
|
import webpush, { PushSubscription, WebPushError } from "web-push";
|
||||||
|
|
||||||
import db from "../../../../db";
|
import db from "../../../../db";
|
||||||
import appLogger from "../../../../integrations/logger";
|
import appLogger from "../../../../integrations/logger";
|
||||||
|
import getTwilioClient from "../../../../integrations/twilio";
|
||||||
|
|
||||||
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig();
|
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig();
|
||||||
const logger = appLogger.child({ queue: "notify-incoming-message" });
|
const logger = appLogger.child({ queue: "notify-incoming-message" });
|
||||||
@ -28,15 +28,12 @@ const notifyIncomingMessageQueue = Queue<Payload>(
|
|||||||
const organization = await db.organization.findFirst({
|
const organization = await db.organization.findFirst({
|
||||||
where: { id: organizationId },
|
where: { id: organizationId },
|
||||||
});
|
});
|
||||||
if (!organization || !organization.twilioAccountSid || !organization.twilioAuthToken) {
|
const twilioClient = getTwilioClient(organization);
|
||||||
return;
|
const message = await twilioClient.messages.get(messageSid).fetch();
|
||||||
}
|
|
||||||
|
|
||||||
const message = await twilio(organization.twilioAccountSid, organization.twilioAuthToken)
|
|
||||||
.messages.get(messageSid)
|
|
||||||
.fetch();
|
|
||||||
const notification = { message: `${message.from} - ${message.body}` };
|
const notification = { message: `${message.from} - ${message.body}` };
|
||||||
const subscriptions = await db.notificationSubscription.findMany({ where: { organizationId, phoneNumberId } });
|
const subscriptions = await db.notificationSubscription.findMany({
|
||||||
|
where: { organizationId, phoneNumberId },
|
||||||
|
});
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
subscriptions.map(async (subscription) => {
|
subscriptions.map(async (subscription) => {
|
||||||
const webPushSubscription: PushSubscription = {
|
const webPushSubscription: PushSubscription = {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Queue } from "quirrel/blitz";
|
import { Queue } from "quirrel/blitz";
|
||||||
import twilio from "twilio";
|
|
||||||
|
|
||||||
import db, { MessageStatus } from "../../../../db";
|
import db, { MessageStatus } from "../../../../db";
|
||||||
|
import getTwilioClient from "../../../../integrations/twilio";
|
||||||
|
|
||||||
type Payload = {
|
type Payload = {
|
||||||
id: string;
|
id: string;
|
||||||
@ -19,12 +19,13 @@ const sendMessageQueue = Queue<Payload>(
|
|||||||
include: { phoneNumbers: true },
|
include: { phoneNumbers: true },
|
||||||
});
|
});
|
||||||
const phoneNumber = organization?.phoneNumbers.find((phoneNumber) => phoneNumber.id === phoneNumberId);
|
const phoneNumber = organization?.phoneNumbers.find((phoneNumber) => phoneNumber.id === phoneNumberId);
|
||||||
if (!organization || !organization.twilioAccountSid || !organization.twilioAuthToken || !phoneNumber) {
|
if (!organization || !phoneNumber) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const twilioClient = getTwilioClient(organization);
|
||||||
try {
|
try {
|
||||||
const message = await twilio(organization.twilioAccountSid, organization.twilioAuthToken).messages.create({
|
const message = await twilioClient.messages.create({
|
||||||
body: content,
|
body: content,
|
||||||
to,
|
to,
|
||||||
from: phoneNumber.number,
|
from: phoneNumber.number,
|
||||||
|
@ -6,7 +6,6 @@ import type { ApiError } from "../../../api/_types";
|
|||||||
import appLogger from "../../../../integrations/logger";
|
import appLogger from "../../../../integrations/logger";
|
||||||
import db from "../../../../db";
|
import db from "../../../../db";
|
||||||
import insertIncomingMessageQueue from "../queue/insert-incoming-message";
|
import insertIncomingMessageQueue from "../queue/insert-incoming-message";
|
||||||
import notifyIncomingMessageQueue from "../queue/notify-incoming-message";
|
|
||||||
|
|
||||||
const logger = appLogger.child({ route: "/api/webhook/incoming-message" });
|
const logger = appLogger.child({ route: "/api/webhook/incoming-message" });
|
||||||
const { serverRuntimeConfig } = getConfig();
|
const { serverRuntimeConfig } = getConfig();
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { NotFoundError, resolver } from "blitz";
|
import { NotFoundError, resolver } from "blitz";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import twilio from "twilio";
|
|
||||||
|
|
||||||
import db, { Direction, MessageStatus } from "../../../db";
|
import db, { Direction, MessageStatus } from "../../../db";
|
||||||
import { encrypt } from "../../../db/_encryption";
|
import { encrypt } from "../../../db/_encryption";
|
||||||
import sendMessageQueue from "../../messages/api/queue/send-message";
|
import sendMessageQueue from "../../messages/api/queue/send-message";
|
||||||
import appLogger from "../../../integrations/logger";
|
import appLogger from "../../../integrations/logger";
|
||||||
|
import getTwilioClient from "../../../integrations/twilio";
|
||||||
|
|
||||||
const logger = appLogger.child({ mutation: "send-message" });
|
const logger = appLogger.child({ mutation: "send-message" });
|
||||||
|
|
||||||
@ -23,12 +23,10 @@ export default resolver.pipe(resolver.zod(Body), resolver.authorize(), async ({
|
|||||||
if (!organization) {
|
if (!organization) {
|
||||||
throw new NotFoundError();
|
throw new NotFoundError();
|
||||||
}
|
}
|
||||||
if (!organization.twilioAccountSid || !organization.twilioAuthToken) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const twilioClient = getTwilioClient(organization);
|
||||||
try {
|
try {
|
||||||
await twilio(organization.twilioAccountSid, organization.twilioAuthToken).lookups.v1.phoneNumbers(to).fetch();
|
await twilioClient.lookups.v1.phoneNumbers(to).fetch();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
return;
|
return;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { resolver } from "blitz";
|
import { resolver } from "blitz";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import twilio from "twilio";
|
|
||||||
|
|
||||||
import db from "../../../db";
|
import db from "../../../db";
|
||||||
import getCurrentUser from "../../users/queries/get-current-user";
|
import getCurrentUser from "../../users/queries/get-current-user";
|
||||||
import fetchMessagesQueue from "../../messages/api/queue/fetch-messages";
|
import fetchMessagesQueue from "../../messages/api/queue/fetch-messages";
|
||||||
import fetchCallsQueue from "../../phone-calls/api/queue/fetch-calls";
|
import fetchCallsQueue from "../../phone-calls/api/queue/fetch-calls";
|
||||||
import setTwilioWebhooks from "../api/queue/set-twilio-webhooks";
|
import setTwilioWebhooks from "../api/queue/set-twilio-webhooks";
|
||||||
|
import getTwilioClient from "../../../integrations/twilio";
|
||||||
|
|
||||||
const Body = z.object({
|
const Body = z.object({
|
||||||
phoneNumberSid: z.string(),
|
phoneNumberSid: z.string(),
|
||||||
@ -15,14 +15,12 @@ const Body = z.object({
|
|||||||
export default resolver.pipe(resolver.zod(Body), resolver.authorize(), async ({ phoneNumberSid }, context) => {
|
export default resolver.pipe(resolver.zod(Body), resolver.authorize(), async ({ phoneNumberSid }, context) => {
|
||||||
const user = await getCurrentUser(null, context);
|
const user = await getCurrentUser(null, context);
|
||||||
const organization = user?.memberships[0]!.organization;
|
const organization = user?.memberships[0]!.organization;
|
||||||
if (!user || !organization || !organization.twilioAccountSid || !organization.twilioAuthToken) {
|
if (!user || !organization) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const phoneNumbers = await twilio(
|
const twilioClient = getTwilioClient(organization);
|
||||||
organization.twilioAccountSid,
|
const phoneNumbers = await twilioClient.incomingPhoneNumbers.list();
|
||||||
organization.twilioAuthToken,
|
|
||||||
).incomingPhoneNumbers.list();
|
|
||||||
const phoneNumber = phoneNumbers.find((phoneNumber) => phoneNumber.sid === phoneNumberSid)!;
|
const phoneNumber = phoneNumbers.find((phoneNumber) => phoneNumber.sid === phoneNumberSid)!;
|
||||||
const organizationId = organization.id;
|
const organizationId = organization.id;
|
||||||
await db.phoneNumber.create({
|
await db.phoneNumber.create({
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import type { BlitzPage, GetServerSideProps } from "blitz";
|
import type { BlitzPage, GetServerSideProps } from "blitz";
|
||||||
import { Routes, getSession, useRouter, useMutation } from "blitz";
|
import { Routes, getSession, useRouter, useMutation } from "blitz";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import twilio from "twilio";
|
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
|
||||||
import db from "../../../../db";
|
import db from "../../../../db";
|
||||||
import OnboardingLayout from "../../components/onboarding-layout";
|
import OnboardingLayout from "../../components/onboarding-layout";
|
||||||
import setPhoneNumber from "../../mutations/set-phone-number";
|
import setPhoneNumber from "../../mutations/set-phone-number";
|
||||||
|
import getTwilioClient from "../../../../integrations/twilio";
|
||||||
|
|
||||||
type PhoneNumber = {
|
type PhoneNumber = {
|
||||||
phoneNumber: string;
|
phoneNumber: string;
|
||||||
@ -130,10 +130,8 @@ export const getServerSideProps: GetServerSideProps<Props> = async ({ req, res }
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const incomingPhoneNumbers = await twilio(
|
const twilioClient = getTwilioClient(organization);
|
||||||
organization.twilioAccountSid,
|
const incomingPhoneNumbers = await twilioClient.incomingPhoneNumbers.list();
|
||||||
organization.twilioAuthToken,
|
|
||||||
).incomingPhoneNumbers.list();
|
|
||||||
const phoneNumbers = incomingPhoneNumbers.map(({ phoneNumber, sid }) => ({ phoneNumber, sid }));
|
const phoneNumbers = incomingPhoneNumbers.map(({ phoneNumber, sid }) => ({ phoneNumber, sid }));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { Queue } from "quirrel/blitz";
|
import { Queue } from "quirrel/blitz";
|
||||||
import twilio from "twilio";
|
|
||||||
|
|
||||||
import db from "../../../../db";
|
import db from "../../../../db";
|
||||||
import insertCallsQueue from "./insert-calls";
|
import insertCallsQueue from "./insert-calls";
|
||||||
|
import getTwilioClient from "../../../../integrations/twilio";
|
||||||
|
|
||||||
type Payload = {
|
type Payload = {
|
||||||
organizationId: string;
|
organizationId: string;
|
||||||
@ -19,17 +19,10 @@ const fetchCallsQueue = Queue<Payload>("api/queue/fetch-calls", async ({ organiz
|
|||||||
}
|
}
|
||||||
|
|
||||||
const organization = phoneNumber.organization;
|
const organization = phoneNumber.organization;
|
||||||
if (!organization.twilioAccountSid || !organization.twilioAuthToken) {
|
const twilioClient = getTwilioClient(organization);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [callsSent, callsReceived] = await Promise.all([
|
const [callsSent, callsReceived] = await Promise.all([
|
||||||
twilio(organization.twilioAccountSid, organization.twilioAuthToken).calls.list({
|
twilioClient.calls.list({ from: phoneNumber.number }),
|
||||||
from: phoneNumber.number,
|
twilioClient.calls.list({ to: phoneNumber.number }),
|
||||||
}),
|
|
||||||
twilio(organization.twilioAccountSid, organization.twilioAuthToken).calls.list({
|
|
||||||
to: phoneNumber.number,
|
|
||||||
}),
|
|
||||||
]);
|
]);
|
||||||
const calls = [...callsSent, ...callsReceived].sort((a, b) => a.dateCreated.getTime() - b.dateCreated.getTime());
|
const calls = [...callsSent, ...callsReceived].sort((a, b) => a.dateCreated.getTime() - b.dateCreated.getTime());
|
||||||
|
|
||||||
|
@ -21,7 +21,8 @@ export default async function getCurrentUser(_ = null, { session }: Ctx) {
|
|||||||
paddleCustomerId: true,
|
paddleCustomerId: true,
|
||||||
paddleSubscriptionId: true,
|
paddleSubscriptionId: true,
|
||||||
twilioAccountSid: true,
|
twilioAccountSid: true,
|
||||||
twilioAuthToken: true,
|
twilioApiKey: true,
|
||||||
|
twilioApiSecret: true,
|
||||||
twimlAppSid: true,
|
twimlAppSid: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
21
integrations/twilio.ts
Normal file
21
integrations/twilio.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { NotFoundError } from "blitz";
|
||||||
|
import twilio from "twilio";
|
||||||
|
|
||||||
|
import type { Organization } from "db";
|
||||||
|
|
||||||
|
type MinimalOrganization = Pick<Organization, "twilioAccountSid" | "twilioApiKey" | "twilioApiSecret">;
|
||||||
|
|
||||||
|
export default function getTwilioClient(organization: MinimalOrganization | null): twilio.Twilio {
|
||||||
|
if (
|
||||||
|
!organization ||
|
||||||
|
!organization.twilioAccountSid ||
|
||||||
|
!organization.twilioApiKey ||
|
||||||
|
!organization.twilioApiSecret
|
||||||
|
) {
|
||||||
|
throw new NotFoundError();
|
||||||
|
}
|
||||||
|
|
||||||
|
return twilio(organization.twilioApiKey, organization.twilioApiSecret, {
|
||||||
|
accountSid: organization.twilioAccountSid,
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user