diff --git a/library.js b/library.js index 5290e8b..a5b9d0c 100644 --- a/library.js +++ b/library.js @@ -1,79 +1,91 @@ -(function(module) { - 'use strict'; - - var User = require.main.require('./src/user'); - var Topics = require.main.require('./src/topics'); - var Categories = require.main.require('./src/categories'); - var translator = require.main.require('./src/translator'); - var meta = require.main.require('./src/meta'); - var nconf = require.main.require('nconf'); - var async = require.main.require('async'); - - var Discord = require('discord.js'); - - var hook = null; - var forumURL = nconf.get('url'); - - var plugin = { - config: { - webhookURL: '', - maxLength: '', - postCategories: '', - topicsOnly: '', - messageContent: '' - }, - regex: /https:\/\/discord(?:app)?\.com\/api\/webhooks\/([0-9]+?)\/(.+?)$/ - }; - - plugin.init = function(params, callback) { - function render(req, res, next) { - res.render('admin/plugins/discord-notification', {}); +'use strict'; + +const user = require.main.require('./src/user'); +const topics = require.main.require('./src/topics'); +const categories = require.main.require('./src/categories'); +const translator = require.main.require('./src/translator'); +const meta = require.main.require('./src/meta'); +const nconf = require.main.require('nconf'); +const async = require.main.require('async'); + +const Discord = require('discord.js'); + +let hook = null; +var forumURL = nconf.get('url'); + +const renderAdmin = async function(req, res, next) { + const allCategories = await categories.buildForSelectAll(['value', 'text']); + res.render( + 'admin/plugins/discord-notification', + { + title: '[[discord-notification:title]]', + allCategories: allCategories, } + ); +} - params.router.get('/admin/plugins/discord-notification', params.middleware.admin.buildHeader, render); - params.router.get('/api/admin/plugins/discord-notification', render); +const discordNotification = { + config: {}, - meta.settings.get('discord-notification', function(err, settings) { - for (var prop in plugin.config) { - if (settings.hasOwnProperty(prop)) { - plugin.config[prop] = settings[prop]; - } - } + onLoad: async function(params) { + const routeHelpers = require.main.require('./src/routes/helpers'); + routeHelpers.setupAdminPageRoute(params.router, '/admin/plugins/discord-notification', renderAdmin); + discordNotification.init(); + }, - // Parse Webhook URL (1: ID, 2: Token) - var match = plugin.config['webhookURL'].match(plugin.regex); + init: function () { + // Load saved config + const _self = this; + const defaults = { + webhookURL: '', + maxLength: 1024, + postCategories: '', + topicsOnly: 'off', + messageContent: '', + }; + const notCheckboxes = ['webhookURL', 'maxLength', 'postCategories', 'messageContent']; - if (match) { - hook = new Discord.WebhookClient(match[1], match[2]); + meta.settings.get('discord-notification', (err, options) => { + if (err) { + winston.warn(`[plugin//discord-notification] Unable to retrieve settings, assuming defaults: ${err.message}`); } - }); - callback(); + Object.keys(defaults).forEach((field) => { + // If not set in config (nil) + if (!options.hasOwnProperty(field)) { + _self.config[field] = defaults[field]; + } else if (!notCheckboxes.includes(field)) { + _self.config[field] = options[field] === 'on'; + } else { + _self.config[field] = options[field]; + } + }); + }); }, - plugin.postSave = function(post) { + postSave: function(post) { post = post.post; - var topicsOnly = plugin.config['topicsOnly'] || 'off'; + var topicsOnly = discordNotification.config['topicsOnly'] || 'off'; if (topicsOnly === 'off' || (topicsOnly === 'on' && post.isMain)) { var content = post.content; async.parallel({ user: function(callback) { - User.getUserFields(post.uid, ['username', 'picture'], callback); + user.getUserFields(post.uid, ['username', 'picture'], callback); }, topic: function(callback) { - Topics.getTopicFields(post.tid, ['title', 'slug'], callback); + topics.getTopicFields(post.tid, ['title', 'slug'], callback); }, category: function(callback) { - Categories.getCategoryFields(post.cid, ['name', 'bgColor'], callback); + categories.getCategoryFields(post.cid, ['name', 'bgColor'], callback); } }, function(err, data) { - var categories = JSON.parse(plugin.config['postCategories']); + var categories = JSON.parse(discordNotification.config['postCategories']); if (!categories || categories.indexOf(String(post.cid)) >= 0) { // Trim long posts: - var maxQuoteLength = plugin.config['maxLength'] || 1024; + var maxQuoteLength = discordNotification.config['maxLength'] || 1024; if (content.length > maxQuoteLength) { content = content.substring(0, maxQuoteLength) + '...'; } // Ensure absolute thumbnail URL if an avatar exists: @@ -86,27 +98,27 @@ } // Add custom message: - var messageContent = plugin.config['messageContent'] || ''; - + const messageContent = discordNotification.config['messageContent'] || ''; + // Make the rich embed: - var embed = new Discord.MessageEmbed() + const embed = new Discord.EmbedBuilder() .setColor(data.category.bgColor) .setURL(forumURL + '/topic/' + data.topic.slug) .setTitle(data.category.name + ': ' + data.topic.title) .setDescription(content) - .setFooter(data.user.username, thumbnail) + .setFooter({ text: data.user.username, iconURL: thumbnail }) .setTimestamp(); - // Send notification: if (hook) { - hook.send(messageContent, {embeds: [embed]}).catch(console.error); + hook.send({content: messageContent, embeds: [embed]}) + .catch(console.error); } } }); } }, - plugin.addAdminMenu = function(header, callback) { + addAdminMenu: function(header, callback) { translator.translate('[[discord-notification:title]]', function(title) { header.plugins.push({ route : '/plugins/discord-notification', @@ -116,8 +128,33 @@ callback(null, header); }); - }; + }, + + getConfig: async (config) => { + let { webhookURL, maxLength, postCategories, topicsOnly, messageContent } = await meta.settings.get('discord-notification'); + + try { + // Parse Webhook URL (1: ID, 2: Token) + const discordRegex = /https:\/\/discord(?:app)?\.com\/api\/webhooks\/([0-9]+?)\/(.+?)$/; + const match = webhookURL.match(discordRegex); + + if (match) { + hook = new Discord.WebhookClient({ id: match[1], token: match[2] }); + } + } catch (e) { + // Do nothing + } - module.exports = plugin; + config.discordNotification = { + webhookURL, + maxLength, + postCategories, + topicsOnly, + messageContent + }; + + return config; + }, +}; -}(module)); +module.exports = discordNotification; \ No newline at end of file diff --git a/package.json b/package.json index 17620b8..954f02c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nodebb-plugin-discord-notification", "title": "Discord Notifications for NodeBB", - "version": "1.5.0", + "version": "1.6.0", "description": "Send notifications of new posts and topics via Discord webhook.", "keywords": [ "discord", @@ -24,9 +24,9 @@ "license": "MIT", "main": "library.js", "dependencies": { - "discord.js": "^12.4.1" + "discord.js": "^14.25.1" }, "nbbpm": { - "compatibility": "^2.0.0" + "compatibility": "^4.0.0" } } diff --git a/plugin.json b/plugin.json index 25fea1e..baa62d6 100644 --- a/plugin.json +++ b/plugin.json @@ -5,8 +5,9 @@ "url": "https://github.com/amargon/nodebb-plugin-discord-notification", "library": "./library.js", "hooks": [ - { "hook": "static:app.load", "method": "init" }, + { "hook": "static:app.load", "method": "onLoad" }, { "hook": "filter:admin.header.build", "method": "addAdminMenu" }, + { "hook": "filter:config.get", "method": "getConfig" }, { "hook": "action:post.save", "method": "postSave"} ], "modules": { @@ -14,5 +15,6 @@ }, "templates": "./public/templates", "languages": "./languages", + "defaultLang": "en_GB", "settingsRoute": "/admin/plugins/discord-notification" } diff --git a/public/src/admin.js b/public/src/admin.js index f8d9d9a..5dac784 100644 --- a/public/src/admin.js +++ b/public/src/admin.js @@ -1,28 +1,39 @@ -const settings = require('settings'); -const hooks = require('hooks'); +'use strict'; -hooks.onPage('action:ajaxify.end', () => { - // note: this is probably deprecated in core soon... - socket.emit('categories.get', function(err, data) { - categories = data; - for (var i = 0; i < categories.length; ++i) { - $('#postCategories').append(''); - } - }); -}) +define('admin/plugins/discord-notification', ['settings'], function (Settings) { + let discordNotification = {}; -settings.load('discord-notification', $('.discord-notification-settings')); + discordNotification.init = function () { + Settings.load('discord-notification', $('.discord-notification-settings'), function (err, settings) { + if (err) { + settings = {}; + } + + var defaults = { + webhookURL: '', + maxLength: 1024, + postCategories: '', + topicsOnly: false, + messageContent: '', + }; -$('#save').on('click', function() { - settings.save('discord-notification', $('.discord-notification-settings'), function() { - app.alert({ - type: 'success', - alert_id: 'discord-notification-saved', - title: 'Settings Saved', - message: 'Please reload your NodeBB to apply these settings', - clickfn: function() { - socket.emit('admin.reload'); + // Set defaults + for (const setting of Object.keys(defaults)) { + if (!settings.hasOwnProperty(setting)) { + if (typeof defaults[setting] === 'boolean') { + $('#' + setting).prop('checked', defaults[setting]); + } else { + $('#' + setting).val(defaults[setting]); + } + } } }); - }); + + $('#save').on('click', function () { + console.log('Saving settings'); + Settings.save('discord-notification', $('.discord-notification-settings')); + }); + }; + + return discordNotification; }); diff --git a/public/templates/admin/plugins/discord-notification.tpl b/public/templates/admin/plugins/discord-notification.tpl index 6dab9c0..6589d79 100644 --- a/public/templates/admin/plugins/discord-notification.tpl +++ b/public/templates/admin/plugins/discord-notification.tpl @@ -1,42 +1,45 @@ -