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; logger.log("sms-inbound", "DEBUG", "api", null, { msid: req.body.SmsMessageSid, text: req.body.Body, image: !!req.body.MediaUrl0, image_path: generateMediaArray(req.body) }); if (!req.body || !req.body.MessagingServiceSid || !req.body.SmsMessageSid) { 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), type: "malformed-request" }); res.status(400).json({ success: false, error: "Malformed Request" }); return; } try { const response = await client.request(queries.FIND_BODYSHOP_BY_MESSAGING_SERVICE_SID, { mssid: req.body.MessagingServiceSid, phone: phone(req.body.From).phoneNumber }); let newMessage = { msid: req.body.SmsMessageSid, text: req.body.Body, image: !!req.body.MediaUrl0, image_path: generateMediaArray(req.body) }; if (response.bodyshops[0]) { const bodyshop = response.bodyshops[0]; if (bodyshop.conversations.length === 0) { newMessage.conversation = { data: { bodyshopid: bodyshop.id, phone_num: phone(req.body.From).phoneNumber, archived: false } }; try { const insertresp = await client.request(queries.RECEIVE_MESSAGE, { msg: newMessage }); const createdConversation = insertresp?.insert_messages?.returning?.[0]?.conversation || null; const message = insertresp?.insert_messages?.returning?.[0]; if (!createdConversation) { throw new Error("Conversation data is missing from the response."); } const broadcastRoom = getBodyshopRoom(createdConversation.bodyshop.id); const conversationRoom = getBodyshopConversationRoom({ bodyshopId: message.conversation.bodyshop.id, conversationId: message.conversation.id }); ioRedis.to(broadcastRoom).emit("new-message-summary", { isoutbound: false, existingConversation: false, newConversation: createdConversation, conversationId: createdConversation.id, updated_at: message.updated_at, msid: message.sid, summary: true }); ioRedis.to(conversationRoom).emit("new-message-detailed", { newMessage: message, isoutbound: false, newConversation: createdConversation, existingConversation: false, conversationId: createdConversation.id, summary: false }); logger.log("sms-inbound-success", "DEBUG", "api", null, { newMessage, createdConversation }); res.status(200).send(""); return; } catch (e) { handleError(req, e, res, "RECEIVE_MESSAGE"); return; } } else if (bodyshop.conversations.length === 1) { newMessage.conversationid = bodyshop.conversations[0].id; } else { 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, type: "duplicate-phone" }); res.status(400).json({ success: false, error: "Duplicate phone number" }); return; } try { const insertresp = await client.request(queries.INSERT_MESSAGE, { msg: newMessage, conversationid: newMessage.conversationid }); const message = insertresp.insert_messages.returning[0]; const data = { type: "messaging-inbound", conversationid: message.conversationid || "", text: message.text || "", messageid: message.id || "", phone_num: message.conversation.phone_num || "" }; const fcmresp = await admin.messaging().send({ topic: `${message.conversation.bodyshop.imexshopid}-messaging`, notification: { title: InstanceManager({ imex: `ImEX Online Message - ${data.phone_num}`, rome: `Rome Online Message - ${data.phone_num}`, promanager: `ProManager Message - ${data.phone_num}` }), body: message.image_path ? `Image ${message.text}` : message.text }, data }); logger.log("sms-inbound-success", "DEBUG", "api", null, { newMessage, fcmresp }); const broadcastRoom = getBodyshopRoom(message.conversation.bodyshop.id); const conversationRoom = getBodyshopConversationRoom({ bodyshopId: message.conversation.bodyshop.id, conversationId: message.conversation.id }); ioRedis.to(broadcastRoom).emit("new-message-summary", { isoutbound: false, existingConversation: true, conversationId: message.conversationid, updated_at: message.updated_at, msid: message.sid, summary: true }); ioRedis.to(conversationRoom).emit("new-message-detailed", { newMessage: message, isoutbound: false, existingConversation: true, conversationId: message.conversationid, summary: false }); res.status(200).send(""); } catch (e) { handleError(req, e, res, "INSERT_MESSAGE"); } } } catch (e) { handleError(req, e, res, "FIND_BODYSHOP_BY_MESSAGING_SERVICE_SID"); } }; 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" }); };