const axios = require('axios'); module.exports = Self => { Self.remoteMethodCtx('sendQueued', { description: 'Send a RocketChat message', accessType: 'WRITE', accepts: [], returns: { type: 'object', root: true }, http: { path: `/sendQueued`, verb: 'POST' } }); Self.sendQueued = async ctx => { const models = Self.app.models; const maxAttempts = 3; const sentStatus = 1; const errorStatus = 2; const chats = await models.Chat.find({ where: { status: {neq: sentStatus}, attempts: {lt: maxAttempts} } }); for (let chat of chats) { if (chat.checkUserStatus) { try { await sendCheckingUserStatus(chat); await updateChat(chat, sentStatus); } catch (error) { await updateChat(chat, errorStatus); } } else { try { await sendMessage(chat.senderFk, chat.recipient, chat.message); await updateChat(chat, sentStatus); } catch (error) { await updateChat(chat, errorStatus); } } } }; async function sendCheckingUserStatus(chat) { const models = Self.app.models; const recipientName = chat.recipient.slice(1); const recipient = await models.Account.findOne({ where: { name: recipientName } }); const {data} = await getUserStatus(recipient.name); if (data) { if (data.status === 'offline' || data.status === 'busy') { // Send message to department room const workerDepartment = await models.WorkerDepartment.findById(recipient.id, { include: { relation: 'department' } }); const department = workerDepartment && workerDepartment.department(); const channelName = department && department.chatName; if (channelName) return sendMessage(chat.senderFk, `#${channelName}`, `@${recipient.name} ➔ ${message}`); else return sendMessage(chat.senderFk, `@${recipient.name}`, chat.message); } else return sendMessage(chat.senderFk, `@${recipient.name}`, chat.message); } } /** * Update status and attempts of a chat * * @param {object} senderFk - The sender id * @param {string} recipient - The user (@) or channel (#) to send the message * @param {string} message - The message to send * @return {Promise} - The request promise */ async function sendMessage(senderFk, recipient, message) { if (process.env.NODE_ENV !== 'production') { return new Promise(resolve => { return resolve({ statusCode: 200, message: 'Fake notification sent' }); }); } const models = Self.app.models; const sender = await models.Account.findById(senderFk); const login = await Self.getServiceAuth(); const avatar = `${login.host}/avatar/${sender.name}`; const options = { headers: { 'X-Auth-Token': login.auth.token, 'X-User-Id': login.auth.userId }, }; return axios.post(`${login.api}/chat.postMessage`, { 'channel': recipient, 'avatar': avatar, 'alias': sender.nickname, 'text': message }, options); } /** * Update status and attempts of a chat * * @param {object} chat - The chat * @param {string} status - The new status * @return {Promise} - The request promise */ async function updateChat(chat, status) { return chat.updateAttributes({ status: status, attempts: ++chat.attempts }); } /** * Returns the current user status on Rocketchat * * @param {string} username - The recipient user name * @return {Promise} - The request promise */ async function getUserStatus(username) { if (process.env.NODE_ENV !== 'production') { return new Promise(resolve => { return resolve({ data: { status: 'online' } }); }); } const login = await Self.getServiceAuth(); const options = { params: {username}, headers: { 'X-Auth-Token': login.auth.token, 'X-User-Id': login.auth.userId }, }; return axios.get(`${login.api}/users.getStatus`, options); } };