From e5cf9f214e11ddb2a9636799016cccfd33245520 Mon Sep 17 00:00:00 2001 From: GramingFoxTeam Date: Mon, 7 Aug 2023 13:15:19 +0300 Subject: [PATCH] feat(bot-discord): mute and unmute command --- apps/bot-discord/src/commands/mute.js | 63 ++++ apps/bot-discord/src/commands/unmute.js | 54 ++++ apps/bot-discord/src/config.example.json | 18 +- apps/bot-discord/src/config.json | 18 +- apps/bot-discord/src/events/guildMemberAdd.js | 20 ++ apps/bot-discord/src/events/ready.js | 18 ++ apps/bot-discord/src/index.js | 6 + apps/bot-discord/src/package-lock.json | 288 +++++++++++++++++- apps/bot-discord/src/package.json | 4 +- apps/bot-discord/src/utils/muteMember.js | 74 +++++ apps/bot-discord/src/utils/reportToLogs.js | 7 +- apps/bot-discord/src/utils/setMuteTimeout.js | 19 ++ apps/bot-discord/src/utils/unmuteMember.js | 22 ++ 13 files changed, 605 insertions(+), 6 deletions(-) create mode 100644 apps/bot-discord/src/commands/mute.js create mode 100644 apps/bot-discord/src/commands/unmute.js create mode 100644 apps/bot-discord/src/events/guildMemberAdd.js create mode 100644 apps/bot-discord/src/events/ready.js create mode 100644 apps/bot-discord/src/utils/muteMember.js create mode 100644 apps/bot-discord/src/utils/setMuteTimeout.js create mode 100644 apps/bot-discord/src/utils/unmuteMember.js diff --git a/apps/bot-discord/src/commands/mute.js b/apps/bot-discord/src/commands/mute.js new file mode 100644 index 0000000..c99a422 --- /dev/null +++ b/apps/bot-discord/src/commands/mute.js @@ -0,0 +1,63 @@ +import { SlashCommandBuilder } from 'discord.js'; +import { checkForPerms } from '../utils/checkModPerms.js'; +import reportToLogs from '../utils/reportToLogs.js'; +import muteMember from '../utils/muteMember.js'; + +export default { + data: new SlashCommandBuilder() + .setName('mute') + .setDescription('Mute a member.') + .setDMPermission(false) + .addStringOption(option => + option + .setName('user') + .setDescription('The member to mute') + .setRequired(true) + ) + .addIntegerOption(option => + option + .setName('duration') + .setDescription('The duration of mute') + .setRequired(true) + ) + .addStringOption(option => + option + .setName('reason') + .setDescription('The reason of the mute') + .setRequired(true) + ), + async execute(_, config, interaction) { + if (!checkForPerms(config, interaction.member)) return interaction.reply({ + epheremal: true, + content: 'You don\'t have the required permissions.' + }); + + await interaction.deferReply(); + + let member; + try { + member = await interaction.guild.members.fetch(interaction.getString('user')); + } catch (_) { + await interaction.editReply({ + content: 'Could not find member.' + }); + + return; + } + + const reason = interaction.getString('reason'); + const parsedDuration = await muteMember(config, member, { + duration: interaction.getString('duration'), + reason, + supportMute: false + }); + + reportToLogs(config, interaction.client, 'muted', null, { + reason, + actionTo: await client.users.fetch(interaction.getString('user')), + actionBy: interaction.member, + channel: interaction.channel, + expire: parsedDuration + }); + } +}; diff --git a/apps/bot-discord/src/commands/unmute.js b/apps/bot-discord/src/commands/unmute.js new file mode 100644 index 0000000..1a95f5c --- /dev/null +++ b/apps/bot-discord/src/commands/unmute.js @@ -0,0 +1,54 @@ +import { SlashCommandBuilder } from 'discord.js'; +import { checkForPerms } from '../utils/checkModPerms.js'; +import reportToLogs from '../utils/reportToLogs.js'; +import unmuteMember from '../utils/unmuteMember.js'; + +export default { + data: new SlashCommandBuilder() + .setName('unmute') + .setDescription('Unmute a member.') + .setDMPermission(false) + .addStringOption(option => + option + .setName('user') + .setDescription('The member to unmute') + .setRequired(true) + ), + async execute(_, config, interaction) { + if (!checkForPerms(config, interaction.member)) return interaction.reply({ + epheremal: true, + content: 'You don\'t have the required permissions.' + }); + + await interaction.deferReply(); + + let member; + try { + member = await interaction.guild.members.fetch(interaction.getString('user')); + } catch (_) { + await interaction.editReply({ + content: 'Could not find member.' + }); + + return; + } + + const reason = interaction.getString('reason'); + const isMuted = await unmuteMember(config, member); + + if (!isMuted) { + await interaction.editReply({ + content: 'Member was not muted.' + }); + + return; + } + + reportToLogs(config, interaction.client, 'unmuted', null, { + reason, + actionTo: await client.users.fetch(interaction.getString('user')), + actionBy: interaction.member, + channel: interaction.channel, + }); + } +}; diff --git a/apps/bot-discord/src/config.example.json b/apps/bot-discord/src/config.example.json index d175c53..79d2185 100644 --- a/apps/bot-discord/src/config.example.json +++ b/apps/bot-discord/src/config.example.json @@ -14,7 +14,23 @@ "953965039105232906", "953964264400515092", "952987428786941952" - ] + ], + "mute": { + "takeRoles": [ + "996121272897519687", + "965267139902705744", + "995126555867086938" + ], + "giveRoles": [ + "953984696491061289" + ], + "supportTakeRoles" : [ + + ], + "supportGiveRoles" : [ + + ] + } }, "logs": { "channelId": "952987428786941952", diff --git a/apps/bot-discord/src/config.json b/apps/bot-discord/src/config.json index 596f0ac..bf94cde 100644 --- a/apps/bot-discord/src/config.json +++ b/apps/bot-discord/src/config.json @@ -14,7 +14,23 @@ "953965039105232906", "953964264400515092", "952987428786941952" - ] + ], + "mute": { + "takeRoles": [ + "996121272897519687", + "965267139902705744", + "995126555867086938" + ], + "giveRoles": [ + "953984696491061289" + ], + "supportTakeRoles" : [ + + ], + "supportGiveRoles" : [ + + ] + } }, "logs": { "channelId": "952987428786941952", diff --git a/apps/bot-discord/src/events/guildMemberAdd.js b/apps/bot-discord/src/events/guildMemberAdd.js new file mode 100644 index 0000000..978d154 --- /dev/null +++ b/apps/bot-discord/src/events/guildMemberAdd.js @@ -0,0 +1,20 @@ +import { Events } from 'discord.js'; + +export default { + name: Events.GuildMemberAdd, + once: false, + async execute(_, config, member) { + const mute = await client.db.collection('mute').findOne({ + guild_id: member.guild.id, + user_id: member.id + }); + + if (mute) { + // Add the roles given. + member.roles.add(mute.support_mute ? + config.mute.supportGiveRoles : + config.mute.giveRoles + ); + } + } +}; diff --git a/apps/bot-discord/src/events/ready.js b/apps/bot-discord/src/events/ready.js new file mode 100644 index 0000000..5ca2eab --- /dev/null +++ b/apps/bot-discord/src/events/ready.js @@ -0,0 +1,18 @@ +import { Events } from 'discord.js'; +import setMuteTimeout from '../utils/setMuteTimeout.js'; + +export default { + name: Events.ClientReady, + once: false, + async execute(_, config, client) { + console.log('Client is ready. Reloading mutes.'); + + const mutes = await client.db.collection('mute').find().toArray(); + + for (const mute of mutes) { + await setMuteTimeout(mute, client.mutes); + } + + console.log(`Loaded ${mutes.length} mutes.`); + } +}; diff --git a/apps/bot-discord/src/index.js b/apps/bot-discord/src/index.js index 27d9cac..7e0878c 100644 --- a/apps/bot-discord/src/index.js +++ b/apps/bot-discord/src/index.js @@ -7,10 +7,14 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); import HelperClient from '@revanced-helper/helper-client'; import config from './config.json' assert { type: 'json' }; +import { MongoClient } from 'mongodb'; const helper = new HelperClient(config); +const mongoDBClient = new MongoClient(process.env.MONGODB_URI); +await mongoDBClient.connect(); helper.connect(); + const client = new Client({ intents: [ GatewayIntentBits.Guilds, @@ -23,6 +27,8 @@ client.commands = new Collection(); client.trainingVotes = new Collection(); client.stickiedMessage = null; client.stickiedMessageTimeout = null; +client.db = mongoDBClient.db('revanced_discord_bot'); +client.mutes = new Collection(); const commandsPath = join(__dirname, 'commands'); const commandFiles = readdirSync(commandsPath).filter((file) => diff --git a/apps/bot-discord/src/package-lock.json b/apps/bot-discord/src/package-lock.json index 3a124d5..ae5a4c4 100644 --- a/apps/bot-discord/src/package-lock.json +++ b/apps/bot-discord/src/package-lock.json @@ -10,10 +10,13 @@ "license": "GPL-3.0-or-later", "dependencies": { "@revanced-helper/helper-client": "file:../../../packages/client", - "discord.js": "^14.11.0" + "discord.js": "^14.11.0", + "mongodb": "^5.7.0", + "parse-duration": "^1.1.0" } }, "../../../packages/client": { + "name": "@revanced-helper/helper-client", "version": "1.0.0", "license": "GPL-3.0-or-later", "dependencies": { @@ -146,6 +149,20 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz", "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==" }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" + }, + "node_modules/@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, "node_modules/@types/ws": { "version": "8.5.4", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", @@ -163,6 +180,14 @@ "npm": ">=7.0.0" } }, + "node_modules/bson": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-5.4.0.tgz", + "integrity": "sha512-WRZ5SQI5GfUuKnPTNmAYPiKIof3ORXAF4IRU5UcgmivNIon01rWQlw5RUH954dpu8yGL8T59YShVddIPaU/gFA==", + "engines": { + "node": ">=14.20.1" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -248,6 +273,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -258,6 +288,66 @@ "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "node_modules/mongodb": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.7.0.tgz", + "integrity": "sha512-zm82Bq33QbqtxDf58fLWBwTjARK3NSvKYjyz997KSy6hpat0prjeX/kxjbPVyZY60XYPDNETaHkHJI2UCzSLuw==", + "dependencies": { + "bson": "^5.4.0", + "mongodb-connection-string-url": "^2.6.0", + "socks": "^2.7.1" + }, + "engines": { + "node": ">=14.20.1" + }, + "optionalDependencies": { + "saslprep": "^1.0.3" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.201.0", + "@mongodb-js/zstd": "^1.1.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=2.3.0 <3", + "snappy": "^7.2.2" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "node_modules/parse-duration": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/parse-duration/-/parse-duration-1.1.0.tgz", + "integrity": "sha512-z6t9dvSJYaPoQq7quMzdEagSFtpGu+utzHqqxmpVWNNZRIXnvqyCvn9XsTdh7c/w0Bqmdz3RB3YnRaKtpRtEXQ==" + }, "node_modules/peek-readable": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", @@ -270,6 +360,14 @@ "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -317,6 +415,49 @@ } ] }, + "node_modules/saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "dependencies": { + "sparse-bitfield": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "optional": true, + "dependencies": { + "memory-pager": "^1.0.2" + } + }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -365,6 +506,17 @@ "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/ts-mixer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", @@ -391,6 +543,26 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/ws": { "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", @@ -511,6 +683,20 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz", "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==" }, + "@types/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" + }, + "@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "requires": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, "@types/ws": { "version": "8.5.4", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", @@ -524,6 +710,11 @@ "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz", "integrity": "sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ==" }, + "bson": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-5.4.0.tgz", + "integrity": "sha512-WRZ5SQI5GfUuKnPTNmAYPiKIof3ORXAF4IRU5UcgmivNIon01rWQlw5RUH954dpu8yGL8T59YShVddIPaU/gFA==" + }, "busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -583,6 +774,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -593,11 +789,47 @@ "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" }, + "memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "mongodb": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.7.0.tgz", + "integrity": "sha512-zm82Bq33QbqtxDf58fLWBwTjARK3NSvKYjyz997KSy6hpat0prjeX/kxjbPVyZY60XYPDNETaHkHJI2UCzSLuw==", + "requires": { + "bson": "^5.4.0", + "mongodb-connection-string-url": "^2.6.0", + "saslprep": "^1.0.3", + "socks": "^2.7.1" + } + }, + "mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "requires": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "parse-duration": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/parse-duration/-/parse-duration-1.1.0.tgz", + "integrity": "sha512-z6t9dvSJYaPoQq7quMzdEagSFtpGu+utzHqqxmpVWNNZRIXnvqyCvn9XsTdh7c/w0Bqmdz3RB3YnRaKtpRtEXQ==" + }, "peek-readable": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==" }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" + }, "readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -621,6 +853,38 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, + "saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, + "socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "optional": true, + "requires": { + "memory-pager": "^1.0.2" + } + }, "streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -652,6 +916,14 @@ "ieee754": "^1.2.1" } }, + "tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "requires": { + "punycode": "^2.1.1" + } + }, "ts-mixer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", @@ -675,6 +947,20 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" + }, + "whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "requires": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + } + }, "ws": { "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", diff --git a/apps/bot-discord/src/package.json b/apps/bot-discord/src/package.json index 30363ff..7bb1501 100644 --- a/apps/bot-discord/src/package.json +++ b/apps/bot-discord/src/package.json @@ -9,6 +9,8 @@ "license": "GPL-3.0-or-later", "dependencies": { "@revanced-helper/helper-client": "file:../../../packages/client", - "discord.js": "^14.11.0" + "discord.js": "^14.11.0", + "mongodb": "^5.7.0", + "parse-duration": "^1.1.0" } } diff --git a/apps/bot-discord/src/utils/muteMember.js b/apps/bot-discord/src/utils/muteMember.js new file mode 100644 index 0000000..f1b3610 --- /dev/null +++ b/apps/bot-discord/src/utils/muteMember.js @@ -0,0 +1,74 @@ +import parse from 'parse-duration' +import setMuteTimeout from './setMuteTimeout.js'; + +parse['mo'] = parse['month'] + +export default async function muteMember(config, member, { duration, reason, supportMute }) { + const parsedDuration = parse(duration); + const expires = Date.now() + parsedDuration; + const takenRoles = []; + for (const takeRole of supportMute ? + config.discord.mute.supportTakeRoles : + config.discord.mute.takeRoles + ) { + if (member.roles.cache.get(takeRole)) { + takenRoles.push(takeRoles); + } + } + + const existingMute = await member.client.db.collection('mute').findOne({ + guild_id: member.guild.id, + user_id: member.id + }); + + if (existingMute) { + // Update existing mute + + await member.client.db.collection('mute').updateOne({ + guild_id: member.guild.id, + user_id: member.id + }, { + $set: { + reason, + expires, + support_mute: supportMute + } + }); + + if (client.mutes.has(member.id)) { + clearTimeout(client.mutes.get(member.id)) + client.mutes.delete(member.id); + } + } else { + await member.client.db.collection('mute').insert({ + guild_id: member.guild.id, + user_id: member.id, + taken_roles: takenRoles, + expires, + reason, + support_mute: supportMute + }); + } + + // Remove the roles, give defined roles. + if (!existingMute) { + member.roles.remove(takenRoles); + member.roles.add(supportMute ? + config.discord.mute.giveRoles : + config.discord.mute.supportGiveRoles + ); + } + + + // Start a timeout. + setMuteTimeout({ + guild_id: member.guild.id, + user_id: member.id, + taken_roles: takenRoles, + expires, + support_mute: supportMute + }, member.client.mutes); + + // Return parsed time for the mute command to resolve. + return expires; +} \ No newline at end of file diff --git a/apps/bot-discord/src/utils/reportToLogs.js b/apps/bot-discord/src/utils/reportToLogs.js index 99a1b7e..50e05a4 100644 --- a/apps/bot-discord/src/utils/reportToLogs.js +++ b/apps/bot-discord/src/utils/reportToLogs.js @@ -3,9 +3,12 @@ import { EmbedBuilder, messageLink } from 'discord.js'; export default async function reportToLogs(config, client, action, message, { reason, expire, actionTo, actionBy }, msgChannel) { const channel = await client.channels.fetch(config.logs.channelId); const thread = await channel.threads.fetch(config.logs.threadId); - + + const actionUpper = action.charAt(0).toUpperCase() + action.slice(1); + const actionTitle = `${actionUpper} ${actionTo.tag}`; const actionEmbed = new EmbedBuilder() - .setThumbnail(actionTo.user.avatarURL()); + .setThumbnail(actionTo.user.avatarURL()) + .setTitle(actionTitle); const fields = [ { name: 'Action', value: `${actionTo.toString()} was ${action} by ${actionBy.toString()}` } diff --git a/apps/bot-discord/src/utils/setMuteTimeout.js b/apps/bot-discord/src/utils/setMuteTimeout.js new file mode 100644 index 0000000..b0f11af --- /dev/null +++ b/apps/bot-discord/src/utils/setMuteTimeout.js @@ -0,0 +1,19 @@ +export default async function setMuteTimeout(mute, mutes) { + const duration = Date.now() - mute.expires; + mutes.set(mute.user_id, setTimeout(async() => { + const guild = await client.guilds.fetch(mute.guild_id); + let member; + try { + member = await guild.members.fetch(mute.user_id); + } catch (_) { + return; + } + + member.roles.add(mute.taken_roles); + member.roles.remove( + mute.support_mute ? + config.discord.mute.supportGiveRoles : + config.discord.mute.giveRoles + ); + }, duration)); +} \ No newline at end of file diff --git a/apps/bot-discord/src/utils/unmuteMember.js b/apps/bot-discord/src/utils/unmuteMember.js new file mode 100644 index 0000000..d59e821 --- /dev/null +++ b/apps/bot-discord/src/utils/unmuteMember.js @@ -0,0 +1,22 @@ +export default async function unmuteMember(config, member) { + const mute = await member.client.db.collection('mute').findOne({ + guild_id: member.guild.id, + user_id: member.id + }); + + if (!mute) return false; + + member.roles.remove(mute.support_mute ? + config.mute.supportGiveRoles : + config.mute.giveRoles + ); + + member.roles.add(mute.taken_roles); + + await member.client.db.collection('mute').remove({ + guild_id: member.guild.id, + user_id: member.id + }); + + return true; +} \ No newline at end of file