diff --git a/app/messages/api/queue/fetch-messages.ts b/app/messages/api/queue/fetch-messages.ts index 5c94074..da9da75 100644 --- a/app/messages/api/queue/fetch-messages.ts +++ b/app/messages/api/queue/fetch-messages.ts @@ -9,12 +9,17 @@ type Payload = { }; const fetchMessagesQueue = Queue("api/queue/fetch-messages", async ({ customerId }) => { - const customer = await db.customer.findFirst({ where: { id: customerId } }); - const phoneNumber = await db.phoneNumber.findFirst({ where: { customerId } }); + const [customer, phoneNumber] = await Promise.all([ + db.customer.findFirst({ where: { id: customerId } }), + db.phoneNumber.findFirst({ where: { customerId } }), + ]); + if (!customer || !customer.accountSid || !customer.authToken || !phoneNumber) { + return; + } const [sent, received] = await Promise.all([ - twilio(customer!.accountSid!, customer!.authToken!).messages.list({ from: phoneNumber!.phoneNumber }), - twilio(customer!.accountSid!, customer!.authToken!).messages.list({ to: phoneNumber!.phoneNumber }), + twilio(customer.accountSid, customer.authToken).messages.list({ from: phoneNumber.phoneNumber }), + twilio(customer.accountSid, customer.authToken).messages.list({ to: phoneNumber.phoneNumber }), ]); const messagesSent = sent.filter((message) => message.direction.startsWith("outbound")); const messagesReceived = received.filter((message) => message.direction === "inbound"); diff --git a/app/messages/api/queue/insert-messages.ts b/app/messages/api/queue/insert-messages.ts index 47a19ed..129f847 100644 --- a/app/messages/api/queue/insert-messages.ts +++ b/app/messages/api/queue/insert-messages.ts @@ -1,7 +1,7 @@ import { Queue } from "quirrel/blitz"; import type { MessageInstance } from "twilio/lib/rest/api/v2010/account/message"; -import db, { MessageStatus, Direction, Message } from "../../../../db"; +import db, { Direction, Message, MessageStatus } from "../../../../db"; import { encrypt } from "../../../../db/_encryption"; type Payload = { @@ -11,12 +11,14 @@ type Payload = { const insertMessagesQueue = Queue("api/queue/insert-messages", async ({ messages, customerId }) => { const customer = await db.customer.findFirst({ where: { id: customerId } }); - const encryptionKey = customer!.encryptionKey; + if (!customer) { + return; + } const sms = messages .map>((message) => ({ customerId, - content: encrypt(message.body, encryptionKey), + content: encrypt(message.body, customer.encryptionKey), from: message.from, to: message.to, status: translateStatus(message.status), diff --git a/app/messages/api/queue/send-message.ts b/app/messages/api/queue/send-message.ts index 6a58da3..5bbd763 100644 --- a/app/messages/api/queue/send-message.ts +++ b/app/messages/api/queue/send-message.ts @@ -13,14 +13,19 @@ type Payload = { const sendMessageQueue = Queue( "api/queue/send-message", async ({ id, customerId, to, content }) => { - const customer = await db.customer.findFirst({ where: { id: customerId } }); - const phoneNumber = await db.phoneNumber.findFirst({ where: { customerId } }); + const [customer, phoneNumber] = await Promise.all([ + db.customer.findFirst({ where: { id: customerId } }), + db.phoneNumber.findFirst({ where: { customerId } }), + ]); + if (!customer || !customer.accountSid || !customer.authToken || !phoneNumber) { + return; + } try { - const message = await twilio(customer!.accountSid!, customer!.authToken!).messages.create({ + const message = await twilio(customer.accountSid, customer.authToken).messages.create({ body: content, to, - from: phoneNumber!.phoneNumber, + from: phoneNumber.phoneNumber, }); await db.message.update({ where: { id }, diff --git a/app/messages/mutations/send-message.ts b/app/messages/mutations/send-message.ts index 54b658d..170204d 100644 --- a/app/messages/mutations/send-message.ts +++ b/app/messages/mutations/send-message.ts @@ -18,24 +18,31 @@ const Body = z.object({ export default resolver.pipe(resolver.zod(Body), resolver.authorize(), async ({ content, to }, context) => { const customer = await getCurrentCustomer(null, context); + if (!customer || !customer.accountSid || !customer.authToken) { + return; + } + try { - await twilio(customer!.accountSid!, customer!.authToken!).lookups.v1.phoneNumbers(to).fetch(); + await twilio(customer.accountSid, customer.authToken).lookups.v1.phoneNumbers(to).fetch(); } catch (error) { logger.error(error); return; } - const customerId = customer!.id; + const customerId = customer.id; const customerPhoneNumber = await getCustomerPhoneNumber({ customerId }, context); + if (!customerPhoneNumber) { + return; + } const message = await db.message.create({ data: { customerId, to, - from: customerPhoneNumber!.phoneNumber, + from: customerPhoneNumber.phoneNumber, direction: Direction.Outbound, status: MessageStatus.Queued, - content: encrypt(content, customer!.encryptionKey), + content: encrypt(content, customer.encryptionKey), sentAt: new Date(), }, }); diff --git a/app/messages/queries/get-conversation.ts b/app/messages/queries/get-conversation.ts index b4ccea3..ad554ff 100644 --- a/app/messages/queries/get-conversation.ts +++ b/app/messages/queries/get-conversation.ts @@ -11,17 +11,19 @@ const GetConversations = z.object({ export default resolver.pipe(resolver.zod(GetConversations), resolver.authorize(), async ({ recipient }, context) => { const customer = await getCurrentCustomer(null, context); + if (!customer) { + return; + } + const conversation = await db.message.findMany({ - where: { - OR: [{ from: recipient }, { to: recipient }], - }, + where: { OR: [{ from: recipient }, { to: recipient }] }, orderBy: { sentAt: Prisma.SortOrder.asc }, }); return conversation.map((message) => { return { ...message, - content: decrypt(message.content, customer!.encryptionKey), + content: decrypt(message.content, customer.encryptionKey), }; }); }); diff --git a/app/messages/queries/get-conversations.ts b/app/messages/queries/get-conversations.ts index 2680ed7..0eeee1e 100644 --- a/app/messages/queries/get-conversations.ts +++ b/app/messages/queries/get-conversations.ts @@ -6,8 +6,12 @@ import { decrypt } from "../../../db/_encryption"; export default resolver.pipe(resolver.authorize(), async (_ = null, context) => { const customer = await getCurrentCustomer(null, context); + if (!customer) { + return; + } + const messages = await db.message.findMany({ - where: { customerId: customer!.id }, + where: { customerId: customer.id }, orderBy: { sentAt: Prisma.SortOrder.asc }, }); @@ -26,7 +30,7 @@ export default resolver.pipe(resolver.authorize(), async (_ = null, context) => conversations[recipient]!.push({ ...message, - content: decrypt(message.content, customer!.encryptionKey), + content: decrypt(message.content, customer.encryptionKey), }); conversations[recipient]!.sort((a, b) => a.sentAt.getTime() - b.sentAt.getTime()); diff --git a/app/onboarding/api/queue/set-twilio-webhooks.ts b/app/onboarding/api/queue/set-twilio-webhooks.ts index 44cfe57..1716b2d 100644 --- a/app/onboarding/api/queue/set-twilio-webhooks.ts +++ b/app/onboarding/api/queue/set-twilio-webhooks.ts @@ -8,10 +8,17 @@ type Payload = { }; const setTwilioWebhooks = Queue("api/queue/set-twilio-webhooks", async ({ customerId }) => { - const customer = await db.customer.findFirst({ where: { id: customerId } }); - const twimlApp = customer!.twimlAppSid - ? await twilio(customer!.accountSid!, customer!.authToken!).applications.get(customer!.twimlAppSid).fetch() - : await twilio(customer!.accountSid!, customer!.authToken!).applications.create({ + const [customer, phoneNumber] = await Promise.all([ + db.customer.findFirst({ where: { id: customerId } }), + db.phoneNumber.findFirst({ where: { customerId } }), + ]); + if (!customer || !customer.accountSid || !customer.authToken || !phoneNumber) { + return; + } + + const twimlApp = customer.twimlAppSid + ? await twilio(customer.accountSid, customer.authToken).applications.get(customer.twimlAppSid).fetch() + : await twilio(customer.accountSid, customer.authToken).applications.create({ friendlyName: "Virtual Phone", smsUrl: "https://phone.mokhtar.dev/api/webhook/incoming-message", smsMethod: "POST", @@ -19,19 +26,16 @@ const setTwilioWebhooks = Queue("api/queue/set-twilio-webhooks", async voiceMethod: "POST", }); const twimlAppSid = twimlApp.sid; - const phoneNumber = await db.phoneNumber.findFirst({ where: { customerId } }); await Promise.all([ db.customer.update({ where: { id: customerId }, data: { twimlAppSid }, }), - twilio(customer!.accountSid!, customer!.authToken!) - .incomingPhoneNumbers.get(phoneNumber!.phoneNumberSid) - .update({ - smsApplicationSid: twimlAppSid, - voiceApplicationSid: twimlAppSid, - }), + twilio(customer.accountSid, customer.authToken).incomingPhoneNumbers.get(phoneNumber.phoneNumberSid).update({ + smsApplicationSid: twimlAppSid, + voiceApplicationSid: twimlAppSid, + }), ]); }); diff --git a/app/onboarding/mutations/set-phone-number.ts b/app/onboarding/mutations/set-phone-number.ts index 1a51d4f..d7adda5 100644 --- a/app/onboarding/mutations/set-phone-number.ts +++ b/app/onboarding/mutations/set-phone-number.ts @@ -14,8 +14,12 @@ const Body = z.object({ export default resolver.pipe(resolver.zod(Body), resolver.authorize(), async ({ phoneNumberSid }, context) => { const customer = await getCurrentCustomer(null, context); - const customerId = customer!.id; - const phoneNumbers = await twilio(customer!.accountSid!, customer!.authToken!).incomingPhoneNumbers.list(); + if (!customer || !customer.accountSid || !customer.authToken) { + return; + } + + const customerId = customer.id; + const phoneNumbers = await twilio(customer.accountSid, customer.authToken).incomingPhoneNumbers.list(); const phoneNumber = phoneNumbers.find((phoneNumber) => phoneNumber.sid === phoneNumberSid)!; await db.phoneNumber.create({ data: { diff --git a/app/onboarding/mutations/set-twilio-api-fields.ts b/app/onboarding/mutations/set-twilio-api-fields.ts index 8ed52fe..6c10a13 100644 --- a/app/onboarding/mutations/set-twilio-api-fields.ts +++ b/app/onboarding/mutations/set-twilio-api-fields.ts @@ -14,9 +14,12 @@ export default resolver.pipe( resolver.authorize(), async ({ twilioAccountSid, twilioAuthToken }, context) => { const customer = await getCurrentCustomer(null, context); - const customerId = customer!.id; + if (!customer) { + return; + } + await db.customer.update({ - where: { id: customerId }, + where: { id: customer.id }, data: { accountSid: twilioAccountSid, authToken: twilioAuthToken, diff --git a/app/phone-calls/api/queue/fetch-calls.ts b/app/phone-calls/api/queue/fetch-calls.ts index 66d68ff..a340e1e 100644 --- a/app/phone-calls/api/queue/fetch-calls.ts +++ b/app/phone-calls/api/queue/fetch-calls.ts @@ -9,15 +9,20 @@ type Payload = { }; const fetchCallsQueue = Queue("api/queue/fetch-calls", async ({ customerId }) => { - const customer = await db.customer.findFirst({ where: { id: customerId } }); - const phoneNumber = await db.phoneNumber.findFirst({ where: { customerId } }); + const [customer, phoneNumber] = await Promise.all([ + db.customer.findFirst({ where: { id: customerId } }), + db.phoneNumber.findFirst({ where: { customerId } }), + ]); + if (!customer || !customer.accountSid || !customer.authToken || !phoneNumber) { + return; + } const [callsSent, callsReceived] = await Promise.all([ - twilio(customer!.accountSid!, customer!.authToken!).calls.list({ - from: phoneNumber!.phoneNumber, + twilio(customer.accountSid, customer.authToken).calls.list({ + from: phoneNumber.phoneNumber, }), - twilio(customer!.accountSid!, customer!.authToken!).calls.list({ - to: phoneNumber!.phoneNumber, + twilio(customer.accountSid, customer.authToken).calls.list({ + to: phoneNumber.phoneNumber, }), ]); const calls = [...callsSent, ...callsReceived].sort((a, b) => a.dateCreated.getTime() - b.dateCreated.getTime()); diff --git a/app/phone-numbers/queries/get-current-customer-phone-number.ts b/app/phone-numbers/queries/get-current-customer-phone-number.ts index 51d5f20..48d11ba 100644 --- a/app/phone-numbers/queries/get-current-customer-phone-number.ts +++ b/app/phone-numbers/queries/get-current-customer-phone-number.ts @@ -5,8 +5,12 @@ import getCurrentCustomer from "../../customers/queries/get-current-customer"; export default resolver.pipe(resolver.authorize(), async (_ = null, context) => { const customer = await getCurrentCustomer(null, context); + if (!customer) { + return; + } + return db.phoneNumber.findFirst({ - where: { customerId: customer!.id }, + where: { customerId: customer.id }, select: { id: true, phoneNumber: true,