From 0d8dffac307d289086d7405345637e82be693a3a Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 22 Feb 2022 07:30:26 +0100 Subject: [PATCH] refactor(chat): check rocketchat status before sending message --- back/methods/chat/getServiceAuth.js | 55 ++++++++++ back/methods/chat/send.js | 119 ++++------------------ back/methods/chat/sendCheckingPresence.js | 67 ++++++++---- back/models/chat.js | 1 + 4 files changed, 118 insertions(+), 124 deletions(-) create mode 100644 back/methods/chat/getServiceAuth.js diff --git a/back/methods/chat/getServiceAuth.js b/back/methods/chat/getServiceAuth.js new file mode 100644 index 0000000000..7eb0ceaa54 --- /dev/null +++ b/back/methods/chat/getServiceAuth.js @@ -0,0 +1,55 @@ +const axios = require('axios'); +const tokenLifespan = 10; +module.exports = Self => { + Self.remoteMethodCtx('getServiceAuth', { + description: 'Send a RocketChat message', + accessType: 'READ', + accepts: [], + returns: { + type: 'object', + root: true + }, + http: { + path: `/getServiceAuth`, + verb: 'GET' + } + }); + + Self.getServiceAuth = async() => { + if (!this.login) + this.login = await requestToken(); + + if (!this.login) return; + + if (Date.now() > this.login.expires) + this.login = await requestToken(); + + return this.login; + }; + + /** + * Requests a new Rocketchat token + */ + async function requestToken() { + const models = Self.app.models; + const chatConfig = await models.ChatConfig.findOne(); + + const {data} = await axios.post(`${chatConfig.api}/login`, { + user: chatConfig.user, + password: chatConfig.password + }); + + const requestData = data.data; + if (requestData) { + return { + host: chatConfig.host, + api: chatConfig.api, + auth: { + userId: requestData.userId, + token: requestData.authToken + }, + expires: Date.now() + (1000 * 60 * tokenLifespan) + }; + } + } +}; diff --git a/back/methods/chat/send.js b/back/methods/chat/send.js index 209dfb0352..5f79449456 100644 --- a/back/methods/chat/send.js +++ b/back/methods/chat/send.js @@ -1,4 +1,4 @@ -const got = require('got'); +const axios = require('axios'); module.exports = Self => { Self.remoteMethodCtx('send', { description: 'Send a RocketChat message', @@ -30,86 +30,12 @@ module.exports = Self => { const sender = await models.Account.findById(accessToken.userId); const recipient = to.replace('@', ''); - if (sender.name != recipient) { - let {body} = await sendMessage(sender, to, message); - if (body) - body = JSON.parse(body); - else - body = false; - - return body; - } - - return false; + if (sender.name != recipient) + return sendMessage(sender, to, message); }; async function sendMessage(sender, channel, message) { - const config = await getConfig(); - const avatar = `${config.host}/avatar/${sender.name}`; - const uri = `${config.api}/chat.postMessage`; - - return sendAuth(uri, { - 'channel': channel, - 'avatar': avatar, - 'alias': sender.nickname, - 'text': message - }).catch(async error => { - if (error.statusCode === 401) { - this.auth = null; - - return sendMessage(sender, channel, message); - } - - throw new Error(error.message); - }); - } - - /** - * Returns a rocketchat token - * @return {Object} userId and authToken - */ - async function getAuthToken() { - if (!this.auth || this.auth && !this.auth.authToken) { - const config = await getConfig(); - const uri = `${config.api}/login`; - let {body} = await send(uri, { - user: config.user, - password: config.password - }); - - if (body) { - body = JSON.parse(body); - this.auth = body.data; - } - } - - return this.auth; - } - - /** - * Returns a rocketchat config - * @return {Object} Auth config - */ - async function getConfig() { - if (!this.chatConfig) { - const models = Self.app.models; - - this.chatConfig = await models.ChatConfig.findOne(); - } - - return this.chatConfig; - } - - /** - * Send unauthenticated request - * @param {*} uri - Request uri - * @param {*} params - Request params - * @param {*} options - Request options - * - * @return {Object} Request response - */ - async function send(uri, params, options = {}) { - if (process.env.NODE_ENV !== 'production') { + /* if (process.env.NODE_ENV !== 'production') { return new Promise(resolve => { return resolve({ body: JSON.stringify( @@ -118,34 +44,23 @@ module.exports = Self => { }); }); } + */ + const login = await Self.getServiceAuth(); - const defaultOptions = { - form: params - }; + const avatar = `${login.host}/avatar/${sender.name}`; - if (options) Object.assign(defaultOptions, options); - - return got.post(uri, defaultOptions); - } - - /** - * Send authenticated request - * @param {*} uri - Request uri - * @param {*} body - Request params - * - * @return {Object} Request response - */ - async function sendAuth(uri, body) { - const login = await getAuthToken(); const options = { - headers: {} + headers: { + 'X-Auth-Token': login.auth.token, + 'X-User-Id': login.auth.userId + }, }; - if (login) { - options.headers['X-Auth-Token'] = login.authToken; - options.headers['X-User-Id'] = login.userId; - } - - return send(uri, body, options); + return axios.post(`${login.api}/chat.postMessage`, { + 'channel': channel, + 'avatar': avatar, + 'alias': sender.nickname, + 'text': message + }, options); } }; diff --git a/back/methods/chat/sendCheckingPresence.js b/back/methods/chat/sendCheckingPresence.js index fcde20130c..671e8f60f9 100644 --- a/back/methods/chat/sendCheckingPresence.js +++ b/back/methods/chat/sendCheckingPresence.js @@ -1,21 +1,23 @@ +const axios = require('axios'); + module.exports = Self => { Self.remoteMethodCtx('sendCheckingPresence', { description: 'Sends a RocketChat message to a working worker or department channel', accessType: 'WRITE', accepts: [{ - arg: 'workerId', - type: 'Number', + arg: 'recipientId', + type: 'number', required: true, - description: 'The worker id of the destinatary' + description: 'The recipient user id' }, { arg: 'message', - type: 'String', + type: 'string', required: true, description: 'The message' }], returns: { - type: 'Object', + type: 'object', root: true }, http: { @@ -33,30 +35,51 @@ module.exports = Self => { Object.assign(myOptions, options); const models = Self.app.models; - const account = await models.Account.findById(recipientId, null, myOptions); const userId = ctx.req.accessToken.userId; + const recipient = await models.Account.findById(recipientId, null, myOptions); + // Prevent sending messages to yourself if (recipientId == userId) return false; - if (!account) + if (!recipient) throw new Error(`Could not send message "${message}" to worker id ${recipientId} from user ${userId}`); - const query = `SELECT worker_isWorking(?) isWorking`; - const [result] = await Self.rawSql(query, [recipientId], myOptions); + const {data} = await getUserStatus(recipient.name); + if (data) { + if (data.status === 'offline') { + // Send message to department room + const workerDepartment = await models.WorkerDepartment.findById(recipientId, { + include: { + relation: 'department' + } + }, myOptions); + const department = workerDepartment && workerDepartment.department(); + const channelName = department && department.chatName; - if (!result.isWorking) { - const workerDepartment = await models.WorkerDepartment.findById(recipientId, { - include: { - relation: 'department' - } - }, myOptions); - const department = workerDepartment && workerDepartment.department(); - const channelName = department && department.chatName; - - if (channelName) - return Self.send(ctx, `#${channelName}`, `@${account.name} ➔ ${message}`); + if (channelName) + return Self.send(ctx, `#${channelName}`, `@${recipient.name} ➔ ${message}`); + } else + return Self.send(ctx, `@${recipient.name}`, message); } - - return Self.send(ctx, `@${account.name}`, message); }; + + /** + * Returns the current user status on Rocketchat + * + * @param {string} username - The recipient user name + * @return {Promise} - The request promise + */ + async function getUserStatus(username) { + 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); + } }; diff --git a/back/models/chat.js b/back/models/chat.js index 5487569c10..7d8468aae8 100644 --- a/back/models/chat.js +++ b/back/models/chat.js @@ -1,4 +1,5 @@ module.exports = Self => { + require('../methods/chat/getServiceAuth')(Self); require('../methods/chat/send')(Self); require('../methods/chat/sendCheckingPresence')(Self); require('../methods/chat/notifyIssues')(Self);