diff --git a/commands/Economy/importmee6.js b/commands/Economy/importmee6.js index 4d55fcf1..ebac4149 100644 --- a/commands/Economy/importmee6.js +++ b/commands/Economy/importmee6.js @@ -1,5 +1,5 @@ const { SlashCommandBuilder } = require("discord.js"), - { getUserXp } = require("mee6-levels-api"); + Mee6Api = require("../../helpers/mee6-api"); const BaseCommand = require("../../base/BaseCommand"); class ImportMee6 extends BaseCommand { @@ -32,14 +32,17 @@ class ImportMee6 extends BaseCommand { * @param {Object} data */ async execute(client, interaction, data) { - const level = (await getUserXp(interaction.guildId, interaction.member)).level; + await interaction.deferReply(); + const level = (await Mee6Api.getUserXp(interaction.guildId, interaction.member)).level; data.memberData.level = level; await data.memberData.save(); - interaction.success("owner/debug:SUCCESS_LEVEL", { - username: interaction.member.toString(), - amount: level + interaction.editReply({ + content: interaction.translate("owner/debug:SUCCESS_LEVEL", { + username: interaction.member.toString(), + amount: level + }) }); } } diff --git a/helpers/mee6-api.js b/helpers/mee6-api.js new file mode 100644 index 00000000..2342d10d --- /dev/null +++ b/helpers/mee6-api.js @@ -0,0 +1,99 @@ +/* eslint-disable no-constant-condition */ + +// Thanks to mee6-levels-api =) +const fetch = require("node-fetch"); + +const fetchMee6 = async args => { + const response = await fetch(`https://mee6.xyz/api/plugins/levels/leaderboard/${args}`).then(res => res.json()); + if (response.statusCode !== 200) { + if (response.error && response.error.message) throw new Error(`${response.statusCode}: ${response.error.message}`); + else throw new Error(`${response.statusCode}: ${response.statusMessage}`); + } + return response; +}; + +class Mee6Api { + /** + * Resolves a guild or user to its ID. + * @param {{id:String}|String} guildOrUser Object to resolve to an ID. + * @returns {String} ID of the guild or user. + */ + static getId(guildOrUser) { + if (typeof guildOrUser === "string") + return guildOrUser; + else if (typeof guildOrUser.id === "string") + return guildOrUser.id; + else throw new Error("Invalid Id specified."); + } + + /** + * Gets role rewards set for a guild. + * @param {{id:String}|String} guild Guild to get role rewards of. + * @returns {Promise<[Object]>} Role rewards set for this guild. + */ + static async getRoleRewards(guild) { + const guildId = this.getId(guild); + const { role_rewards } = await fetchMee6(`${guildId}?limit=1`); + return role_rewards.sort((a, b) => a.rank - b.rank).map(({ rank, ...rest }) => ({ ...rest, level: rank })); + } + + /** + * Get a page of the leaderboard of a guild. + * @param {{id:String}|String} guild Guild to get the leaderboard of. + * @param {Number} limit Limit of users to fetch per page. Maximum 1000. + * @param {Number} page Number of pages to skip. + * @returns {Promise<[Object]>} Leaderboard page. + */ + static async getLeaderboardPage(guild, limit = 1000, page = 0) { + const guildId = this.getId(guild); + const { players } = await fetchMee6(`${guildId}?limit=${limit}&page=${page}`); + return players.map((user, index) => { + const { id, level, username, discriminator, avatar, message_count: messageCount } = user; + const avatarUrl = `https://cdn.discordapp.com/avatars/${id}/${avatar}`; + const [userXp, levelXp, totalXp] = user.detailed_xp; + return { + id, level, username, discriminator, avatarUrl, messageCount, + tag: `${username}#${discriminator}`, + xp: { userXp, levelXp, totalXp }, + rank: (limit * page) + index + 1 + }; + }); + } + + /** + * Get the leaderboard of a guild. + * @param {{id:String}|String} guild Guild to get the leaderboard of. + * @returns {Promise<[Object]>} Leaderboard of the guild. + */ + static async getLeaderboard(guild) { + const leaderboard = []; + let pageNumber = 0, page; + while (true) { + page = await this.getLeaderboardPage(guild, 1000, pageNumber); + leaderboard.push(...page); + if (page.length < 1000) break; + pageNumber += 1; + } + return leaderboard; + } + + /** + * Get the XP of an individual user in a guild. + * @param {{id:String}|String} guild Guild the user is in. + * @param {{id:String}|String} user User to get the XP of. + * @returns {Promise} XP information of the user. + */ + static async getUserXp(guild, user) { + const userId = this.getId(user); + let pageNumber = 0, page, userInfo; + while (true) { + page = await this.getLeaderboardPage(guild, 1000, pageNumber); + userInfo = page.find(u => u.id === userId); + if (page.length < 1000 || userInfo) break; + pageNumber += 1; + } + return userInfo; + } +} + +module.exports = Mee6Api; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 91d12d86..7ae46b7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,6 @@ "libsodium-wrappers": "^0.7.10", "markdown-table": "2.0.0", "md5": "^2.2.1", - "mee6-levels-api": "^1.3.0", "moment": "^2.26.0", "mongoose": "^5.13.14", "ms": "^2.1.3", @@ -1497,11 +1496,6 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/duplexer3": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", - "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==" - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -3108,112 +3102,6 @@ "node": ">= 0.6" } }, - "node_modules/mee6-levels-api": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/mee6-levels-api/-/mee6-levels-api-1.3.0.tgz", - "integrity": "sha512-F7JjRPbTHARWzZavnkAJHCzS58C0Fhr4sf2Bae8N5LBay4bBUvNZbajbYrZ3eR08MuIUh7SSx+6+kl6L61BJiQ==", - "dependencies": { - "got": "^10.3.0" - } - }, - "node_modules/mee6-levels-api/node_modules/@sindresorhus/is": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.1.tgz", - "integrity": "sha512-/aPsuoj/1Dw/kzhkgz+ES6TxG0zfTMGLwuK2ZG00k/iJzYHTLCE8mVU8EPqEOp/lmxPoq1C1C9RYToRKb2KEfg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/mee6-levels-api/node_modules/cacheable-lookup": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-2.0.1.tgz", - "integrity": "sha512-EMMbsiOTcdngM/K6gV/OxF2x0t07+vMOWxZNSCRQMjO2MY2nhZQ6OYhOOpyQrbhqsgtvKGI7hcq6xjnA92USjg==", - "dependencies": { - "@types/keyv": "^3.1.1", - "keyv": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mee6-levels-api/node_modules/decompress-response": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-5.0.0.tgz", - "integrity": "sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==", - "dependencies": { - "mimic-response": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mee6-levels-api/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mee6-levels-api/node_modules/got": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/got/-/got-10.7.0.tgz", - "integrity": "sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg==", - "dependencies": { - "@sindresorhus/is": "^2.0.0", - "@szmarczak/http-timer": "^4.0.0", - "@types/cacheable-request": "^6.0.1", - "cacheable-lookup": "^2.0.0", - "cacheable-request": "^7.0.1", - "decompress-response": "^5.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^5.0.0", - "lowercase-keys": "^2.0.0", - "mimic-response": "^2.1.0", - "p-cancelable": "^2.0.0", - "p-event": "^4.0.0", - "responselike": "^2.0.0", - "to-readable-stream": "^2.0.0", - "type-fest": "^0.10.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, - "node_modules/mee6-levels-api/node_modules/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mee6-levels-api/node_modules/type-fest": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", - "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", @@ -3652,39 +3540,6 @@ "node": ">=8" } }, - "node_modules/p-event": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", - "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", - "dependencies": { - "p-timeout": "^3.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "engines": { - "node": ">=4" - } - }, - "node_modules/p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", - "dependencies": { - "p-finally": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -4506,14 +4361,6 @@ "resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz", "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==" }, - "node_modules/to-readable-stream": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-2.1.0.tgz", - "integrity": "sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==", - "engines": { - "node": ">=8" - } - }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -6003,11 +5850,6 @@ "domhandler": "^4.2.0" } }, - "duplexer3": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", - "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==" - }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -7259,78 +7101,6 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, - "mee6-levels-api": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/mee6-levels-api/-/mee6-levels-api-1.3.0.tgz", - "integrity": "sha512-F7JjRPbTHARWzZavnkAJHCzS58C0Fhr4sf2Bae8N5LBay4bBUvNZbajbYrZ3eR08MuIUh7SSx+6+kl6L61BJiQ==", - "requires": { - "got": "^10.3.0" - }, - "dependencies": { - "@sindresorhus/is": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.1.tgz", - "integrity": "sha512-/aPsuoj/1Dw/kzhkgz+ES6TxG0zfTMGLwuK2ZG00k/iJzYHTLCE8mVU8EPqEOp/lmxPoq1C1C9RYToRKb2KEfg==" - }, - "cacheable-lookup": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-2.0.1.tgz", - "integrity": "sha512-EMMbsiOTcdngM/K6gV/OxF2x0t07+vMOWxZNSCRQMjO2MY2nhZQ6OYhOOpyQrbhqsgtvKGI7hcq6xjnA92USjg==", - "requires": { - "@types/keyv": "^3.1.1", - "keyv": "^4.0.0" - } - }, - "decompress-response": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-5.0.0.tgz", - "integrity": "sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==", - "requires": { - "mimic-response": "^2.0.0" - } - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "requires": { - "pump": "^3.0.0" - } - }, - "got": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/got/-/got-10.7.0.tgz", - "integrity": "sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg==", - "requires": { - "@sindresorhus/is": "^2.0.0", - "@szmarczak/http-timer": "^4.0.0", - "@types/cacheable-request": "^6.0.1", - "cacheable-lookup": "^2.0.0", - "cacheable-request": "^7.0.1", - "decompress-response": "^5.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^5.0.0", - "lowercase-keys": "^2.0.0", - "mimic-response": "^2.1.0", - "p-cancelable": "^2.0.0", - "p-event": "^4.0.0", - "responselike": "^2.0.0", - "to-readable-stream": "^2.0.0", - "type-fest": "^0.10.0" - } - }, - "mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" - }, - "type-fest": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", - "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==" - } - } - }, "memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", @@ -7643,27 +7413,6 @@ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==" }, - "p-event": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", - "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", - "requires": { - "p-timeout": "^3.1.0" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==" - }, - "p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", - "requires": { - "p-finally": "^1.0.0" - } - }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -8280,11 +8029,6 @@ "resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz", "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==" }, - "to-readable-stream": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-2.1.0.tgz", - "integrity": "sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==" - }, "toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", diff --git a/package.json b/package.json index 84c8115e..ece04984 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,6 @@ "libsodium-wrappers": "^0.7.10", "markdown-table": "2.0.0", "md5": "^2.2.1", - "mee6-levels-api": "^1.3.0", "moment": "^2.26.0", "mongoose": "^5.13.14", "ms": "^2.1.3",