diff --git a/server/sms/receive.js b/server/sms/receive.js index f08cf727e..f880105e9 100644 --- a/server/sms/receive.js +++ b/server/sms/receive.js @@ -1,16 +1,61 @@ -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 { + FIND_BODYSHOP_BY_MESSAGING_SERVICE_SID, + UNARCHIVE_CONVERSATION, + CREATE_CONVERSATION, + INSERT_MESSAGE +} = 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) => { +/** + * Generate an array of media URLs from the request body + * @param body + * @returns {null|*[]} + */ +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; + } +}; + +/** + * Handle errors during the message receiving process + * @param req + * @param error + * @param res + * @param context + */ +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" }); +}; + +/** + * Receive an inbound SMS message + * @param req + * @param res + * @returns {Promise<*>} + */ +const receive = async (req, res) => { const { ioRedis, ioHelpers: { getBodyshopRoom, getBodyshopConversationRoom } @@ -35,7 +80,7 @@ exports.receive = async (req, res) => { try { // Step 1: Find the bodyshop and existing conversation - const response = await client.request(queries.FIND_BODYSHOP_BY_MESSAGING_SERVICE_SID, { + const response = await client.request(FIND_BODYSHOP_BY_MESSAGING_SERVICE_SID, { mssid: req.body.MessagingServiceSid, phone: phone(req.body.From).phoneNumber }); @@ -68,14 +113,14 @@ exports.receive = async (req, res) => { // Unarchive the conversation if necessary if (existingConversation.archived) { - await client.request(queries.UNARCHIVE_CONVERSATION, { + await client.request(UNARCHIVE_CONVERSATION, { id: conversationid, archived: false }); } } else { // Create a new conversation - const newConversationResponse = await client.request(queries.CREATE_CONVERSATION, { + const newConversationResponse = await client.request(CREATE_CONVERSATION, { conversation: { bodyshopid: bodyshop.id, phone_num: phone(req.body.From).phoneNumber, @@ -90,7 +135,7 @@ exports.receive = async (req, res) => { newMessage.conversationid = conversationid; // Step 3: Insert the message into the conversation - const insertresp = await client.request(queries.INSERT_MESSAGE, { + const insertresp = await client.request(INSERT_MESSAGE, { msg: newMessage, conversationid: conversationid }); @@ -137,7 +182,7 @@ exports.receive = async (req, res) => { notification: { title: InstanceManager({ imex: `ImEX Online Message - ${message.conversation.phone_num}`, - rome: `Rome Online Message - ${message.conversation.phone_num}`, + rome: `Rome Online Message - ${message.conversation.phone_num}` }), body: message.image_path ? `Image ${message.text}` : message.text }, @@ -161,29 +206,6 @@ exports.receive = async (req, res) => { } }; -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" }); +module.exports = { + receive }; diff --git a/server/sms/send.js b/server/sms/send.js index eb8cb6e5f..bc0a95da9 100644 --- a/server/sms/send.js +++ b/server/sms/send.js @@ -1,16 +1,17 @@ -const path = require("path"); -require("dotenv").config({ - path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) -}); - const twilio = require("twilio"); const { phone } = require("phone"); -const queries = require("../graphql-client/queries"); +const { INSERT_MESSAGE } = require("../graphql-client/queries"); const logger = require("../utils/logger"); const client = twilio(process.env.TWILIO_AUTH_TOKEN, process.env.TWILIO_AUTH_KEY); const gqlClient = require("../graphql-client/graphql-client").client; -exports.send = async (req, res) => { +/** + * Send an outbound SMS message + * @param req + * @param res + * @returns {Promise} + */ +const send = async (req, res) => { const { to, messagingServiceSid, body, conversationid, selectedMedia, imexshopid } = req.body; const { ioRedis, @@ -64,7 +65,10 @@ exports.send = async (req, res) => { }; try { - const gqlResponse = await gqlClient.request(queries.INSERT_MESSAGE, { msg: newMessage, conversationid }); + const gqlResponse = await gqlClient.request(INSERT_MESSAGE, { + msg: newMessage, + conversationid + }); logger.log("sms-outbound-success", "DEBUG", req.user.email, null, { msid: message.sid, @@ -111,3 +115,7 @@ exports.send = async (req, res) => { res.status(500).json({ success: false, message: "Failed to send message through Twilio." }); } }; + +module.exports = { + send +}; diff --git a/server/sms/status.js b/server/sms/status.js index 0e29bbf8f..509c76d6b 100644 --- a/server/sms/status.js +++ b/server/sms/status.js @@ -1,13 +1,14 @@ -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 { UPDATE_MESSAGE_STATUS, MARK_MESSAGES_AS_READ } = require("../graphql-client/queries"); const logger = require("../utils/logger"); -exports.status = async (req, res) => { +/** + * Handle the status of an SMS message + * @param req + * @param res + * @returns {Promise<*>} + */ +const status = async (req, res) => { const { SmsSid, SmsStatus } = req.body; const { ioRedis, @@ -21,7 +22,7 @@ exports.status = async (req, res) => { } // Update message status in the database - const response = await client.request(queries.UPDATE_MESSAGE_STATUS, { + const response = await client.request(UPDATE_MESSAGE_STATUS, { msid: SmsSid, fields: { status: SmsStatus } }); @@ -65,7 +66,13 @@ exports.status = async (req, res) => { } }; -exports.markConversationRead = async (req, res) => { +/** + * Mark a conversation as read + * @param req + * @param res + * @returns {Promise<*>} + */ +const markConversationRead = async (req, res) => { const { ioRedis, ioHelpers: { getBodyshopRoom, getBodyshopConversationRoom } @@ -80,7 +87,7 @@ exports.markConversationRead = async (req, res) => { } try { - const response = await client.request(queries.MARK_MESSAGES_AS_READ, { + const response = await client.request(MARK_MESSAGES_AS_READ, { conversationId }); @@ -104,3 +111,8 @@ exports.markConversationRead = async (req, res) => { res.status(500).json({ error: "Failed to mark conversation as read." }); } }; + +module.exports = { + status, + markConversationRead +}; diff --git a/server/utils/ioHelpers.js b/server/utils/ioHelpers.js index 584d45ce7..f26440a50 100644 --- a/server/utils/ioHelpers.js +++ b/server/utils/ioHelpers.js @@ -1,3 +1,11 @@ +/** + * @module ioHelpers + * @param app + * @param api + * @param io + * @param logger + * @returns {{getBodyshopRoom: (function(*): string), getBodyshopConversationRoom: (function({bodyshopId: *, conversationId: *}): string)}} + */ const applyIOHelpers = ({ app, api, io, logger }) => { // Global Bodyshop Room const getBodyshopRoom = (bodyshopId) => `bodyshop-broadcast-room:${bodyshopId}`;