diff --git a/app/commands/add-feed.js b/app/commands/add-feed.js new file mode 100644 index 0000000..9116471 --- /dev/null +++ b/app/commands/add-feed.js @@ -0,0 +1,50 @@ +const Core = require("../../discord-bot-core"); +const GetUrls = require("get-urls"); +const FeedData = require("../models/feed-data.js"); +const GuildData = require("../models/guild-data.js"); +// @ts-ignore +const Config = require("../config.json"); + +module.exports = new Core.Command({ + name: "add-feed", + description: "Add an RSS feed to be posted in a channel, with an optional role to tag", + syntax: "add-feed <#channel> [@role]", + admin: true, + invoke: invoke +}); + +function invoke({ message, params, guildData, client }) { + const feedUrl = [...GetUrls(message.content)][0]; + const channel = message.mentions.channels.first(); + + if (!feedUrl || !channel) + return Promise.reject("Please provide both a channel and an RSS feed URL. You can optionally @mention a role also."); + + const role = message.mentions.roles.first(); + + const feedData = new FeedData({ + url: feedUrl, + channelName: channel.name, + roleName: role ? role.name : null, + maxCacheSize: Config.maxCacheSize + }); + + return new Promise((resolve, reject) => { + //ask the user if they're happy with the details they set up, save if yes, don't if no + Core.util.ask(client, message.channel, message.member, "Are you happy with this (yes/no)?\n" + feedData.toString()) + .then(responseMessage => { + + //if they responded yes, save the feed and let them know, else tell them to start again + if (responseMessage.content.toLowerCase() === "yes") { + if (!guildData) + guildData = new GuildData({ id: message.guild.id, feeds: [] }); + + guildData.feeds.push(feedData); + guildData.cachePastPostedLinks(message.guild) + .then(() => resolve("Your new feed has been saved!")); + } + else + reject("Your feed has not been saved, please add it again with the correct details"); + }); + }); +} \ No newline at end of file diff --git a/app/commands/on-text-message.js b/app/commands/on-text-message.js new file mode 100644 index 0000000..e69de29 diff --git a/app/commands/remove-feed.js b/app/commands/remove-feed.js new file mode 100644 index 0000000..c16990f --- /dev/null +++ b/app/commands/remove-feed.js @@ -0,0 +1,18 @@ +const Core = require("../../discord-bot-core"); + +module.exports = new Core.Command({ + name: "remove-feed", + description: "Remove an RSS feed by it's ID", + syntax: "remove-feed ", + admin: true, + invoke: invoke +}); + +function invoke({ message, params, guildData, client }) { + const idx = guildData.feeds.findIndex(feed => feed.id === params[2]); + if (!Number.isInteger(idx)) + return Promise.reject("Can't find feed with id " + params[2]); + + guildData.feeds.splice(idx, 1); + return Promise.resolve("Feed removed!"); +} \ No newline at end of file diff --git a/app/commands/view-feeds.js b/app/commands/view-feeds.js new file mode 100644 index 0000000..1ff56c3 --- /dev/null +++ b/app/commands/view-feeds.js @@ -0,0 +1,16 @@ +const Core = require("../../discord-bot-core"); + +module.exports = new Core.Command({ + name: "view-feeds", + description: "View a list of configured feeds and their associated details", + syntax: "view-feed", + admin: true, + invoke: invoke +}); + +function invoke({ message, params, guildData, client }) { + if (!guildData) + return Promise.reject("Guild not setup"); + + return Promise.resolve(guildData.feeds.map(f => f.toString()).join("\n")); +} \ No newline at end of file diff --git a/app/index.js b/app/index.js index 4b137d4..36f9ad5 100644 --- a/app/index.js +++ b/app/index.js @@ -1,79 +1,32 @@ -const GetUrls = require("get-urls"); //for extracting urls from messages const Core = require("../discord-bot-core"); +const GetUrls = require("get-urls"); const GuildData = require("./models/guild-data.js"); -const FeedData = require("./models/feed-data.js"); +// @ts-ignore const Config = require("./config.json"); -//IMPLEMENTATIONS// -function onReady(coreClient) { - return new Promise((resolve, reject) => { - parseLinksInGuilds(coreClient.actual.guilds, coreClient.guildsData) - .then(() => checkFeedsInGuilds(coreClient.actual.guilds, coreClient.guildsData)) - .then(() => setInterval(() => checkFeedsInGuilds(coreClient.actual.guilds, coreClient.guildsData), Config.feedCheckIntervalSec * 1000)) - .then(resolve) - .catch(reject); - }); -} +const token = require("../" + process.argv[2]).token, + dataFile = process.argv[3]; -function onTextMessage(message, guildData) { +const client = new Core.Client(token, dataFile, __dirname + "/commands", GuildData); + +client.on("beforeLogin", () => { + setInterval(() => checkFeedsInGuilds(client.guilds, client.guildsData), Config.feedCheckIntervalSec * 1000); +}); + +client.on("ready", (coreClient) => { + parseLinksInGuilds(coreClient.actual.guilds, coreClient.guildsData) + .then(() => checkFeedsInGuilds(coreClient.actual.guilds, coreClient.guildsData)); +}); + +client.on("message", message => { + const guildData = client.guildsData[message.guild.id]; guildData.feeds.forEach(feedData => { if (message.channel.name === feedData.channelName) - feedData.cachedLinks.push(...GetUrls(message.content)); //spread the urlSet returned by GetUrls into the cache array + feedData.cachedLinks.push(...GetUrls(message.content)); }); - return Promise.resolve(); -} +}); -function addFeed({ command, params, guildData, botName, message, coreClient }) { - const feedUrl = [...GetUrls(message.content)][0]; - const channel = message.mentions.channels.first(); - - if (!feedUrl || !channel) - return Promise.reject("Please provide both a channel and an RSS feed URL. You can optionally @mention a role also."); - - const role = message.mentions.roles.first(); - - const feedData = new FeedData({ - url: feedUrl, - channelName: channel.name, - roleName: role ? role.name : null, - maxCacheSize: Config.maxCacheSize - }); - - return new Promise((resolve, reject) => { - //ask the user if they're happy with the details they set up, save if yes, don't if no - Core.util.ask(coreClient.actual, message.channel, message.member, "Are you happy with this (yes/no)?\n" + feedData.toString()) - .then(responseMessage => { - - //if they responded yes, save the feed and let them know, else tell them to start again - if (responseMessage.content.toLowerCase() === "yes") { - if (!guildData) - guildData = new GuildData({ id: message.guild.id, feeds: [] }); - - guildData.feeds.push(feedData); - guildData.cachePastPostedLinks(message.guild) - .then(() => resolve("Your new feed has been saved!")); - } - else - reject("Your feed has not been saved, please add it again with the correct details"); - }); - }); -} - -function removeFeed({ command, params, guildData, botName, message, coreClient }) { - const idx = guildData.feeds.findIndex(feed => feed.id === params[2]); - if (!Number.isInteger(idx)) - return Promise.reject("Can't find feed with id " + params[2]); - - guildData.feeds.splice(idx, 1); - return Promise.resolve("Feed removed!"); -} - -function viewFeeds({ command, params, guildData, botName, message, coreClient }) { - if (!guildData) - return Promise.reject("Guild not setup"); - - return Promise.resolve(guildData.feeds.map(f => f.toString()).join("\n")); -} +client.bootstrap(); //INTERNAL FUNCTIONS// function checkFeedsInGuilds(guilds, guildsData) { @@ -88,18 +41,4 @@ function parseLinksInGuilds(guilds, guildsData) { promises.push(guildData.cachePastPostedLinks(guilds.get(guildId))); } return Promise.all(promises); -} - -//CLIENT SETUP// -const token = require("../" + process.argv[2]).token, - dataFile = process.argv[3], - commands = require("./commands.json"), - implementations = { - onReady, - onTextMessage, - addFeed, - removeFeed, - viewFeeds - }; -const client = new Core.Client(token, dataFile, commands, implementations, GuildData); -client.bootstrap(); \ No newline at end of file +} \ No newline at end of file diff --git a/app/models/feed-data.js b/app/models/feed-data.js index b84f651..5d3bed6 100644 --- a/app/models/feed-data.js +++ b/app/models/feed-data.js @@ -9,7 +9,7 @@ const GetUrls = require("get-urls"); //for extracting urls from messages const ShortID = require("shortid"); //to provide ids for each feed, allowing guilds to remove them module.exports = class FeedData { - constructor({ id, url, channelName, roleName, cachedLinks, maxCacheSize }) { + constructor({ id = null, url, channelName, roleName, cachedLinks = null, maxCacheSize }) { this.id = id || ShortID.generate(); this.url = url; this.channelName = channelName; @@ -28,14 +28,10 @@ module.exports = class FeedData { }; } - /** - * Returns a promise providing all the links posted in the last 100 messages - * @param {Discord.Guild} guild The guild this feed belongs to - * @returns {Promise} Links posted in last 100 messages - */ + /**@param param*/ updatePastPostedLinks(guild) { const channel = guild.channels.find(ch => ch.type === "text" && ch.name === this.channelName); - + return new Promise((resolve, reject) => { channel.fetchMessages({ limit: 100 }) .then(messages => { @@ -46,6 +42,7 @@ module.exports = class FeedData { }); } + /**@param param */ check(guild) { Dns.resolve(Url.parse(this.url).host || "", err => { //check we can resolve the host, so we can throw an appropriate error if it fails if (err)