Files
bodyshop/server/sms/receive.js
Dave Richer 38f13346e5 feature/IO-3000-messaging-sockets-migrations2 -
- testing and edge cases

Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-11-21 18:44:38 -08:00

185 lines
5.6 KiB
JavaScript

const path = require("path");
require("dotenv").config({
path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`)
});
const client = require("../graphql-client/graphql-client").client;
const queries = require("../graphql-client/queries");
const { phone } = require("phone");
const { admin } = require("../firebase/firebase-handler");
const logger = require("../utils/logger");
const InstanceManager = require("../utils/instanceMgr").default;
exports.receive = async (req, res) => {
const {
ioRedis,
ioHelpers: { getBodyshopRoom, getBodyshopConversationRoom }
} = req;
const loggerData = {
msid: req.body.SmsMessageSid,
text: req.body.Body,
image: !!req.body.MediaUrl0,
image_path: generateMediaArray(req.body)
};
logger.log("sms-inbound", "DEBUG", "api", null, loggerData);
if (!req.body || !req.body.MessagingServiceSid || !req.body.SmsMessageSid) {
logger.log("sms-inbound-error", "ERROR", "api", null, {
...loggerData,
type: "malformed-request"
});
return res.status(400).json({ success: false, error: "Malformed Request" });
}
try {
const response = await client.request(queries.FIND_BODYSHOP_BY_MESSAGING_SERVICE_SID, {
mssid: req.body.MessagingServiceSid,
phone: phone(req.body.From).phoneNumber
});
if (!response.bodyshops[0]) {
return res.status(400).json({ success: false, error: "No matching bodyshop" });
}
const bodyshop = response.bodyshops[0];
const isNewConversation = bodyshop.conversations.length === 0;
const isDuplicate = bodyshop.conversations.length > 1;
let newMessage = {
msid: req.body.SmsMessageSid,
text: req.body.Body,
image: !!req.body.MediaUrl0,
image_path: generateMediaArray(req.body)
};
if (isDuplicate) {
logger.log("sms-inbound-error", "ERROR", "api", null, {
...loggerData,
messagingServiceSid: req.body.MessagingServiceSid,
type: "duplicate-phone"
});
return res.status(400).json({ success: false, error: "Duplicate phone number" });
}
if (isNewConversation) {
newMessage.conversation = {
data: {
bodyshopid: bodyshop.id,
phone_num: phone(req.body.From).phoneNumber,
archived: false
}
};
} else {
const existingConversation = bodyshop.conversations[0];
// Update the conversation to unarchive it
if (existingConversation.archived) {
await client.request(queries.UNARCHIVE_CONVERSATION, {
id: existingConversation.id,
archived: false
});
}
newMessage.conversationid = existingConversation.id;
}
const query = isNewConversation ? queries.RECEIVE_MESSAGE : queries.INSERT_MESSAGE;
const variables = isNewConversation
? { msg: newMessage }
: { msg: newMessage, conversationid: newMessage.conversationid };
const insertresp = await client.request(query, variables);
const message = insertresp?.insert_messages?.returning?.[0];
const conversation = message?.conversation || null;
if (!conversation) {
throw new Error("Conversation data is missing from the response.");
}
const broadcastRoom = getBodyshopRoom(conversation.bodyshop.id);
const conversationRoom = getBodyshopConversationRoom({
bodyshopId: conversation.bodyshop.id,
conversationId: conversation.id
});
const commonPayload = {
isoutbound: false,
conversationId: conversation.id,
updated_at: message.updated_at,
msid: message.sid
};
ioRedis.to(broadcastRoom).emit("new-message-summary", {
...commonPayload,
existingConversation: !isNewConversation,
newConversation: isNewConversation ? conversation : null,
summary: true
});
ioRedis.to(conversationRoom).emit("new-message-detailed", {
newMessage: message,
...commonPayload,
newConversation: isNewConversation ? conversation : null,
existingConversation: !isNewConversation,
summary: false
});
const fcmresp = await admin.messaging().send({
topic: `${message.conversation.bodyshop.imexshopid}-messaging`,
notification: {
title: InstanceManager({
imex: `ImEX Online Message - ${message.conversation.phone_num}`,
rome: `Rome Online Message - ${message.conversation.phone_num}`,
promanager: `ProManager Message - ${message.conversation.phone_num}`
}),
body: message.image_path ? `Image ${message.text}` : message.text
},
data: {
type: "messaging-inbound",
conversationid: message.conversationid || "",
text: message.text || "",
messageid: message.id || "",
phone_num: message.conversation.phone_num || ""
}
});
logger.log("sms-inbound-success", "DEBUG", "api", null, {
newMessage,
fcmresp
});
res.status(200).send("");
} catch (e) {
handleError(req, e, res, "RECEIVE_MESSAGE");
}
};
const generateMediaArray = (body) => {
const { NumMedia } = body;
if (parseInt(NumMedia) > 0) {
const ret = [];
for (let i = 0; i < parseInt(NumMedia); i++) {
ret.push(body[`MediaUrl${i}`]);
}
return ret;
} else {
return null;
}
};
const handleError = (req, error, res, context) => {
logger.log("sms-inbound-error", "ERROR", "api", null, {
msid: req.body.SmsMessageSid,
text: req.body.Body,
image: !!req.body.MediaUrl0,
image_path: generateMediaArray(req.body),
messagingServiceSid: req.body.MessagingServiceSid,
context,
error
});
res.status(500).json({ error: error.message || "Internal Server Error" });
};