From 8a975d7da477c6bd43276592522528914f9aa71e Mon Sep 17 00:00:00 2001 From: Dragory <2606411+Dragory@users.noreply.github.com> Date: Tue, 14 Jul 2020 01:11:48 +0300 Subject: [PATCH] Add message formatters. Expose message formatters to plugins. --- src/data/Thread.js | 138 ++---------------------------- src/formatters.js | 208 +++++++++++++++++++++++++++++++++++++++++++++ src/plugins.js | 2 + 3 files changed, 216 insertions(+), 132 deletions(-) create mode 100644 src/formatters.js diff --git a/src/data/Thread.js b/src/data/Thread.js index 3d686fa..3e5faf9 100644 --- a/src/data/Thread.js +++ b/src/data/Thread.js @@ -5,6 +5,7 @@ const knex = require('../knex'); const utils = require('../utils'); const config = require('../config'); const attachments = require('./attachments'); +const { formatters } = require('../formatters'); const ThreadMessage = require('./ThreadMessage'); @@ -28,133 +29,6 @@ class Thread { utils.setDataModelProps(this, props); } - /** - * @param {Eris.Member} moderator - * @param {string} text - * @param {boolean} isAnonymous - * @returns {string} - * @private - */ - _formatStaffReplyDM(moderator, text, isAnonymous) { - const mainRole = utils.getMainRole(moderator); - const modName = (config.useNicknames ? moderator.nick || moderator.user.username : moderator.user.username); - const modInfo = isAnonymous - ? (mainRole ? mainRole.name : 'Moderator') - : (mainRole ? `(${mainRole.name}) ${modName}` : modName); - - return `**${modInfo}:** ${text}`; - } - - /** - * @param {Eris.Member} moderator - * @param {string} text - * @param {boolean} isAnonymous - * @param {number} messageNumber - * @param {number} timestamp - * @returns {string} - * @private - */ - _formatStaffReplyThreadMessage(moderator, text, isAnonymous, messageNumber, timestamp) { - const mainRole = utils.getMainRole(moderator); - const modName = (config.useNicknames ? moderator.nick || moderator.user.username : moderator.user.username); - const modInfo = isAnonymous - ? `(Anonymous) (${modName}) ${mainRole ? mainRole.name : 'Moderator'}` - : (mainRole ? `(${mainRole.name}) ${modName}` : modName); - - // TODO: Add \`[${messageNumber}]\` here once !edit and !delete exist - let result = `**${modInfo}:** ${text}`; - - if (config.threadTimestamps) { - const formattedTimestamp = timestamp ? utils.getTimestamp(timestamp, 'x') : utils.getTimestamp(); - result = `[${formattedTimestamp}] ${result}`; - } - - return result; - } - - /** - * @param {Eris.Member} moderator - * @param {string} text - * @param {boolean} isAnonymous - * @param {string[]} attachmentLinks - * @returns {string} - * @private - */ - _formatStaffReplyLogMessage(moderator, text, isAnonymous, attachmentLinks = []) { - const mainRole = utils.getMainRole(moderator); - const modName = moderator.user.username; - - // Mirroring the DM formatting here... - const modInfo = isAnonymous - ? (mainRole ? mainRole.name : 'Moderator') - : (mainRole ? `(${mainRole.name}) ${modName}` : modName); - - let result = `**${modInfo}:** ${text}`; - - if (attachmentLinks.length) { - result += '\n'; - for (const link of attachmentLinks) { - result += `\n**Attachment:** ${link}`; - } - } - - return result; - } - - /** - * @param {Eris.User} user - * @param {string} body - * @param {Eris.EmbedBase[]} embeds - * @param {string[]} formattedAttachments - * @param {number} timestamp - * @return string - * @private - */ - _formatUserReplyThreadMessage(user, body, embeds, formattedAttachments = [], timestamp) { - const content = (body.trim() === '' && embeds.length) - ? '' - : body; - - let result = `**${user.username}#${user.discriminator}:** ${content}`; - - if (formattedAttachments.length) { - for (const formatted of formattedAttachments) { - result += `\n\n${formatted}`; - } - } - - if (config.threadTimestamps) { - const formattedTimestamp = timestamp ? utils.getTimestamp(timestamp, 'x') : utils.getTimestamp(); - result = `[${formattedTimestamp}] ${result}`; - } - - return result; - } - - /** - * @param {Eris.User} user - * @param {string} body - * @param {Eris.EmbedBase[]} embeds - * @param {string[]} formattedAttachments - * @return string - * @private - */ - _formatUserReplyLogMessage(user, body, embeds, formattedAttachments = []) { - const content = (body.trim() === '' && embeds.length) - ? '' - : body; - - let result = content; - - if (formattedAttachments.length) { - for (const formatted of formattedAttachments) { - result += `\n\n${formatted}`; - } - } - - return result; - } - /** * @param {string} text * @param {Eris.MessageFile|Eris.MessageFile[]} file @@ -285,7 +159,7 @@ class Thread { } // Send the reply DM - const dmContent = this._formatStaffReplyDM(moderator, text, isAnonymous); + const dmContent = formatters.formatStaffReplyDM(moderator, text, { isAnonymous }); let dmMessage; try { dmMessage = await this._sendDMToUser(dmContent, files); @@ -295,7 +169,7 @@ class Thread { } // Save the log entry - const logContent = this._formatStaffReplyLogMessage(moderator, text, isAnonymous, attachmentLinks); + const logContent = formatters.formatStaffReplyLogMessage(moderator, text, { isAnonymous, attachmentLinks }); const threadMessage = await this._addThreadMessageToDB({ message_type: THREAD_MESSAGE_TYPE.TO_USER, user_id: moderator.id, @@ -306,7 +180,7 @@ class Thread { }); // Show the reply in the inbox thread - const inboxContent = this._formatStaffReplyThreadMessage(moderator, text, isAnonymous, threadMessage.message_number, null); + const inboxContent = formatters.formatStaffReplyThreadMessage(moderator, text, threadMessage.message_number, { isAnonymous }); const inboxMessage = await this._postToThreadChannel(inboxContent, files); await this._updateThreadMessage(threadMessage.id, { inbox_message_id: inboxMessage.id }); @@ -347,7 +221,7 @@ class Thread { } // Save log entry - const logContent = this._formatUserReplyLogMessage(msg.author, msg.content, msg.embeds, logFormattedAttachments); + const logContent = formatters.formatUserReplyLogMessage(msg.author, msg, { attachmentLinks: logFormattedAttachments }); const threadMessage = await this._addThreadMessageToDB({ message_type: THREAD_MESSAGE_TYPE.FROM_USER, user_id: this.user_id, @@ -358,7 +232,7 @@ class Thread { }); // Show user reply in the inbox thread - const inboxContent = this._formatUserReplyThreadMessage(msg.author, msg.content, msg.embeds, threadFormattedAttachments, null); + const inboxContent = formatters.formatUserReplyThreadMessage(msg.author, msg, { attachmentLinks: threadFormattedAttachments }); const inboxMessage = await this._postToThreadChannel(inboxContent, attachmentFiles); if (inboxMessage) await this._updateThreadMessage(threadMessage.id, { inbox_message_id: inboxMessage.id }); diff --git a/src/formatters.js b/src/formatters.js new file mode 100644 index 0000000..15b5660 --- /dev/null +++ b/src/formatters.js @@ -0,0 +1,208 @@ +const Eris = require('eris'); +const utils = require('./utils'); +const config = require('./config'); + +/** + * Function to format the DM that is sent to the user when a staff member replies to them via !reply + * @callback FormatStaffReplyDM + * @param {Eris.Member} moderator Staff member that is replying + * @param {string} text Reply text + * @param {{ + * isAnonymous: boolean, + * }} opts={} + * @return {string} Message content to send as a DM + */ + +/** + * Function to format a staff reply in a thread channel + * @callback FormatStaffReplyThreadMessage + * @param {Eris.Member} moderator + * @param {string} text + * @param {number} messageNumber + * @param {{ + * isAnonymous: boolean, + * }} opts={} + * @return {string} Message content to post in the thread channel + */ + +/** + * Function to format a staff reply in a log + * @callback FormatStaffReplyLogMessage + * @param {Eris.Member} moderator + * @param {string} text + * @param {{ + * isAnonymous: boolean, + * attachmentLinks: string[], + * }} opts={} + * @returns {string} Text to show in the log + */ + +/** + * Function to format a user reply in a thread channel + * @callback FormatUserReplyThreadMessage + * @param {Eris.User} user Use that sent the reply + * @param {Eris.Message} msg The message object that the user sent + * @param {{ + * attachmentLinks: string[], + * }} opts + * @return {string} Message content to post in the thread channel + */ + +/** + * @callback FormatUserReplyLogMessage + * @param {Eris.User} user + * @param {Eris.Message} msg + * @param {{ + * attachmentLinks: string[], + * }} opts={} + * @return {string} Text to show in the log + */ + +/** + * @typedef MessageFormatters + * @property {FormatStaffReplyDM} formatStaffReplyDM + * @property {FormatStaffReplyThreadMessage} formatStaffReplyThreadMessage + * @property {FormatStaffReplyLogMessage} formatStaffReplyLogMessage + * @property {FormatUserReplyThreadMessage} formatUserReplyThreadMessage + * @property {FormatUserReplyLogMessage} formatUserReplyLogMessage + */ + +/** + * @type {MessageFormatters} + */ +const defaultFormatters = { + formatStaffReplyDM(moderator, text, opts = {}) { + const mainRole = utils.getMainRole(moderator); + const modName = (config.useNicknames ? moderator.nick || moderator.user.username : moderator.user.username); + const modInfo = opts.isAnonymous + ? (mainRole ? mainRole.name : 'Moderator') + : (mainRole ? `(${mainRole.name}) ${modName}` : modName); + + return `**${modInfo}:** ${text}`; + }, + + formatStaffReplyThreadMessage(moderator, text, messageNumber, opts = {}) { + const mainRole = utils.getMainRole(moderator); + const modName = (config.useNicknames ? moderator.nick || moderator.user.username : moderator.user.username); + const modInfo = opts.isAnonymous + ? `(Anonymous) (${modName}) ${mainRole ? mainRole.name : 'Moderator'}` + : (mainRole ? `(${mainRole.name}) ${modName}` : modName); + + // TODO: Add \`[${messageNumber}]\` here once !edit and !delete exist + let result = `**${modInfo}:** ${text}`; + + if (config.threadTimestamps) { + const formattedTimestamp = utils.getTimestamp(); + result = `[${formattedTimestamp}] ${result}`; + } + + return result; + }, + + formatStaffReplyLogMessage(moderator, text, opts = {}) { + const mainRole = utils.getMainRole(moderator); + const modName = moderator.user.username; + + // Mirroring the DM formatting here... + const modInfo = opts.isAnonymous + ? (mainRole ? mainRole.name : 'Moderator') + : (mainRole ? `(${mainRole.name}) ${modName}` : modName); + + let result = `**${modInfo}:** ${text}`; + + if (opts.attachmentLinks && opts.attachmentLinks.length) { + result += '\n'; + for (const link of opts.attachmentLinks) { + result += `\n**Attachment:** ${link}`; + } + } + + return result; + }, + + formatUserReplyThreadMessage(user, msg, opts = {}) { + const content = (msg.content.trim() === '' && msg.embeds.length) + ? '' + : msg.content; + + let result = `**${user.username}#${user.discriminator}:** ${content}`; + + if (opts.attachmentLinks && opts.attachmentLinks.length) { + for (const link of opts.attachmentLinks) { + result += `\n\n${link}`; + } + } + + if (config.threadTimestamps) { + const formattedTimestamp = utils.getTimestamp(msg.timestamp, 'x'); + result = `[${formattedTimestamp}] ${result}`; + } + + return result; + }, + + formatUserReplyLogMessage(user, msg, opts = {}) { + const content = (msg.content.trim() === '' && msg.embeds.length) + ? '' + : msg.content; + + let result = content; + + if (opts.attachmentLinks && opts.attachmentLinks.length) { + for (const link of opts.attachmentLinks) { + result += `\n\n${link}`; + } + } + + return result; + }, +}; + +/** + * @type {MessageFormatters} + */ +const formatters = { ...defaultFormatters }; + +module.exports = { + formatters, + + /** + * @param {FormatStaffReplyDM} fn + * @return {void} + */ + setStaffReplyDMFormatter(fn) { + formatters.formatStaffReplyDM = fn; + }, + + /** + * @param {FormatStaffReplyThreadMessage} fn + * @return {void} + */ + setStaffReplyThreadMessageFormatter(fn) { + formatters.formatStaffReplyThreadMessage = fn; + }, + + /** + * @param {FormatStaffReplyLogMessage} fn + * @return {void} + */ + setStaffReplyLogMessageFormatter(fn) { + formatters.formatStaffReplyLogMessage = fn; + }, + + /** + * @param {FormatUserReplyThreadMessage} fn + * @return {void} + */ + setUserReplyThreadMessageFormatter(fn) { + formatters.formatUserReplyThreadMessage = fn; + }, + + /** + * @param {FormatUserReplyLogMessage} fn + * @return {void} + */ + setUserReplyLogMessageFormatter(fn) { + formatters.formatUserReplyLogMessage = fn; + }, +}; diff --git a/src/plugins.js b/src/plugins.js index 311cecd..7cf3a7f 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -1,5 +1,6 @@ const attachments = require('./data/attachments'); const { beforeNewThread } = require('./hooks'); +const formats = require('./formatters'); module.exports = { getPluginAPI({ bot, knex, config, commands }) { @@ -21,6 +22,7 @@ module.exports = { hooks: { beforeNewThread, }, + formats, }; },