From a334819db498145244362099f3270483b5d6d405 Mon Sep 17 00:00:00 2001 From: Dragon Fire Date: Tue, 18 May 2021 19:56:45 -0400 Subject: [PATCH] Clean-up --- .gitignore | 2 +- Xiao.js | 48 ++++----- commands/cleverbot/cleverbot-end.js | 2 +- commands/cleverbot/cleverbot.js | 2 +- commands/util/allow-cleverbot.js | 30 ------ commands/util/disallow-cleverbot.js | 31 ------ commands/util/force-patron.js | 29 ++++++ commands/util/unforce-patron.js | 30 ++++++ structures/BotList.js | 96 ++++++++++++++++++ structures/Client.js | 145 +--------------------------- structures/Patreon.js | 65 +++++++++++++ 11 files changed, 248 insertions(+), 232 deletions(-) delete mode 100644 commands/util/allow-cleverbot.js delete mode 100644 commands/util/disallow-cleverbot.js create mode 100644 commands/util/force-patron.js create mode 100644 commands/util/unforce-patron.js create mode 100644 structures/BotList.js create mode 100644 structures/Patreon.js diff --git a/.gitignore b/.gitignore index d0781de3..b8fad264 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,7 @@ config.json command-leaderboard.json command-last-run.json blacklist.json -cleverbot.json +patreon.json # Tensorflow Models tf_models/ diff --git a/Xiao.js b/Xiao.js index 19e4863b..69ddc8db 100644 --- a/Xiao.js +++ b/Xiao.js @@ -121,16 +121,16 @@ client.on('ready', async () => { } }, 1.8e+6); - // Import Cleverbot users + // Import forced patrons try { - const results = client.importCleverbotAllowed(); + const results = client.patreon.importForced(); if (results) { - client.logger.info('[CLEVERBOT] cleverbot.json successfully loaded.'); + client.logger.info('[CLEVERBOT] patreon.json successfully loaded.'); } else { - client.logger.error('[CLEVERBOT] cleverbot.json is not formatted correctly.'); + client.logger.error('[CLEVERBOT] patreon.json is not formatted correctly.'); } } catch (err) { - client.logger.error(`[CLEVERBOT] Could not parse cleverbot.json:\n${err.stack}`); + client.logger.error(`[CLEVERBOT] Could not parse patreon.json:\n${err.stack}`); } // Import blacklist @@ -213,37 +213,29 @@ client.on('ready', async () => { // Import Patrons try { - await client.fetchPatrons(); - for (const patron of client.patrons) { - if (client.allowedUsers.includes(patron)) continue; - client.allowedUsers.push(patron); - } + await client.patreon.fetchPatrons(); setInterval(() => { - client.fetchPatrons().then(() => { - for (const patron of client.patrons) { - if (client.allowedUsers.includes(patron)) continue; - client.allowedUsers.push(patron); - } - client.logger.info('[PATREON] Updated patron list.'); - }).catch(err => client.logger.error(`[PATREON] Failed to update patron list:\n${err.stack}`)); + client.patreon.fetchPatrons() + .then(() => client.logger.info('[PATREON] Updated patron list.')) + .catch(err => client.logger.error(`[PATREON] Failed to update patron list:\n${err.stack}`)); }, 3.6e+6); - client.logger.info(`[PATREON] Fetched ${client.patrons.length} patrons.`); + client.logger.info('[PATREON] Fetched patrons.'); } catch (err) { client.logger.error(`[PATREON] Failed to fetch patrons:\n${err.stack}`); } // Post bot list stats - await client.postTopGGStats(); - await client.postBotsGGStats(); - await client.postDiscordBotListStats(); - await client.postCarbonStats(); - await client.postBlistStats(); + await client.botList.postTopGGStats(); + await client.botList.postBotsGGStats(); + await client.botList.postDiscordBotListStats(); + await client.botList.postCarbonStats(); + await client.botList.postBlistStats(); setInterval(() => { - client.postTopGGStats(); - client.postBotsGGStats(); - client.postDiscordBotListStats(); - client.postCarbonStats(); - client.postBlistStats(); + client.botList.postTopGGStats(); + client.botList.postBotsGGStats(); + client.botList.postDiscordBotListStats(); + client.botList.postCarbonStats(); + client.botList.postBlistStats(); }, 1.8e+6); }); diff --git a/commands/cleverbot/cleverbot-end.js b/commands/cleverbot/cleverbot-end.js index a549ca98..1db5bc07 100644 --- a/commands/cleverbot/cleverbot-end.js +++ b/commands/cleverbot/cleverbot-end.js @@ -13,7 +13,7 @@ module.exports = class CleverbotEndCommand extends Command { } run(msg) { - if (!this.client.isOwner(msg.author) && !this.client.allowedUsers.includes(msg.author.id)) { + if (!this.client.isOwner(msg.author) && !this.client.patreon.isPatron(msg.author.id)) { return msg.say(stripIndents` You are not currently allowed to use Cleverbot. Please visit ${this.client.options.invite} for more information. diff --git a/commands/cleverbot/cleverbot.js b/commands/cleverbot/cleverbot.js index 7401adc0..8a79e7ac 100644 --- a/commands/cleverbot/cleverbot.js +++ b/commands/cleverbot/cleverbot.js @@ -22,7 +22,7 @@ module.exports = class CleverbotCommand extends Command { } run(msg) { - if (!this.client.isOwner(msg.author) && !this.client.allowedUsers.includes(msg.author.id)) { + if (!this.client.isOwner(msg.author) && !this.client.patreon.isPatron(msg.author.id)) { return msg.say(stripIndents` You are not currently allowed to use Cleverbot. Please visit ${this.client.options.invite} for more information. diff --git a/commands/util/allow-cleverbot.js b/commands/util/allow-cleverbot.js deleted file mode 100644 index 50f56bf7..00000000 --- a/commands/util/allow-cleverbot.js +++ /dev/null @@ -1,30 +0,0 @@ -const Command = require('../../structures/Command'); - -module.exports = class AllowCleverbotCommand extends Command { - constructor(client) { - super(client, { - name: 'allow-cleverbot', - aliases: ['allow-clevs'], - group: 'util', - memberName: 'allow-cleverbot', - description: 'Allows a user to use Cleverbot.', - details: 'Only the bot owner(s) may use this command.', - ownerOnly: true, - guarded: true, - args: [ - { - key: 'target', - prompt: 'Who do you want to allow? Use the ID.', - type: 'string' - } - ] - }); - } - - run(msg, { target }) { - if (this.client.allowedUsers.includes(target)) return msg.say(`🧠 \`${target}\` is already allowed.`); - this.client.allowedUsers.push(target); - this.client.exportCleverbotAllowed(); - return msg.say(`🧠 Allowed \`${target}\` to use Cleverbot.`); - } -}; diff --git a/commands/util/disallow-cleverbot.js b/commands/util/disallow-cleverbot.js deleted file mode 100644 index dd6837cc..00000000 --- a/commands/util/disallow-cleverbot.js +++ /dev/null @@ -1,31 +0,0 @@ -const Command = require('../../structures/Command'); -const { removeFromArray } = require('../../util/Util'); - -module.exports = class DisallowCleverbotCommand extends Command { - constructor(client) { - super(client, { - name: 'disallow-cleverbot', - aliases: ['disallow-clevs'], - group: 'util', - memberName: 'disallow-cleverbot', - description: 'Disallows a user from using Cleverbot.', - details: 'Only the bot owner(s) may use this command.', - ownerOnly: true, - guarded: true, - args: [ - { - key: 'target', - prompt: 'Who do you want to disallow? Use the ID.', - type: 'string' - } - ] - }); - } - - run(msg, { target }) { - if (!this.client.allowedUsers.includes(target)) return msg.say(`🧠 \`${target}\` is not allowed.`); - removeFromArray(this.client.allowedUsers, target); - this.client.exportCleverbotAllowed(); - return msg.say(`🧠 Disallowed \`${target}\` from using Cleverbot.`); - } -}; diff --git a/commands/util/force-patron.js b/commands/util/force-patron.js new file mode 100644 index 00000000..2ea8539c --- /dev/null +++ b/commands/util/force-patron.js @@ -0,0 +1,29 @@ +const Command = require('../../structures/Command'); + +module.exports = class ForcePatronCommand extends Command { + constructor(client) { + super(client, { + name: 'force-patron', + group: 'util', + memberName: 'force-patron', + description: 'Allows a user to use patron-only commands.', + details: 'Only the bot owner(s) may use this command.', + ownerOnly: true, + guarded: true, + args: [ + { + key: 'target', + prompt: 'Who do you want to allow? Use the ID.', + type: 'string' + } + ] + }); + } + + run(msg, { target }) { + if (this.client.patreon.isPatron(target)) return msg.say(`💸 \`${target}\` is already a patron.`); + this.client.patreon.forced.push(target); + this.client.patreon.exportForced(); + return msg.say(`💸 Allowed \`${target}\` to use patron-only commands.`); + } +}; diff --git a/commands/util/unforce-patron.js b/commands/util/unforce-patron.js new file mode 100644 index 00000000..825a62b1 --- /dev/null +++ b/commands/util/unforce-patron.js @@ -0,0 +1,30 @@ +const Command = require('../../structures/Command'); +const { removeFromArray } = require('../../util/Util'); + +module.exports = class UnforcePatronCommand extends Command { + constructor(client) { + super(client, { + name: 'unforce-patron', + group: 'util', + memberName: 'unforce-patron', + description: 'Disallows a user from using patron-only commands.', + details: 'Only the bot owner(s) may use this command.', + ownerOnly: true, + guarded: true, + args: [ + { + key: 'target', + prompt: 'Who do you want to disallow? Use the ID.', + type: 'string' + } + ] + }); + } + + run(msg, { target }) { + if (!this.client.patreon.isPatron(target)) return msg.say(`💸 \`${target}\` is not a patron.`); + removeFromArray(this.client.patreon.forced, target); + this.client.patreon.exportForced(); + return msg.say(`💸 Disallowed \`${target}\` from using patron-only commands.`); + } +}; diff --git a/structures/BotList.js b/structures/BotList.js new file mode 100644 index 00000000..1beb3d50 --- /dev/null +++ b/structures/BotList.js @@ -0,0 +1,96 @@ +const request = require('node-superfetch'); +const { + TOP_GG_TOKEN, + BOTS_GG_TOKEN, + DISCORDBOTLIST_TOKEN, + CARBON_TOKEN, + BLIST_TOKEN +} = process.env; + +module.exports = class BotList { + constructor(client) { + Object.defineProperty(this, 'client', { value: client }); + } + + async postTopGGStats() { + if (!TOP_GG_TOKEN) return null; + try { + const { body } = await request + .post(`https://top.gg/api/bots/${this.client.user.id}/stats`) + .set({ Authorization: TOP_GG_TOKEN }) + .send({ server_count: this.client.guilds.cache.size }); + this.client.logger.info('[TOP.GG] Posted stats.'); + return body; + } catch (err) { + this.client.logger.error(`[TOP.GG] Failed to post stats:\n${err.stack}`); + return err; + } + } + + async postBotsGGStats() { + if (!BOTS_GG_TOKEN) return null; + try { + const { body } = await request + .post(`https://discord.bots.gg/api/v1/bots/${this.client.user.id}/stats`) + .set({ Authorization: BOTS_GG_TOKEN }) + .send({ guildCount: this.client.guilds.cache.size }); + this.client.logger.info('[BOTS.GG] Posted stats.'); + return body; + } catch (err) { + this.client.logger.error(`[BOTS.GG] Failed to post stats:\n${err.stack}`); + return err; + } + } + + async postDiscordBotListStats() { + if (!DISCORDBOTLIST_TOKEN) return null; + try { + const { body } = await request + .post(`https://discordbotlist.com/api/v1/bots/${this.client.user.id}/stats`) + .set({ Authorization: DISCORDBOTLIST_TOKEN }) + .send({ + guilds: this.client.guilds.cache.size, + users: this.client.users.cache.size, + voice_connections: this.client.dispatchers.size + }); + this.client.logger.info('[DISCORDBOTLIST] Posted stats.'); + return body; + } catch (err) { + this.client.logger.error(`[DISCORDBOTLIST] Failed to post stats:\n${err.stack}`); + return err; + } + } + + async postCarbonStats() { + if (!CARBON_TOKEN) return null; + try { + const { body } = await request + .post('https://www.carbonitex.net/discord/data/botdata.php') + .send({ + key: CARBON_TOKEN, + servercount: this.client.guilds.cache.size, + botid: this.client.user.id + }); + this.client.logger.info('[CARBON] Posted stats.'); + return body; + } catch (err) { + this.client.logger.error(`[CARBON] Failed to post stats:\n${err.stack}`); + return err; + } + } + + async postBlistStats() { + if (!BLIST_TOKEN) return null; + try { + const { body } = await request + .patch(`https://blist.xyz/api/v2/bot/${this.client.user.id}/stats/`) + .set({ Authorization: BLIST_TOKEN }) + .send({ server_count: this.client.guilds.cache.size }); + this.client.logger.info('[BLIST] Posted stats.'); + return body; + } catch (err) { + this.client.logger.error(`[BLIST] Failed to post stats:\n${err.stack}`); + return err; + } + } +}; diff --git a/structures/Client.js b/structures/Client.js index b6dd0339..580bd15a 100644 --- a/structures/Client.js +++ b/structures/Client.js @@ -11,6 +11,8 @@ const url = require('url'); const path = require('path'); const Redis = require('./Redis'); const Font = require('./Font'); +const BotList = require('./BotList'); +const Patreon = require('./Patreon'); const PhoneManager = require('./phone/PhoneManager'); const TimerManager = require('./remind/TimerManager'); const PokemonStore = require('./pokemon/PokemonStore'); @@ -21,14 +23,7 @@ const { XIAO_WEBHOOK_TOKEN, REPORT_CHANNEL_ID, JOIN_LEAVE_CHANNEL_ID, - COMMAND_CHANNEL_ID, - PATREON_ACCESS_TOKEN, - PATREON_CAMPAIGN_ID, - TOP_GG_TOKEN, - BOTS_GG_TOKEN, - DISCORDBOTLIST_TOKEN, - CARBON_TOKEN, - BLIST_TOKEN + COMMAND_CHANNEL_ID } = process.env; module.exports = class XiaoClient extends CommandoClient { @@ -46,13 +41,14 @@ module.exports = class XiaoClient extends CommandoClient { this.redis = Redis ? Redis.db : null; this.webhook = new WebhookClient(XIAO_WEBHOOK_ID, XIAO_WEBHOOK_TOKEN, { disableMentions: 'everyone' }); this.timers = new TimerManager(this); + this.botList = new BotList(this); + this.patreon = new Patreon(); this.blacklist = { guild: [], user: [] }; this.patrons = null; this.pokemon = new PokemonStore(); this.games = new Collection(); this.dispatchers = new Map(); this.cleverbots = new Map(); - this.allowedUsers = []; this.phone = new PhoneManager(this); this.activities = activities; this.leaveMessages = leaveMsgs; @@ -77,111 +73,6 @@ module.exports = class XiaoClient extends CommandoClient { moment.tz.link('America/New_York|Dragon'); } - async fetchPatrons() { - if (!PATREON_ACCESS_TOKEN || !PATREON_CAMPAIGN_ID) return null; - const { text } = await request - .get(`https://www.patreon.com/api/oauth2/v2/campaigns/${PATREON_CAMPAIGN_ID}/members`) - .set({ Authorization: `Bearer ${PATREON_ACCESS_TOKEN}` }) - .query({ - include: 'currently_entitled_tiers,user', - 'fields[user]': 'social_connections', - 'fields[member]': 'patron_status' - }); - const body = JSON.parse(text); - const patrons = []; - for (const patron of body.data) { - if (patron.attributes.patron_status !== 'active_patron') continue; - const socials = body.included.find(user => user.id === patron.relationships.user.data.id) - ?.attributes?.social_connections; - if (!socials || !socials.discord || !socials.discord.user_id) continue; - patrons.push(socials.discord.user_id); - } - this.patrons = patrons; - return patrons; - } - - async postTopGGStats() { - if (!TOP_GG_TOKEN) return null; - try { - const { body } = await request - .post(`https://top.gg/api/bots/${this.user.id}/stats`) - .set({ Authorization: TOP_GG_TOKEN }) - .send({ server_count: this.guilds.cache.size }); - this.logger.info('[TOP.GG] Posted stats.'); - return body; - } catch (err) { - this.logger.error(`[TOP.GG] Failed to post stats:\n${err.stack}`); - return err; - } - } - - async postBotsGGStats() { - if (!BOTS_GG_TOKEN) return null; - try { - const { body } = await request - .post(`https://discord.bots.gg/api/v1/bots/${this.user.id}/stats`) - .set({ Authorization: BOTS_GG_TOKEN }) - .send({ guildCount: this.guilds.cache.size }); - this.logger.info('[BOTS.GG] Posted stats.'); - return body; - } catch (err) { - this.logger.error(`[BOTS.GG] Failed to post stats:\n${err.stack}`); - return err; - } - } - - async postDiscordBotListStats() { - if (!DISCORDBOTLIST_TOKEN) return null; - try { - const { body } = await request - .post(`https://discordbotlist.com/api/v1/bots/${this.user.id}/stats`) - .set({ Authorization: DISCORDBOTLIST_TOKEN }) - .send({ - guilds: this.guilds.cache.size, - users: this.users.cache.size, - voice_connections: this.dispatchers.size - }); - this.logger.info('[DISCORDBOTLIST] Posted stats.'); - return body; - } catch (err) { - this.logger.error(`[DISCORDBOTLIST] Failed to post stats:\n${err.stack}`); - return err; - } - } - - async postCarbonStats() { - if (!CARBON_TOKEN) return null; - try { - const { body } = await request - .post('https://www.carbonitex.net/discord/data/botdata.php') - .send({ - key: CARBON_TOKEN, - servercount: this.guilds.cache.size, - botid: this.user.id - }); - this.logger.info('[CARBON] Posted stats.'); - return body; - } catch (err) { - this.logger.error(`[CARBON] Failed to post stats:\n${err.stack}`); - return err; - } - } - - async postBlistStats() { - if (!BLIST_TOKEN) return null; - try { - const { body } = await request - .patch(`https://blist.xyz/api/v2/bot/${this.user.id}/stats/`) - .set({ Authorization: BLIST_TOKEN }) - .send({ server_count: this.guilds.cache.size }); - this.logger.info('[BLIST] Posted stats.'); - return body; - } catch (err) { - this.logger.error(`[BLIST] Failed to post stats:\n${err.stack}`); - return err; - } - } - importBlacklist() { const read = fs.readFileSync(path.join(__dirname, '..', 'blacklist.json'), { encoding: 'utf8' }); const file = JSON.parse(read); @@ -221,32 +112,6 @@ module.exports = class XiaoClient extends CommandoClient { return buf; } - importCleverbotAllowed() { - const read = fs.readFileSync(path.join(__dirname, '..', 'cleverbot.json'), { encoding: 'utf8' }); - const file = JSON.parse(read); - if (!Array.isArray(file)) return null; - for (const id of file) { - if (typeof id !== 'string') continue; - if (this.allowedUsers.includes(id)) continue; - this.allowedUsers.push(id); - } - return file; - } - - exportCleverbotAllowed() { - let text = '[\n '; - if (this.allowedUsers.length) { - for (const id of this.allowedUsers) { - text += `"${id}",\n `; - } - text = text.slice(0, -3); - } - text += '\n]\n'; - const buf = Buffer.from(text); - fs.writeFileSync(path.join(__dirname, '..', 'cleverbot.json'), buf, { encoding: 'utf8' }); - return buf; - } - importCommandLeaderboard(add = false) { const read = fs.readFileSync(path.join(__dirname, '..', 'command-leaderboard.json'), { encoding: 'utf8' diff --git a/structures/Patreon.js b/structures/Patreon.js new file mode 100644 index 00000000..a5099f4b --- /dev/null +++ b/structures/Patreon.js @@ -0,0 +1,65 @@ +const request = require('node-superfetch'); +const fs = require('fs'); +const { PATREON_ACCESS_TOKEN, PATREON_CAMPAIGN_ID } = process.env; + +module.exports = class Patreon { + constructor(accessToken, campaignID) { + this.patrons = []; + this.forced = []; + this.accessToken = accessToken || PATREON_ACCESS_TOKEN; + this.campignID = campaignID || PATREON_CAMPAIGN_ID; + } + + isPatron(id) { + return this.patrons.includes(id) || this.forced.includes(id); + } + + async fetchPatrons() { + if (!this.accessToken || !this.campignID) return null; + const { text } = await request + .get(`https://www.patreon.com/api/oauth2/v2/campaigns/${PATREON_CAMPAIGN_ID}/members`) + .set({ Authorization: `Bearer ${PATREON_ACCESS_TOKEN}` }) + .query({ + include: 'currently_entitled_tiers,user', + 'fields[user]': 'social_connections', + 'fields[member]': 'patron_status' + }); + const body = JSON.parse(text); + const patrons = []; + for (const patron of body.data) { + if (patron.attributes.patron_status !== 'active_patron') continue; + const socials = body.included.find(user => user.id === patron.relationships.user.data.id) + ?.attributes?.social_connections; + if (!socials || !socials.discord || !socials.discord.user_id) continue; + patrons.push(socials.discord.user_id); + } + this.patrons = patrons; + return this.patrons; + } + + importForced() { + const read = fs.readFileSync(path.join(__dirname, '..', 'patreon.json'), { encoding: 'utf8' }); + const file = JSON.parse(read); + if (!Array.isArray(file)) return null; + for (const id of file) { + if (typeof id !== 'string') continue; + if (this.forced.includes(id)) continue; + this.forced.push(id); + } + return file; + } + + exportForced() { + let text = '[\n '; + if (this.forced.length) { + for (const id of this.forced) { + text += `"${id}",\n `; + } + text = text.slice(0, -3); + } + text += '\n]\n'; + const buf = Buffer.from(text); + fs.writeFileSync(path.join(__dirname, '..', 'patreon.json'), buf, { encoding: 'utf8' }); + return buf; + } +};