return early when data is not available as expected
This commit is contained in:
parent
09568ef684
commit
827ed9f1c0
@ -9,12 +9,17 @@ type Payload = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fetchMessagesQueue = Queue<Payload>("api/queue/fetch-messages", async ({ customerId }) => {
|
const fetchMessagesQueue = Queue<Payload>("api/queue/fetch-messages", async ({ customerId }) => {
|
||||||
const customer = await db.customer.findFirst({ where: { id: customerId } });
|
const [customer, phoneNumber] = await Promise.all([
|
||||||
const phoneNumber = await db.phoneNumber.findFirst({ where: { customerId } });
|
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([
|
const [sent, received] = await Promise.all([
|
||||||
twilio(customer!.accountSid!, customer!.authToken!).messages.list({ from: phoneNumber!.phoneNumber }),
|
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({ to: phoneNumber.phoneNumber }),
|
||||||
]);
|
]);
|
||||||
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,7 +1,7 @@
|
|||||||
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 db, { MessageStatus, Direction, Message } from "../../../../db";
|
import db, { Direction, Message, MessageStatus } from "../../../../db";
|
||||||
import { encrypt } from "../../../../db/_encryption";
|
import { encrypt } from "../../../../db/_encryption";
|
||||||
|
|
||||||
type Payload = {
|
type Payload = {
|
||||||
@ -11,12 +11,14 @@ type Payload = {
|
|||||||
|
|
||||||
const insertMessagesQueue = Queue<Payload>("api/queue/insert-messages", async ({ messages, customerId }) => {
|
const insertMessagesQueue = Queue<Payload>("api/queue/insert-messages", async ({ messages, customerId }) => {
|
||||||
const customer = await db.customer.findFirst({ where: { id: customerId } });
|
const customer = await db.customer.findFirst({ where: { id: customerId } });
|
||||||
const encryptionKey = customer!.encryptionKey;
|
if (!customer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const sms = messages
|
const sms = messages
|
||||||
.map<Omit<Message, "id">>((message) => ({
|
.map<Omit<Message, "id">>((message) => ({
|
||||||
customerId,
|
customerId,
|
||||||
content: encrypt(message.body, encryptionKey),
|
content: encrypt(message.body, customer.encryptionKey),
|
||||||
from: message.from,
|
from: message.from,
|
||||||
to: message.to,
|
to: message.to,
|
||||||
status: translateStatus(message.status),
|
status: translateStatus(message.status),
|
||||||
|
@ -13,14 +13,19 @@ type Payload = {
|
|||||||
const sendMessageQueue = Queue<Payload>(
|
const sendMessageQueue = Queue<Payload>(
|
||||||
"api/queue/send-message",
|
"api/queue/send-message",
|
||||||
async ({ id, customerId, to, content }) => {
|
async ({ id, customerId, to, content }) => {
|
||||||
const customer = await db.customer.findFirst({ where: { id: customerId } });
|
const [customer, phoneNumber] = await Promise.all([
|
||||||
const phoneNumber = await db.phoneNumber.findFirst({ where: { customerId } });
|
db.customer.findFirst({ where: { id: customerId } }),
|
||||||
|
db.phoneNumber.findFirst({ where: { customerId } }),
|
||||||
|
]);
|
||||||
|
if (!customer || !customer.accountSid || !customer.authToken || !phoneNumber) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const message = await twilio(customer!.accountSid!, customer!.authToken!).messages.create({
|
const message = await twilio(customer.accountSid, customer.authToken).messages.create({
|
||||||
body: content,
|
body: content,
|
||||||
to,
|
to,
|
||||||
from: phoneNumber!.phoneNumber,
|
from: phoneNumber.phoneNumber,
|
||||||
});
|
});
|
||||||
await db.message.update({
|
await db.message.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
|
@ -18,24 +18,31 @@ const Body = z.object({
|
|||||||
|
|
||||||
export default resolver.pipe(resolver.zod(Body), resolver.authorize(), async ({ content, to }, context) => {
|
export default resolver.pipe(resolver.zod(Body), resolver.authorize(), async ({ content, to }, context) => {
|
||||||
const customer = await getCurrentCustomer(null, context);
|
const customer = await getCurrentCustomer(null, context);
|
||||||
|
if (!customer || !customer.accountSid || !customer.authToken) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
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) {
|
} catch (error) {
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const customerId = customer!.id;
|
const customerId = customer.id;
|
||||||
const customerPhoneNumber = await getCustomerPhoneNumber({ customerId }, context);
|
const customerPhoneNumber = await getCustomerPhoneNumber({ customerId }, context);
|
||||||
|
if (!customerPhoneNumber) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const message = await db.message.create({
|
const message = await db.message.create({
|
||||||
data: {
|
data: {
|
||||||
customerId,
|
customerId,
|
||||||
to,
|
to,
|
||||||
from: customerPhoneNumber!.phoneNumber,
|
from: customerPhoneNumber.phoneNumber,
|
||||||
direction: Direction.Outbound,
|
direction: Direction.Outbound,
|
||||||
status: MessageStatus.Queued,
|
status: MessageStatus.Queued,
|
||||||
content: encrypt(content, customer!.encryptionKey),
|
content: encrypt(content, customer.encryptionKey),
|
||||||
sentAt: new Date(),
|
sentAt: new Date(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -11,17 +11,19 @@ const GetConversations = z.object({
|
|||||||
|
|
||||||
export default resolver.pipe(resolver.zod(GetConversations), resolver.authorize(), async ({ recipient }, context) => {
|
export default resolver.pipe(resolver.zod(GetConversations), resolver.authorize(), async ({ recipient }, context) => {
|
||||||
const customer = await getCurrentCustomer(null, context);
|
const customer = await getCurrentCustomer(null, context);
|
||||||
|
if (!customer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const conversation = await db.message.findMany({
|
const conversation = await db.message.findMany({
|
||||||
where: {
|
where: { OR: [{ from: recipient }, { to: recipient }] },
|
||||||
OR: [{ from: recipient }, { to: recipient }],
|
|
||||||
},
|
|
||||||
orderBy: { sentAt: Prisma.SortOrder.asc },
|
orderBy: { sentAt: Prisma.SortOrder.asc },
|
||||||
});
|
});
|
||||||
|
|
||||||
return conversation.map((message) => {
|
return conversation.map((message) => {
|
||||||
return {
|
return {
|
||||||
...message,
|
...message,
|
||||||
content: decrypt(message.content, customer!.encryptionKey),
|
content: decrypt(message.content, customer.encryptionKey),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -6,8 +6,12 @@ import { decrypt } from "../../../db/_encryption";
|
|||||||
|
|
||||||
export default resolver.pipe(resolver.authorize(), async (_ = null, context) => {
|
export default resolver.pipe(resolver.authorize(), async (_ = null, context) => {
|
||||||
const customer = await getCurrentCustomer(null, context);
|
const customer = await getCurrentCustomer(null, context);
|
||||||
|
if (!customer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const messages = await db.message.findMany({
|
const messages = await db.message.findMany({
|
||||||
where: { customerId: customer!.id },
|
where: { customerId: customer.id },
|
||||||
orderBy: { sentAt: Prisma.SortOrder.asc },
|
orderBy: { sentAt: Prisma.SortOrder.asc },
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -26,7 +30,7 @@ export default resolver.pipe(resolver.authorize(), async (_ = null, context) =>
|
|||||||
|
|
||||||
conversations[recipient]!.push({
|
conversations[recipient]!.push({
|
||||||
...message,
|
...message,
|
||||||
content: decrypt(message.content, customer!.encryptionKey),
|
content: decrypt(message.content, customer.encryptionKey),
|
||||||
});
|
});
|
||||||
|
|
||||||
conversations[recipient]!.sort((a, b) => a.sentAt.getTime() - b.sentAt.getTime());
|
conversations[recipient]!.sort((a, b) => a.sentAt.getTime() - b.sentAt.getTime());
|
||||||
|
@ -8,10 +8,17 @@ type Payload = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const setTwilioWebhooks = Queue<Payload>("api/queue/set-twilio-webhooks", async ({ customerId }) => {
|
const setTwilioWebhooks = Queue<Payload>("api/queue/set-twilio-webhooks", async ({ customerId }) => {
|
||||||
const customer = await db.customer.findFirst({ where: { id: customerId } });
|
const [customer, phoneNumber] = await Promise.all([
|
||||||
const twimlApp = customer!.twimlAppSid
|
db.customer.findFirst({ where: { id: customerId } }),
|
||||||
? await twilio(customer!.accountSid!, customer!.authToken!).applications.get(customer!.twimlAppSid).fetch()
|
db.phoneNumber.findFirst({ where: { customerId } }),
|
||||||
: await twilio(customer!.accountSid!, customer!.authToken!).applications.create({
|
]);
|
||||||
|
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",
|
friendlyName: "Virtual Phone",
|
||||||
smsUrl: "https://phone.mokhtar.dev/api/webhook/incoming-message",
|
smsUrl: "https://phone.mokhtar.dev/api/webhook/incoming-message",
|
||||||
smsMethod: "POST",
|
smsMethod: "POST",
|
||||||
@ -19,19 +26,16 @@ const setTwilioWebhooks = Queue<Payload>("api/queue/set-twilio-webhooks", async
|
|||||||
voiceMethod: "POST",
|
voiceMethod: "POST",
|
||||||
});
|
});
|
||||||
const twimlAppSid = twimlApp.sid;
|
const twimlAppSid = twimlApp.sid;
|
||||||
const phoneNumber = await db.phoneNumber.findFirst({ where: { customerId } });
|
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
db.customer.update({
|
db.customer.update({
|
||||||
where: { id: customerId },
|
where: { id: customerId },
|
||||||
data: { twimlAppSid },
|
data: { twimlAppSid },
|
||||||
}),
|
}),
|
||||||
twilio(customer!.accountSid!, customer!.authToken!)
|
twilio(customer.accountSid, customer.authToken).incomingPhoneNumbers.get(phoneNumber.phoneNumberSid).update({
|
||||||
.incomingPhoneNumbers.get(phoneNumber!.phoneNumberSid)
|
smsApplicationSid: twimlAppSid,
|
||||||
.update({
|
voiceApplicationSid: twimlAppSid,
|
||||||
smsApplicationSid: twimlAppSid,
|
}),
|
||||||
voiceApplicationSid: twimlAppSid,
|
|
||||||
}),
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -14,8 +14,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 customer = await getCurrentCustomer(null, context);
|
const customer = await getCurrentCustomer(null, context);
|
||||||
const customerId = customer!.id;
|
if (!customer || !customer.accountSid || !customer.authToken) {
|
||||||
const phoneNumbers = await twilio(customer!.accountSid!, customer!.authToken!).incomingPhoneNumbers.list();
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const customerId = customer.id;
|
||||||
|
const phoneNumbers = await twilio(customer.accountSid, customer.authToken).incomingPhoneNumbers.list();
|
||||||
const phoneNumber = phoneNumbers.find((phoneNumber) => phoneNumber.sid === phoneNumberSid)!;
|
const phoneNumber = phoneNumbers.find((phoneNumber) => phoneNumber.sid === phoneNumberSid)!;
|
||||||
await db.phoneNumber.create({
|
await db.phoneNumber.create({
|
||||||
data: {
|
data: {
|
||||||
|
@ -14,9 +14,12 @@ export default resolver.pipe(
|
|||||||
resolver.authorize(),
|
resolver.authorize(),
|
||||||
async ({ twilioAccountSid, twilioAuthToken }, context) => {
|
async ({ twilioAccountSid, twilioAuthToken }, context) => {
|
||||||
const customer = await getCurrentCustomer(null, context);
|
const customer = await getCurrentCustomer(null, context);
|
||||||
const customerId = customer!.id;
|
if (!customer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await db.customer.update({
|
await db.customer.update({
|
||||||
where: { id: customerId },
|
where: { id: customer.id },
|
||||||
data: {
|
data: {
|
||||||
accountSid: twilioAccountSid,
|
accountSid: twilioAccountSid,
|
||||||
authToken: twilioAuthToken,
|
authToken: twilioAuthToken,
|
||||||
|
@ -9,15 +9,20 @@ type Payload = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fetchCallsQueue = Queue<Payload>("api/queue/fetch-calls", async ({ customerId }) => {
|
const fetchCallsQueue = Queue<Payload>("api/queue/fetch-calls", async ({ customerId }) => {
|
||||||
const customer = await db.customer.findFirst({ where: { id: customerId } });
|
const [customer, phoneNumber] = await Promise.all([
|
||||||
const phoneNumber = await db.phoneNumber.findFirst({ where: { customerId } });
|
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([
|
const [callsSent, callsReceived] = await Promise.all([
|
||||||
twilio(customer!.accountSid!, customer!.authToken!).calls.list({
|
twilio(customer.accountSid, customer.authToken).calls.list({
|
||||||
from: phoneNumber!.phoneNumber,
|
from: phoneNumber.phoneNumber,
|
||||||
}),
|
}),
|
||||||
twilio(customer!.accountSid!, customer!.authToken!).calls.list({
|
twilio(customer.accountSid, customer.authToken).calls.list({
|
||||||
to: phoneNumber!.phoneNumber,
|
to: phoneNumber.phoneNumber,
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
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());
|
||||||
|
@ -5,8 +5,12 @@ import getCurrentCustomer from "../../customers/queries/get-current-customer";
|
|||||||
|
|
||||||
export default resolver.pipe(resolver.authorize(), async (_ = null, context) => {
|
export default resolver.pipe(resolver.authorize(), async (_ = null, context) => {
|
||||||
const customer = await getCurrentCustomer(null, context);
|
const customer = await getCurrentCustomer(null, context);
|
||||||
|
if (!customer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return db.phoneNumber.findFirst({
|
return db.phoneNumber.findFirst({
|
||||||
where: { customerId: customer!.id },
|
where: { customerId: customer.id },
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
phoneNumber: true,
|
phoneNumber: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user