Explorar o código

discord.js v13

Markus-Rost %!s(int64=3) %!d(string=hai) anos
pai
achega
e4f9f9574f

+ 1 - 1
.github/workflows/nodejs.yml

@@ -22,7 +22,7 @@ jobs:
           - 5432:5432
           - 5432:5432
     strategy:	
     strategy:	
       matrix:	
       matrix:	
-        node-version: [14.x]
+        node-version: [16.6.x]
     steps:
     steps:
     - uses: actions/checkout@v2
     - uses: actions/checkout@v2
     - name: Use Node.js ${{ matrix.node-version }}
     - name: Use Node.js ${{ matrix.node-version }}

+ 149 - 194
bot.js

@@ -2,77 +2,70 @@ const util = require('util');
 util.inspect.defaultOptions = {compact:false,breakLength:Infinity};
 util.inspect.defaultOptions = {compact:false,breakLength:Infinity};
 
 
 global.isDebug = ( process.argv[2] === 'debug' );
 global.isDebug = ( process.argv[2] === 'debug' );
-global.shardId = null;
-process.on( 'message', message => {
-	if ( !message.shard ) return;
-	shardId = message.shard.id;
-} );
 
 
 const Lang = require('./util/i18n.js');
 const Lang = require('./util/i18n.js');
 const Wiki = require('./util/wiki.js');
 const Wiki = require('./util/wiki.js');
 const newMessage = require('./util/newMessage.js');
 const newMessage = require('./util/newMessage.js');
-const {slashCommands, allowDelete} = require('./util/functions.js');
+const {allowDelete} = require('./util/functions.js');
 global.patreons = {};
 global.patreons = {};
 global.voice = {};
 global.voice = {};
 const db = require('./util/database.js');
 const db = require('./util/database.js');
 
 
 const Discord = require('discord.js');
 const Discord = require('discord.js');
 const client = new Discord.Client( {
 const client = new Discord.Client( {
-	messageEditHistoryMaxSize: 1,
-	messageCacheLifetime: 300,
-	messageSweepInterval: 300,
+	makeCache: Discord.Options.cacheWithLimits( {
+		MessageManager: {
+			maxSize: 100,
+			sweepInterval: 300,
+			sweepFilter: Discord.LimitedCollection.filterByLifetime( {
+				lifetime: 300,
+			} )
+		},
+		PresenceManager: 0
+	} ),
 	allowedMentions: {
 	allowedMentions: {
-		parse: []
+		parse: [],
+		repliedUser: true
 	},
 	},
+	failIfNotExists: false,
 	presence: ( process.env.READONLY ? {
 	presence: ( process.env.READONLY ? {
 		status: 'dnd',
 		status: 'dnd',
-		activity: {
+		activities: [{
 			type: 'PLAYING',
 			type: 'PLAYING',
-			name: 'READONLY: ' + process.env.prefix + 'test'
-		}
+			name: 'READONLY: ' + process.env.prefix + 'test' + ( process.env.SHARD_COUNT > 1 ? ' • Shard: ' + process.env.SHARDS : '' ),
+		}],
+		shardId: process.env.SHARDS
 	} : {
 	} : {
 		status: 'online',
 		status: 'online',
-		activity: {
+		activities: [{
 			type: 'STREAMING',
 			type: 'STREAMING',
-			name: process.env.prefix + 'help',
+			name: process.env.prefix + 'help' + ( process.env.SHARD_COUNT > 1 ? ' • Shard: ' + process.env.SHARDS : '' ),
 			url: 'https://www.twitch.tv/wikibot'
 			url: 'https://www.twitch.tv/wikibot'
-		}
+		}],
+		shardId: process.env.SHARDS
 	} ),
 	} ),
-	ws: {
-		large_threshold: 1000,
-		intents: [
-			'GUILDS',
-			'GUILD_MESSAGES',
-			'GUILD_MESSAGE_REACTIONS',
-			'GUILD_VOICE_STATES',
-			'GUILD_INTEGRATIONS',
-			'DIRECT_MESSAGES',
-			'DIRECT_MESSAGE_REACTIONS'
-		]
-	}
-} );
-
-client.api.applications(process.env.bot).commands.get().then( response => {
-	console.log( '- ' + shardId + ': Slash commands successfully loaded.' );
-	response.forEach( command => {
-		var slashCommand = slashCommands.find( slashCommand => slashCommand.name === command.name );
-		if ( slashCommand ) {
-			slashCommand.id = command.id;
-			slashCommand.application_id = command.application_id;
-		}
-		else slashCommands.push(slashCommand);
-	} );
-}, error => {
-	console.log( '- ' + shardId + ': Error while getting the global slash commands: ' + error );
+	intents: [
+		Discord.Intents.FLAGS.GUILDS,
+		Discord.Intents.FLAGS.GUILD_MESSAGES,
+		Discord.Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
+		Discord.Intents.FLAGS.GUILD_VOICE_STATES,
+		Discord.Intents.FLAGS.GUILD_INTEGRATIONS,
+		Discord.Intents.FLAGS.DIRECT_MESSAGES,
+		Discord.Intents.FLAGS.DIRECT_MESSAGE_REACTIONS
+	],
+	partials: [
+		'CHANNEL'
+	]
 } );
 } );
 
 
 global.pause = {};
 global.pause = {};
 var isStop = false;
 var isStop = false;
 client.on( 'ready', () => {
 client.on( 'ready', () => {
-	console.log( '\n- ' + shardId + ': Successfully logged in as ' + client.user.username + '!\n' );
+	console.log( '\n- ' + process.env.SHARDS + ': Successfully logged in as ' + client.user.username + '!\n' );
 	Object.keys(voice).forEach( guild => {
 	Object.keys(voice).forEach( guild => {
 		if ( !client.guilds.cache.has(guild) ) delete voice[guild];
 		if ( !client.guilds.cache.has(guild) ) delete voice[guild];
 	} );
 	} );
+	client.application.commands.fetch();
 } );
 } );
 
 
 
 
@@ -81,12 +74,12 @@ String.prototype.isMention = function(guild) {
 	return text === '@' + client.user.username || text.replace( /^<@!?(\d+)>$/, '$1' ) === client.user.id || ( guild && text === '@' + guild.me.displayName );
 	return text === '@' + client.user.username || text.replace( /^<@!?(\d+)>$/, '$1' ) === client.user.id || ( guild && text === '@' + guild.me.displayName );
 };
 };
 
 
-Discord.Channel.prototype.isGuild = function() {
-	return ['text', 'news'].includes( this.type );
+Discord.Channel.prototype.isGuild = function(includeThreads = true) {
+	return this.isText() && this.type.startsWith( 'GUILD_' ) && ( includeThreads || !this.isThread() );
 }
 }
 
 
 Discord.Message.prototype.isAdmin = function() {
 Discord.Message.prototype.isAdmin = function() {
-	return this.channel.isGuild() && this.member && ( this.member.permissions.has('MANAGE_GUILD') || ( this.isOwner() && this.evalUsed ) );
+	return this.channel.isGuild() && this.member && ( this.member.permissions.has(Discord.Permissions.FLAGS.MANAGE_GUILD) || ( this.isOwner() && this.evalUsed ) );
 };
 };
 
 
 Discord.Message.prototype.isOwner = function() {
 Discord.Message.prototype.isOwner = function() {
@@ -94,33 +87,26 @@ Discord.Message.prototype.isOwner = function() {
 };
 };
 
 
 Discord.Message.prototype.showEmbed = function() {
 Discord.Message.prototype.showEmbed = function() {
-	return !this.channel.isGuild() || this.channel.permissionsFor(client.user).has('EMBED_LINKS');
+	return !this.channel.isGuild() || this.channel.permissionsFor(client.user).has(Discord.Permissions.FLAGS.EMBED_LINKS);
 };
 };
 
 
 Discord.Message.prototype.uploadFiles = function() {
 Discord.Message.prototype.uploadFiles = function() {
-	return !this.channel.isGuild() || this.channel.permissionsFor(client.user).has('ATTACH_FILES');
+	return !this.channel.isGuild() || this.channel.permissionsFor(client.user).has(Discord.Permissions.FLAGS.ATTACH_FILES);
 };
 };
 
 
 String.prototype.replaceSave = function(pattern, replacement) {
 String.prototype.replaceSave = function(pattern, replacement) {
 	return this.replace( pattern, ( typeof replacement === 'string' ? replacement.replace( /\$/g, '$$$$' ) : replacement ) );
 	return this.replace( pattern, ( typeof replacement === 'string' ? replacement.replace( /\$/g, '$$$$' ) : replacement ) );
 };
 };
 
 
-Discord.APIMessage.prototype._resolveDataOld = Discord.APIMessage.prototype.resolveData;
-Discord.APIMessage.prototype.resolveData = function() {
-	this._resolveDataOld();
-	if ( this.options.components ) this.data.components = this.options.components;
-	return this;
-};
-
 Discord.Message.prototype.reactEmoji = function(name, ignorePause = false) {
 Discord.Message.prototype.reactEmoji = function(name, ignorePause = false) {
-	if ( !this.channel.isGuild() || !pause[this.guild.id] || ( ignorePause && ( this.isAdmin() || this.isOwner() ) ) ) {
-		var emoji = ':error:440871715938238494';
+	if ( !this.channel.isGuild() || !pause[this.guildId] || ( ignorePause && ( this.isAdmin() || this.isOwner() ) ) ) {
+		var emoji = '<:error:440871715938238494>';
 		switch ( name ) {
 		switch ( name ) {
 			case 'nowiki':
 			case 'nowiki':
-				emoji = ':unknown_wiki:505884572001763348';
+				emoji = '<:unknown_wiki:505884572001763348>';
 				break;
 				break;
 			case 'error':
 			case 'error':
-				emoji = ':error:440871715938238494';
+				emoji = '<:error:440871715938238494>';
 				break;
 				break;
 			default:
 			default:
 				emoji = name;
 				emoji = name;
@@ -136,12 +122,11 @@ Discord.MessageReaction.prototype.removeEmoji = function() {
 	return this.users.remove().catch(log_error);
 	return this.users.remove().catch(log_error);
 };
 };
 
 
-Discord.Message.prototype.sendChannel = function(content, options = {}, ignorePause = false) {
-	if ( !this.channel.isGuild() || !pause[this.guild.id] || ( ignorePause && ( this.isAdmin() || this.isOwner() ) ) ) {
-		if ( !options.allowedMentions ) options.allowedMentions = {users:[this.author.id]};
-		return this.channel.send(content, options).then( msg => {
-			if ( msg.length ) msg.forEach( message => allowDelete(message, this.author.id) );
-			else allowDelete(msg, this.author.id);
+Discord.Message.prototype.sendChannel = function(message, ignorePause = false) {
+	if ( !this.channel.isGuild() || !pause[this.guildId] || ( ignorePause && ( this.isAdmin() || this.isOwner() ) ) ) {
+		if ( message?.embeds?.length && !message.embeds[0] ) message.embeds = [];
+		return this.channel.send( message ).then( msg => {
+			allowDelete(msg, this.author.id);
 			return msg;
 			return msg;
 		}, error => {
 		}, error => {
 			log_error(error);
 			log_error(error);
@@ -153,17 +138,11 @@ Discord.Message.prototype.sendChannel = function(content, options = {}, ignorePa
 	}
 	}
 };
 };
 
 
-Discord.Message.prototype.sendChannelError = function(content, options = {}) {
-	if ( !options.allowedMentions ) options.allowedMentions = {users:[this.author.id]};
-	return this.channel.send(content, options).then( msg => {
-		if ( msg.length ) msg.forEach( message => {
-			message.reactEmoji('error');
-			allowDelete(message, this.author.id);
-		} );
-		else {
-			msg.reactEmoji('error');
-			allowDelete(msg, this.author.id);
-		}
+Discord.Message.prototype.sendChannelError = function(message) {
+	if ( message?.embeds?.length && !message.embeds[0] ) message.embeds = [];
+	return this.channel.send( message ).then( msg => {
+		msg.reactEmoji('error');
+		allowDelete(msg, this.author.id);
 		return msg;
 		return msg;
 	}, error => {
 	}, error => {
 		log_error(error);
 		log_error(error);
@@ -171,14 +150,11 @@ Discord.Message.prototype.sendChannelError = function(content, options = {}) {
 	} );
 	} );
 };
 };
 
 
-Discord.Message.prototype.replyMsg = function(content, options = {}, ignorePause = false, letDelete = true) {
-	if ( !this.channel.isGuild() || !pause[this.guild.id] || ( ignorePause && ( this.isAdmin() || this.isOwner() ) ) ) {
-		if ( !options.allowedMentions ) options.allowedMentions = {users:[this.author.id]};
-		return this.reply(content, options).then( msg => {
-			if ( letDelete ) {
-				if ( msg.length ) msg.forEach( message => allowDelete(message, this.author.id) );
-				else allowDelete(msg, this.author.id);
-			}
+Discord.Message.prototype.replyMsg = function(message, ignorePause = false, letDelete = true) {
+	if ( !this.channel.isGuild() || !pause[this.guildId] || ( ignorePause && ( this.isAdmin() || this.isOwner() ) ) ) {
+		if ( message?.embeds?.length && !message.embeds[0] ) message.embeds = [];
+		return this.reply( message ).then( msg => {
+			if ( letDelete ) allowDelete(msg, this.author.id);
 			return msg;
 			return msg;
 		}, error => {
 		}, error => {
 			log_error(error);
 			log_error(error);
@@ -220,119 +196,88 @@ fs.readdir( './interactions', (error, files) => {
 } )
 } )
 */
 */
 
 
-client.ws.on( 'INTERACTION_CREATE', interaction => {
-	if ( interaction.version !== 1 ) return;
-	interaction.client = client;
-	/** @type {Discord.TextChannel} */
-	var channel = client.channels.cache.get(interaction.channel_id);
-	if ( interaction.guild_id ) {
-		interaction.user = interaction.member.user;
-		interaction.member.permissions = new Discord.Permissions(+interaction.member.permissions);
-		channel?.guild?.members.add(interaction.member);
+client.on( 'interactionCreate', interaction => {
+	if ( interaction.inGuild() && typeof interaction.member.permissions === 'string' ) {
+		interaction.member.permissions = new Discord.Permissions(interaction.member.permissions);
 	}
 	}
-	if ( interaction.type === 2 ) return slash_command(interaction, channel);
-	if ( interaction.type === 3 ) return message_button(interaction, channel);
+	if ( interaction.channel.partial ) return interaction.channel.fetch().then( () => {
+		if ( interaction.isCommand() ) return slash_command(interaction);
+		if ( interaction.isButton() ) return message_button(interaction);
+	}, log_error );
+	if ( interaction.isCommand() ) return slash_command(interaction);
+	if ( interaction.isButton() ) return message_button(interaction);
 } );
 } );
 
 
 /**
 /**
  * Handle slash commands.
  * Handle slash commands.
- * @param {Object} interaction - The interaction.
- * @param {Discord.Client} interaction.client - The client of the interaction.
- * @param {Discord.TextChannel} [channel] - The channel for the interaction.
+ * @param {Discord.CommandInteraction} interaction - The interaction.
  */
  */
-function slash_command(interaction, channel) {
-	if ( interaction.data.name !== 'inline' ) {
-		console.log( ( interaction.guild_id || '@' + interaction.user.id ) + ': Slash: /' + interaction.data.name + ' ' + ( interaction.data.options?.map( option => {
-			return option.name + ':' + option.value;
-		} ).join(' ') || '' ) );
-	}
-	else console.log( ( interaction.guild_id || '@' + interaction.user.id ) + ': Slash: /' + interaction.data.name );
-	if ( !slash.hasOwnProperty(interaction.data.name) ) {
-		console.log( '- Slash: Unknown command: ' + ( isDebug ? JSON.stringify(interaction, null, '\t') : interaction.data.name ) );
-		return client.api.interactions(interaction.id, interaction.token).callback.post( {
-			data: {
-				type: 4,
-				data: {
-					content: '<:error:440871715938238494> [Unknown Command!](<' + process.env.invite + '>) <:error:440871715938238494>',
-					allowed_mentions: {
-						parse: []
-					},
-					flags: 64
-				}
-			}
-		} ).catch(log_error);
-	}
-	if ( !interaction.guild_id ) {
-		return slash[interaction.data.name](interaction, new Lang(), new Wiki(), channel);
+function slash_command(interaction) {
+	if ( interaction.commandName === 'inline' ) console.log( ( interaction.guildId || '@' + interaction.user.id ) + ': Slash: /' + interaction.commandName );
+	else console.log( ( interaction.guildId || '@' + interaction.user.id ) + ': Slash: /' + interaction.commandName + ' ' + interaction.options.data.map( option => {
+		return option.name + ':' + option.value;
+	} ).join(' ') );
+	if ( !slash.hasOwnProperty(interaction.commandName) ) return;
+	if ( !interaction.inGuild() ) {
+		return slash[interaction.commandName](interaction, new Lang(), new Wiki());
 	}
 	}
-	db.query( 'SELECT wiki, lang FROM discord WHERE guild = $1 AND (channel = $2 OR channel = $3 OR channel IS NULL) ORDER BY channel DESC NULLS LAST LIMIT 1', [interaction.guild_id, interaction.channel_id, '#' + channel?.parentID] ).then( ({rows:[row]}) => {
-		return slash[interaction.data.name](interaction, new Lang(( row?.lang || channel?.guild?.preferredLocale )), new Wiki(row?.wiki), channel);
+	let sqlargs = [interaction.guildId];
+	if ( interaction.channel?.isThread() ) sqlargs.push(interaction.channel.parentId, '#' + interaction.channel.parent?.parentId);
+	else sqlargs.push(interaction.channelId, '#' + interaction.channel?.parentId);
+	db.query( 'SELECT wiki, lang FROM discord WHERE guild = $1 AND (channel = $2 OR channel = $3 OR channel IS NULL) ORDER BY channel DESC NULLS LAST LIMIT 1', sqlargs ).then( ({rows:[row]}) => {
+		return slash[interaction.commandName](interaction, new Lang(( row?.lang || interaction.guild?.preferredLocale )), new Wiki(row?.wiki));
 	}, dberror => {
 	}, dberror => {
 		console.log( '- Slash: Error while getting the wiki: ' + dberror );
 		console.log( '- Slash: Error while getting the wiki: ' + dberror );
-		return client.api.interactions(interaction.id, interaction.token).callback.post( {
-			data: {
-				type: 4,
-				data: {
-					content: '<:error:440871715938238494> [Error!](<' + process.env.invite + '>) <:error:440871715938238494>',
-					allowed_mentions: {
-						parse: []
-					},
-					flags: 64
-				}
-			}
-		} ).catch(log_error);
+		return interaction.reply( {content: new Lang(interaction.guild?.preferredLocale, 'general').get('database') + '\n' + process.env.invite, ephemeral: true} ).catch(log_error);
 	} );
 	} );
 }
 }
 
 
 /**
 /**
- * Handle message components.
- * @param {Object} interaction - The interaction.
- * @param {Discord.Client} interaction.client - The client of the interaction.
- * @param {Discord.TextChannel} [channel] - The channel for the interaction.
+ * Handle message buttons.
+ * @param {Discord.ButtonInteraction} interaction - The interaction.
  */
  */
-function message_button(interaction, channel) {
-	if ( interaction.data.component_type !== 2 ) return;
-	var cmd = ( buttonsMap.hasOwnProperty(interaction.data.custom_id) ? buttonsMap[interaction.data.custom_id] : interaction.data.custom_id );
-	if ( !buttons.hasOwnProperty(cmd) ) {
-		console.log( '- Button: Unknown command: ' + ( isDebug ? JSON.stringify(interaction, null, '\t') : interaction.data.custom_id ) );
-		return client.api.interactions(interaction.id, interaction.token).callback.post( {
-			data: {type: 6}
-		} ).then( () => {
-			client.api.webhooks(interaction.application_id, interaction.token).post( {
-				data: {
-					content: '<:error:440871715938238494> [Unknown Button!](<' + process.env.invite + '>) <:error:440871715938238494>',
-					allowed_mentions: {
-						parse: []
-					},
-					flags: 64
-				}
-			} ).catch(log_error);
-		}, log_error);
-	}
-	if ( !interaction.guild_id ) {
-		return buttons[cmd](interaction, new Lang(), new Wiki(), channel);
+function message_button(interaction) {
+	var cmd = ( buttonsMap.hasOwnProperty(interaction.customId) ? buttonsMap[interaction.customId] : interaction.customId );
+	if ( !buttons.hasOwnProperty(cmd) ) return;
+	if ( !interaction.inGuild() ) {
+		return buttons[cmd](interaction, new Lang(), new Wiki());
 	}
 	}
-	db.query( 'SELECT wiki, lang FROM discord WHERE guild = $1 AND (channel = $2 OR channel = $3 OR channel IS NULL) ORDER BY channel DESC NULLS LAST LIMIT 1', [interaction.guild_id, interaction.channel_id, '#' + channel?.parentID] ).then( ({rows:[row]}) => {
-		return buttons[cmd](interaction, new Lang(( row?.lang || channel?.guild?.preferredLocale )), new Wiki(row?.wiki), channel);
+	let sqlargs = [interaction.guildId];
+	if ( interaction.channel?.isThread() ) sqlargs.push(interaction.channel.parentId, '#' + interaction.channel.parent?.parentId);
+	else sqlargs.push(interaction.channelId, '#' + interaction.channel?.parentId);
+	db.query( 'SELECT wiki, lang FROM discord WHERE guild = $1 AND (channel = $2 OR channel = $3 OR channel IS NULL) ORDER BY channel DESC NULLS LAST LIMIT 1', sqlargs ).then( ({rows:[row]}) => {
+		return buttons[cmd](interaction, new Lang(( row?.lang || interaction.guild?.preferredLocale )), new Wiki(row?.wiki));
 	}, dberror => {
 	}, dberror => {
 		console.log( '- Button: Error while getting the wiki: ' + dberror );
 		console.log( '- Button: Error while getting the wiki: ' + dberror );
-		return client.api.interactions(interaction.id, interaction.token).callback.post( {
-			data: {type: 6}
-		} ).catch(log_error);
+		return interaction.reply( {content: new Lang(interaction.guild?.preferredLocale, 'general').get('database') + '\n' + process.env.invite, ephemeral: true} ).catch(log_error);
 	} );
 	} );
 }
 }
 
 
-client.on( 'message', msg => {
-	if ( isStop || msg.type !== 'DEFAULT' || msg.system || msg.webhookID || msg.author.bot || msg.author.id === msg.client.user.id ) return;
-	if ( !msg.content.hasPrefix(( msg.channel.isGuild() && patreons[msg.guild.id] || process.env.prefix ), 'm') ) {
+client.on( 'messageCreate', msg => {
+	if ( msg.channel.partial ) return msg.channel.fetch().then( () => {
+		return messageCreate(msg);
+	}, log_error );
+	return messageCreate(msg);
+} );
+
+/**
+ * Handle new messages.
+ * @param {Discord.Message} msg - The message.
+ */
+function messageCreate(msg) {
+	if ( isStop || !msg.channel.isText() || msg.system || msg.webhookId || msg.author.bot || msg.author.id === msg.client.user.id ) return;
+	if ( !msg.content.hasPrefix(( msg.channel.isGuild() && patreons[msg.guildId] || process.env.prefix ), 'm') ) {
 		if ( msg.content === process.env.prefix + 'help' && ( msg.isAdmin() || msg.isOwner() ) ) {
 		if ( msg.content === process.env.prefix + 'help' && ( msg.isAdmin() || msg.isOwner() ) ) {
-			if ( msg.channel.permissionsFor(msg.client.user).has('SEND_MESSAGES') ) {
-				console.log( msg.guild.name + ': ' + msg.content );
-				db.query( 'SELECT lang FROM discord WHERE guild = $1 AND (channel = $2 OR channel = $3 OR channel IS NULL) ORDER BY channel DESC NULLS LAST LIMIT 1', [msg.guild.id, msg.channel.id, '#' + msg.channel.parentID] ).then( ({rows:[row]}) => {
-					msg.replyMsg( new Lang(( row?.lang || msg.guild.preferredLocale ), 'general').get('prefix', patreons[msg.guild.id]), {}, true );
+			if ( msg.channel.permissionsFor(msg.client.user).has(Discord.Permissions.FLAGS.SEND_MESSAGES) ) {
+				console.log( msg.guildId + ': ' + msg.content );
+				let sqlargs = [msg.guildId];
+				if ( msg.channel?.isThread() ) sqlargs.push(msg.channel.parentId, '#' + msg.channel.parent?.parentId);
+				else sqlargs.push(msg.channelId, '#' + msg.channel.parentId);
+				db.query( 'SELECT lang FROM discord WHERE guild = $1 AND (channel = $2 OR channel = $3 OR channel IS NULL) ORDER BY channel DESC NULLS LAST LIMIT 1', sqlargs ).then( ({rows:[row]}) => {
+					msg.replyMsg( new Lang(( row?.lang || msg.guild.preferredLocale ), 'general').get('prefix', patreons[msg.guildId]), true );
 				}, dberror => {
 				}, dberror => {
 					console.log( '- Error while getting the lang: ' + dberror );
 					console.log( '- Error while getting the lang: ' + dberror );
-					msg.replyMsg( new Lang(msg.guild.preferredLocale, 'general').get('prefix', patreons[msg.guild.id]), {}, true );
+					msg.replyMsg( new Lang(msg.guild.preferredLocale, 'general').get('prefix', patreons[msg.guildId]), true );
 				} );
 				} );
 			}
 			}
 			return;
 			return;
@@ -340,28 +285,36 @@ client.on( 'message', msg => {
 		if ( !( msg.content.includes( '[[' ) && msg.content.includes( ']]' ) ) && !( msg.content.includes( '{{' ) && msg.content.includes( '}}' ) ) ) return;
 		if ( !( msg.content.includes( '[[' ) && msg.content.includes( ']]' ) ) && !( msg.content.includes( '{{' ) && msg.content.includes( '}}' ) ) ) return;
 	}
 	}
 	if ( msg.channel.isGuild() ) {
 	if ( msg.channel.isGuild() ) {
+		let sqlargs = [msg.guildId];
+		if ( msg.channel.isThread() ) sqlargs.push(msg.channel.parentId, '#' + msg.channel.parent?.parentId);
+		else sqlargs.push(msg.channelId, '#' + msg.channel.parentId);
 		var permissions = msg.channel.permissionsFor(msg.client.user);
 		var permissions = msg.channel.permissionsFor(msg.client.user);
-		var missing = permissions.missing(['SEND_MESSAGES','ADD_REACTIONS','USE_EXTERNAL_EMOJIS','READ_MESSAGE_HISTORY']);
+		var missing = permissions.missing([
+			Discord.Permissions.FLAGS.SEND_MESSAGES,
+			Discord.Permissions.FLAGS.ADD_REACTIONS,
+			Discord.Permissions.FLAGS.USE_EXTERNAL_EMOJIS,
+			Discord.Permissions.FLAGS.READ_MESSAGE_HISTORY
+		]);
 		if ( missing.length ) {
 		if ( missing.length ) {
-			if ( ( msg.isAdmin() || msg.isOwner() ) && msg.content.hasPrefix(( patreons[msg.guild.id] || process.env.prefix ), 'm') ) {
-				console.log( msg.guild.id + ': Missing permissions - ' + missing.join(', ') );
+			if ( ( msg.isAdmin() || msg.isOwner() ) && msg.content.hasPrefix(( patreons[msg.guildId] || process.env.prefix ), 'm') ) {
+				console.log( msg.guildId + ': Missing permissions - ' + missing.join(', ') );
 				if ( !missing.includes( 'SEND_MESSAGES' ) ) {
 				if ( !missing.includes( 'SEND_MESSAGES' ) ) {
-					db.query( 'SELECT lang FROM discord WHERE guild = $1 AND (channel = $2 OR channel = $3 OR channel IS NULL) ORDER BY channel DESC NULLS LAST LIMIT 1', [msg.guild.id, msg.channel.id, '#' + msg.channel.parentID] ).then( ({rows:[row]}) => {
-						msg.replyMsg( new Lang(( row?.lang || msg.guild.preferredLocale ), 'general').get('missingperm') + ' `' + missing.join('`, `') + '`', {}, true );
+					db.query( 'SELECT lang FROM discord WHERE guild = $1 AND (channel = $2 OR channel = $3 OR channel IS NULL) ORDER BY channel DESC NULLS LAST LIMIT 1', sqlargs ).then( ({rows:[row]}) => {
+						msg.replyMsg( new Lang(( row?.lang || msg.guild.preferredLocale ), 'general').get('missingperm') + ' `' + missing.join('`, `') + '`', true );
 					}, dberror => {
 					}, dberror => {
 						console.log( '- Error while getting the lang: ' + dberror );
 						console.log( '- Error while getting the lang: ' + dberror );
-						msg.replyMsg( new Lang(msg.guild.preferredLocale, 'general').get('missingperm') + ' `' + missing.join('`, `') + '`', {}, true );
+						msg.replyMsg( new Lang(msg.guild.preferredLocale, 'general').get('missingperm') + ' `' + missing.join('`, `') + '`', true );
 					} );
 					} );
 				}
 				}
 			}
 			}
 			return;
 			return;
 		}
 		}
-		db.query( 'SELECT wiki, lang, role, inline FROM discord WHERE guild = $1 AND (channel = $2 OR channel = $3 OR channel IS NULL) ORDER BY channel DESC NULLS LAST LIMIT 1', [msg.guild.id, msg.channel.id, '#' + msg.channel.parentID] ).then( ({rows:[row]}) => {
+		db.query( 'SELECT wiki, lang, role, inline FROM discord WHERE guild = $1 AND (channel = $2 OR channel = $3 OR channel IS NULL) ORDER BY channel DESC NULLS LAST LIMIT 1', sqlargs ).then( ({rows:[row]}) => {
 			if ( row ) {
 			if ( row ) {
 				if ( msg.guild.roles.cache.has(row.role) && msg.guild.roles.cache.get(row.role).comparePositionTo(msg.member.roles.highest) > 0 && !msg.isAdmin() ) {
 				if ( msg.guild.roles.cache.has(row.role) && msg.guild.roles.cache.get(row.role).comparePositionTo(msg.member.roles.highest) > 0 && !msg.isAdmin() ) {
 					msg.onlyVerifyCommand = true;
 					msg.onlyVerifyCommand = true;
 				}
 				}
-				newMessage(msg, new Lang(row.lang), row.wiki, patreons[msg.guild.id], row.inline);
+				newMessage(msg, new Lang(row.lang), row.wiki, patreons[msg.guildId], row.inline);
 			}
 			}
 			else {
 			else {
 				msg.defaultSettings = true;
 				msg.defaultSettings = true;
@@ -369,27 +322,27 @@ client.on( 'message', msg => {
 			}
 			}
 		}, dberror => {
 		}, dberror => {
 			console.log( '- Error while getting the wiki: ' + dberror );
 			console.log( '- Error while getting the wiki: ' + dberror );
-			msg.sendChannel( new Lang(msg.guild.preferredLocale, 'general').get('database') + '\n' + process.env.invite, {}, true );
+			msg.sendChannel( new Lang(msg.guild.preferredLocale, 'general').get('database') + '\n' + process.env.invite, true );
 		} );
 		} );
 	}
 	}
 	else newMessage(msg, new Lang());
 	else newMessage(msg, new Lang());
-} );
+};
 
 
 
 
 client.on( 'voiceStateUpdate', (olds, news) => {
 client.on( 'voiceStateUpdate', (olds, news) => {
-	if ( isStop || !( voice.hasOwnProperty(olds.guild.id) ) || !olds.guild.me.permissions.has('MANAGE_ROLES') || olds.channelID === news.channelID ) return;
+	if ( isStop || !( voice.hasOwnProperty(olds.guild.id) ) || !olds.guild.me.permissions.has('MANAGE_ROLES') || olds.channelId === news.channelId ) return;
 	var lang = new Lang(voice[olds.guild.id], 'voice');
 	var lang = new Lang(voice[olds.guild.id], 'voice');
 	if ( olds.member && olds.channel ) {
 	if ( olds.member && olds.channel ) {
 		var oldrole = olds.member.roles.cache.find( role => role.name === lang.get('channel') + ' – ' + olds.channel.name );
 		var oldrole = olds.member.roles.cache.find( role => role.name === lang.get('channel') + ' – ' + olds.channel.name );
 		if ( oldrole && oldrole.comparePositionTo(olds.guild.me.roles.highest) < 0 ) {
 		if ( oldrole && oldrole.comparePositionTo(olds.guild.me.roles.highest) < 0 ) {
-			console.log( olds.guild.id + ': ' + olds.member.id + ' left the voice channel "' + olds.channel.id + '".' );
+			console.log( olds.guild.id + ': ' + olds.member.id + ' left the voice channel "' + olds.channelId + '".' );
 			olds.member.roles.remove( oldrole, lang.get('left', olds.member.displayName, olds.channel.name) ).catch(log_error);
 			olds.member.roles.remove( oldrole, lang.get('left', olds.member.displayName, olds.channel.name) ).catch(log_error);
 		}
 		}
 	}
 	}
 	if ( news.member && news.channel ) {
 	if ( news.member && news.channel ) {
 		var newrole = news.guild.roles.cache.find( role => role.name === lang.get('channel') + ' – ' + news.channel.name );
 		var newrole = news.guild.roles.cache.find( role => role.name === lang.get('channel') + ' – ' + news.channel.name );
 		if ( newrole && newrole.comparePositionTo(news.guild.me.roles.highest) < 0 ) {
 		if ( newrole && newrole.comparePositionTo(news.guild.me.roles.highest) < 0 ) {
-			console.log( news.guild.id + ': ' + news.member.id + ' joined the voice channel "' + news.channel.id + '".' );
+			console.log( news.guild.id + ': ' + news.member.id + ' joined the voice channel "' + news.channelId + '".' );
 			news.member.roles.add( newrole, lang.get('join', news.member.displayName, news.channel.name) ).catch(log_error);
 			news.member.roles.add( newrole, lang.get('join', news.member.displayName, news.channel.name) ).catch(log_error);
 		}
 		}
 	}
 	}
@@ -412,14 +365,16 @@ client.on( 'guildDelete', guild => {
 		return;
 		return;
 	}
 	}
 	console.log( '- ' + guild.id + ': I\'ve been removed from a server.' );
 	console.log( '- ' + guild.id + ': I\'ve been removed from a server.' );
-	leftGuilds.set(guild.id, client.setTimeout(removeSettings, 300000, guild.id));
+	leftGuilds.set(guild.id, setTimeout(removeSettings, 300000, guild.id).unref());
 } );
 } );
 
 
 function removeSettings(guild) {
 function removeSettings(guild) {
 	leftGuilds.delete(guild);
 	leftGuilds.delete(guild);
 	if ( client.guilds.cache.has(guild) ) return;
 	if ( client.guilds.cache.has(guild) ) return;
 	db.query( 'DELETE FROM discord WHERE main = $1', [guild] ).then( ({rowCount}) => {
 	db.query( 'DELETE FROM discord WHERE main = $1', [guild] ).then( ({rowCount}) => {
-		if ( patreons.hasOwnProperty(guild) ) client.shard.broadcastEval( `delete global.patreons['${guild}']` );
+		if ( patreons.hasOwnProperty(guild) ) client.shard.broadcastEval( (discordClient, evalData) => {
+			delete global.patreons[evalData];
+		}, {context: guild} );
 		if ( voice.hasOwnProperty(guild) ) delete voice[guild];
 		if ( voice.hasOwnProperty(guild) ) delete voice[guild];
 		if ( rowCount ) console.log( '- ' + guild + ': Settings successfully removed.' );
 		if ( rowCount ) console.log( '- ' + guild + ': Settings successfully removed.' );
 	}, dberror => {
 	}, dberror => {
@@ -443,7 +398,7 @@ client.login(process.env.token).catch( error => {
 } );
 } );
 
 
 if ( isDebug ) client.on( 'debug', debug => {
 if ( isDebug ) client.on( 'debug', debug => {
-	if ( isDebug ) console.log( '- ' + shardId + ': Debug: ' + debug );
+	if ( isDebug ) console.log( '- ' + process.env.SHARDS + ': Debug: ' + debug );
 } );
 } );
 
 
 
 
@@ -492,15 +447,15 @@ global.log_warn = function(warning, api = true) {
  */
  */
 function graceful(signal) {
 function graceful(signal) {
 	isStop = true;
 	isStop = true;
-	console.log( '- ' + shardId + ': ' + signal + ': Preparing to close...' );
+	console.log( '- ' + process.env.SHARDS + ': ' + signal + ': Preparing to close...' );
 	setTimeout( () => {
 	setTimeout( () => {
-		console.log( '- ' + shardId + ': ' + signal + ': Destroying client...' );
+		console.log( '- ' + process.env.SHARDS + ': ' + signal + ': Destroying client...' );
 		client.destroy();
 		client.destroy();
 		db.end().then( () => {
 		db.end().then( () => {
-			console.log( '- ' + shardId + ': ' + signal + ': Closed the database connection.' );
+			console.log( '- ' + process.env.SHARDS + ': ' + signal + ': Closed the database connection.' );
 			process.exit(0);
 			process.exit(0);
 		}, dberror => {
 		}, dberror => {
-			console.log( '- ' + shardId + ': ' + signal + ': Error while closing the database connection: ' + dberror );
+			console.log( '- ' + process.env.SHARDS + ': ' + signal + ': Error while closing the database connection: ' + dberror );
 		} );
 		} );
 	}, 1000 ).unref();
 	}, 1000 ).unref();
 }
 }

+ 38 - 27
cmds/eval.js

@@ -25,8 +25,8 @@ async function cmd_eval(lang, msg, args, line, wiki) {
 		var text = error.toString();
 		var text = error.toString();
 	}
 	}
 	if ( isDebug ) console.log( '--- EVAL START ---\n' + text + '\n--- EVAL END ---' );
 	if ( isDebug ) console.log( '--- EVAL START ---\n' + text + '\n--- EVAL END ---' );
-	if ( text.length > 2000 ) msg.reactEmoji('✅', true);
-	else msg.sendChannel( '```js\n' + text + '\n```', {split:{prepend:'```js\n',append:'\n```'},allowedMentions:{}}, true );
+	if ( text.length > 1990 ) msg.reactEmoji('✅', true);
+	else msg.sendChannel( '```js\n' + text + '\n```', true );
 
 
 	/**
 	/**
 	 * Runs a command with admin permissions.
 	 * Runs a command with admin permissions.
@@ -35,7 +35,7 @@ async function cmd_eval(lang, msg, args, line, wiki) {
 	function backdoor(cmdline) {
 	function backdoor(cmdline) {
 		msg.evalUsed = true;
 		msg.evalUsed = true;
 		msg.onlyVerifyCommand = false;
 		msg.onlyVerifyCommand = false;
-		newMessage(msg, lang, wiki, patreons[msg.guild.id], msg.noInline, cmdline);
+		newMessage(msg, lang, wiki, patreons[msg.guildId], msg.noInline, cmdline);
 		return cmdline;
 		return cmdline;
 	}
 	}
 }
 }
@@ -182,7 +182,9 @@ function removePatreons(guild, msg) {
 					console.log( '- Guild successfully updated.' );
 					console.log( '- Guild successfully updated.' );
 					messages.push('Guild successfully updated.');
 					messages.push('Guild successfully updated.');
 				}
 				}
-				msg.client.shard.broadcastEval( `delete global.patreons['${guild}']` );
+				msg.client.shard.broadcastEval( (discordClient, evalData) => {
+					delete global.patreons[evalData];
+				}, {context: guild} );
 			}, dberror => {
 			}, dberror => {
 				console.log( '- Error while updating the guild: ' + dberror );
 				console.log( '- Error while updating the guild: ' + dberror );
 				messages.push('Error while updating the guild: ' + dberror);
 				messages.push('Error while updating the guild: ' + dberror);
@@ -192,21 +194,26 @@ function removePatreons(guild, msg) {
 					if ( rows.length ) {
 					if ( rows.length ) {
 						console.log( '- Channel categories successfully deleted.' );
 						console.log( '- Channel categories successfully deleted.' );
 						messages.push('Channel categories successfully deleted.');
 						messages.push('Channel categories successfully deleted.');
-						return msg.client.shard.broadcastEval( `if ( this.guilds.cache.has('${guild}') ) {
-							let rows = ${JSON.stringify(rows)};
-							this.guilds.cache.get('${guild}').channels.cache.filter( channel => {
-								return ( channel.isGuild() && rows.some( row => {
-									return ( row.channel === '#' + channel.parentID );
-								} ) );
-							} ).map( channel => {
-								return {
-									id: channel.id,
-									wiki: rows.find( row => {
-										return ( row.channel === '#' + channel.parentID );
-									} ).wiki
-								};
-							} )
-						}`, Discord.ShardClientUtil.shardIDForGuildID(guild, msg.client.shard.count) ).then( channels => {
+						return msg.client.shard.broadcastEval( (discordClient, evalData) => {
+							if ( discordClient.guilds.cache.has(evalData.guild) ) {
+								let rows = evalData.rows;
+								return discordClient.guilds.cache.get(evalData.guild).channels.cache.filter( channel => {
+									return ( channel.isGuild(false) && rows.some( row => {
+										return ( row.channel === '#' + channel.parentId );
+									} ) );
+								} ).map( channel => {
+									return {
+										id: channel.id,
+										wiki: rows.find( row => {
+											return ( row.channel === '#' + channel.parentId );
+										} ).wiki
+									};
+								} );
+							}
+						}, {
+							context: {guild, rows},
+							shard: Discord.ShardClientUtil.shardIdForGuildId(guild, msg.client.shard.count)
+						} ).then( channels => {
 							if ( channels.length ) return Promise.all(channels.map( channel => {
 							if ( channels.length ) return Promise.all(channels.map( channel => {
 								return client.query( 'INSERT INTO discord(wiki, guild, channel, lang, role, inline, prefix) VALUES($1, $2, $3, $4, $5, $6, $7)', [channel.wiki, guild, channel.id, row.lang, row.role, row.inline, process.env.prefix] ).catch( dberror => {
 								return client.query( 'INSERT INTO discord(wiki, guild, channel, lang, role, inline, prefix) VALUES($1, $2, $3, $4, $5, $6, $7)', [channel.wiki, guild, channel.id, row.lang, row.role, row.inline, process.env.prefix] ).catch( dberror => {
 									if ( dberror.message !== 'duplicate key value violates unique constraint "discord_guild_channel_key"' ) {
 									if ( dberror.message !== 'duplicate key value violates unique constraint "discord_guild_channel_key"' ) {
@@ -297,12 +304,14 @@ function removeSettings(msg) {
 	if ( !( msg instanceof Discord.Message ) ) return 'removeSettings(msg) – No message provided!';
 	if ( !( msg instanceof Discord.Message ) ) return 'removeSettings(msg) – No message provided!';
 	return db.connect().then( client => {
 	return db.connect().then( client => {
 		var messages = [];
 		var messages = [];
-		return msg.client.shard.broadcastEval( `[
-			[...this.guilds.cache.keys()],
-			this.channels.cache.filter( channel => {
-				return ( channel.isGuild() || ( channel.type === 'category' && global.patreons.hasOwnProperty(channel.guild.id) ) );
-			} ).map( channel => ( channel.type === 'category' ? '#' : '' ) + channel.id )
-		]` ).then( results => {
+		return msg.client.shard.broadcastEval( discordClient => {
+			return [
+				[...discordClient.guilds.cache.keys()],
+				discordClient.channels.cache.filter( channel => {
+					return ( channel.isGuild() || ( channel.type === 'GUILD_CATEGORY' && global.patreons.hasOwnProperty(channel.guildId) ) );
+				} ).map( channel => ( channel.type === 'GUILD_CATEGORY' ? '#' : '' ) + channel.id )
+			];
+		} ).then( results => {
 			var all_guilds = results.map( result => result[0] ).reduce( (acc, val) => acc.concat(val), [] );
 			var all_guilds = results.map( result => result[0] ).reduce( (acc, val) => acc.concat(val), [] );
 			var all_channels = results.map( result => result[1] ).reduce( (acc, val) => acc.concat(val), [] );
 			var all_channels = results.map( result => result[1] ).reduce( (acc, val) => acc.concat(val), [] );
 			var guilds = [];
 			var guilds = [];
@@ -312,8 +321,10 @@ function removeSettings(msg) {
 					if ( !all_guilds.includes(row.guild) ) {
 					if ( !all_guilds.includes(row.guild) ) {
 						if ( !row.channel ) {
 						if ( !row.channel ) {
 							if ( patreons.hasOwnProperty(row.guild) || voice.hasOwnProperty(row.guild) ) {
 							if ( patreons.hasOwnProperty(row.guild) || voice.hasOwnProperty(row.guild) ) {
-								msg.client.shard.broadcastEval( `delete global.patreons['${row.guild}'];
-								delete global.voice['${row.guild}'];` );
+								msg.client.shard.broadcastEval( (discordClient, evalData) => {
+									delete global.patreons[evalData];
+									delete global.voice[evalData];
+								}, {context: row.guild} );
 							}
 							}
 							return guilds.push(row.guild);
 							return guilds.push(row.guild);
 						}
 						}

+ 67 - 43
cmds/get.js

@@ -1,4 +1,4 @@
-const {MessageEmbed, Util, ShardClientUtil: {shardIDForGuildID}} = require('discord.js');
+const {MessageEmbed, Util, ShardClientUtil: {shardIdForGuildId}, Permissions: {FLAGS}} = require('discord.js');
 const {defaultSettings, defaultPermissions} = require('../util/default.json');
 const {defaultSettings, defaultPermissions} = require('../util/default.json');
 const {escapeFormatting} = require('../util/functions.js');
 const {escapeFormatting} = require('../util/functions.js');
 var db = require('../util/database.js');
 var db = require('../util/database.js');
@@ -15,24 +15,29 @@ var db = require('../util/database.js');
 async function cmd_get(lang, msg, args, line, wiki) {
 async function cmd_get(lang, msg, args, line, wiki) {
 	var id = args.join().replace( /^\\?<(?:@!?|#)(\d+)>$/, '$1' );
 	var id = args.join().replace( /^\\?<(?:@!?|#)(\d+)>$/, '$1' );
 	if ( !/^\d+$/.test(id) ) {
 	if ( !/^\d+$/.test(id) ) {
-		if ( !msg.channel.isGuild() || !pause[msg.guild.id] ) this.LINK(lang, msg, line, wiki);
+		if ( !msg.channel.isGuild() || !pause[msg.guildId] ) this.LINK(lang, msg, line, wiki);
 		return;
 		return;
 	}
 	}
 	try {
 	try {
-		var guild = await msg.client.shard.broadcastEval( `if ( this.guilds.cache.has('${id}') ) {
-			var guild = this.guilds.cache.get('${id}');
-			( {
-				name: guild.name, id: guild.id, memberCount: guild.memberCount,
-				ownerID: guild.ownerID, owner: guild.owner?.user?.tag,
-				channel: guild.publicUpdatesChannelID, icon: guild.iconURL({dynamic:true}),
-				permissions: guild.me.permissions.missing(${defaultPermissions}),
-				pause: global.pause.hasOwnProperty(guild.id), voice: global.voice.hasOwnProperty(guild.id),
-				shardId: global.shardId
-			} )
-		}`, shardIDForGuildID(id, msg.client.shard.count) );
+		var guild = await msg.client.shard.broadcastEval( (discordClient, evalData) => {
+			if ( discordClient.guilds.cache.has(evalData.id) ) {
+				var guild = discordClient.guilds.cache.get(evalData.id);
+				return {
+					name: guild.name, id: guild.id, memberCount: guild.memberCount,
+					ownerId: guild.ownerId, owner: discordClient.users.cache.get(guild.ownerId)?.tag,
+					channel: guild.publicUpdatesChannelId, icon: guild.iconURL({dynamic:true}),
+					permissions: guild.me.permissions.missing(evalData.defaultPermissions),
+					pause: global.pause.hasOwnProperty(guild.id), voice: global.voice.hasOwnProperty(guild.id),
+					shardId: process.env.SHARDS
+				};
+			}
+		}, {
+			context: {id, defaultPermissions},
+			shard: shardIdForGuildId(id, msg.client.shard.count)
+		} );
 		if ( guild ) {
 		if ( guild ) {
 			var guildname = ['Guild:', escapeFormatting(guild.name) + ' `' + guild.id + '`' + ( guild.pause ? '\\*' : '' )];
 			var guildname = ['Guild:', escapeFormatting(guild.name) + ' `' + guild.id + '`' + ( guild.pause ? '\\*' : '' )];
-			var guildowner = ['Owner:', ( guild.owner ? escapeFormatting(guild.owner) + ' ' : '' ) + '`' + guild.ownerID + '` <@' + guild.ownerID + '>'];
+			var guildowner = ['Owner:', ( guild.owner ? escapeFormatting(guild.owner) + ' ' : '' ) + '`' + guild.ownerId + '` <@' + guild.ownerId + '>'];
 			var guildsize = ['Size:', guild.memberCount + ' members'];
 			var guildsize = ['Size:', guild.memberCount + ' members'];
 			var guildshard = ['Shard:', guild.shardId];
 			var guildshard = ['Shard:', guild.shardId];
 			var guildpermissions = ['Missing permissions:', ( guild.permissions.length ? '`' + guild.permissions.join('`, `') + '`' : '*none*' )];
 			var guildpermissions = ['Missing permissions:', ( guild.permissions.length ? '`' + guild.permissions.join('`, `') + '`' : '*none*' )];
@@ -55,41 +60,58 @@ async function cmd_get(lang, msg, args, line, wiki) {
 					if ( guild.channel ) embed.addField( guildchannel[0], guildchannel[1] );
 					if ( guild.channel ) embed.addField( guildchannel[0], guildchannel[1] );
 					var split = Util.splitMessage( guildsettings[1], {char:',\n',maxLength:1000,prepend:'```json\n',append:',\n```'} );
 					var split = Util.splitMessage( guildsettings[1], {char:',\n',maxLength:1000,prepend:'```json\n',append:',\n```'} );
 					if ( split.length > 5 ) {
 					if ( split.length > 5 ) {
-						msg.sendChannel( '', {embed}, true );
-						msg.sendChannel( guildsettings.join(' '), {split:{char:',\n',prepend:'```json\n',append:',\n```'}}, true );
+						msg.sendChannel( {embeds: [embed]}, true );
+						Util.splitMessage( guildsettings.join(' '), {
+							char: ',\n',
+							maxLength: 2000,
+							prepend: '```json\n',
+							append: ',\n```'
+						} ).forEach( textpart => msg.sendChannel( textpart, true ) );
 					}
 					}
 					else {
 					else {
-						split.forEach( guildsettingspart => embed.addField( guildsettings[0], guildsettingspart ) );
-						msg.sendChannel( '', {embed}, true );
+						split.forEach( textpart => embed.addField( guildsettings[0], textpart ) );
+						msg.sendChannel( {embeds: [embed]}, true );
 					}
 					}
 				}
 				}
 				else {
 				else {
 					var text = guildname.join(' ') + '\n' + guildowner.join(' ') + '\n' + guildsize.join(' ') + '\n' + guildshard.join(' ') + '\n' + guildpermissions.join(' ') + ( guild.channel ? '\n' + guildchannel.join(' ') : '' ) + '\n' + guildsettings.join(' ');
 					var text = guildname.join(' ') + '\n' + guildowner.join(' ') + '\n' + guildsize.join(' ') + '\n' + guildshard.join(' ') + '\n' + guildpermissions.join(' ') + ( guild.channel ? '\n' + guildchannel.join(' ') : '' ) + '\n' + guildsettings.join(' ');
-					msg.sendChannel( text, {split:{char:',\n',prepend:'```json\n',append:',\n```'}}, true );
+					Util.splitMessage( text, {
+						char: ',\n',
+						maxLength: 2000,
+						prepend: '```json\n',
+						append: ',\n```'
+					} ).forEach( textpart => msg.sendChannel( textpart, true ) );
 				}
 				}
 			} );
 			} );
 		}
 		}
 		
 		
-		var channel = await msg.client.shard.broadcastEval( `if ( this.channels.cache.filter( channel => channel.isGuild() || channel.type === 'category' ).has('${id}') ) {
-			var {name, id, type, parentID, guild: {name: guild, id: guildID, me}} = this.channels.cache.get('${id}');
-			( {
-				name, id, type, parentID, guild, guildID,
-				permissions: me.permissionsIn(id).missing(${defaultPermissions}),
-				pause: global.pause.hasOwnProperty(guildID),
-				shardId: global.shardId
-			} )
-		}` ).then( results => results.find( result => result ) );
+		var channel = await msg.client.shard.broadcastEval( (discordClient, evalData) => {
+			if ( discordClient.channels.cache.filter( channel => channel.isGuild() || channel.type === 'GUILD_CATEGORY' ).has(evalData.id) ) {
+				var channel = discordClient.channels.cache.get(evalData.id);
+				return {
+					name: channel.name, id: channel.id, type: channel.type, parentId: channel.parentId,
+					isThread: channel.isThread(), threadParentId: channel.parent?.parentId,
+					guild: channel.guild.name, guildId: channel.guildId,
+					permissions: channel.guild.me.permissionsIn(channel.id).missing(evalData.defaultPermissions),
+					pause: global.pause.hasOwnProperty(channel.guildId),
+					shardId: process.env.SHARDS
+				};
+			}
+		}, {context: {id, defaultPermissions}} ).then( results => results.find( result => result ) );
 		if ( channel ) {
 		if ( channel ) {
-			var channelguild = ['Guild:', escapeFormatting(channel.guild) + ' `' + channel.guildID + '`' + ( channel.pause ? '\\*' : '' )];
+			var channelguild = ['Guild:', escapeFormatting(channel.guild) + ' `' + channel.guildId + '`' + ( channel.pause ? '\\*' : '' )];
 			var channelname = ['Channel:', '#' + escapeFormatting(channel.name) + ' `' + channel.id + '` <#' + channel.id + '>'];
 			var channelname = ['Channel:', '#' + escapeFormatting(channel.name) + ' `' + channel.id + '` <#' + channel.id + '>'];
-			var channeldetails = ['Details:', '`' + channel.type + '`' + ( channel.parentID ? ' – `' + channel.parentID + '` <#' + channel.parentID + '>' : '' )];
+			var channeldetails = ['Details:', '`' + channel.type + '`' + ( channel.parentId ? ' – `' + channel.parentId + '` <#' + channel.parentId + '>' + ( channel.isThread ? ' – `' + channel.threadParentId + '` <#' + channel.threadParentId + '>' : '' ) : '' )];
 			var channelpermissions = ['Missing permissions:', ( channel.permissions.length ? '`' + channel.permissions.join('`, `') + '`' : '*none*' )];
 			var channelpermissions = ['Missing permissions:', ( channel.permissions.length ? '`' + channel.permissions.join('`, `') + '`' : '*none*' )];
 			var channellang = ['Language:', '*unknown*'];
 			var channellang = ['Language:', '*unknown*'];
 			var channelwiki = ['Default Wiki:', '*unknown*'];
 			var channelwiki = ['Default Wiki:', '*unknown*'];
 			var channelrole = ['Minimal Role:', '*unknown*'];
 			var channelrole = ['Minimal Role:', '*unknown*'];
 			var channelinline = ['Inline commands:', '*unknown*'];
 			var channelinline = ['Inline commands:', '*unknown*'];
 			
 			
-			return db.query( 'SELECT wiki, lang, role, inline FROM discord WHERE guild = $1 AND (channel = $2 OR channel = $3 OR channel IS NULL) ORDER BY channel DESC NULLS LAST LIMIT 1', [channel.guildID, channel.id, '#' + ( channel.type === 'category' ? channel.id : channel.parentID )] ).then( ({rows:[row]}) => {
+			let sqlargs = [channel.guildId];
+			if ( channel.isThread ) sqlargs.push(channel.parentId, '#' + channel.threadParentId);
+			else sqlargs.push(channel.id, '#' + ( channel.type === 'GUILD_CATEGORY' ? channel.id : channel.parentId ));
+			return db.query( 'SELECT wiki, lang, role, inline FROM discord WHERE guild = $1 AND (channel = $2 OR channel = $3 OR channel IS NULL) ORDER BY channel DESC NULLS LAST LIMIT 1', sqlargs ).then( ({rows:[row]}) => {
 				if ( row ) {
 				if ( row ) {
 					channellang[1] = row.lang;
 					channellang[1] = row.lang;
 					channelwiki[1] = row.wiki;
 					channelwiki[1] = row.wiki;
@@ -113,7 +135,7 @@ async function cmd_get(lang, msg, args, line, wiki) {
 				else {
 				else {
 					text += channelguild.join(' ') + '\n' + channelname.join(' ') + '\n' + channeldetails.join(' ') + '\n' + channelpermissions.join(' ') + '\n' + channellang.join(' ') + '\n' + channelwiki[0] + ' <' + channelwiki[1] + '>\n' + channelrole.join(' ') + '\n' + channelinline.join(' ');
 					text += channelguild.join(' ') + '\n' + channelname.join(' ') + '\n' + channeldetails.join(' ') + '\n' + channelpermissions.join(' ') + '\n' + channellang.join(' ') + '\n' + channelwiki[0] + ' <' + channelwiki[1] + '>\n' + channelrole.join(' ') + '\n' + channelinline.join(' ');
 				}
 				}
-				msg.sendChannel( text, {embed}, true );
+				msg.sendChannel( {content: text, embeds: [embed]}, true );
 			} );
 			} );
 		}
 		}
 		
 		
@@ -121,15 +143,17 @@ async function cmd_get(lang, msg, args, line, wiki) {
 		if ( user ) {
 		if ( user ) {
 			var username = ['User:', escapeFormatting(user.tag) + ' `' + user.id + '` <@' + user.id + '>'];
 			var username = ['User:', escapeFormatting(user.tag) + ' `' + user.id + '` <@' + user.id + '>'];
 			var guildlist = ['Guilds:', '*none*'];
 			var guildlist = ['Guilds:', '*none*'];
-			var guilds = await msg.client.shard.broadcastEval( `this.guilds.cache.filter( guild => guild.members.cache.has('${user.id}') ).map( guild => {
-				var member = guild.members.cache.get('${user.id}');
-				return {
-					name: guild.name,
-					id: guild.id,
-					isAdmin: member.permissions.has('MANAGE_GUILD'),
-					shardId: global.shardId
-				}
-			} )` ).then( results => {
+			var guilds = await msg.client.shard.broadcastEval( (discordClient, evalData) => {
+				return discordClient.guilds.cache.filter( guild => guild.members.cache.has(evalData.user) ).map( guild => {
+					var member = guild.members.cache.get(evalData.user);
+					return {
+						name: guild.name,
+						id: guild.id,
+						isAdmin: member.permissions.has(evalData.MANAGE_GUILD),
+						shardId: process.env.SHARDS
+					}
+				} );
+			}, {context: {user: user.id, MANAGE_GUILD: FLAGS.MANAGE_GUILD.toString()}} ).then( results => {
 				return results.reduce( (acc, val) => acc.concat(val), [] ).map( user_guild => {
 				return results.reduce( (acc, val) => acc.concat(val), [] ).map( user_guild => {
 					return escapeFormatting(user_guild.name) + ' `' + user_guild.id + '`' + ( user_guild.isAdmin ? '\\*' : '' );
 					return escapeFormatting(user_guild.name) + ' `' + user_guild.id + '`' + ( user_guild.isAdmin ? '\\*' : '' );
 				} );
 				} );
@@ -140,10 +164,10 @@ async function cmd_get(lang, msg, args, line, wiki) {
 			var embed = null;
 			var embed = null;
 			if ( msg.showEmbed() ) embed = new MessageEmbed().setThumbnail( user.displayAvatarURL({dynamic:true}) ).addField( username[0], username[1] ).addField( guildlist[0], guildlist[1] );
 			if ( msg.showEmbed() ) embed = new MessageEmbed().setThumbnail( user.displayAvatarURL({dynamic:true}) ).addField( username[0], username[1] ).addField( guildlist[0], guildlist[1] );
 			else text += username.join(' ') + '\n' + guildlist.join('\n');
 			else text += username.join(' ') + '\n' + guildlist.join('\n');
-			return msg.sendChannel( text, {embed}, true );
+			return msg.sendChannel( {content: text, embeds: [embed]}, true );
 		}
 		}
 		
 		
-		msg.replyMsg( 'I couldn\'t find a result for `' + id + '`', {}, true );
+		msg.replyMsg( 'I couldn\'t find a result for `' + id + '`', true );
 	} catch ( error ) {
 	} catch ( error ) {
 		log_error(error);
 		log_error(error);
 		msg.reactEmoji('error');
 		msg.reactEmoji('error');

+ 12 - 11
cmds/help.js

@@ -1,3 +1,4 @@
+const {Util} = require('discord.js');
 const help_server = require('../functions/helpserver.js');
 const help_server = require('../functions/helpserver.js');
 const {wikis: mcw} = require('./minecraft/commands.json');
 const {wikis: mcw} = require('./minecraft/commands.json');
 
 
@@ -79,7 +80,7 @@ const restrictions = {
  * @param {import('../util/wiki.js')} wiki - The wiki for the message.
  * @param {import('../util/wiki.js')} wiki - The wiki for the message.
  */
  */
 function cmd_help(lang, msg, args, line, wiki) {
 function cmd_help(lang, msg, args, line, wiki) {
-	if ( msg.channel.isGuild() && pause[msg.guild.id] && ( args.join('') || !msg.isAdmin() ) ) return;
+	if ( msg.channel.isGuild() && pause[msg.guildId] && ( args.join('') || !msg.isAdmin() ) ) return;
 	if ( msg.isAdmin() && msg.defaultSettings ) help_server(lang, msg);
 	if ( msg.isAdmin() && msg.defaultSettings ) help_server(lang, msg);
 	var isMinecraft = mcw.hasOwnProperty(wiki.href);
 	var isMinecraft = mcw.hasOwnProperty(wiki.href);
 	var maxLength = ( ['hi', 'bn'].includes( lang.lang ) ? 480 : 2000 );
 	var maxLength = ( ['hi', 'bn'].includes( lang.lang ) ? 480 : 2000 );
@@ -96,17 +97,17 @@ function cmd_help(lang, msg, args, line, wiki) {
 				if ( process.env.READONLY ) cmdlist = msg.author.toString() + ', ' + lang.get('general.readonly') + '\n' + process.env.invite + '\n\n' + cmdlist;
 				if ( process.env.READONLY ) cmdlist = msg.author.toString() + ', ' + lang.get('general.readonly') + '\n' + process.env.invite + '\n\n' + cmdlist;
 				cmdlist += formathelp(helplist.admin, msg, lang);
 				cmdlist += formathelp(helplist.admin, msg, lang);
 				cmdlist += '\n\n🔸 ' + lang.get('help.adminfooter');
 				cmdlist += '\n\n🔸 ' + lang.get('help.adminfooter');
-				if ( process.env.dashboard ) cmdlist += '\n\t\t' + new URL(( msg.channel.isGuild() ? `/guild/${msg.guild.id}/settings` : '/' ), process.env.dashboard).href;
-				msg.sendChannel( cmdlist, {split:{char:'\n🔹',prepend:'🔹',maxLength}} );
+				if ( process.env.dashboard ) cmdlist += '\n\t\t' + new URL(( msg.channel.isGuild() ? `/guild/${msg.guildId}/settings` : '/' ), process.env.dashboard).href;
+				Util.splitMessage( cmdlist, {char: '\n🔹', maxLength, prepend: '🔹'} ).forEach( textpart => msg.sendChannel( textpart ) );
 			}
 			}
 			else {
 			else {
-				msg.replyMsg( lang.get('help.noadmin') );
+				msg.replyMsg( {content: lang.get('help.noadmin'), allowedMentions: {repliedUser: false}} );
 			}
 			}
 		}
 		}
 		else if ( cmd === 'minecraft' ) {
 		else if ( cmd === 'minecraft' ) {
 			var cmdlist = '<' + ( isMinecraft ? wiki : 'https://minecraft.fandom.com/' ) + '>\n';
 			var cmdlist = '<' + ( isMinecraft ? wiki : 'https://minecraft.fandom.com/' ) + '>\n';
 			cmdlist += formathelp(helplist.minecraft, msg, lang);
 			cmdlist += formathelp(helplist.minecraft, msg, lang);
-			msg.sendChannel( cmdlist, {split:{char:'\n🔹',prepend:'🔹',maxLength}} );
+			Util.splitMessage( cmdlist, {char: '\n🔹', maxLength, prepend: '🔹'} ).forEach( textpart => msg.sendChannel( textpart ) );
 		}
 		}
 		else if ( helpmap.hasOwnProperty(cmd) && 
 		else if ( helpmap.hasOwnProperty(cmd) && 
 		( !restrictions.fandom.includes( cmd ) || wiki.isFandom(false) ) && 
 		( !restrictions.fandom.includes( cmd ) || wiki.isFandom(false) ) && 
@@ -114,14 +115,14 @@ function cmd_help(lang, msg, args, line, wiki) {
 		( !restrictions.admin.includes( cmd ) || msg.isAdmin() ) ) {
 		( !restrictions.admin.includes( cmd ) || msg.isAdmin() ) ) {
 			var cmdlist = formathelp(helpmap[cmd], msg, lang);
 			var cmdlist = formathelp(helpmap[cmd], msg, lang);
 			if ( !cmdlist.length ) msg.reactEmoji('❓');
 			if ( !cmdlist.length ) msg.reactEmoji('❓');
-			else msg.sendChannel( cmdlist, {split:{char:'\n🔹',prepend:'🔹',maxLength}} );
+			else Util.splitMessage( cmdlist, {char: '\n🔹', maxLength, prepend: '🔹'} ).forEach( textpart => msg.sendChannel( textpart ) );
 		}
 		}
 		else msg.reactEmoji('❓');
 		else msg.reactEmoji('❓');
 	}
 	}
-	else if ( msg.isAdmin() && pause[msg.guild.id] ) {
+	else if ( msg.isAdmin() && pause[msg.guildId] ) {
 		var cmdlist = lang.get('help.pause') + '\n';
 		var cmdlist = lang.get('help.pause') + '\n';
 		cmdlist += formathelp(helplist.pause, msg, lang);
 		cmdlist += formathelp(helplist.pause, msg, lang);
-		msg.sendChannel( cmdlist, {split:{char:'\n🔹',prepend:'🔹',maxLength}}, true );
+		Util.splitMessage( cmdlist, {char: '\n🔹', maxLength, prepend: '🔹'} ).forEach( textpart => msg.sendChannel( textpart ) );
 	}
 	}
 	else {
 	else {
 		var cmdlist = lang.get('help.all') + '\n';
 		var cmdlist = lang.get('help.all') + '\n';
@@ -132,7 +133,7 @@ function cmd_help(lang, msg, args, line, wiki) {
 			}
 			}
 		} );
 		} );
 		cmdlist += '\n🔸 ' + lang.get('help.footer');
 		cmdlist += '\n🔸 ' + lang.get('help.footer');
-		msg.sendChannel( cmdlist, {split:{char:'\n🔹',prepend:'🔹',maxLength}} );
+		Util.splitMessage( cmdlist, {char: '\n🔹', maxLength, prepend: '🔹'} ).forEach( textpart => msg.sendChannel( textpart ) );
 	}
 	}
 }
 }
 
 
@@ -143,12 +144,12 @@ function cmd_help(lang, msg, args, line, wiki) {
  * @param {import('../util/i18n.js')} lang - The user language.
  * @param {import('../util/i18n.js')} lang - The user language.
  */
  */
 function formathelp(messages, msg, lang) {
 function formathelp(messages, msg, lang) {
-	var prefix = ( msg.channel.isGuild() && patreons[msg.guild.id] || process.env.prefix );
+	var prefix = ( msg.channel.isGuild() && patreons[msg.guildId] || process.env.prefix );
 	var mention = '@' + ( msg.channel.isGuild() ? msg.guild.me.displayName : msg.client.user.username );
 	var mention = '@' + ( msg.channel.isGuild() ? msg.guild.me.displayName : msg.client.user.username );
 	return messages.filter( message => {
 	return messages.filter( message => {
 		if ( restrictions.inline.includes( message ) && msg.noInline ) return false;
 		if ( restrictions.inline.includes( message ) && msg.noInline ) return false;
 		if ( !restrictions.patreon.includes( message ) ) return true;
 		if ( !restrictions.patreon.includes( message ) ) return true;
-		return ( msg.channel.isGuild() && patreons[msg.guild.id] );
+		return ( msg.channel.isGuild() && patreons[msg.guildId] );
 	} ).map( message => {
 	} ).map( message => {
 		var cmd = message.split('.')[0];
 		var cmd = message.split('.')[0];
 		var intro = ( restrictions.inline.includes( message ) ? '' : prefix );
 		var intro = ( restrictions.inline.includes( message ) ? '' : prefix );

+ 2 - 1
cmds/invite.js

@@ -13,9 +13,10 @@ function cmd_invite(lang, msg, args, line, wiki) {
 		this.LINK(lang, msg, line, wiki);
 		this.LINK(lang, msg, line, wiki);
 	} else {
 	} else {
 		msg.client.generateInvite({
 		msg.client.generateInvite({
+			scopes: ['bot', 'applications.commands'],
 			permissions: defaultPermissions
 			permissions: defaultPermissions
 		}).then( invite => {
 		}).then( invite => {
-			msg.sendChannel( lang.get('invite.bot') + '\n<' + invite + '+applications.commands' + '>' );
+			msg.sendChannel( lang.get('invite.bot') + '\n<' + invite + '>' );
 		}, log_error );
 		}, log_error );
 	}
 	}
 }
 }

+ 2 - 2
cmds/minecraft/bug.js

@@ -73,7 +73,7 @@ function minecraft_bug(lang, msg, wiki, args, title, cmd, reaction, spoiler, noE
 					if ( body.fields.resolution && body.fields.fixVersions && body.fields.fixVersions.length ) {
 					if ( body.fields.resolution && body.fields.fixVersions && body.fields.fixVersions.length ) {
 						fixed = '\n' + lang.get('minecraft.fixed', body.fields.fixVersions.length) + ' ' + body.fields.fixVersions.map( v => v.name ).join(', ');
 						fixed = '\n' + lang.get('minecraft.fixed', body.fields.fixVersions.length) + ' ' + body.fields.fixVersions.map( v => v.name ).join(', ');
 					}
 					}
-					msg.sendChannel( spoiler + '**' + ( statusList?.[status] || status ) + '**: ' + escapeFormatting(body.fields.summary) + '\n<' + baseBrowseUrl + body.key + '>' + fixed + spoiler, {embed} );
+					msg.sendChannel( {content: spoiler + '**' + ( statusList?.[status] || status ) + '**: ' + escapeFormatting(body.fields.summary) + '\n<' + baseBrowseUrl + body.key + '>' + fixed + spoiler, embeds: [embed]} );
 				}
 				}
 			}
 			}
 		}, error => {
 		}, error => {
@@ -128,7 +128,7 @@ function minecraft_bug(lang, msg, wiki, args, title, cmd, reaction, spoiler, noE
 						}
 						}
 					}
 					}
 					var total = '**' + args.join(' ') + ':** ' + lang.get('minecraft.total', body.total.toLocaleString(lang.get('dateformat')), body.total);
 					var total = '**' + args.join(' ') + ':** ' + lang.get('minecraft.total', body.total.toLocaleString(lang.get('dateformat')), body.total);
-					msg.sendChannel( spoiler + total + '\n<' + uri + '>' + spoiler, {embed} );
+					msg.sendChannel( {content: spoiler + total + '\n<' + uri + '>' + spoiler, embeds: [embed]} );
 				}
 				}
 			}
 			}
 		}, error => {
 		}, error => {

+ 2 - 1
cmds/minecraft/syntax.js

@@ -1,3 +1,4 @@
+const {Util} = require('discord.js');
 const {got} = require('../../util/functions.js');
 const {got} = require('../../util/functions.js');
 const Wiki = require('../../util/wiki.js');
 const Wiki = require('../../util/wiki.js');
 const commands = require('./commands.json');
 const commands = require('./commands.json');
@@ -67,7 +68,7 @@ function minecraft_syntax(lang, msg, wiki, mccmd, args, title, cmd, reaction, sp
 		}, error => {
 		}, error => {
 			console.log( '- Error while getting the command page: ' + error );
 			console.log( '- Error while getting the command page: ' + error );
 		} ).finally( () => {
 		} ).finally( () => {
-			msg.sendChannel( spoiler + '```md\n' + cmdSyntax + '```<' + wiki.toLink(( cmdpage.endsWith( '/' ) ? cmdpage + aliasCmd : cmdpage ), '', ( cmdpage.endsWith( '/' ) ? '' : aliasCmd )) + '>' + spoiler, {split:{maxLength:2000,prepend:spoiler + '```md\n',append:'```' + spoiler}} );
+			Util.splitMessage( spoiler + '```md\n' + cmdSyntax + '```<' + wiki.toLink(( cmdpage.endsWith( '/' ) ? cmdpage + aliasCmd : cmdpage ), '', ( cmdpage.endsWith( '/' ) ? '' : aliasCmd )) + '>' + spoiler, {maxLength: 2000, prepend: spoiler + '```md\n', append: '```' + spoiler} ).forEach( textpart => msg.sendChannel( textpart ) );
 
 
 			if ( reaction ) reaction.removeEmoji();
 			if ( reaction ) reaction.removeEmoji();
 		} );
 		} );

+ 113 - 81
cmds/patreon.js

@@ -1,4 +1,4 @@
-const {ShardClientUtil: {shardIDForGuildID}} = require('discord.js');
+const {ShardClientUtil: {shardIdForGuildId}} = require('discord.js');
 const {defaultPermissions, limit: {verification: verificationLimit, rcgcdw: rcgcdwLimit}} = require('../util/default.json');
 const {defaultPermissions, limit: {verification: verificationLimit, rcgcdw: rcgcdwLimit}} = require('../util/default.json');
 var db = require('../util/database.js');
 var db = require('../util/database.js');
 
 
@@ -11,84 +11,107 @@ var db = require('../util/database.js');
  * @param {import('../util/wiki.js')} wiki - The wiki for the message.
  * @param {import('../util/wiki.js')} wiki - The wiki for the message.
  */
  */
 function cmd_patreon(lang, msg, args, line, wiki) {
 function cmd_patreon(lang, msg, args, line, wiki) {
-	if ( !( process.env.channel.split('|').includes( msg.channel.id ) && args.join('') ) ) {
-		if ( !msg.channel.isGuild() || !pause[msg.guild.id] ) this.LINK(lang, msg, line, wiki);
+	if ( !( process.env.channel.split('|').includes( msg.channelId ) && args.join('') ) ) {
+		if ( !msg.channel.isGuild() || !pause[msg.guildId] ) this.LINK(lang, msg, line, wiki);
 		return;
 		return;
 	}
 	}
 	
 	
-	if ( args[0] === 'enable' && /^\d+$/.test(args.slice(1).join(' ')) ) return msg.client.shard.broadcastEval( `this.guilds.cache.get('${args[1]}')?.name`, shardIDForGuildID(args[1], msg.client.shard.count) ).then( guild => {
+	if ( args[0] === 'enable' && /^\d+$/.test(args.slice(1).join(' ')) ) return msg.client.shard.broadcastEval( (discordClient, evalData) => {
+		return discordClient.guilds.cache.get(evalData)?.name;
+	}, {
+		context: args[1],
+		shard: shardIdForGuildId(args[1], msg.client.shard.count)
+	} ).then( guild => {
 		if ( !guild ) return msg.client.generateInvite({
 		if ( !guild ) return msg.client.generateInvite({
-			permissions: defaultPermissions
+			scopes: ['bot', 'applications.commands'],
+			permissions: defaultPermissions,
+			guild: args[1],
+			disableGuildSelect: true
 		}).then( invite => {
 		}).then( invite => {
-			msg.replyMsg( 'I\'m not on a server with the id `' + args[1] + '`.\n<' + invite + '+applications.commands&guild_id=' + args[1] + '&disable_guild_select=true' + '>', {}, true )
+			msg.replyMsg( 'I\'m not on a server with the id `' + args[1] + '`.\n<' + invite + '>', true )
 		}, log_error );
 		}, log_error );
-		if ( patreons[args[1]] ) return msg.replyMsg( '"' + guild + '" has the patreon features already enabled.', {}, true );
+		if ( patreons[args[1]] ) return msg.replyMsg( '"' + guild + '" has the patreon features already enabled.', true );
 		db.query( 'SELECT count, COUNT(guild) guilds FROM patreons LEFT JOIN discord ON discord.patreon = patreons.patreon WHERE patreons.patreon = $1 GROUP BY patreons.patreon', [msg.author.id] ).then( ({rows:[row]}) => {
 		db.query( 'SELECT count, COUNT(guild) guilds FROM patreons LEFT JOIN discord ON discord.patreon = patreons.patreon WHERE patreons.patreon = $1 GROUP BY patreons.patreon', [msg.author.id] ).then( ({rows:[row]}) => {
-			if ( !row ) return msg.replyMsg( 'you can\'t have any servers.', {}, true );
-			if ( row.count <= row.guilds ) return msg.replyMsg( 'you already reached your maximal server count.', {}, true );
-			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+			if ( !row ) return msg.replyMsg( 'You can\'t have any servers.', true );
+			if ( row.count <= row.guilds ) return msg.replyMsg( 'You already reached your maximal server count.', true );
+			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 			db.query( 'UPDATE discord SET patreon = $1 WHERE guild = $2 AND channel IS NULL', [msg.author.id, args[1]] ).then( ({rowCount}) => {
 			db.query( 'UPDATE discord SET patreon = $1 WHERE guild = $2 AND channel IS NULL', [msg.author.id, args[1]] ).then( ({rowCount}) => {
 				if ( !rowCount ) return db.query( 'INSERT INTO discord(main, guild, patreon) VALUES($1, $1, $2)', [args[1], msg.author.id] ).then( () => {
 				if ( !rowCount ) return db.query( 'INSERT INTO discord(main, guild, patreon) VALUES($1, $1, $2)', [args[1], msg.author.id] ).then( () => {
 					console.log( '- Guild successfully added.' );
 					console.log( '- Guild successfully added.' );
-					msg.client.shard.broadcastEval( `global.patreons['${args[1]}'] = '${process.env.prefix}'` );
-					msg.replyMsg( 'the patreon features are now enabled on "' + guild + '".', {}, true );
+					msg.client.shard.broadcastEval( (discordClient, evalData) => {
+						global.patreons[evalData.guild] = evalData.prefix;
+					}, {context: {guild: args[1], prefix: process.env.prefix}} );
+					msg.replyMsg( 'The patreon features are now enabled on "' + guild + '".', true );
 				}, dberror => {
 				}, dberror => {
 					console.log( '- Error while adding the guild: ' + dberror );
 					console.log( '- Error while adding the guild: ' + dberror );
-					msg.replyMsg( 'I got an error while updating the server, please try again later.', {}, true );
+					msg.replyMsg( 'I got an error while updating the server, please try again later.', true );
 				} );
 				} );
 				console.log( '- Guild successfully updated.' );
 				console.log( '- Guild successfully updated.' );
-				msg.client.shard.broadcastEval( `global.patreons['${args[1]}'] = '${process.env.prefix}'` );
-				msg.replyMsg( 'the patreon features are now enabled on "' + guild + '".', {}, true );
+				msg.client.shard.broadcastEval( (discordClient, evalData) => {
+					global.patreons[evalData.guild] = evalData.prefix;
+				}, {context: {guild: args[1], prefix: process.env.prefix}} );
+				msg.replyMsg( 'The patreon features are now enabled on "' + guild + '".', true );
 			}, dberror => {
 			}, dberror => {
 				console.log( '- Error while updating the guild: ' + dberror );
 				console.log( '- Error while updating the guild: ' + dberror );
-				msg.replyMsg( 'I got an error while updating the server, please try again later.', {}, true );
+				msg.replyMsg( 'I got an error while updating the server, please try again later.', true );
 			} );
 			} );
 		}, dberror => {
 		}, dberror => {
 			console.log( '- Error while getting the patreon: ' + dberror );
 			console.log( '- Error while getting the patreon: ' + dberror );
-			msg.replyMsg( 'I got an error while searching for you, please try again later.', {}, true );
+			msg.replyMsg( 'I got an error while searching for you, please try again later.', true );
 		} );
 		} );
 	} );
 	} );
 	
 	
-	if ( args[0] === 'disable' && /^\d+$/.test(args.slice(1).join(' ')) ) return msg.client.shard.broadcastEval( `this.guilds.cache.get('${args[1]}')?.name`, shardIDForGuildID(args[1], msg.client.shard.count) ).then( guild => {
-		if ( !guild ) return msg.replyMsg( 'I\'m not on a server with the id `' + args[1] + '`.', {}, true );
-		if ( !patreons[args[1]] ) return msg.replyMsg( '"' + guild + '" doesn\'t have the patreon features enabled.', {}, true );
+	if ( args[0] === 'disable' && /^\d+$/.test(args.slice(1).join(' ')) ) return msg.client.shard.broadcastEval( (discordClient, evalData) => {
+		return discordClient.guilds.cache.get(evalData)?.name;
+	}, {
+		context: args[1],
+		shard: shardIdForGuildId(args[1], msg.client.shard.count)
+	} ).then( guild => {
+		if ( !guild ) return msg.replyMsg( 'I\'m not on a server with the id `' + args[1] + '`.', true );
+		if ( !patreons[args[1]] ) return msg.replyMsg( '"' + guild + '" doesn\'t have the patreon features enabled.', true );
 		return db.connect().then( client => {
 		return db.connect().then( client => {
 			return client.query( 'SELECT lang, role, inline FROM discord WHERE guild = $1 AND patreon = $2', [args[1], msg.author.id] ).then( ({rows:[row]}) => {
 			return client.query( 'SELECT lang, role, inline FROM discord WHERE guild = $1 AND patreon = $2', [args[1], msg.author.id] ).then( ({rows:[row]}) => {
 				if ( !row ) {
 				if ( !row ) {
-					msg.replyMsg( 'you didn\'t enable the patreon features for "' + guild + '"!', {}, true );
+					msg.replyMsg( 'You didn\'t enable the patreon features for "' + guild + '"!', true );
 					return Promise.reject();
 					return Promise.reject();
 				}
 				}
 				if ( process.env.READONLY ) {
 				if ( process.env.READONLY ) {
-					msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+					msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 					return Promise.reject();
 					return Promise.reject();
 				}
 				}
 				return client.query( 'UPDATE discord SET lang = $1, role = $2, inline = $3, prefix = $4, patreon = NULL WHERE guild = $5', [row.lang, row.role, row.inline, process.env.prefix, args[1]] ).then( () => {
 				return client.query( 'UPDATE discord SET lang = $1, role = $2, inline = $3, prefix = $4, patreon = NULL WHERE guild = $5', [row.lang, row.role, row.inline, process.env.prefix, args[1]] ).then( () => {
 					console.log( '- Guild successfully updated.' );
 					console.log( '- Guild successfully updated.' );
-					msg.client.shard.broadcastEval( `delete global.patreons['${args[1]}']` );
-					msg.replyMsg( 'the patreon features are now disabled on "' + guild + '".', {}, true );
+					msg.client.shard.broadcastEval( (discordClient, evalData) => {
+						delete global.patreons[evalData];
+					}, {context: args[1]} );
+					msg.replyMsg( 'The patreon features are now disabled on "' + guild + '".', true );
 				}, dberror => {
 				}, dberror => {
 					console.log( '- Error while updating the guild: ' + dberror );
 					console.log( '- Error while updating the guild: ' + dberror );
-					msg.replyMsg( 'I got an error while searching for the server, please try again later.', {}, true );
+					msg.replyMsg( 'I got an error while searching for the server, please try again later.', true );
 					return Promise.reject();
 					return Promise.reject();
 				} ).then( () => {
 				} ).then( () => {
 					return client.query( 'DELETE FROM discord WHERE guild = $1 AND channel LIKE $2 RETURNING channel, wiki', [args[1], '#%'] ).then( ({rows}) => {
 					return client.query( 'DELETE FROM discord WHERE guild = $1 AND channel LIKE $2 RETURNING channel, wiki', [args[1], '#%'] ).then( ({rows}) => {
 						if ( rows.length ) {
 						if ( rows.length ) {
 							console.log( '- Channel categories successfully deleted.' );
 							console.log( '- Channel categories successfully deleted.' );
-							return msg.client.shard.broadcastEval( `if ( this.guilds.cache.has('${args[1]}') ) {
-								let rows = ${JSON.stringify(rows)};
-								this.guilds.cache.get('${args[1]}').channels.cache.filter( channel => {
-									return ( channel.isGuild() && rows.some( row => {
-										return ( row.channel === '#' + channel.parentID );
-									} ) );
-								} ).map( channel => {
-									return {
-										id: channel.id,
-										wiki: rows.find( row => {
-											return ( row.channel === '#' + channel.parentID );
-										} ).wiki
-									};
-								} )
-							}`, shardIDForGuildID(args[1], msg.client.shard.count) ).then( channels => {
+							return msg.client.shard.broadcastEval( (discordClient, evalData) => {
+								if ( discordClient.guilds.cache.has(evalData.guild) ) {
+									return discordClient.guilds.cache.get(evalData.guild).channels.cache.filter( channel => {
+										return ( channel.isGuild(false) && evalData.rows.some( row => {
+											return ( row.channel === '#' + channel.parentId );
+										} ) );
+									} ).map( channel => {
+										return {
+											id: channel.id,
+											wiki: evalData.rows.find( row => {
+												return ( row.channel === '#' + channel.parentId );
+											} ).wiki
+										};
+									} );
+								}
+							}, {
+								context: {guild: args[1], rows},
+								shard: shardIdForGuildId(args[1], msg.client.shard.count)
+							} ).then( channels => {
 								if ( channels.length ) return Promise.all(channels.map( channel => {
 								if ( channels.length ) return Promise.all(channels.map( channel => {
 									return client.query( 'INSERT INTO discord(wiki, guild, channel, lang, role, inline, prefix) VALUES($1, $2, $3, $4, $5, $6, $7)', [channel.wiki, args[1], channel.id, row.lang, row.role, row.inline, process.env.prefix] ).catch( dberror => {
 									return client.query( 'INSERT INTO discord(wiki, guild, channel, lang, role, inline, prefix) VALUES($1, $2, $3, $4, $5, $6, $7)', [channel.wiki, args[1], channel.id, row.lang, row.role, row.inline, process.env.prefix] ).catch( dberror => {
 										if ( dberror.message !== 'duplicate key value violates unique constraint "discord_guild_channel_key"' ) {
 										if ( dberror.message !== 'duplicate key value violates unique constraint "discord_guild_channel_key"' ) {
@@ -106,7 +129,7 @@ function cmd_patreon(lang, msg, args, line, wiki) {
 				} );
 				} );
 			}, dberror => {
 			}, dberror => {
 				console.log( '- Error while getting the guild: ' + dberror );
 				console.log( '- Error while getting the guild: ' + dberror );
-				msg.replyMsg( 'I got an error while searching for the server, please try again later.', {}, true );
+				msg.replyMsg( 'I got an error while searching for the server, please try again later.', true );
 				return Promise.reject();
 				return Promise.reject();
 			} ).then( () => {
 			} ).then( () => {
 				return client.query( 'SELECT configid FROM verification WHERE guild = $1 ORDER BY configid ASC OFFSET $2', [args[1], verificationLimit.default] ).then( ({rows}) => {
 				return client.query( 'SELECT configid FROM verification WHERE guild = $1 ORDER BY configid ASC OFFSET $2', [args[1], verificationLimit.default] ).then( ({rows}) => {
@@ -148,7 +171,7 @@ function cmd_patreon(lang, msg, args, line, wiki) {
 			} );
 			} );
 		}, dberror => {
 		}, dberror => {
 			console.log( '- Error while connecting to the database client: ' + dberror );
 			console.log( '- Error while connecting to the database client: ' + dberror );
-			msg.replyMsg( 'I got an error while searching for the server, please try again later.', {}, true );
+			msg.replyMsg( 'I got an error while searching for the server, please try again later.', true );
 		} );
 		} );
 	} );
 	} );
 	
 	
@@ -156,42 +179,46 @@ function cmd_patreon(lang, msg, args, line, wiki) {
 	
 	
 	if ( args[0] === 'check' ) {
 	if ( args[0] === 'check' ) {
 		if ( !args.slice(1).join('') ) return db.query( 'SELECT count, ARRAY_REMOVE(ARRAY_AGG(guild), NULL) guilds FROM patreons LEFT JOIN discord ON discord.patreon = patreons.patreon WHERE patreons.patreon = $1 GROUP BY patreons.patreon', [msg.author.id] ).then( ({rows:[row]}) => {
 		if ( !args.slice(1).join('') ) return db.query( 'SELECT count, ARRAY_REMOVE(ARRAY_AGG(guild), NULL) guilds FROM patreons LEFT JOIN discord ON discord.patreon = patreons.patreon WHERE patreons.patreon = $1 GROUP BY patreons.patreon', [msg.author.id] ).then( ({rows:[row]}) => {
-			if ( !row ) return msg.replyMsg( 'you can\'t have any servers.', {}, true );
-			var text = 'you can have up to ' + row.count + ' servers.\n\n';
+			if ( !row ) return msg.replyMsg( 'You can\'t have any servers.', true );
+			var text = 'You can have up to ' + row.count + ' servers.\n\n';
 			if ( row.guilds.length ) {
 			if ( row.guilds.length ) {
-				msg.client.shard.broadcastEval( `${JSON.stringify(row.guilds)}.map( guild => this.guilds.cache.get(guild)?.name )` ).then( results => {
+				msg.client.shard.broadcastEval( (discordClient, evalData) => {
+					return evalData.map( guild => discordClient.guilds.cache.get(guild)?.name );
+				}, {context: row.guilds} ).then( results => {
 					var guilds = row.guilds.map( (guild, i) => '`' + guild + '` ' + ( results.find( result => result[i] !== null )?.[i] || '' ) );
 					var guilds = row.guilds.map( (guild, i) => '`' + guild + '` ' + ( results.find( result => result[i] !== null )?.[i] || '' ) );
 					text += 'Currently you have ' + guilds.length + ' servers:\n' + guilds.join('\n');
 					text += 'Currently you have ' + guilds.length + ' servers:\n' + guilds.join('\n');
 					if ( row.count < guilds.length ) text += '\n\n**You are above your server limit!**';
 					if ( row.count < guilds.length ) text += '\n\n**You are above your server limit!**';
-					msg.replyMsg( text, {}, true );
+					msg.replyMsg( text, true );
 				} );
 				} );
 			}
 			}
 			else {
 			else {
 				text += '*You don\'t have any servers yet.*';
 				text += '*You don\'t have any servers yet.*';
-				msg.replyMsg( text, {}, true );
+				msg.replyMsg( text, true );
 			}
 			}
 		}, dberror => {
 		}, dberror => {
 			console.log( '- Error while getting the patreon: ' + dberror );
 			console.log( '- Error while getting the patreon: ' + dberror );
-			msg.replyMsg( 'I got an error while searching for you, please try again later.', {}, true );
+			msg.replyMsg( 'I got an error while searching for you, please try again later.', true );
 		} );
 		} );
 		if ( msg.isOwner() && /^\d+$/.test(args.slice(1).join(' ')) ) return db.query( 'SELECT count, ARRAY_REMOVE(ARRAY_AGG(guild), NULL) guilds FROM patreons LEFT JOIN discord ON discord.patreon = patreons.patreon WHERE patreons.patreon = $1 GROUP BY patreons.patreon', [args[1]] ).then( ({rows:[row]}) => {
 		if ( msg.isOwner() && /^\d+$/.test(args.slice(1).join(' ')) ) return db.query( 'SELECT count, ARRAY_REMOVE(ARRAY_AGG(guild), NULL) guilds FROM patreons LEFT JOIN discord ON discord.patreon = patreons.patreon WHERE patreons.patreon = $1 GROUP BY patreons.patreon', [args[1]] ).then( ({rows:[row]}) => {
-			if ( !row ) return msg.replyMsg( '<@' + args[1] + '> can\'t have any servers.', {}, true );
+			if ( !row ) return msg.replyMsg( '<@' + args[1] + '> can\'t have any servers.', true );
 			var text = '<@' + args[1] + '> can have up to ' + row.count + ' servers.\n\n';
 			var text = '<@' + args[1] + '> can have up to ' + row.count + ' servers.\n\n';
 			if ( row.guilds.length ) {
 			if ( row.guilds.length ) {
-				msg.client.shard.broadcastEval( `${JSON.stringify(row.guilds)}.map( guild => this.guilds.cache.get(guild)?.name )` ).then( results => {
+				msg.client.shard.broadcastEval( (discordClient, evalData) => {
+					return evalData.map( guild => discordClient.guilds.cache.get(guild)?.name );
+				}, {context: row.guilds} ).then( results => {
 					var guilds = row.guilds.map( (guild, i) => '`' + guild + '` ' + ( results.find( result => result[i] !== null )?.[i] || '' ) );
 					var guilds = row.guilds.map( (guild, i) => '`' + guild + '` ' + ( results.find( result => result[i] !== null )?.[i] || '' ) );
 					text += 'Currently they have ' + guilds.length + ' servers:\n' + guilds.join('\n');
 					text += 'Currently they have ' + guilds.length + ' servers:\n' + guilds.join('\n');
 					if ( row.count < guilds.length ) text += '\n\n**They are above their server limit!**';
 					if ( row.count < guilds.length ) text += '\n\n**They are above their server limit!**';
-					msg.replyMsg( text, {}, true );
+					msg.replyMsg( text, true );
 				} );
 				} );
 			}
 			}
 			else {
 			else {
 				text += '*They don\'t have any servers yet.*';
 				text += '*They don\'t have any servers yet.*';
-				msg.replyMsg( text, {}, true );
+				msg.replyMsg( text, true );
 			}
 			}
 		}, dberror => {
 		}, dberror => {
 			console.log( '- Error while getting the patreon: ' + dberror );
 			console.log( '- Error while getting the patreon: ' + dberror );
-			msg.replyMsg( 'I got an error while searching for <@' + args[1] + '>, please try again later.', {}, true );
+			msg.replyMsg( 'I got an error while searching for <@' + args[1] + '>, please try again later.', true );
 		} );
 		} );
 	}
 	}
 	
 	
@@ -201,16 +228,20 @@ function cmd_patreon(lang, msg, args, line, wiki) {
 		var guilds = ( row ? row.guilds : [] );
 		var guilds = ( row ? row.guilds : [] );
 		if ( args[2].startsWith( '+' ) || args[2].startsWith( '-' ) ) count += value;
 		if ( args[2].startsWith( '+' ) || args[2].startsWith( '-' ) ) count += value;
 		else count = value;
 		else count = value;
-		if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+		if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 		if ( count <= 0 ) return db.connect().then( client => {
 		if ( count <= 0 ) return db.connect().then( client => {
 			return client.query( 'DELETE FROM patreons WHERE patreon = $1', [args[1]] ).then( () => {
 			return client.query( 'DELETE FROM patreons WHERE patreon = $1', [args[1]] ).then( () => {
 				console.log( '- Patreon successfully deleted.' );
 				console.log( '- Patreon successfully deleted.' );
-				msg.replyMsg( '<@' + args[1] + '> is no longer a patreon.', {}, true );
+				msg.replyMsg( '<@' + args[1] + '> is no longer a patreon.', true );
 				if ( !guilds.length ) return Promise.reject();
 				if ( !guilds.length ) return Promise.reject();
-				msg.client.shard.broadcastEval( `${JSON.stringify(row.guilds)}.forEach( guild => delete global.patreons[guild] )` );
+				msg.client.shard.broadcastEval( (discordClient, evalData) => {
+					return evalData.map( guild => {
+						delete global.patreons[guild];
+					} );
+				}, {context: row.guilds} );
 			}, dberror => {
 			}, dberror => {
 				console.log( '- Error while deleting the patreon: ' + dberror );
 				console.log( '- Error while deleting the patreon: ' + dberror );
-				msg.replyMsg( 'I got an error while deleting <@' + args[1] + '>, please try again later.', {}, true );
+				msg.replyMsg( 'I got an error while deleting <@' + args[1] + '>, please try again later.', true );
 				return Promise.reject();
 				return Promise.reject();
 			} ).then( () => {
 			} ).then( () => {
 				return client.query( 'SELECT guild, lang, role, inline FROM discord WHERE guild IN (' + guilds.map( (guild, i) => '$' + ( i + 1 ) ).join(', ') + ') AND channel IS NULL', guilds ).then( ({rows}) => {
 				return client.query( 'SELECT guild, lang, role, inline FROM discord WHERE guild IN (' + guilds.map( (guild, i) => '$' + ( i + 1 ) ).join(', ') + ') AND channel IS NULL', guilds ).then( ({rows}) => {
@@ -228,24 +259,25 @@ function cmd_patreon(lang, msg, args, line, wiki) {
 				return client.query( 'DELETE FROM discord WHERE guild IN (' + guilds.map( (guild, i) => '$' + ( i + 2 ) ).join(', ') + ') AND channel LIKE $1 RETURNING wiki, guild, channel, lang, role, inline', ['#%', ...guilds] ).then( ({rows}) => {
 				return client.query( 'DELETE FROM discord WHERE guild IN (' + guilds.map( (guild, i) => '$' + ( i + 2 ) ).join(', ') + ') AND channel LIKE $1 RETURNING wiki, guild, channel, lang, role, inline', ['#%', ...guilds] ).then( ({rows}) => {
 					if ( rows.length ) {
 					if ( rows.length ) {
 						console.log( '- Channel categories successfully deleted.' );
 						console.log( '- Channel categories successfully deleted.' );
-						return msg.client.shard.broadcastEval( `let rows = ${JSON.stringify(rows)};
-						[].concat(...${JSON.stringify(guilds)}.filter( guild => {
-							return this.guilds.cache.has(guild);
-						} ).map( guild => {
-							return this.guilds.cache.get(guild).channels.cache.filter( channel => {
-								return ( channel.isGuild() && rows.some( row => {
-									return ( row.channel === '#' + channel.parentID );
-								} ) );
-							} ).map( channel => {
-								let row = rows.find( row => {
-									return ( row.channel === '#' + channel.parentID );
+						return msg.client.shard.broadcastEval( (discordClient, evalData) => {
+							return [].concat(...evalData.guilds.filter( guild => {
+								return discordClient.guilds.cache.has(guild);
+							} ).map( guild => {
+								return discordClient.guilds.cache.get(guild).channels.cache.filter( channel => {
+									return ( channel.isGuild(false) && evalData.rows.some( row => {
+										return ( row.channel === '#' + channel.parentId );
+									} ) );
+								} ).map( channel => {
+									let row = evalData.rows.find( row => {
+										return ( row.channel === '#' + channel.parentId );
+									} );
+									return {
+										id: channel.id, guild: row.guild, wiki: row.wiki,
+										lang: row.lang, role: row.role, inline: row.inline
+									};
 								} );
 								} );
-								return {
-									id: channel.id, guild: row.guild, wiki: row.wiki,
-									lang: row.lang, role: row.role, inline: row.inline
-								};
-							} );
-						} ))` ).then( response => {
+							} ));
+						}, {context: {rows, guilds}} ).then( response => {
 							var channels = [].concat(...response);
 							var channels = [].concat(...response);
 							if ( channels.length ) return Promise.all(channels.map( channel => {
 							if ( channels.length ) return Promise.all(channels.map( channel => {
 								return client.query( 'INSERT INTO discord(wiki, guild, channel, lang, role, inline, prefix) VALUES($1, $2, $3, $4, $5, $6, $7)', [channel.wiki, channel.guild, channel.id, channel.lang, channel.role, channel.inline, process.env.prefix] ).catch( dberror => {
 								return client.query( 'INSERT INTO discord(wiki, guild, channel, lang, role, inline, prefix) VALUES($1, $2, $3, $4, $5, $6, $7)', [channel.wiki, channel.guild, channel.id, channel.lang, channel.role, channel.inline, process.env.prefix] ).catch( dberror => {
@@ -305,30 +337,30 @@ function cmd_patreon(lang, msg, args, line, wiki) {
 			} );
 			} );
 		}, dberror => {
 		}, dberror => {
 			console.log( '- Error while connecting to the database client: ' + dberror );
 			console.log( '- Error while connecting to the database client: ' + dberror );
-			msg.replyMsg( 'I got an error while updating <@' + args[1] + '>, please try again later.', {}, true );
+			msg.replyMsg( 'I got an error while updating <@' + args[1] + '>, please try again later.', true );
 		} );
 		} );
 		if ( !row ) return db.query( 'INSERT INTO patreons(patreon, count) VALUES($1, $2)', [args[1], count] ).then( () => {
 		if ( !row ) return db.query( 'INSERT INTO patreons(patreon, count) VALUES($1, $2)', [args[1], count] ).then( () => {
 			console.log( '- Patreon successfully added.' );
 			console.log( '- Patreon successfully added.' );
-			msg.replyMsg( '<@' + args[1] + '> can now have up to ' + count + ' servers.', {}, true );
+			msg.replyMsg( '<@' + args[1] + '> can now have up to ' + count + ' servers.', true );
 		}, dberror => {
 		}, dberror => {
 			console.log( '- Error while adding the patreon: ' + dberror );
 			console.log( '- Error while adding the patreon: ' + dberror );
-			msg.replyMsg( 'I got an error while adding <@' + args[1] + '>, please try again later.', {}, true );
+			msg.replyMsg( 'I got an error while adding <@' + args[1] + '>, please try again later.', true );
 		} );
 		} );
 		db.query( 'UPDATE patreons SET count = $1 WHERE patreon = $2', [count, args[1]] ).then( () => {
 		db.query( 'UPDATE patreons SET count = $1 WHERE patreon = $2', [count, args[1]] ).then( () => {
 			console.log( '- Patreon successfully updated.' );
 			console.log( '- Patreon successfully updated.' );
 			var text = '<@' + args[1] + '> can now have up to ' + count + ' servers.';
 			var text = '<@' + args[1] + '> can now have up to ' + count + ' servers.';
 			if ( count < guilds.length ) text += '\n\n**They are now above their server limit!**';
 			if ( count < guilds.length ) text += '\n\n**They are now above their server limit!**';
-			msg.replyMsg( text, {}, true );
+			msg.replyMsg( text, true );
 		}, dberror => {
 		}, dberror => {
 			console.log( '- Error while updating the patreon: ' + dberror );
 			console.log( '- Error while updating the patreon: ' + dberror );
-			msg.replyMsg( 'I got an error while updating <@' + args[1] + '>, please try again later.', {}, true );
+			msg.replyMsg( 'I got an error while updating <@' + args[1] + '>, please try again later.', true );
 		} );
 		} );
 	}, dberror => {
 	}, dberror => {
 		console.log( '- Error while getting the patreon: ' + dberror );
 		console.log( '- Error while getting the patreon: ' + dberror );
-		msg.replyMsg( 'I got an error while searching for <@' + args[1] + '>, please try again later.', {}, true );
+		msg.replyMsg( 'I got an error while searching for <@' + args[1] + '>, please try again later.', true );
 	} );
 	} );
 	
 	
-	if ( !msg.channel.isGuild() || !pause[msg.guild.id] ) this.LINK(lang, msg, line, wiki);
+	if ( !msg.channel.isGuild() || !pause[msg.guildId] ) this.LINK(lang, msg, line, wiki);
 }
 }
 
 
 module.exports = {
 module.exports = {

+ 6 - 6
cmds/pause.js

@@ -8,16 +8,16 @@
  */
  */
 function cmd_pause(lang, msg, args, line, wiki) {
 function cmd_pause(lang, msg, args, line, wiki) {
 	if ( msg.channel.isGuild() && args.join(' ').split('\n')[0].isMention(msg.guild) && ( msg.isAdmin() || msg.isOwner() ) ) {
 	if ( msg.channel.isGuild() && args.join(' ').split('\n')[0].isMention(msg.guild) && ( msg.isAdmin() || msg.isOwner() ) ) {
-		if ( pause[msg.guild.id] ) {
-			delete pause[msg.guild.id];
+		if ( pause[msg.guildId] ) {
+			delete pause[msg.guildId];
 			console.log( '- Pause ended.' );
 			console.log( '- Pause ended.' );
-			msg.replyMsg( lang.get('pause.off'), {}, true );
+			msg.replyMsg( lang.get('pause.off'), true );
 		} else {
 		} else {
-			msg.replyMsg( lang.get('pause.on'), {}, true );
+			msg.replyMsg( lang.get('pause.on'), true );
 			console.log( '- Pause started.' );
 			console.log( '- Pause started.' );
-			pause[msg.guild.id] = true;
+			pause[msg.guildId] = true;
 		}
 		}
-	} else if ( !msg.channel.isGuild() || !pause[msg.guild.id] ) {
+	} else if ( !msg.channel.isGuild() || !pause[msg.guildId] ) {
 		this.LINK(lang, msg, line, wiki);
 		this.LINK(lang, msg, line, wiki);
 	}
 	}
 }
 }

+ 107 - 119
cmds/rcscript.js

@@ -1,4 +1,5 @@
 const cheerio = require('cheerio');
 const cheerio = require('cheerio');
+const {Util, MessageActionRow, MessageButton, Permissions: {FLAGS}} = require('discord.js');
 const help_setup = require('../functions/helpsetup.js');
 const help_setup = require('../functions/helpsetup.js');
 const {limit: {rcgcdw: rcgcdwLimit}} = require('../util/default.json');
 const {limit: {rcgcdw: rcgcdwLimit}} = require('../util/default.json');
 const {got} = require('../util/functions.js');
 const {got} = require('../util/functions.js');
@@ -30,53 +31,40 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 	if ( !msg.isAdmin() ) return msg.reactEmoji('❌');
 	if ( !msg.isAdmin() ) return msg.reactEmoji('❌');
 	if ( msg.defaultSettings ) return help_setup(lang, msg);
 	if ( msg.defaultSettings ) return help_setup(lang, msg);
 	
 	
-	db.query( 'SELECT configid, webhook, wiki, lang, display, rcid, postid FROM rcgcdw WHERE guild = $1 ORDER BY configid ASC', [msg.guild.id] ).then( ({rows}) => {
+	db.query( 'SELECT configid, webhook, wiki, lang, display, rcid, postid FROM rcgcdw WHERE guild = $1 ORDER BY configid ASC', [msg.guildId] ).then( ({rows}) => {
 		var prefix = process.env.prefix;
 		var prefix = process.env.prefix;
 		var limit = rcgcdwLimit.default;
 		var limit = rcgcdwLimit.default;
 		var display = display_types.slice(0, rcgcdwLimit.display + 1);
 		var display = display_types.slice(0, rcgcdwLimit.display + 1);
-		if ( patreons[msg.guild.id] ) {
-			prefix = patreons[msg.guild.id];
+		if ( patreons[msg.guildId] ) {
+			prefix = patreons[msg.guildId];
 			limit = rcgcdwLimit.patreon;
 			limit = rcgcdwLimit.patreon;
 			display = display_types.slice();
 			display = display_types.slice();
 		}
 		}
-		var button = {
-			type: 2,
-			style: 5,
-			label: lang.get('settings.button'),
-			emoji: {
-				id: '588723255972593672',
-				name: 'wikibot',
-				animated: false
-			},
-			url: new URL(`/guild/${msg.guild.id}/rcscript`, process.env.dashboard).href,
-			disabled: false
-		};
+		var button = null;
 		var components = [];
 		var components = [];
-		if ( process.env.dashboard ) components.push({
-			type: 1,
-			components: [
-				button
-			]
-		});
+		if ( process.env.dashboard ) {
+			button = new MessageButton().setLabel(lang.get('settings.button')).setEmoji('<:wikibot:588723255972593672>').setStyle('LINK').setURL(new URL(`/guild/${msg.guildId}/rcscript`, process.env.dashboard).href);
+			components.push(new MessageActionRow().addComponents(button));
+		}
 
 
 		if ( args[0] === 'add' ) {
 		if ( args[0] === 'add' ) {
-			if ( !msg.channel.permissionsFor(msg.client.user).has('MANAGE_WEBHOOKS') ) {
-				console.log( msg.guild.id + ': Missing permissions - MANAGE_WEBHOOKS' );
+			if ( !msg.channel.permissionsFor(msg.client.user).has(FLAGS.MANAGE_WEBHOOKS) ) {
+				console.log( msg.guildId + ': Missing permissions - MANAGE_WEBHOOKS' );
 				return msg.replyMsg( lang.get('general.missingperm') + ' `MANAGE_WEBHOOKS`' );
 				return msg.replyMsg( lang.get('general.missingperm') + ' `MANAGE_WEBHOOKS`' );
 			}
 			}
-			if ( !( msg.channel.permissionsFor(msg.member).has('MANAGE_WEBHOOKS') || ( msg.isOwner() && msg.evalUsed ) ) ) {
+			if ( !( msg.channel.permissionsFor(msg.member).has(FLAGS.MANAGE_WEBHOOKS) || ( msg.isOwner() && msg.evalUsed ) ) ) {
 				return msg.replyMsg( lang.get('rcscript.noadmin') );
 				return msg.replyMsg( lang.get('rcscript.noadmin') );
 			}
 			}
-			if ( rows.length >= limit ) return msg.replyMsg( lang.get('rcscript.max_entries'), {}, true );
-			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+			if ( rows.length >= limit ) return msg.replyMsg( lang.get('rcscript.max_entries'), true );
+			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 
 
-			button.url = new URL(`/guild/${msg.guild.id}/rcscript/new`, process.env.dashboard).href;
+			button?.setURL(new URL(`/guild/${msg.guildId}/rcscript/new`, button.url).href);
 			var wikihelp = '\n`' + prefix + 'rcscript add ' + lang.get('rcscript.new_wiki') + '`\n' + lang.get('rcscript.help_wiki');
 			var wikihelp = '\n`' + prefix + 'rcscript add ' + lang.get('rcscript.new_wiki') + '`\n' + lang.get('rcscript.help_wiki');
 			var input = args.slice(1).join(' ').toLowerCase().trim().replace( /^<\s*(.*?)\s*>$/, '$1' );
 			var input = args.slice(1).join(' ').toLowerCase().trim().replace( /^<\s*(.*?)\s*>$/, '$1' );
 			var wikinew = new Wiki(wiki);
 			var wikinew = new Wiki(wiki);
 			if ( input ) {
 			if ( input ) {
 				wikinew = Wiki.fromInput(input);
 				wikinew = Wiki.fromInput(input);
-				if ( !wikinew ) return msg.replyMsg( lang.get('settings.wikiinvalid') + wikihelp, {components}, true );
+				if ( !wikinew ) return msg.replyMsg( {content: lang.get('settings.wikiinvalid') + wikihelp, components}, true );
 			}
 			}
 			return msg.reactEmoji('⏳', true).then( reaction => got.get( wikinew + 'api.php?&action=query&meta=allmessages|siteinfo&ammessages=custom-RcGcDw|recentchanges&amenableparser=true&siprop=general&titles=Special:RecentChanges&format=json', {
 			return msg.reactEmoji('⏳', true).then( reaction => got.get( wikinew + 'api.php?&action=query&meta=allmessages|siteinfo&ammessages=custom-RcGcDw|recentchanges&amenableparser=true&siprop=general&titles=Special:RecentChanges&format=json', {
 				responseType: 'text'
 				responseType: 'text'
@@ -100,25 +88,25 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 					console.log( '- ' + response.statusCode + ': Error while testing the wiki: ' + body?.error?.info );
 					console.log( '- ' + response.statusCode + ': Error while testing the wiki: ' + body?.error?.info );
 					if ( reaction ) reaction.removeEmoji();
 					if ( reaction ) reaction.removeEmoji();
 					if ( body?.error?.info === 'You need read permission to use this module.' ) {
 					if ( body?.error?.info === 'You need read permission to use this module.' ) {
-						return msg.replyMsg( lang.get('settings.wikiinvalid_private') + wikihelp, {components}, true );
+						return msg.replyMsg( {content: lang.get('settings.wikiinvalid_private') + wikihelp, components}, true );
 					}
 					}
 					msg.reactEmoji('nowiki', true);
 					msg.reactEmoji('nowiki', true);
-					return msg.replyMsg( lang.get('settings.wikiinvalid') + wikihelp, {components}, true );
+					return msg.replyMsg( {content: lang.get('settings.wikiinvalid') + wikihelp, components}, true );
 				}
 				}
 				wikinew.updateWiki(body.query.general);
 				wikinew.updateWiki(body.query.general);
 				if ( body.query.general.generator.replace( /^MediaWiki 1\.(\d\d).*$/, '$1' ) < 30 ) {
 				if ( body.query.general.generator.replace( /^MediaWiki 1\.(\d\d).*$/, '$1' ) < 30 ) {
 					if ( reaction ) reaction.removeEmoji();
 					if ( reaction ) reaction.removeEmoji();
-					return msg.replyMsg( lang.get('test.MediaWiki', 'MediaWiki 1.30', body.query.general.generator) + '\nhttps://www.mediawiki.org/wiki/MediaWiki_1.30', {components}, true );
+					return msg.replyMsg( {content: lang.get('test.MediaWiki', 'MediaWiki 1.30', body.query.general.generator) + '\nhttps://www.mediawiki.org/wiki/MediaWiki_1.30', components}, true );
 				}
 				}
-				if ( body.query.allmessages[0]['*'] !== msg.guild.id ) {
+				if ( body.query.allmessages[0]['*'] !== msg.guildId ) {
 					if ( reaction ) reaction.removeEmoji();
 					if ( reaction ) reaction.removeEmoji();
-					return msg.replyMsg( lang.get('rcscript.sysmessage', 'MediaWiki:Custom-RcGcDw', msg.guild.id) + '\n<' + wikinew.toLink('MediaWiki:Custom-RcGcDw', 'action=edit') + '>', {components}, true );
+					return msg.replyMsg( {content: lang.get('rcscript.sysmessage', 'MediaWiki:Custom-RcGcDw', msg.guildId) + '\n<' + wikinew.toLink('MediaWiki:Custom-RcGcDw', 'action=edit') + '>', components}, true );
 				}
 				}
 				return db.query( 'SELECT reason FROM blocklist WHERE wiki = $1', [wikinew.href] ).then( ({rows:[block]}) => {
 				return db.query( 'SELECT reason FROM blocklist WHERE wiki = $1', [wikinew.href] ).then( ({rows:[block]}) => {
 					if ( block ) {
 					if ( block ) {
 						console.log( '- This wiki is blocked: ' + block.reason );
 						console.log( '- This wiki is blocked: ' + block.reason );
 						if ( reaction ) reaction.removeEmoji();
 						if ( reaction ) reaction.removeEmoji();
-						return msg.replyMsg( ( block.reason ? lang.get('rcscript.blocked_reason', block.reason) : lang.get('rcscript.blocked') ), {components}, true );
+						return msg.replyMsg( {content: ( block.reason ? lang.get('rcscript.blocked_reason', block.reason) : lang.get('rcscript.blocked') ), components}, true );
 					}
 					}
 					if ( wikinew.isFandom(false) ) return got.get( wikinew + 'wikia.php?controller=DiscussionPost&method=getPosts&includeCounters=false&limit=1&format=json&cache=' + Date.now(), {
 					if ( wikinew.isFandom(false) ) return got.get( wikinew + 'wikia.php?controller=DiscussionPost&method=getPosts&includeCounters=false&limit=1&format=json&cache=' + Date.now(), {
 						headers: {
 						headers: {
@@ -154,19 +142,19 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 								if ( new_configid === i ) new_configid++;
 								if ( new_configid === i ) new_configid++;
 								else break;
 								else break;
 							}
 							}
-							db.query( 'INSERT INTO rcgcdw(guild, configid, webhook, wiki, lang, display, postid) VALUES($1, $2, $3, $4, $5, $6, $7)', [msg.guild.id, new_configid, webhook.id + '/' + webhook.token, wikinew.href, webhook_lang.lang, ( msg.showEmbed() ? 1 : 0 ), ( enableFeeds ? null : '-1' )] ).then( () => {
+							db.query( 'INSERT INTO rcgcdw(guild, configid, webhook, wiki, lang, display, postid) VALUES($1, $2, $3, $4, $5, $6, $7)', [msg.guildId, new_configid, webhook.id + '/' + webhook.token, wikinew.href, webhook_lang.lang, ( msg.showEmbed() ? 1 : 0 ), ( enableFeeds ? null : '-1' )] ).then( () => {
 								console.log( '- RcGcDw successfully added.' );
 								console.log( '- RcGcDw successfully added.' );
 								if ( reaction ) reaction.removeEmoji();
 								if ( reaction ) reaction.removeEmoji();
-								msg.replyMsg( lang.get('rcscript.added') + ' <' + wikinew + '>\n`' + prefix + 'rcscript' + ( rows.length ? ' ' + new_configid : '' ) + '`', {components}, true );
+								msg.replyMsg( {content: lang.get('rcscript.added') + ' <' + wikinew + '>\n`' + prefix + 'rcscript' + ( rows.length ? ' ' + new_configid : '' ) + '`', components}, true );
 							}, dberror => {
 							}, dberror => {
 								console.log( '- Error while adding the RcGcDw: ' + dberror );
 								console.log( '- Error while adding the RcGcDw: ' + dberror );
 								if ( reaction ) reaction.removeEmoji();
 								if ( reaction ) reaction.removeEmoji();
-								msg.replyMsg( lang.get('settings.save_failed'), {components}, true );
+								msg.replyMsg( {content: lang.get('settings.save_failed'), components}, true );
 							} );
 							} );
 						}, error => {
 						}, error => {
 							console.log( '- Error while creating the webhook: ' + error );
 							console.log( '- Error while creating the webhook: ' + error );
 							if ( reaction ) reaction.removeEmoji();
 							if ( reaction ) reaction.removeEmoji();
-							msg.replyMsg( lang.get('rcscript.webhook_failed'), {components}, true );
+							msg.replyMsg( {content: lang.get('rcscript.webhook_failed'), components}, true );
 						} );
 						} );
 					}
 					}
 				}, dberror => {
 				}, dberror => {
@@ -178,14 +166,14 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 				if ( reaction ) reaction.removeEmoji();
 				if ( reaction ) reaction.removeEmoji();
 				if ( error.message?.startsWith( 'connect ECONNREFUSED ' ) || error.message?.startsWith( 'Hostname/IP does not match certificate\'s altnames: ' ) || error.message === 'certificate has expired' || error.message === 'self signed certificate' ) {
 				if ( error.message?.startsWith( 'connect ECONNREFUSED ' ) || error.message?.startsWith( 'Hostname/IP does not match certificate\'s altnames: ' ) || error.message === 'certificate has expired' || error.message === 'self signed certificate' ) {
 					console.log( '- Error while testing the wiki: No HTTPS' );
 					console.log( '- Error while testing the wiki: No HTTPS' );
-					return msg.replyMsg( lang.get('settings.wikiinvalid_http') + wikihelp, {components}, true );
+					return msg.replyMsg( {content: lang.get('settings.wikiinvalid_http') + wikihelp, components}, true );
 				}
 				}
 				console.log( '- Error while testing the wiki: ' + error );
 				console.log( '- Error while testing the wiki: ' + error );
 				if ( error.message === `Timeout awaiting 'request' for ${got.defaults.options.timeout.request}ms` ) {
 				if ( error.message === `Timeout awaiting 'request' for ${got.defaults.options.timeout.request}ms` ) {
-					return msg.replyMsg( lang.get('settings.wikiinvalid_timeout') + wikihelp, {components}, true );
+					return msg.replyMsg( {content: lang.get('settings.wikiinvalid_timeout') + wikihelp, components}, true );
 				}
 				}
 				msg.reactEmoji('nowiki', true);
 				msg.reactEmoji('nowiki', true);
-				return msg.replyMsg( lang.get('settings.wikiinvalid') + wikihelp, {components}, true );
+				return msg.replyMsg( {content: lang.get('settings.wikiinvalid') + wikihelp, components}, true );
 			} ) );
 			} ) );
 		}
 		}
 
 
@@ -205,10 +193,10 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 			let cmd = prefix + 'rcscript' + ( rows.length === 1 ? '' : ' ' + selected_row.configid );
 			let cmd = prefix + 'rcscript' + ( rows.length === 1 ? '' : ' ' + selected_row.configid );
 
 
 			if ( args[0] === 'delete' && !args[1] ) {
 			if ( args[0] === 'delete' && !args[1] ) {
-				if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+				if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 				return msg.client.fetchWebhook(...selected_row.webhook.split('/')).then( webhook => {
 				return msg.client.fetchWebhook(...selected_row.webhook.split('/')).then( webhook => {
-					var channel = msg.guild.channels.cache.get(webhook.channelID);
-					if ( !channel || !channel.permissionsFor(msg.member).has('MANAGE_WEBHOOKS') ) {
+					var channel = msg.guild.channels.cache.get(webhook.channelId);
+					if ( !channel || !channel.permissionsFor(msg.member).has(FLAGS.MANAGE_WEBHOOKS) ) {
 						return msg.replyMsg( lang.get('rcscript.noadmin') );
 						return msg.replyMsg( lang.get('rcscript.noadmin') );
 					}
 					}
 					db.query( 'DELETE FROM rcgcdw WHERE webhook = $1', [selected_row.webhook] ).then( () => {
 					db.query( 'DELETE FROM rcgcdw WHERE webhook = $1', [selected_row.webhook] ).then( () => {
@@ -216,38 +204,38 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 						webhook.send( webhook_lang.get('deleted') ).catch(log_error).finally( () => {
 						webhook.send( webhook_lang.get('deleted') ).catch(log_error).finally( () => {
 							webhook.delete(lang.get('rcscript.audit_reason_delete')).catch(log_error);
 							webhook.delete(lang.get('rcscript.audit_reason_delete')).catch(log_error);
 						} );
 						} );
-						msg.replyMsg( lang.get('rcscript.deleted'), {components}, true );
+						msg.replyMsg( {content: lang.get('rcscript.deleted'), components}, true );
 					}, dberror => {
 					}, dberror => {
 						console.log( '- Error while removing the RcGcDw: ' + dberror );
 						console.log( '- Error while removing the RcGcDw: ' + dberror );
-						button.url = new URL(`/guild/${msg.guild.id}/rcscript/${selected_row.configid}`, process.env.dashboard).href;
-						msg.replyMsg( lang.get('settings.save_failed'), {components}, true );
+						button?.setURL(new URL(`/guild/${msg.guildId}/rcscript/${selected_row.configid}`, button.url).href);
+						msg.replyMsg( {content: lang.get('settings.save_failed'), components}, true );
 					} );
 					} );
 				}, error => {
 				}, error => {
 					log_error(error);
 					log_error(error);
 					if ( error.name === 'DiscordAPIError' && ['Unknown Webhook', 'Invalid Webhook Token'].includes( error.message ) ) {
 					if ( error.name === 'DiscordAPIError' && ['Unknown Webhook', 'Invalid Webhook Token'].includes( error.message ) ) {
-						button.url = new URL(`/guild/${msg.guild.id}/rcscript/${selected_row.configid}`, process.env.dashboard).href;
-						return msg.replyMsg( lang.get('settings.save_failed'), {components}, true );
+						button?.setURL(new URL(`/guild/${msg.guildId}/rcscript/${selected_row.configid}`, button.url).href);
+						return msg.replyMsg( {content: lang.get('settings.save_failed'), components}, true );
 					}
 					}
 					db.query( 'DELETE FROM rcgcdw WHERE webhook = $1', [selected_row.webhook] ).then( () => {
 					db.query( 'DELETE FROM rcgcdw WHERE webhook = $1', [selected_row.webhook] ).then( () => {
 						console.log( '- RcGcDw successfully removed.' );
 						console.log( '- RcGcDw successfully removed.' );
-						msg.replyMsg( lang.get('rcscript.deleted'), {components}, true );
+						msg.replyMsg( {content: lang.get('rcscript.deleted'), components}, true );
 					}, dberror => {
 					}, dberror => {
 						console.log( '- Error while removing the RcGcDw: ' + dberror );
 						console.log( '- Error while removing the RcGcDw: ' + dberror );
-						button.url = new URL(`/guild/${msg.guild.id}/rcscript/${selected_row.configid}`, process.env.dashboard).href;
-						msg.replyMsg( lang.get('settings.save_failed'), {components}, true );
+						button?.setURL(new URL(`/guild/${msg.guildId}/rcscript/${selected_row.configid}`, button.url).href);
+						msg.replyMsg( {content: lang.get('settings.save_failed'), components}, true );
 					} );
 					} );
 				} );
 				} );
 			}
 			}
-			button.url = new URL(`/guild/${msg.guild.id}/rcscript/${selected_row.configid}`, process.env.dashboard).href;
+			button?.setURL(new URL(`/guild/${msg.guildId}/rcscript/${selected_row.configid}`, button.url).href);
 			if ( args[0] === 'wiki' ) {
 			if ( args[0] === 'wiki' ) {
 				if ( !args[1] ) {
 				if ( !args[1] ) {
-					return msg.replyMsg( lang.get('rcscript.current_wiki') + ' <' + selected_row.wiki + '>\n`' + cmd + ' wiki ' + lang.get('rcscript.new_wiki') + '`\n' + lang.get('rcscript.help_wiki'), {components}, true );
+					return msg.replyMsg( {content: lang.get('rcscript.current_wiki') + ' <' + selected_row.wiki + '>\n`' + cmd + ' wiki ' + lang.get('rcscript.new_wiki') + '`\n' + lang.get('rcscript.help_wiki'), components}, true );
 				}
 				}
-				if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+				if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 
 
 				var wikihelp = '\n`' + cmd + ' wiki ' + lang.get('rcscript.new_wiki') + '`\n' + lang.get('rcscript.help_wiki');
 				var wikihelp = '\n`' + cmd + ' wiki ' + lang.get('rcscript.new_wiki') + '`\n' + lang.get('rcscript.help_wiki');
 				var wikinew = Wiki.fromInput(args[1]);
 				var wikinew = Wiki.fromInput(args[1]);
-				if ( !wikinew ) return msg.replyMsg( lang.get('settings.wikiinvalid') + wikihelp, {components}, true );
+				if ( !wikinew ) return msg.replyMsg( {content: lang.get('settings.wikiinvalid') + wikihelp, components}, true );
 				return msg.reactEmoji('⏳', true).then( reaction => got.get( wikinew + 'api.php?&action=query&meta=allmessages|siteinfo&ammessages=custom-RcGcDw&amenableparser=true&siprop=general&titles=Special:RecentChanges&format=json', {
 				return msg.reactEmoji('⏳', true).then( reaction => got.get( wikinew + 'api.php?&action=query&meta=allmessages|siteinfo&ammessages=custom-RcGcDw&amenableparser=true&siprop=general&titles=Special:RecentChanges&format=json', {
 					responseType: 'text'
 					responseType: 'text'
 				} ).then( response => {
 				} ).then( response => {
@@ -270,26 +258,26 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 						console.log( '- ' + response.statusCode + ': Error while testing the wiki: ' + body?.error?.info );
 						console.log( '- ' + response.statusCode + ': Error while testing the wiki: ' + body?.error?.info );
 						if ( reaction ) reaction.removeEmoji();
 						if ( reaction ) reaction.removeEmoji();
 						if ( body?.error?.info === 'You need read permission to use this module.' ) {
 						if ( body?.error?.info === 'You need read permission to use this module.' ) {
-							return msg.replyMsg( lang.get('settings.wikiinvalid_private') + wikihelp, {components}, true );
+							return msg.replyMsg( {content: lang.get('settings.wikiinvalid_private') + wikihelp, components}, true );
 						}
 						}
 						msg.reactEmoji('nowiki', true);
 						msg.reactEmoji('nowiki', true);
-						return msg.replyMsg( lang.get('settings.wikiinvalid') + wikihelp, {components}, true );
+						return msg.replyMsg( {content: lang.get('settings.wikiinvalid') + wikihelp, components}, true );
 					}
 					}
 					wikinew.updateWiki(body.query.general);
 					wikinew.updateWiki(body.query.general);
 					if ( body.query.general.generator.replace( /^MediaWiki 1\.(\d\d).*$/, '$1' ) <= 30 ) {
 					if ( body.query.general.generator.replace( /^MediaWiki 1\.(\d\d).*$/, '$1' ) <= 30 ) {
 						console.log( '- This wiki is using ' + body.query.general.generator + '.' );
 						console.log( '- This wiki is using ' + body.query.general.generator + '.' );
 						if ( reaction ) reaction.removeEmoji();
 						if ( reaction ) reaction.removeEmoji();
-						return msg.replyMsg( lang.get('test.MediaWiki', 'MediaWiki 1.30', body.query.general.generator) + '\nhttps://www.mediawiki.org/wiki/MediaWiki_1.30', {components}, true );
+						return msg.replyMsg( {content: lang.get('test.MediaWiki', 'MediaWiki 1.30', body.query.general.generator) + '\nhttps://www.mediawiki.org/wiki/MediaWiki_1.30', components}, true );
 					}
 					}
-					if ( body.query.allmessages[0]['*'] !== msg.guild.id ) {
+					if ( body.query.allmessages[0]['*'] !== msg.guildId ) {
 						if ( reaction ) reaction.removeEmoji();
 						if ( reaction ) reaction.removeEmoji();
-						return msg.replyMsg( lang.get('rcscript.sysmessage', 'MediaWiki:Custom-RcGcDw', msg.guild.id) + '\n<' + wikinew.toLink('MediaWiki:Custom-RcGcDw', 'action=edit') + '>', {components}, true );
+						return msg.replyMsg( {content: lang.get('rcscript.sysmessage', 'MediaWiki:Custom-RcGcDw', msg.guildId) + '\n<' + wikinew.toLink('MediaWiki:Custom-RcGcDw', 'action=edit') + '>', components}, true );
 					}
 					}
 					return db.query( 'SELECT reason FROM blocklist WHERE wiki = $1', [wikinew.href] ).then( ({rows:[block]}) => {
 					return db.query( 'SELECT reason FROM blocklist WHERE wiki = $1', [wikinew.href] ).then( ({rows:[block]}) => {
 						if ( block ) {
 						if ( block ) {
 							console.log( '- This wiki is blocked: ' + block.reason );
 							console.log( '- This wiki is blocked: ' + block.reason );
 							if ( reaction ) reaction.removeEmoji();
 							if ( reaction ) reaction.removeEmoji();
-							return msg.replyMsg( ( block.reason ? lang.get('rcscript.blocked_reason', block.reason) : lang.get('rcscript.blocked') ), {components}, true );
+							return msg.replyMsg( {content: ( block.reason ? lang.get('rcscript.blocked_reason', block.reason) : lang.get('rcscript.blocked') ), components}, true );
 						}
 						}
 						if ( wikinew.isFandom(false) ) return got.get( wikinew + 'wikia.php?controller=DiscussionPost&method=getPosts&includeCounters=false&limit=1&format=json&cache=' + Date.now(), {
 						if ( wikinew.isFandom(false) ) return got.get( wikinew + 'wikia.php?controller=DiscussionPost&method=getPosts&includeCounters=false&limit=1&format=json&cache=' + Date.now(), {
 							headers: {
 							headers: {
@@ -319,11 +307,11 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 							db.query( 'UPDATE rcgcdw SET wiki = $1, rcid = $2, postid = $3 WHERE webhook = $4', [wikinew.href, null, ( enableFeeds ? null : '-1' ), selected_row.webhook] ).then( () => {
 							db.query( 'UPDATE rcgcdw SET wiki = $1, rcid = $2, postid = $3 WHERE webhook = $4', [wikinew.href, null, ( enableFeeds ? null : '-1' ), selected_row.webhook] ).then( () => {
 								console.log( '- RcGcDw successfully updated.' );
 								console.log( '- RcGcDw successfully updated.' );
 								if ( reaction ) reaction.removeEmoji();
 								if ( reaction ) reaction.removeEmoji();
-								msg.replyMsg( lang.get('rcscript.updated_wiki') + ' <' + wikinew + '>\n`' + cmd + '`', {components}, true );
+								msg.replyMsg( {content: lang.get('rcscript.updated_wiki') + ' <' + wikinew + '>\n`' + cmd + '`', components}, true );
 							}, dberror => {
 							}, dberror => {
 								console.log( '- Error while updating the RcGcDw: ' + dberror );
 								console.log( '- Error while updating the RcGcDw: ' + dberror );
 								if ( reaction ) reaction.removeEmoji();
 								if ( reaction ) reaction.removeEmoji();
-								msg.replyMsg( lang.get('settings.save_failed'), {components}, true );
+								msg.replyMsg( {content: lang.get('settings.save_failed'), components}, true );
 							} );
 							} );
 						}
 						}
 					}, dberror => {
 					}, dberror => {
@@ -335,43 +323,43 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 					if ( reaction ) reaction.removeEmoji();
 					if ( reaction ) reaction.removeEmoji();
 					if ( error.message?.startsWith( 'connect ECONNREFUSED ' ) || error.message?.startsWith( 'Hostname/IP does not match certificate\'s altnames: ' ) || error.message === 'certificate has expired' || error.message === 'self signed certificate' ) {
 					if ( error.message?.startsWith( 'connect ECONNREFUSED ' ) || error.message?.startsWith( 'Hostname/IP does not match certificate\'s altnames: ' ) || error.message === 'certificate has expired' || error.message === 'self signed certificate' ) {
 						console.log( '- Error while testing the wiki: No HTTPS' );
 						console.log( '- Error while testing the wiki: No HTTPS' );
-						return msg.replyMsg( lang.get('settings.wikiinvalid_http') + wikihelp, {components}, true );
+						return msg.replyMsg( {content: lang.get('settings.wikiinvalid_http') + wikihelp, components}, true );
 					}
 					}
 					console.log( '- Error while testing the wiki: ' + error );
 					console.log( '- Error while testing the wiki: ' + error );
 					if ( error.message === `Timeout awaiting 'request' for ${got.defaults.options.timeout.request}ms` ) {
 					if ( error.message === `Timeout awaiting 'request' for ${got.defaults.options.timeout.request}ms` ) {
-						return msg.replyMsg( lang.get('settings.wikiinvalid_timeout') + wikihelp, {components}, true );
+						return msg.replyMsg( {content: lang.get('settings.wikiinvalid_timeout') + wikihelp, components}, true );
 					}
 					}
 					msg.reactEmoji('nowiki', true);
 					msg.reactEmoji('nowiki', true);
-					return msg.replyMsg( lang.get('settings.wikiinvalid') + wikihelp, {components}, true );
+					return msg.replyMsg( {content: lang.get('settings.wikiinvalid') + wikihelp, components}, true );
 				} ) );
 				} ) );
 			}
 			}
 			if ( args[0] === 'lang' || args[0] === 'language' ) {
 			if ( args[0] === 'lang' || args[0] === 'language' ) {
 				if ( !args[1] ) {
 				if ( !args[1] ) {
-					return msg.replyMsg( lang.get('rcscript.current_lang') + ' `' + allLangs.names[selected_row.lang] + '`\n`' + cmd + ' lang ' + lang.get('rcscript.new_lang') + '`\n' + lang.get('rcscript.help_lang') + ' `' + Object.values(allLangs.names).join('`, `') + '`', {files:( msg.uploadFiles() ? [`./RcGcDb/locale/widgets/${selected_row.lang}.png`] : [] ),components}, true );
+					return msg.replyMsg( {content: lang.get('rcscript.current_lang') + ' `' + allLangs.names[selected_row.lang] + '`\n`' + cmd + ' lang ' + lang.get('rcscript.new_lang') + '`\n' + lang.get('rcscript.help_lang') + ' `' + Object.values(allLangs.names).join('`, `') + '`', files: ( msg.uploadFiles() ? [`./RcGcDb/locale/widgets/${selected_row.lang}.png`] : [] ), components}, true );
 				}
 				}
-				if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+				if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 				if ( !allLangs.map.hasOwnProperty(args[1]) ) {
 				if ( !allLangs.map.hasOwnProperty(args[1]) ) {
-					return msg.replyMsg( lang.get('settings.langinvalid') + '\n`' + cmd + ' lang ' + lang.get('rcscript.new_lang') + '`\n' + lang.get('rcscript.help_lang') + ' `' + Object.values(allLangs.names).join('`, `') + '`', {components}, true );
+					return msg.replyMsg( {content: lang.get('settings.langinvalid') + '\n`' + cmd + ' lang ' + lang.get('rcscript.new_lang') + '`\n' + lang.get('rcscript.help_lang') + ' `' + Object.values(allLangs.names).join('`, `') + '`', components}, true );
 				}
 				}
 
 
 				msg.client.fetchWebhook(...selected_row.webhook.split('/')).then( webhook => {
 				msg.client.fetchWebhook(...selected_row.webhook.split('/')).then( webhook => {
-					webhook.send( new Lang(allLangs.map[args[1]], 'rcscript.webhook').get('updated_lang', allLangs.names[allLangs.map[args[1]]]), {files:[`./RcGcDb/locale/widgets/${allLangs.map[args[1]]}.png`]} ).catch(log_error);
+					webhook.send( {content: new Lang(allLangs.map[args[1]], 'rcscript.webhook').get('updated_lang', allLangs.names[allLangs.map[args[1]]]), files: [`./RcGcDb/locale/widgets/${allLangs.map[args[1]]}.png`]} ).catch(log_error);
 				}, log_error );
 				}, log_error );
 				return db.query( 'UPDATE rcgcdw SET lang = $1 WHERE webhook = $2', [allLangs.map[args[1]], selected_row.webhook] ).then( () => {
 				return db.query( 'UPDATE rcgcdw SET lang = $1 WHERE webhook = $2', [allLangs.map[args[1]], selected_row.webhook] ).then( () => {
 					console.log( '- RcGcDw successfully updated.' );
 					console.log( '- RcGcDw successfully updated.' );
-					msg.replyMsg( lang.get('rcscript.updated_lang') + ' `' + allLangs.names[allLangs.map[args[1]]] + '`\n`' + cmd + '`', {files:( msg.uploadFiles() ? [`./RcGcDb/locale/widgets/${allLangs.map[args[1]]}.png`] : [] ),components}, true );
+					msg.replyMsg( {content: lang.get('rcscript.updated_lang') + ' `' + allLangs.names[allLangs.map[args[1]]] + '`\n`' + cmd + '`', files: ( msg.uploadFiles() ? [`./RcGcDb/locale/widgets/${allLangs.map[args[1]]}.png`] : [] ), components}, true );
 				}, dberror => {
 				}, dberror => {
 					console.log( '- Error while updating the RcGcDw: ' + dberror );
 					console.log( '- Error while updating the RcGcDw: ' + dberror );
-					msg.replyMsg( lang.get('settings.save_failed'), {components}, true );
+					msg.replyMsg( {content: lang.get('settings.save_failed'), components}, true );
 				} );
 				} );
 			}
 			}
 			if ( args[0] === 'display' ) {
 			if ( args[0] === 'display' ) {
 				if ( !args[1] || !display_types.includes( args[1] ) ) {
 				if ( !args[1] || !display_types.includes( args[1] ) ) {
-					return msg.replyMsg( lang.get('rcscript.current_display') + ' `' + display_types[selected_row.display] + '`\n`' + cmd + ' display (' + display.join('|') + ')`\n' + display.map( display_type => '`' + display_type + '`: ' + lang.get('rcscript.help_display_' + display_type) ).join('\n'), {components}, true );
+					return msg.replyMsg( {content: lang.get('rcscript.current_display') + ' `' + display_types[selected_row.display] + '`\n`' + cmd + ' display (' + display.join('|') + ')`\n' + display.map( display_type => '`' + display_type + '`: ' + lang.get('rcscript.help_display_' + display_type) ).join('\n'), components}, true );
 				}
 				}
-				if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+				if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 				if ( !display.includes( args[1] ) ) {
 				if ( !display.includes( args[1] ) ) {
-					return msg.replyMsg( lang.get('general.patreon') + '\n<' + process.env.patreon + '>', {}, true );
+					return msg.replyMsg( lang.get('general.patreon') + '\n<' + process.env.patreon + '>', true );
 				}
 				}
 
 
 				msg.client.fetchWebhook(...selected_row.webhook.split('/')).then( webhook => {
 				msg.client.fetchWebhook(...selected_row.webhook.split('/')).then( webhook => {
@@ -379,14 +367,14 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 				}, log_error );
 				}, log_error );
 				return db.query( 'UPDATE rcgcdw SET display = $1 WHERE webhook = $2', [display_types.indexOf(args[1]), selected_row.webhook] ).then( () => {
 				return db.query( 'UPDATE rcgcdw SET display = $1 WHERE webhook = $2', [display_types.indexOf(args[1]), selected_row.webhook] ).then( () => {
 					console.log( '- RcGcDw successfully updated.' );
 					console.log( '- RcGcDw successfully updated.' );
-					msg.replyMsg( lang.get('rcscript.updated_display') + ' `' + args[1] + '`\n`' + cmd + '`', {components}, true );
+					msg.replyMsg( {content: lang.get('rcscript.updated_display') + ' `' + args[1] + '`\n`' + cmd + '`', components}, true );
 				}, dberror => {
 				}, dberror => {
 					console.log( '- Error while updating the RcGcDw: ' + dberror );
 					console.log( '- Error while updating the RcGcDw: ' + dberror );
-					msg.replyMsg( lang.get('settings.save_failed'), {components}, true );
+					msg.replyMsg( {content: lang.get('settings.save_failed'), components}, true );
 				} );
 				} );
 			}
 			}
 			if ( new Wiki(selected_row.wiki).isFandom(false) && args[0] === 'feeds' ) {
 			if ( new Wiki(selected_row.wiki).isFandom(false) && args[0] === 'feeds' ) {
-				if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+				if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 				if ( args[1] === 'only' ) {
 				if ( args[1] === 'only' ) {
 					if ( selected_row.rcid === -1 ) {
 					if ( selected_row.rcid === -1 ) {
 						msg.client.fetchWebhook(...selected_row.webhook.split('/')).then( webhook => {
 						msg.client.fetchWebhook(...selected_row.webhook.split('/')).then( webhook => {
@@ -394,41 +382,41 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 						}, log_error );
 						}, log_error );
 						return db.query( 'UPDATE rcgcdw SET rcid = $1 WHERE webhook = $2', [null, selected_row.webhook] ).then( () => {
 						return db.query( 'UPDATE rcgcdw SET rcid = $1 WHERE webhook = $2', [null, selected_row.webhook] ).then( () => {
 							console.log( '- RcGcDw successfully updated.' );
 							console.log( '- RcGcDw successfully updated.' );
-							msg.replyMsg( lang.get('rcscript.enabled_rc') + '\n`' + cmd + '`', {components}, true );
+							msg.replyMsg( {content: lang.get('rcscript.enabled_rc') + '\n`' + cmd + '`', components}, true );
 						}, dberror => {
 						}, dberror => {
 							console.log( '- Error while updating the RcGcDw: ' + dberror );
 							console.log( '- Error while updating the RcGcDw: ' + dberror );
-							msg.replyMsg( lang.get('settings.save_failed'), {components}, true );
+							msg.replyMsg( {content: lang.get('settings.save_failed'), components}, true );
 						} );
 						} );
 					}
 					}
 
 
 					if ( selected_row.postid === '-1' ) {
 					if ( selected_row.postid === '-1' ) {
-						return msg.replyMsg( lang.get('rcscript.all_inactive') + '\n\n' + lang.get('rcscript.delete') + '\n`' + cmd + ' delete`', {components}, true );
+						return msg.replyMsg( {content: lang.get('rcscript.all_inactive') + '\n\n' + lang.get('rcscript.delete') + '\n`' + cmd + ' delete`', components}, true );
 					}
 					}
 					msg.client.fetchWebhook(...selected_row.webhook.split('/')).then( webhook => {
 					msg.client.fetchWebhook(...selected_row.webhook.split('/')).then( webhook => {
 						webhook.send( webhook_lang.get('disabled_rc') ).catch(log_error);
 						webhook.send( webhook_lang.get('disabled_rc') ).catch(log_error);
 					}, log_error );
 					}, log_error );
 					return db.query( 'UPDATE rcgcdw SET rcid = $1 WHERE webhook = $2', [-1, selected_row.webhook] ).then( () => {
 					return db.query( 'UPDATE rcgcdw SET rcid = $1 WHERE webhook = $2', [-1, selected_row.webhook] ).then( () => {
 						console.log( '- RcGcDw successfully updated.' );
 						console.log( '- RcGcDw successfully updated.' );
-						msg.replyMsg( lang.get('rcscript.disabled_rc') + '\n`' + cmd + '`', {components}, true );
+						msg.replyMsg( {content: lang.get('rcscript.disabled_rc') + '\n`' + cmd + '`', components}, true );
 					}, dberror => {
 					}, dberror => {
 						console.log( '- Error while updating the RcGcDw: ' + dberror );
 						console.log( '- Error while updating the RcGcDw: ' + dberror );
-						msg.replyMsg( lang.get('settings.save_failed'), {components}, true );
+						msg.replyMsg( {content: lang.get('settings.save_failed'), components}, true );
 					} );
 					} );
 				}
 				}
 
 
 				if ( selected_row.postid !== '-1' ) {
 				if ( selected_row.postid !== '-1' ) {
 					if ( selected_row.rcid === -1 ) {
 					if ( selected_row.rcid === -1 ) {
-						return msg.replyMsg( lang.get('rcscript.all_inactive') + '\n\n' + lang.get('rcscript.delete') + '\n`' + cmd + ' delete`', {components}, true );
+						return msg.replyMsg( {content: lang.get('rcscript.all_inactive') + '\n\n' + lang.get('rcscript.delete') + '\n`' + cmd + ' delete`', components}, true );
 					}
 					}
 					msg.client.fetchWebhook(...selected_row.webhook.split('/')).then( webhook => {
 					msg.client.fetchWebhook(...selected_row.webhook.split('/')).then( webhook => {
 						webhook.send( webhook_lang.get('disabled_feeds') ).catch(log_error);
 						webhook.send( webhook_lang.get('disabled_feeds') ).catch(log_error);
 					}, log_error );
 					}, log_error );
 					return db.query( 'UPDATE rcgcdw SET postid = $1 WHERE webhook = $2', ['-1', selected_row.webhook] ).then( () => {
 					return db.query( 'UPDATE rcgcdw SET postid = $1 WHERE webhook = $2', ['-1', selected_row.webhook] ).then( () => {
 						console.log( '- RcGcDw successfully updated.' );
 						console.log( '- RcGcDw successfully updated.' );
-						msg.replyMsg( lang.get('rcscript.disabled_feeds') + '\n`' + cmd + '`', {components}, true );
+						msg.replyMsg( {content: lang.get('rcscript.disabled_feeds') + '\n`' + cmd + '`', components}, true );
 					}, dberror => {
 					}, dberror => {
 						console.log( '- Error while updating the RcGcDw: ' + dberror );
 						console.log( '- Error while updating the RcGcDw: ' + dberror );
-						msg.replyMsg( lang.get('settings.save_failed'), {components}, true );
+						msg.replyMsg( {content: lang.get('settings.save_failed'), components}, true );
 					} );
 					} );
 				}
 				}
 
 
@@ -441,7 +429,7 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 					if ( dsresponse.statusCode !== 200 || !dsbody || dsbody.status === 404 ) {
 					if ( dsresponse.statusCode !== 200 || !dsbody || dsbody.status === 404 ) {
 						if ( dsbody?.status !== 404 ) console.log( '- ' + dsresponse.statusCode + ': Error while checking for discussions: ' + dsbody?.title );
 						if ( dsbody?.status !== 404 ) console.log( '- ' + dsresponse.statusCode + ': Error while checking for discussions: ' + dsbody?.title );
 						if ( reaction ) reaction.removeEmoji();
 						if ( reaction ) reaction.removeEmoji();
-						return msg.replyMsg( lang.get('rcscript.no_feeds'), {components}, true );
+						return msg.replyMsg( {content: lang.get('rcscript.no_feeds'), components}, true );
 					}
 					}
 					msg.client.fetchWebhook(...selected_row.webhook.split('/')).then( webhook => {
 					msg.client.fetchWebhook(...selected_row.webhook.split('/')).then( webhook => {
 						webhook.send( webhook_lang.get('enabled_feeds') + '\n<' + selected_row.wiki + 'f>' ).catch(log_error);
 						webhook.send( webhook_lang.get('enabled_feeds') + '\n<' + selected_row.wiki + 'f>' ).catch(log_error);
@@ -449,21 +437,21 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 					db.query( 'UPDATE rcgcdw SET postid = $1 WHERE webhook = $2', [null, selected_row.webhook] ).then( () => {
 					db.query( 'UPDATE rcgcdw SET postid = $1 WHERE webhook = $2', [null, selected_row.webhook] ).then( () => {
 						console.log( '- RcGcDw successfully updated.' );
 						console.log( '- RcGcDw successfully updated.' );
 						if ( reaction ) reaction.removeEmoji();
 						if ( reaction ) reaction.removeEmoji();
-						msg.replyMsg( lang.get('rcscript.enabled_feeds') + '\n`' + cmd + '`', {components}, true );
+						msg.replyMsg( {content: lang.get('rcscript.enabled_feeds') + '\n`' + cmd + '`', components}, true );
 					}, dberror => {
 					}, dberror => {
 						console.log( '- Error while updating the RcGcDw: ' + dberror );
 						console.log( '- Error while updating the RcGcDw: ' + dberror );
 						if ( reaction ) reaction.removeEmoji();
 						if ( reaction ) reaction.removeEmoji();
-						msg.replyMsg( lang.get('settings.save_failed'), {components}, true );
+						msg.replyMsg( {content: lang.get('settings.save_failed'), components}, true );
 					} );
 					} );
 				}, error => {
 				}, error => {
 					console.log( '- Error while checking for discussions: ' + error );
 					console.log( '- Error while checking for discussions: ' + error );
 					if ( reaction ) reaction.removeEmoji();
 					if ( reaction ) reaction.removeEmoji();
-					return msg.replyMsg( lang.get('rcscript.no_feeds'), {components}, true );
+					return msg.replyMsg( {content: lang.get('rcscript.no_feeds'), components}, true );
 				} ) );
 				} ) );
 			}
 			}
 
 
 			if ( rows.length > 1 ) return msg.client.fetchWebhook(...selected_row.webhook.split('/')).then( webhook => {
 			if ( rows.length > 1 ) return msg.client.fetchWebhook(...selected_row.webhook.split('/')).then( webhook => {
-				return webhook.channelID;
+				return webhook.channelId;
 			}, error => {
 			}, error => {
 				log_error(error);
 				log_error(error);
 				if ( error.name === 'DiscordAPIError' && ['Unknown Webhook', 'Invalid Webhook Token'].includes( error.message ) ) {
 				if ( error.name === 'DiscordAPIError' && ['Unknown Webhook', 'Invalid Webhook Token'].includes( error.message ) ) {
@@ -477,7 +465,7 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 				return;
 				return;
 			} ).then( channel => {
 			} ).then( channel => {
 				var text = lang.get('rcscript.current_selected', selected_row.configid);
 				var text = lang.get('rcscript.current_selected', selected_row.configid);
-				if ( process.env.dashboard ) text += `\n<${button.url}>\n`;
+				if ( button ) text += `\n<${button.url}>\n`;
 				text += '\n' + lang.get('rcscript.channel') + ' <#' + channel + '>\n';
 				text += '\n' + lang.get('rcscript.channel') + ' <#' + channel + '>\n';
 				text += '\n' + lang.get('rcscript.wiki') + ' <' + selected_row.wiki + '>';
 				text += '\n' + lang.get('rcscript.wiki') + ' <' + selected_row.wiki + '>';
 				text += '\n`' + cmd + ' wiki ' + lang.get('rcscript.new_wiki') + '`\n';
 				text += '\n`' + cmd + ' wiki ' + lang.get('rcscript.new_wiki') + '`\n';
@@ -494,12 +482,12 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 					text += '\n' + lang.get('rcscript.help_feeds') + '\n`' + cmd + ' feeds` ' + lang.get('rcscript.toggle') + '\n';
 					text += '\n' + lang.get('rcscript.help_feeds') + '\n`' + cmd + ' feeds` ' + lang.get('rcscript.toggle') + '\n';
 				}
 				}
 				text += '\n' + lang.get('rcscript.delete') + '\n`' + cmd + ' delete`\n';
 				text += '\n' + lang.get('rcscript.delete') + '\n`' + cmd + ' delete`\n';
-				msg.replyMsg( text, {components}, true );
-			}, () => msg.replyMsg( lang.get('rcscript.deleted'), {components}, true ) );
+				msg.replyMsg( {content: text, components}, true );
+			}, () => msg.replyMsg( {content: lang.get('rcscript.deleted'), components}, true ) );
 		}
 		}
 
 
 		Promise.all(rows.map( row => msg.client.fetchWebhook(...row.webhook.split('/')).then( webhook => {
 		Promise.all(rows.map( row => msg.client.fetchWebhook(...row.webhook.split('/')).then( webhook => {
-			return webhook.channelID;
+			return webhook.channelId;
 		}, error => {
 		}, error => {
 			log_error(error);
 			log_error(error);
 			if ( error.name === 'DiscordAPIError' && ['Unknown Webhook', 'Invalid Webhook Token'].includes( error.message ) ) {
 			if ( error.name === 'DiscordAPIError' && ['Unknown Webhook', 'Invalid Webhook Token'].includes( error.message ) ) {
@@ -520,7 +508,7 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 			var text = '';
 			var text = '';
 			if ( rows.length ) {
 			if ( rows.length ) {
 				text += lang.get('rcscript.current');
 				text += lang.get('rcscript.current');
-				if ( process.env.dashboard ) text += `\n<${button.url}>`;
+				if ( button ) text += `\n<${button.url}>`;
 				text += rows.map( row => {
 				text += rows.map( row => {
 					var cmd = prefix + 'rcscript' + ( only ? '' : ' ' + row.configid );
 					var cmd = prefix + 'rcscript' + ( only ? '' : ' ' + row.configid );
 					var row_text = '\n';
 					var row_text = '\n';
@@ -547,10 +535,10 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
 			}
 			}
 			else {
 			else {
 				text += lang.get('rcscript.missing');
 				text += lang.get('rcscript.missing');
-				if ( process.env.dashboard ) text += `\n<${button.url}>`;
+				if ( button ) text += `\n<${button.url}>`;
 			}
 			}
 			if ( rows.length < limit ) text += '\n\n' + lang.get('rcscript.add_more') + '\n`' + prefix + 'rcscript add ' + lang.get('rcscript.new_wiki') + '`';
 			if ( rows.length < limit ) text += '\n\n' + lang.get('rcscript.add_more') + '\n`' + prefix + 'rcscript add ' + lang.get('rcscript.new_wiki') + '`';
-			msg.replyMsg( text, {split:true,components}, true );
+			Util.splitMessage( text ).forEach( textpart => msg.replyMsg( {content: textpart, components}, true ) );
 		} );
 		} );
 	}, dberror => {
 	}, dberror => {
 		console.log( '- Error while getting the RcGcDw: ' + dberror );
 		console.log( '- Error while getting the RcGcDw: ' + dberror );
@@ -564,19 +552,19 @@ function cmd_rcscript(lang, msg, args, line, wiki) {
  * @param {String[]} args - The command arguments.
  * @param {String[]} args - The command arguments.
  */
  */
 function blocklist(msg, args) {
 function blocklist(msg, args) {
-	var prefix = ( patreons[msg?.guild?.id] || process.env.prefix );
+	var prefix = ( patreons[msg?.guildId] || process.env.prefix );
 	if ( args[0] === 'add' ) {
 	if ( args[0] === 'add' ) {
-		if ( !args[1] ) return msg.replyMsg( '`' + prefix + 'rcscript block add <wiki> [<reason>]`', {}, true );
-		if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+		if ( !args[1] ) return msg.replyMsg( '`' + prefix + 'rcscript block add <wiki> [<reason>]`', true );
+		if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 		let input = args[1].toLowerCase().replace( /^<(.*?)>$/, '$1' );
 		let input = args[1].toLowerCase().replace( /^<(.*?)>$/, '$1' );
 		let wiki = Wiki.fromInput(input);
 		let wiki = Wiki.fromInput(input);
-		if ( !wiki ) return msg.replyMsg( '`' + prefix + 'rcscript block add <wiki> [<reason>]`', {}, true );
+		if ( !wiki ) return msg.replyMsg( '`' + prefix + 'rcscript block add <wiki> [<reason>]`', true );
 		let reason = ( args.slice(2).join(' ').trim() || null );
 		let reason = ( args.slice(2).join(' ').trim() || null );
 		return db.query( 'INSERT INTO blocklist(wiki, reason) VALUES($1, $2)', [wiki.href, reason] ).then( () => {
 		return db.query( 'INSERT INTO blocklist(wiki, reason) VALUES($1, $2)', [wiki.href, reason] ).then( () => {
 			console.log( '- Successfully added to the blocklist.' );
 			console.log( '- Successfully added to the blocklist.' );
 			db.query( 'DELETE FROM rcgcdw WHERE wiki = $1 RETURNING webhook, lang', [wiki.href] ).then( ({rows}) => {
 			db.query( 'DELETE FROM rcgcdw WHERE wiki = $1 RETURNING webhook, lang', [wiki.href] ).then( ({rows}) => {
 				console.log( '- Successfully removed ' + rows.length + ' webhooks.' );
 				console.log( '- Successfully removed ' + rows.length + ' webhooks.' );
-				msg.replyMsg( 'I added `' + wiki + '` to the blocklist for `' + reason + '` and removed ' + rows.length + ' webhooks.', {}, true );
+				msg.replyMsg( 'I added `' + wiki + '` to the blocklist for `' + reason + '` and removed ' + rows.length + ' webhooks.', true );
 				if ( rows.length ) rows.forEach( row => {
 				if ( rows.length ) rows.forEach( row => {
 					msg.client.fetchWebhook(...row.webhook.split('/')).then( webhook => {
 					msg.client.fetchWebhook(...row.webhook.split('/')).then( webhook => {
 						var lang = new Lang(row.lang, 'rcscript.webhook');
 						var lang = new Lang(row.lang, 'rcscript.webhook');
@@ -587,50 +575,50 @@ function blocklist(msg, args) {
 				} );
 				} );
 			}, dberror => {
 			}, dberror => {
 				console.log( '- Error while removing the webhooks: ' + dberror );
 				console.log( '- Error while removing the webhooks: ' + dberror );
-				msg.replyMsg( 'I added `' + wiki + '` to the blocklist for `' + reason + '` but got an error while removing the webhooks: ' + dberror, {}, true );
+				msg.replyMsg( 'I added `' + wiki + '` to the blocklist for `' + reason + '` but got an error while removing the webhooks: ' + dberror, true );
 			} );
 			} );
 		}, dberror => {
 		}, dberror => {
 			if ( dberror.message === 'duplicate key value violates unique constraint "blocklist_wiki_key"' ) {
 			if ( dberror.message === 'duplicate key value violates unique constraint "blocklist_wiki_key"' ) {
-				return msg.replyMsg( '`' + wiki + '` is already on the blocklist.\n`' + prefix + 'rcscript block <' + wiki + '>`', {}, true );
+				return msg.replyMsg( '`' + wiki + '` is already on the blocklist.\n`' + prefix + 'rcscript block <' + wiki + '>`', true );
 			}
 			}
 			console.log( '- Error while adding to the blocklist: ' + dberror );
 			console.log( '- Error while adding to the blocklist: ' + dberror );
-			msg.replyMsg( 'I got an error while adding to the blocklist: ' + dberror, {}, true );
+			msg.replyMsg( 'I got an error while adding to the blocklist: ' + dberror, true );
 		} );
 		} );
 	}
 	}
 	if ( args[0] === 'remove' ) {
 	if ( args[0] === 'remove' ) {
 		let input = args.slice(1).join(' ').toLowerCase().trim().replace( /^<\s*(.*?)\s*>$/, '$1' );
 		let input = args.slice(1).join(' ').toLowerCase().trim().replace( /^<\s*(.*?)\s*>$/, '$1' );
 		let wiki = Wiki.fromInput(input);
 		let wiki = Wiki.fromInput(input);
-		if ( !wiki ) return msg.replyMsg( '`' + prefix + 'rcscript block remove <wiki>`', {}, true );
-		if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+		if ( !wiki ) return msg.replyMsg( '`' + prefix + 'rcscript block remove <wiki>`', true );
+		if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 		return db.query( 'DELETE FROM blocklist WHERE wiki = $1', [wiki.href] ).then( ({rowCount}) => {
 		return db.query( 'DELETE FROM blocklist WHERE wiki = $1', [wiki.href] ).then( ({rowCount}) => {
 			if ( rowCount ) {
 			if ( rowCount ) {
 				console.log( '- Successfully removed from the blocklist.' );
 				console.log( '- Successfully removed from the blocklist.' );
-				msg.replyMsg( 'I removed `' + wiki + '` from the blocklist.', {}, true );
+				msg.replyMsg( 'I removed `' + wiki + '` from the blocklist.', true );
 			}
 			}
-			else msg.replyMsg( '`' + wiki + '` was not on the blocklist.', {}, true );
+			else msg.replyMsg( '`' + wiki + '` was not on the blocklist.', true );
 		}, dberror => {
 		}, dberror => {
 			console.log( '- Error while removing from the blocklist: ' + dberror );
 			console.log( '- Error while removing from the blocklist: ' + dberror );
-			msg.replyMsg( 'I got an error while removing from the blocklist: ' + dberror, {}, true );
+			msg.replyMsg( 'I got an error while removing from the blocklist: ' + dberror, true );
 		} );
 		} );
 	}
 	}
 	if ( args.length ) {
 	if ( args.length ) {
 		let input = args.join(' ').toLowerCase().trim().replace( /^<\s*(.*?)\s*>$/, '$1' );
 		let input = args.join(' ').toLowerCase().trim().replace( /^<\s*(.*?)\s*>$/, '$1' );
 		let wiki = Wiki.fromInput(input);
 		let wiki = Wiki.fromInput(input);
-		if ( !wiki ) return msg.replyMsg( '`' + prefix + 'rcscript block <wiki>`\n`' + prefix + 'rcscript block add <wiki> [<reason>]`\n`' + prefix + 'rcscript block remove <wiki>`', {}, true );
+		if ( !wiki ) return msg.replyMsg( '`' + prefix + 'rcscript block <wiki>`\n`' + prefix + 'rcscript block add <wiki> [<reason>]`\n`' + prefix + 'rcscript block remove <wiki>`', true );
 		return db.query( 'SELECT reason FROM blocklist WHERE wiki = $1', [wiki.href] ).then( ({rows:[row]}) => {
 		return db.query( 'SELECT reason FROM blocklist WHERE wiki = $1', [wiki.href] ).then( ({rows:[row]}) => {
-			if ( !row ) return msg.replyMsg( '`' + wiki + '` is currently not on the blocklist.\n`' + prefix + 'rcscript block add <' + wiki + '> [<reason>]`', {}, true );
-			msg.replyMsg( '`' + wiki + '` is currently on the blocklist ' + ( row.reason ? 'for `' + row.reason + '`' : 'with no reason provided' ) + '.\n`' + prefix + 'rcscript block remove <' + wiki + '>`', {}, true );
+			if ( !row ) return msg.replyMsg( '`' + wiki + '` is currently not on the blocklist.\n`' + prefix + 'rcscript block add <' + wiki + '> [<reason>]`', true );
+			msg.replyMsg( '`' + wiki + '` is currently on the blocklist ' + ( row.reason ? 'for `' + row.reason + '`' : 'with no reason provided' ) + '.\n`' + prefix + 'rcscript block remove <' + wiki + '>`', true );
 		}, dberror => {
 		}, dberror => {
 			console.log( '- Error while checking the blocklist: ' + dberror );
 			console.log( '- Error while checking the blocklist: ' + dberror );
-			msg.replyMsg( 'I got an error while checking the blocklist: ' + dberror, {}, true );
+			msg.replyMsg( 'I got an error while checking the blocklist: ' + dberror, true );
 		} );
 		} );
 	}
 	}
 	db.query( 'SELECT wiki, reason FROM blocklist' ).then( ({rows}) => {
 	db.query( 'SELECT wiki, reason FROM blocklist' ).then( ({rows}) => {
-		if ( !rows.length ) return msg.replyMsg( 'there are currently no wikis on the blocklist.\n`' + prefix + 'rcscript block add <wiki> [<reason>]`', {}, true );
-		msg.replyMsg( 'there are currently ' + row.length + ' wikis the blocklist:\n' + rows.map( row => '`' + row.wiki + '` – ' + ( row.reason ? '`' + row.reason + '`' : 'No reason provided.' ) ).join('\n') + '\n`' + prefix + 'rcscript block remove <wiki>`', {split:true}, true );
+		if ( !rows.length ) return msg.replyMsg( 'There are currently no wikis on the blocklist.\n`' + prefix + 'rcscript block add <wiki> [<reason>]`', true );
+		Util.splitMessage( 'There are currently ' + row.length + ' wikis the blocklist:\n' + rows.map( row => '`' + row.wiki + '` – ' + ( row.reason ? '`' + row.reason + '`' : 'No reason provided.' ) ).join('\n') + '\n`' + prefix + 'rcscript block remove <wiki>`' ).forEach( textpart => msg.replyMsg( textpart, true ) );
 	}, dberror => {
 	}, dberror => {
 		console.log( '- Error while checking the blocklist: ' + dberror );
 		console.log( '- Error while checking the blocklist: ' + dberror );
-		msg.replyMsg( 'I got an error while checking the blocklist: ' + dberror, {}, true );
+		msg.replyMsg( 'I got an error while checking the blocklist: ' + dberror, true );
 	} );
 	} );
 }
 }
 
 

+ 5 - 3
cmds/say.js

@@ -1,3 +1,5 @@
+const {Permissions: {FLAGS}} = require('discord.js');
+
 /**
 /**
  * Processes the "say" command.
  * Processes the "say" command.
  * @param {import('../util/i18n.js')} lang - The user language.
  * @param {import('../util/i18n.js')} lang - The user language.
@@ -21,13 +23,13 @@ function cmd_say(lang, msg, args, line, wiki) {
 	}
 	}
 	if ( text.trim() || imgs.length ) {
 	if ( text.trim() || imgs.length ) {
 		var allowedMentions = {parse:['users']};
 		var allowedMentions = {parse:['users']};
-		if ( msg.member.hasPermission(['MENTION_EVERYONE']) ) allowedMentions.parse = ['users','roles','everyone'];
+		if ( msg.member.permissions.has(FLAGS.MENTION_EVERYONE) ) allowedMentions.parse = ['users','roles','everyone'];
 		else allowedMentions.roles = msg.guild.roles.cache.filter( role => role.mentionable ).map( role => role.id ).slice(0,100)
 		else allowedMentions.roles = msg.guild.roles.cache.filter( role => role.mentionable ).map( role => role.id ).slice(0,100)
-		msg.channel.send( text, {allowedMentions,files:imgs} ).then( () => msg.delete().catch(log_error), error => {
+		msg.channel.send( {content: text, allowedMentions, files: imgs} ).then( () => msg.delete().catch(log_error), error => {
 			log_error(error);
 			log_error(error);
 			msg.reactEmoji('error', true);
 			msg.reactEmoji('error', true);
 		} );
 		} );
-	} else if ( !pause[msg.guild.id] ) this.LINK(lang, msg, line, wiki);
+	} else if ( !pause[msg.guildId] ) this.LINK(lang, msg, line, wiki);
 }
 }
 
 
 module.exports = {
 module.exports = {

+ 79 - 89
cmds/settings.js

@@ -1,5 +1,5 @@
 const cheerio = require('cheerio');
 const cheerio = require('cheerio');
-const {MessageEmbed} = require('discord.js');
+const {MessageEmbed, Util, MessageActionRow, MessageButton} = require('discord.js');
 const {defaultSettings} = require('../util/default.json');
 const {defaultSettings} = require('../util/default.json');
 const {got} = require('../util/functions.js');
 const {got} = require('../util/functions.js');
 const Lang = require('../util/i18n.js');
 const Lang = require('../util/i18n.js');
@@ -18,7 +18,7 @@ var db = require('../util/database.js');
 function cmd_settings(lang, msg, args, line, wiki) {
 function cmd_settings(lang, msg, args, line, wiki) {
 	if ( !msg.isAdmin() ) return msg.reactEmoji('❌');
 	if ( !msg.isAdmin() ) return msg.reactEmoji('❌');
 	
 	
-	db.query( 'SELECT channel, wiki, lang, role, inline, prefix FROM discord WHERE guild = $1 ORDER BY channel DESC NULLS LAST', [msg.guild.id] ).then( ({rows}) => {
+	db.query( 'SELECT channel, wiki, lang, role, inline, prefix FROM discord WHERE guild = $1 ORDER BY channel DESC NULLS LAST', [msg.guildId] ).then( ({rows}) => {
 		var guild = rows.find( row => !row.channel );
 		var guild = rows.find( row => !row.channel );
 		if ( !guild ) guild = Object.assign({
 		if ( !guild ) guild = Object.assign({
 			role: null, inline: null,
 			role: null, inline: null,
@@ -26,64 +26,52 @@ function cmd_settings(lang, msg, args, line, wiki) {
 		}, defaultSettings);
 		}, defaultSettings);
 		var prefix = guild.prefix;
 		var prefix = guild.prefix;
 		var inlinepage = ( lang.localNames.page || 'page' );
 		var inlinepage = ( lang.localNames.page || 'page' );
-		var button = {
-			type: 2,
-			style: 5,
-			label: lang.get('settings.button'),
-			emoji: {
-				id: '588723255972593672',
-				name: 'wikibot',
-				animated: false
-			},
-			url: new URL(`/guild/${msg.guild.id}/settings`, process.env.dashboard).href,
-			disabled: false
-		};
+		var button = null;
 		var components = [];
 		var components = [];
-		if ( process.env.dashboard ) components.push({
-			type: 1,
-			components: [
-				button
-			]
-		});
+		if ( process.env.dashboard ) {
+			button = new MessageButton().setLabel(lang.get('settings.button')).setEmoji('<:wikibot:588723255972593672>').setStyle('LINK').setURL(new URL(`/guild/${msg.guildId}/settings`, process.env.dashboard).href);
+			components.push(new MessageActionRow().addComponents(button));
+		}
 		var text = lang.get('settings.missing', '`' + prefix + 'settings lang`', '`' + prefix + 'settings wiki`');
 		var text = lang.get('settings.missing', '`' + prefix + 'settings lang`', '`' + prefix + 'settings wiki`');
 		if ( rows.length ) {
 		if ( rows.length ) {
 			text = lang.get('settings.current');
 			text = lang.get('settings.current');
-			if ( process.env.dashboard ) text += `\n<${button.url}>`;
+			if ( button ) text += `\n<${button.url}>`;
 			text += '\n' + lang.get('settings.currentlang') + ' `' + allLangs.names[guild.lang] + '` - `' + prefix + 'settings lang`';
 			text += '\n' + lang.get('settings.currentlang') + ' `' + allLangs.names[guild.lang] + '` - `' + prefix + 'settings lang`';
-			if ( patreons[msg.guild.id] ) text += '\n' + lang.get('settings.currentprefix') + ' `' + prefix + '` - `' + prefix + 'settings prefix`';
+			if ( patreons[msg.guildId] ) text += '\n' + lang.get('settings.currentprefix') + ' `' + prefix + '` - `' + prefix + 'settings prefix`';
 			text += '\n' + lang.get('settings.currentrole') + ' ' + ( guild.role ? `<@&${guild.role}>` : '@everyone' ) + ' - `' + prefix + 'settings role`';
 			text += '\n' + lang.get('settings.currentrole') + ' ' + ( guild.role ? `<@&${guild.role}>` : '@everyone' ) + ' - `' + prefix + 'settings role`';
 			text += '\n' + lang.get('settings.currentinline') + ' ' + ( guild.inline ? '~~' : '' ) + '`[[' + inlinepage + ']]`' + ( guild.inline ? '~~' : '' ) + ' - `' + prefix + 'settings inline`';
 			text += '\n' + lang.get('settings.currentinline') + ' ' + ( guild.inline ? '~~' : '' ) + '`[[' + inlinepage + ']]`' + ( guild.inline ? '~~' : '' ) + ' - `' + prefix + 'settings inline`';
 			text += '\n' + lang.get('settings.currentwiki') + ' ' + guild.wiki + ' - `' + prefix + 'settings wiki`';
 			text += '\n' + lang.get('settings.currentwiki') + ' ' + guild.wiki + ' - `' + prefix + 'settings wiki`';
 			text += '\n' + lang.get('settings.currentchannel') + ' `' + prefix + 'settings channel`\n';
 			text += '\n' + lang.get('settings.currentchannel') + ' `' + prefix + 'settings channel`\n';
 			if ( rows.length === 1 ) text += lang.get('settings.nochannels');
 			if ( rows.length === 1 ) text += lang.get('settings.nochannels');
-			else text += rows.filter( row => row !== guild ).map( row => '<#' + row.channel.replace( /^#/, '' ) + '>: ' + ( patreons[msg.guild.id] ? '`' + allLangs.names[row.lang] + '` - ' : '' ) + '<' + row.wiki + '>' + ( patreons[msg.guild.id] ? ' - ' + ( row.role ? `<@&${row.role}>` : '@everyone' ) + ' - ' + ( row.inline ? '~~' : '' ) + '`[[' + inlinepage + ']]`' + ( row.inline ? '~~' : '' ) : '' ) ).join('\n');
+			else text += rows.filter( row => row !== guild ).map( row => '<#' + row.channel.replace( /^#/, '' ) + '>: ' + ( patreons[msg.guildId] ? '`' + allLangs.names[row.lang] + '` - ' : '' ) + '<' + row.wiki + '>' + ( patreons[msg.guildId] ? ' - ' + ( row.role ? `<@&${row.role}>` : '@everyone' ) + ' - ' + ( row.inline ? '~~' : '' ) + '`[[' + inlinepage + ']]`' + ( row.inline ? '~~' : '' ) : '' ) ).join('\n');
 		}
 		}
 		
 		
 		if ( !args.length ) {
 		if ( !args.length ) {
-			return msg.replyMsg( text, {split:true,components}, true );
+			return Util.splitMessage( text ).forEach( textpart => msg.replyMsg( {content: textpart, components}, true ) );
 		}
 		}
+		var channelId = ( msg.channel.isThread() ? msg.channel.parentId : msg.channelId );
 		
 		
 		var prelang = '';
 		var prelang = '';
 		args[0] = args[0].toLowerCase();
 		args[0] = args[0].toLowerCase();
 		if ( args[0] === 'channel' ) {
 		if ( args[0] === 'channel' ) {
 			prelang = 'channel ';
 			prelang = 'channel ';
-			if ( !rows.length ) return msg.replyMsg( text, {split:true,components}, true );
+			if ( !rows.length ) return Util.splitMessage( text ).forEach( textpart => msg.replyMsg( {content: textpart, components}, true ) );
 			
 			
-			var channel = rows.find( row => row.channel === msg.channel.id );
+			var channel = rows.find( row => row.channel === channelId );
 			if ( !channel ) channel = Object.assign({}, rows.find( row => {
 			if ( !channel ) channel = Object.assign({}, rows.find( row => {
-				return ( row.channel === '#' + msg.channel.parentID );
-			} ) || guild, {channel: msg.channel.id});
-			text = lang.get('settings.' + prelang + 'current');
-			button.url = new URL(`/guild/${msg.guild.id}/settings/${msg.channel.id}`, process.env.dashboard).href;
-			if ( process.env.dashboard ) text += `\n<${button.url}>`;
-			if ( patreons[msg.guild.id] ) {
+				return ( row.channel === '#' + msg.channel.parentId );
+			} ) || guild, {channel: channelId});
+			text = lang.get('settings.channel current');
+			button?.setURL(new URL(`/guild/${msg.guildId}/settings/${channelId}`, button.url).href);
+			if ( button ) text += `\n<${button.url}>`;
+			if ( patreons[msg.guildId] ) {
 				text += '\n' + lang.get('settings.currentlang') + ' `' + allLangs.names[channel.lang] + '` - `' + prefix + 'settings channel lang`';
 				text += '\n' + lang.get('settings.currentlang') + ' `' + allLangs.names[channel.lang] + '` - `' + prefix + 'settings channel lang`';
 				text += '\n' + lang.get('settings.currentrole') + ' ' + ( channel.role ? `<@&${channel.role}>` : '@everyone' ) + ' - `' + prefix + 'settings channel role`';
 				text += '\n' + lang.get('settings.currentrole') + ' ' + ( channel.role ? `<@&${channel.role}>` : '@everyone' ) + ' - `' + prefix + 'settings channel role`';
 				text += '\n' + lang.get('settings.currentinline') + ' ' + ( channel.inline ? '~~' : '' ) + '`[[' + inlinepage + ']]`' + ( channel.inline ? '~~' : '' ) + ' - `' + prefix + 'settings channel inline`';
 				text += '\n' + lang.get('settings.currentinline') + ' ' + ( channel.inline ? '~~' : '' ) + '`[[' + inlinepage + ']]`' + ( channel.inline ? '~~' : '' ) + ' - `' + prefix + 'settings channel inline`';
 			}
 			}
 			text += '\n' + lang.get('settings.currentwiki') + ' ' + channel.wiki + ' - `' + prefix + 'settings channel wiki`';
 			text += '\n' + lang.get('settings.currentwiki') + ' ' + channel.wiki + ' - `' + prefix + 'settings channel wiki`';
 			
 			
-			if ( !args[1] ) return msg.replyMsg( text, {components}, true );
+			if ( !args[1] ) return msg.replyMsg( {content: text, components}, true );
 			
 			
 			args[0] = args[1].toLowerCase();
 			args[0] = args[1].toLowerCase();
 			args[1] = args.slice(2).join(' ').toLowerCase().trim().replace( /^<\s*(.*)\s*>$/, '$1' );
 			args[1] = args.slice(2).join(' ').toLowerCase().trim().replace( /^<\s*(.*)\s*>$/, '$1' );
@@ -94,15 +82,15 @@ function cmd_settings(lang, msg, args, line, wiki) {
 			prelang += 'wiki';
 			prelang += 'wiki';
 			var wikihelp = '\n' + lang.get('settings.wikihelp', prefix + 'settings ' + prelang);
 			var wikihelp = '\n' + lang.get('settings.wikihelp', prefix + 'settings ' + prelang);
 			if ( !args[1] ) {
 			if ( !args[1] ) {
-				if ( !rows.length ) return msg.replyMsg( lang.get('settings.wikimissing') + wikihelp, {components}, true );
-				else return msg.replyMsg( lang.get('settings.' + prelang) + ' ' + ( channel || guild ).wiki + wikihelp, {components}, true );
+				if ( !rows.length ) return msg.replyMsg( {content: lang.get('settings.wikimissing') + wikihelp, components}, true );
+				else return msg.replyMsg( {content: lang.get('settings.' + prelang) + ' ' + ( channel || guild ).wiki + wikihelp, components}, true );
 			}
 			}
-			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 			var wikinew = Wiki.fromInput(args[1]);
 			var wikinew = Wiki.fromInput(args[1]);
 			if ( !wikinew ) {
 			if ( !wikinew ) {
-				var text = lang.get('settings.wikiinvalid') + wikihelp;
-				//text += '\n\n' + lang.get('settings.foundwikis') + '\n' + sites.map( site => site.wiki_display_name + ': `' + site.wiki_domain + '`' ).join('\n');
-				return msg.replyMsg( text, {split:true,components}, true );
+				let wikisuggest = lang.get('settings.wikiinvalid') + wikihelp;
+				//wikisuggest += '\n\n' + lang.get('settings.foundwikis') + '\n' + sites.map( site => site.wiki_display_name + ': `' + site.wiki_domain + '`' ).join('\n');
+				return Util.splitMessage( wikisuggest ).forEach( textpart => msg.replyMsg( {content: textpart, components}, true ) );
 			}
 			}
 			return msg.reactEmoji('⏳', true).then( reaction => {
 			return msg.reactEmoji('⏳', true).then( reaction => {
 				got.get( wikinew + 'api.php?&action=query&meta=siteinfo&siprop=general&format=json', {
 				got.get( wikinew + 'api.php?&action=query&meta=siteinfo&siprop=general&format=json', {
@@ -127,10 +115,10 @@ function cmd_settings(lang, msg, args, line, wiki) {
 						console.log( '- ' + response.statusCode + ': Error while testing the wiki: ' + body?.error?.info );
 						console.log( '- ' + response.statusCode + ': Error while testing the wiki: ' + body?.error?.info );
 						if ( reaction ) reaction.removeEmoji();
 						if ( reaction ) reaction.removeEmoji();
 						if ( body?.error?.info === 'You need read permission to use this module.' ) {
 						if ( body?.error?.info === 'You need read permission to use this module.' ) {
-							return msg.replyMsg( lang.get('settings.wikiinvalid_private') + wikihelp, {components}, true );
+							return msg.replyMsg( {content: lang.get('settings.wikiinvalid_private') + wikihelp, components}, true );
 						}
 						}
 						msg.reactEmoji('nowiki', true);
 						msg.reactEmoji('nowiki', true);
-						return msg.replyMsg( lang.get('settings.wikiinvalid') + wikihelp, {components}, true );
+						return msg.replyMsg( {content: lang.get('settings.wikiinvalid') + wikihelp, components}, true );
 					}
 					}
 					wikinew.updateWiki(body.query.general);
 					wikinew.updateWiki(body.query.general);
 					var embed;
 					var embed;
@@ -148,18 +136,18 @@ function cmd_settings(lang, msg, args, line, wiki) {
 						}
 						}
 					}
 					}
 					var sql = 'UPDATE discord SET wiki = $1 WHERE guild = $2 AND wiki = $3';
 					var sql = 'UPDATE discord SET wiki = $1 WHERE guild = $2 AND wiki = $3';
-					var sqlargs = [wikinew.href, msg.guild.id, guild.wiki];
+					var sqlargs = [wikinew.href, msg.guildId, guild.wiki];
 					if ( !rows.length ) {
 					if ( !rows.length ) {
 						sql = 'INSERT INTO discord(wiki, guild, main, lang) VALUES($1, $2, $2, $3)';
 						sql = 'INSERT INTO discord(wiki, guild, main, lang) VALUES($1, $2, $2, $3)';
 						sqlargs[2] = lang.lang;
 						sqlargs[2] = lang.lang;
 					}
 					}
 					else if ( channel ) {
 					else if ( channel ) {
 						sql = 'UPDATE discord SET wiki = $1 WHERE guild = $2 AND channel = $3';
 						sql = 'UPDATE discord SET wiki = $1 WHERE guild = $2 AND channel = $3';
-						sqlargs[2] = msg.channel.id;
+						sqlargs[2] = channelId;
 						if ( !rows.includes( channel ) ) {
 						if ( !rows.includes( channel ) ) {
 							if ( channel.wiki === wikinew.href ) {
 							if ( channel.wiki === wikinew.href ) {
 								if ( reaction ) reaction.removeEmoji();
 								if ( reaction ) reaction.removeEmoji();
-								return msg.replyMsg( lang.get('settings.' + prelang + 'changed') + ' ' + channel.wiki + wikihelp, {embed,components}, true );
+								return msg.replyMsg( {content: lang.get('settings.' + prelang + 'changed') + ' ' + channel.wiki + wikihelp, embeds: [embed], components}, true );
 							}
 							}
 							sql = 'INSERT INTO discord(wiki, guild, channel, lang, role, inline, prefix) VALUES($1, $2, $3, $4, $5, $6, $7)';
 							sql = 'INSERT INTO discord(wiki, guild, channel, lang, role, inline, prefix) VALUES($1, $2, $3, $4, $5, $6, $7)';
 							sqlargs.push(guild.lang, guild.role, guild.inline, guild.prefix);
 							sqlargs.push(guild.lang, guild.role, guild.inline, guild.prefix);
@@ -174,9 +162,9 @@ function cmd_settings(lang, msg, args, line, wiki) {
 							} );
 							} );
 							guild.wiki = wikinew.href;
 							guild.wiki = wikinew.href;
 						}
 						}
-						if ( channel || !rows.some( row => row.channel === msg.channel.id ) ) wiki = new Wiki(wikinew);
+						if ( channel || !rows.some( row => row.channel === channelId ) ) wiki = new Wiki(wikinew);
 						if ( reaction ) reaction.removeEmoji();
 						if ( reaction ) reaction.removeEmoji();
-						msg.replyMsg( lang.get('settings.' + prelang + 'changed') + ' ' + wikinew + wikihelp, {embed,components}, true );
+						msg.replyMsg( {content: lang.get('settings.' + prelang + 'changed') + ' ' + wikinew + wikihelp, embeds: [embed], components}, true );
 						var channels = rows.filter( row => row.channel && row.lang === guild.lang && row.wiki === guild.wiki && row.prefix === guild.prefix && row.role === guild.role && row.inline === guild.inline ).map( row => row.channel );
 						var channels = rows.filter( row => row.channel && row.lang === guild.lang && row.wiki === guild.wiki && row.prefix === guild.prefix && row.role === guild.role && row.inline === guild.inline ).map( row => row.channel );
 						if ( channels.length ) db.query( 'DELETE FROM discord WHERE channel IN (' + channels.map( (row, i) => '$' + ( i + 1 ) ).join(', ') + ')', channels ).then( () => {
 						if ( channels.length ) db.query( 'DELETE FROM discord WHERE channel IN (' + channels.map( (row, i) => '$' + ( i + 1 ) ).join(', ') + ')', channels ).then( () => {
 							console.log( '- Settings successfully removed.' );
 							console.log( '- Settings successfully removed.' );
@@ -185,48 +173,48 @@ function cmd_settings(lang, msg, args, line, wiki) {
 						} );
 						} );
 					}, dberror => {
 					}, dberror => {
 						console.log( '- Error while editing the settings: ' + dberror );
 						console.log( '- Error while editing the settings: ' + dberror );
-						msg.replyMsg( lang.get('settings.save_failed'), {embed,components}, true );
+						msg.replyMsg( {content: lang.get('settings.save_failed'), embeds: [embed], components}, true );
 						if ( reaction ) reaction.removeEmoji();
 						if ( reaction ) reaction.removeEmoji();
 					} );
 					} );
 				}, ferror => {
 				}, ferror => {
 					if ( reaction ) reaction.removeEmoji();
 					if ( reaction ) reaction.removeEmoji();
 					if ( ferror.message?.startsWith( 'connect ECONNREFUSED ' ) || ferror.message?.startsWith( 'Hostname/IP does not match certificate\'s altnames: ' ) || ferror.message === 'certificate has expired' || ferror.message === 'self signed certificate' ) {
 					if ( ferror.message?.startsWith( 'connect ECONNREFUSED ' ) || ferror.message?.startsWith( 'Hostname/IP does not match certificate\'s altnames: ' ) || ferror.message === 'certificate has expired' || ferror.message === 'self signed certificate' ) {
 						console.log( '- Error while testing the wiki: No HTTPS' );
 						console.log( '- Error while testing the wiki: No HTTPS' );
-						return msg.replyMsg( lang.get('settings.wikiinvalid_http') + wikihelp, {components}, true );
+						return msg.replyMsg( {content: lang.get('settings.wikiinvalid_http') + wikihelp, components}, true );
 					}
 					}
 					console.log( '- Error while testing the wiki: ' + ferror );
 					console.log( '- Error while testing the wiki: ' + ferror );
 					if ( ferror.message === `Timeout awaiting 'request' for ${got.defaults.options.timeout.request}ms` ) {
 					if ( ferror.message === `Timeout awaiting 'request' for ${got.defaults.options.timeout.request}ms` ) {
-						return msg.replyMsg( lang.get('settings.wikiinvalid_timeout') + wikihelp, {components}, true );
+						return msg.replyMsg( {content: lang.get('settings.wikiinvalid_timeout') + wikihelp, components}, true );
 					}
 					}
 					msg.reactEmoji('nowiki', true);
 					msg.reactEmoji('nowiki', true);
-					return msg.replyMsg( lang.get('settings.wikiinvalid') + wikihelp, {components}, true );
+					return msg.replyMsg( {content: lang.get('settings.wikiinvalid') + wikihelp, components}, true );
 				} );
 				} );
 			} );
 			} );
 		}
 		}
 		
 		
 		if ( args[0] === 'lang' || args[0] === 'language' ) {
 		if ( args[0] === 'lang' || args[0] === 'language' ) {
-			if ( channel && !patreons[msg.guild.id] ) return msg.replyMsg( lang.get('general.patreon') + '\n<' + process.env.patreon + '>', {}, true );
+			if ( channel && !patreons[msg.guildId] ) return msg.replyMsg( lang.get('general.patreon') + '\n<' + process.env.patreon + '>', true );
 			prelang += 'lang';
 			prelang += 'lang';
 			var langhelp = '\n' + lang.get('settings.langhelp', prefix + 'settings ' + prelang) + ' `' + Object.values(allLangs.names).join('`, `') + '`';
 			var langhelp = '\n' + lang.get('settings.langhelp', prefix + 'settings ' + prelang) + ' `' + Object.values(allLangs.names).join('`, `') + '`';
 			if ( !args[1] ) {
 			if ( !args[1] ) {
-				return msg.replyMsg( lang.get('settings.' + prelang) + ' `' + allLangs.names[( channel || guild ).lang] + '`' + langhelp, {files:( msg.uploadFiles() ? [`./i18n/widgets/${( channel || guild ).lang}.png`] : [] ),components}, true );
+				return msg.replyMsg( {content: lang.get('settings.' + prelang) + ' `' + allLangs.names[( channel || guild ).lang] + '`' + langhelp, files: ( msg.uploadFiles() ? [`./i18n/widgets/${( channel || guild ).lang}.png`] : [] ), components}, true );
 			}
 			}
-			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 			if ( !allLangs.map.hasOwnProperty(args[1]) ) {
 			if ( !allLangs.map.hasOwnProperty(args[1]) ) {
-				return msg.replyMsg( lang.get('settings.langinvalid') + langhelp, {components}, true );
+				return msg.replyMsg( {content: lang.get('settings.langinvalid') + langhelp, components}, true );
 			}
 			}
 			var sql = 'UPDATE discord SET lang = $1 WHERE guild = $2 AND lang = $3';
 			var sql = 'UPDATE discord SET lang = $1 WHERE guild = $2 AND lang = $3';
-			var sqlargs = [allLangs.map[args[1]], msg.guild.id, guild.lang];
+			var sqlargs = [allLangs.map[args[1]], msg.guildId, guild.lang];
 			if ( !rows.length ) {
 			if ( !rows.length ) {
 				sql = 'INSERT INTO discord(lang, guild, main) VALUES($1, $2, $2)';
 				sql = 'INSERT INTO discord(lang, guild, main) VALUES($1, $2, $2)';
 				sqlargs.pop();
 				sqlargs.pop();
 			}
 			}
 			else if ( channel ) {
 			else if ( channel ) {
 				sql = 'UPDATE discord SET lang = $1 WHERE guild = $2 AND channel = $3';
 				sql = 'UPDATE discord SET lang = $1 WHERE guild = $2 AND channel = $3';
-				sqlargs[2] = msg.channel.id;
+				sqlargs[2] = channelId;
 				if ( !rows.includes( channel ) ) {
 				if ( !rows.includes( channel ) ) {
 					if ( channel.lang === allLangs.map[args[1]] ) {
 					if ( channel.lang === allLangs.map[args[1]] ) {
-						return msg.replyMsg( lang.get('settings.' + prelang + 'changed') + ' `' + allLangs.names[channel.lang] + '`' + langhelp, {files:( msg.uploadFiles() ? [`./i18n/widgets/${channel.lang}.png`] : [] ),components}, true );
+						return msg.replyMsg( {content: lang.get('settings.' + prelang + 'changed') + ' `' + allLangs.names[channel.lang] + '`' + langhelp, files: ( msg.uploadFiles() ? [`./i18n/widgets/${channel.lang}.png`] : [] ), components}, true );
 					}
 					}
 					sql = 'INSERT INTO discord(lang, guild, channel, wiki, role, inline, prefix) VALUES($1, $2, $3, $4, $5, $6, $7)';
 					sql = 'INSERT INTO discord(lang, guild, channel, wiki, role, inline, prefix) VALUES($1, $2, $3, $4, $5, $6, $7)';
 					sqlargs.push(guild.wiki, guild.role, guild.inline, guild.prefix);
 					sqlargs.push(guild.wiki, guild.role, guild.inline, guild.prefix);
@@ -240,10 +228,10 @@ function cmd_settings(lang, msg, args, line, wiki) {
 						if ( row.channel && row.lang === guild.lang ) row.lang = allLangs.map[args[1]];
 						if ( row.channel && row.lang === guild.lang ) row.lang = allLangs.map[args[1]];
 					} );
 					} );
 					guild.lang = allLangs.map[args[1]];
 					guild.lang = allLangs.map[args[1]];
-					if ( voice[msg.guild.id] ) voice[msg.guild.id] = guild.lang;
+					if ( voice[msg.guildId] ) voice[msg.guildId] = guild.lang;
 				}
 				}
-				if ( channel || !patreons[msg.guild.id] || !rows.some( row => row.channel === msg.channel.id ) ) lang = new Lang(allLangs.map[args[1]]);
-				msg.replyMsg( lang.get('settings.' + prelang + 'changed') + ' `' + allLangs.names[allLangs.map[args[1]]] + '`\n' + lang.get('settings.langhelp', prefix + 'settings ' + prelang) + ' `' + Object.values(allLangs.names).join('`, `') + '`', {files:( msg.uploadFiles() ? [`./i18n/widgets/${allLangs.map[args[1]]}.png`] : [] ),components}, true );
+				if ( channel || !patreons[msg.guildId] || !rows.some( row => row.channel === channelId ) ) lang = new Lang(allLangs.map[args[1]]);
+				msg.replyMsg( {content: lang.get('settings.' + prelang + 'changed') + ' `' + allLangs.names[allLangs.map[args[1]]] + '`\n' + lang.get('settings.langhelp', prefix + 'settings ' + prelang) + ' `' + Object.values(allLangs.names).join('`, `') + '`', files: ( msg.uploadFiles() ? [`./i18n/widgets/${allLangs.map[args[1]]}.png`] : [] ), components}, true );
 				var channels = rows.filter( row => row.channel && row.lang === guild.lang && row.wiki === guild.wiki && row.prefix === guild.prefix && row.role === guild.role && row.inline === guild.inline ).map( row => row.channel );
 				var channels = rows.filter( row => row.channel && row.lang === guild.lang && row.wiki === guild.wiki && row.prefix === guild.prefix && row.role === guild.role && row.inline === guild.inline ).map( row => row.channel );
 				if ( channels.length ) db.query( 'DELETE FROM discord WHERE channel IN (' + channels.map( (row, i) => '$' + ( i + 1 ) ).join(', ') + ')', channels ).then( () => {
 				if ( channels.length ) db.query( 'DELETE FROM discord WHERE channel IN (' + channels.map( (row, i) => '$' + ( i + 1 ) ).join(', ') + ')', channels ).then( () => {
 					console.log( '- Settings successfully removed.' );
 					console.log( '- Settings successfully removed.' );
@@ -252,40 +240,40 @@ function cmd_settings(lang, msg, args, line, wiki) {
 				} );
 				} );
 			}, dberror => {
 			}, dberror => {
 				console.log( '- Error while editing the settings: ' + dberror );
 				console.log( '- Error while editing the settings: ' + dberror );
-				msg.replyMsg( lang.get('settings.save_failed'), {components}, true );
+				msg.replyMsg( {content: lang.get('settings.save_failed'), components}, true );
 			} );
 			} );
 		}
 		}
 		
 		
 		if ( args[0] === 'role' ) {
 		if ( args[0] === 'role' ) {
-			if ( channel && !patreons[msg.guild.id] ) return msg.replyMsg( lang.get('general.patreon') + '\n<' + process.env.patreon + '>', {}, true );
+			if ( channel && !patreons[msg.guildId] ) return msg.replyMsg( lang.get('general.patreon') + '\n<' + process.env.patreon + '>', true );
 			prelang += 'role';
 			prelang += 'role';
 			var rolehelp = '\n' + lang.get('settings.rolehelp', prefix + 'settings ' + prelang);
 			var rolehelp = '\n' + lang.get('settings.rolehelp', prefix + 'settings ' + prelang);
 			if ( !args[1] ) {
 			if ( !args[1] ) {
-				return msg.replyMsg( lang.get('settings.' + prelang) + ' ' + ( ( channel || guild ).role ? `<@&${( channel || guild ).role}>` : '@everyone' ) + rolehelp, {components}, true );
+				return msg.replyMsg( {content: lang.get('settings.' + prelang) + ' ' + ( ( channel || guild ).role ? `<@&${( channel || guild ).role}>` : '@everyone' ) + rolehelp, components}, true );
 			}
 			}
-			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 			var role = null;
 			var role = null;
 			if ( /^\d+$/.test(args[1]) ) role = msg.guild.roles.cache.get(args[1]);
 			if ( /^\d+$/.test(args[1]) ) role = msg.guild.roles.cache.get(args[1]);
 			if ( !role ) role = msg.guild.roles.cache.find( gc => gc.name.toLowerCase() === args[1].replace( /^@/, '' ) );
 			if ( !role ) role = msg.guild.roles.cache.find( gc => gc.name.toLowerCase() === args[1].replace( /^@/, '' ) );
 			if ( !role && ['everyone', 'here', 'none', 'all'].includes( args[1].replace( /^@/, '' ) ) ) {
 			if ( !role && ['everyone', 'here', 'none', 'all'].includes( args[1].replace( /^@/, '' ) ) ) {
-				role = msg.guild.roles.cache.get(msg.guild.id);
+				role = msg.guild.roles.cache.get(msg.guildId);
 			}
 			}
 			if ( !role ) {
 			if ( !role ) {
-				return msg.replyMsg( lang.get('settings.roleinvalid') + rolehelp, {components}, true );
+				return msg.replyMsg( {content: lang.get('settings.roleinvalid') + rolehelp, components}, true );
 			}
 			}
-			role = ( role.id === msg.guild.id ? null : role.id );
+			role = ( role.id === msg.guildId ? null : role.id );
 			var sql = 'UPDATE discord SET role = $1 WHERE guild = $2';
 			var sql = 'UPDATE discord SET role = $1 WHERE guild = $2';
-			var sqlargs = [role, msg.guild.id];
+			var sqlargs = [role, msg.guildId];
 			if ( !rows.length ) {
 			if ( !rows.length ) {
 				sql = 'INSERT INTO discord(role, guild, main, lang) VALUES($1, $2, $2, $3)';
 				sql = 'INSERT INTO discord(role, guild, main, lang) VALUES($1, $2, $2, $3)';
 				sqlargs.push(lang.lang);
 				sqlargs.push(lang.lang);
 			}
 			}
 			else if ( channel ) {
 			else if ( channel ) {
 				sql = 'UPDATE discord SET role = $1 WHERE guild = $2 AND channel = $3';
 				sql = 'UPDATE discord SET role = $1 WHERE guild = $2 AND channel = $3';
-				sqlargs.push(msg.channel.id);
+				sqlargs.push(channelId);
 				if ( !rows.includes( channel ) ) {
 				if ( !rows.includes( channel ) ) {
 					if ( channel.role === role ) {
 					if ( channel.role === role ) {
-						return msg.replyMsg( lang.get('settings.' + prelang + 'changed') + ' ' + ( channel.role ? `<@&${channel.role}>` : '@everyone' ) + rolehelp, {components}, true );
+						return msg.replyMsg( {content: lang.get('settings.' + prelang + 'changed') + ' ' + ( channel.role ? `<@&${channel.role}>` : '@everyone' ) + rolehelp, components}, true );
 					}
 					}
 					sql = 'INSERT INTO discord(role, guild, channel, wiki, lang, inline, prefix) VALUES($1, $2, $3, $4, $5, $6, $7)';
 					sql = 'INSERT INTO discord(role, guild, channel, wiki, lang, inline, prefix) VALUES($1, $2, $3, $4, $5, $6, $7)';
 					sqlargs.push(guild.wiki, guild.lang, guild.inline, guild.prefix);
 					sqlargs.push(guild.wiki, guild.lang, guild.inline, guild.prefix);
@@ -305,7 +293,7 @@ function cmd_settings(lang, msg, args, line, wiki) {
 					} );
 					} );
 					guild.role = role;
 					guild.role = role;
 				}
 				}
-				msg.replyMsg( lang.get('settings.' + prelang + 'changed') + ' ' + ( role ? `<@&${role}>` : '@everyone' ) + rolehelp, {components}, true );
+				msg.replyMsg( {content: lang.get('settings.' + prelang + 'changed') + ' ' + ( role ? `<@&${role}>` : '@everyone' ) + rolehelp, components}, true );
 				var channels = rows.filter( row => row.channel && row.lang === guild.lang && row.wiki === guild.wiki && row.prefix === guild.prefix && row.role === guild.role && row.inline === guild.inline ).map( row => row.channel );
 				var channels = rows.filter( row => row.channel && row.lang === guild.lang && row.wiki === guild.wiki && row.prefix === guild.prefix && row.role === guild.role && row.inline === guild.inline ).map( row => row.channel );
 				if ( channels.length ) db.query( 'DELETE FROM discord WHERE channel IN (' + channels.map( (row, i) => '$' + ( i + 1 ) ).join(', ') + ')', channels ).then( () => {
 				if ( channels.length ) db.query( 'DELETE FROM discord WHERE channel IN (' + channels.map( (row, i) => '$' + ( i + 1 ) ).join(', ') + ')', channels ).then( () => {
 					console.log( '- Settings successfully removed.' );
 					console.log( '- Settings successfully removed.' );
@@ -314,26 +302,26 @@ function cmd_settings(lang, msg, args, line, wiki) {
 				} );
 				} );
 			}, dberror => {
 			}, dberror => {
 				console.log( '- Error while editing the settings: ' + dberror );
 				console.log( '- Error while editing the settings: ' + dberror );
-				msg.replyMsg( lang.get('settings.save_failed'), {components}, true );
+				msg.replyMsg( {content: lang.get('settings.save_failed'), components}, true );
 			} );
 			} );
 		}
 		}
 		
 		
 		if ( args[0] === 'prefix' && !channel ) {
 		if ( args[0] === 'prefix' && !channel ) {
-			if ( !patreons[msg.guild.id] ) {
-				return msg.replyMsg( lang.get('general.patreon') + '\n<' + process.env.patreon + '>', {}, true );
+			if ( !patreons[msg.guildId] ) {
+				return msg.replyMsg( lang.get('general.patreon') + '\n<' + process.env.patreon + '>', true );
 			}
 			}
 			var prefixhelp = '\n' + lang.get('settings.prefixhelp', prefix + 'settings prefix');
 			var prefixhelp = '\n' + lang.get('settings.prefixhelp', prefix + 'settings prefix');
 			args[1] = args[1].replace( /(?<!\\)_$/, ' ' ).replace( /\\([_\W])/g, '$1' );
 			args[1] = args[1].replace( /(?<!\\)_$/, ' ' ).replace( /\\([_\W])/g, '$1' );
 			if ( !args[1].trim() ) {
 			if ( !args[1].trim() ) {
-				return msg.replyMsg( lang.get('settings.prefix') + ' `' + prefix + '`' + prefixhelp, {components}, true );
+				return msg.replyMsg( {content: lang.get('settings.prefix') + ' `' + prefix + '`' + prefixhelp, components}, true );
 			}
 			}
-			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 			if ( args[1].includes( '`' ) || args[1].includes( '\\' ) || args[1].length > 100 ) {
 			if ( args[1].includes( '`' ) || args[1].includes( '\\' ) || args[1].length > 100 ) {
-				return msg.replyMsg( lang.get('settings.prefixinvalid') + prefixhelp, {components}, true );
+				return msg.replyMsg( {content: lang.get('settings.prefixinvalid') + prefixhelp, components}, true );
 			}
 			}
 			if ( args[1] === 'reset' || args[1] === 'default' ) args[1] = process.env.prefix;
 			if ( args[1] === 'reset' || args[1] === 'default' ) args[1] = process.env.prefix;
 			var sql = 'UPDATE discord SET prefix = $1 WHERE guild = $2';
 			var sql = 'UPDATE discord SET prefix = $1 WHERE guild = $2';
-			var sqlargs = [args[1], msg.guild.id];
+			var sqlargs = [args[1], msg.guildId];
 			if ( !rows.length ) {
 			if ( !rows.length ) {
 				sql = 'INSERT INTO discord(prefix, guild, main, lang) VALUES($1, $2, $2, $3)';
 				sql = 'INSERT INTO discord(prefix, guild, main, lang) VALUES($1, $2, $2, $3)';
 				sqlargs.push(lang.lang);
 				sqlargs.push(lang.lang);
@@ -341,33 +329,35 @@ function cmd_settings(lang, msg, args, line, wiki) {
 			return db.query( sql, sqlargs ).then( () => {
 			return db.query( sql, sqlargs ).then( () => {
 				console.log( '- Settings successfully updated.' );
 				console.log( '- Settings successfully updated.' );
 				guild.prefix = args[1];
 				guild.prefix = args[1];
-				msg.client.shard.broadcastEval( `global.patreons['${msg.guild.id}'] = '${args[1]}'` );
-				msg.replyMsg( lang.get('settings.prefixchanged') + ' `' + args[1] + '`\n' + lang.get('settings.prefixhelp', args[1] + 'settings prefix'), {components}, true );
+				msg.client.shard.broadcastEval( (discordClient, evalData) => {
+					global.patreons[evalData.guild] = evalData.prefix;
+				}, {context: {guild: msg.guildId, prefix: args[1]}} );
+				msg.replyMsg( {content: lang.get('settings.prefixchanged') + ' `' + args[1] + '`\n' + lang.get('settings.prefixhelp', args[1] + 'settings prefix'), components}, true );
 			}, dberror => {
 			}, dberror => {
 				console.log( '- Error while editing the settings: ' + dberror );
 				console.log( '- Error while editing the settings: ' + dberror );
-				msg.replyMsg( lang.get('settings.save_failed'), {components}, true );
+				msg.replyMsg( {content: lang.get('settings.save_failed'), components}, true );
 			} );
 			} );
 		}
 		}
 		
 		
 		if ( args[0] === 'inline' ) {
 		if ( args[0] === 'inline' ) {
-			if ( channel && !patreons[msg.guild.id] ) return msg.replyMsg( lang.get('general.patreon') + '\n<' + process.env.patreon + '>', {}, true );
+			if ( channel && !patreons[msg.guildId] ) return msg.replyMsg( lang.get('general.patreon') + '\n<' + process.env.patreon + '>', true );
 			prelang += 'inline';
 			prelang += 'inline';
 			var toggle = 'inline ' + ( ( channel || guild ).inline ? 'disabled' : 'enabled' );
 			var toggle = 'inline ' + ( ( channel || guild ).inline ? 'disabled' : 'enabled' );
 			var inlinehelp = '\n' + lang.get('settings.' + toggle + '.help', prefix + 'settings ' + prelang + ' toggle', inlinepage);
 			var inlinehelp = '\n' + lang.get('settings.' + toggle + '.help', prefix + 'settings ' + prelang + ' toggle', inlinepage);
 			if ( args[1] !== 'toggle' ) {
 			if ( args[1] !== 'toggle' ) {
-				return msg.replyMsg( lang.get('settings.' + toggle + '.' + prelang) + inlinehelp, {components}, true );
+				return msg.replyMsg( {content: lang.get('settings.' + toggle + '.' + prelang) + inlinehelp, components}, true );
 			}
 			}
-			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 			var value = ( ( channel || guild ).inline ? null : 1 );
 			var value = ( ( channel || guild ).inline ? null : 1 );
 			var sql = 'UPDATE discord SET inline = $1 WHERE guild = $2';
 			var sql = 'UPDATE discord SET inline = $1 WHERE guild = $2';
-			var sqlargs = [value, msg.guild.id];
+			var sqlargs = [value, msg.guildId];
 			if ( !rows.length ) {
 			if ( !rows.length ) {
 				sql = 'INSERT INTO discord(inline, guild, main, lang) VALUES($1, $2, $2, $3)';
 				sql = 'INSERT INTO discord(inline, guild, main, lang) VALUES($1, $2, $2, $3)';
 				sqlargs.push(lang.lang);
 				sqlargs.push(lang.lang);
 			}
 			}
 			else if ( channel ) {
 			else if ( channel ) {
 				sql = 'UPDATE discord SET inline = $1 WHERE guild = $2 AND channel = $3';
 				sql = 'UPDATE discord SET inline = $1 WHERE guild = $2 AND channel = $3';
-				sqlargs.push(msg.channel.id);
+				sqlargs.push(channelId);
 				if ( !rows.includes( channel ) ) {
 				if ( !rows.includes( channel ) ) {
 					sql = 'INSERT INTO discord(inline, guild, channel, wiki, lang, role, prefix) VALUES($1, $2, $3, $4, $5, $6, $7)';
 					sql = 'INSERT INTO discord(inline, guild, channel, wiki, lang, role, prefix) VALUES($1, $2, $3, $4, $5, $6, $7)';
 					sqlargs.push(guild.wiki, guild.lang, guild.role, guild.prefix);
 					sqlargs.push(guild.wiki, guild.lang, guild.role, guild.prefix);
@@ -383,7 +373,7 @@ function cmd_settings(lang, msg, args, line, wiki) {
 					guild.inline = value;
 					guild.inline = value;
 				}
 				}
 				toggle = 'inline ' + ( ( channel || guild ).inline ? 'disabled' : 'enabled' );
 				toggle = 'inline ' + ( ( channel || guild ).inline ? 'disabled' : 'enabled' );
-				msg.replyMsg( lang.get('settings.' + toggle + '.' + prelang + 'changed') + '\n' + lang.get('settings.' + toggle + '.help', prefix + 'settings ' + prelang + ' toggle', inlinepage), {components}, true );
+				msg.replyMsg( {content: lang.get('settings.' + toggle + '.' + prelang + 'changed') + '\n' + lang.get('settings.' + toggle + '.help', prefix + 'settings ' + prelang + ' toggle', inlinepage), components}, true );
 				var channels = rows.filter( row => row.channel && row.lang === guild.lang && row.wiki === guild.wiki && row.prefix === guild.prefix && row.role === guild.role && row.inline === guild.inline ).map( row => row.channel );
 				var channels = rows.filter( row => row.channel && row.lang === guild.lang && row.wiki === guild.wiki && row.prefix === guild.prefix && row.role === guild.role && row.inline === guild.inline ).map( row => row.channel );
 				if ( channels.length ) db.query( 'DELETE FROM discord WHERE channel IN (' + channels.map( (row, i) => '$' + ( i + 1 ) ).join(', ') + ')', channels ).then( () => {
 				if ( channels.length ) db.query( 'DELETE FROM discord WHERE channel IN (' + channels.map( (row, i) => '$' + ( i + 1 ) ).join(', ') + ')', channels ).then( () => {
 					console.log( '- Settings successfully removed.' );
 					console.log( '- Settings successfully removed.' );
@@ -392,11 +382,11 @@ function cmd_settings(lang, msg, args, line, wiki) {
 				} );
 				} );
 			}, dberror => {
 			}, dberror => {
 				console.log( '- Error while editing the settings: ' + dberror );
 				console.log( '- Error while editing the settings: ' + dberror );
-				msg.replyMsg( lang.get('settings.save_failed'), {components}, true );
+				msg.replyMsg( {content: lang.get('settings.save_failed'), components}, true );
 			} );
 			} );
 		}
 		}
 		
 		
-		return msg.replyMsg( text, {split:true,components}, true );
+		return Util.splitMessage( text ).forEach( textpart => msg.replyMsg( {content: textpart, components}, true ) );
 	}, dberror => {
 	}, dberror => {
 		console.log( '- Error while getting the settings: ' + dberror );
 		console.log( '- Error while getting the settings: ' + dberror );
 		msg.reactEmoji('error', true);
 		msg.reactEmoji('error', true);

+ 4 - 4
cmds/stop.js

@@ -9,13 +9,13 @@
  */
  */
 async function cmd_stop(lang, msg, args, line, wiki) {
 async function cmd_stop(lang, msg, args, line, wiki) {
 	if ( args[0] === 'force' && args.slice(1).join(' ').split('\n')[0].isMention(msg.guild) ) {
 	if ( args[0] === 'force' && args.slice(1).join(' ').split('\n')[0].isMention(msg.guild) ) {
-		await msg.replyMsg( 'I\'ll destroy myself now!', {}, true );
+		await msg.replyMsg( 'I\'ll destroy myself now!', true );
 		await msg.client.shard.send('SIGKILL');
 		await msg.client.shard.send('SIGKILL');
 	} else if ( args.join(' ').split('\n')[0].isMention(msg.guild) ) {
 	} else if ( args.join(' ').split('\n')[0].isMention(msg.guild) ) {
-		await msg.replyMsg( 'I\'ll restart myself now!', {}, true );
+		await msg.replyMsg( 'I\'ll restart myself now!', true );
 		console.log( '\n- Restarting all shards!\n\n' );
 		console.log( '\n- Restarting all shards!\n\n' );
-		await msg.client.shard.respawnAll(5000, 500, -1);
-	} else if ( !msg.channel.isGuild() || !pause[msg.guild.id] ) {
+		await msg.client.shard.respawnAll({timeout: -1});
+	} else if ( !msg.channel.isGuild() || !pause[msg.guildId] ) {
 		this.LINK(lang, msg, line, wiki);
 		this.LINK(lang, msg, line, wiki);
 	}
 	}
 }
 }

+ 9 - 9
cmds/test.js

@@ -25,19 +25,19 @@ const wsStatus = [
  */
  */
 function cmd_test(lang, msg, args, line, wiki) {
 function cmd_test(lang, msg, args, line, wiki) {
 	if ( args.join('') ) {
 	if ( args.join('') ) {
-		if ( !msg.channel.isGuild() || !pause[msg.guild.id] ) this.LINK(lang, msg, line, wiki);
+		if ( !msg.channel.isGuild() || !pause[msg.guildId] ) this.LINK(lang, msg, line, wiki);
 	}
 	}
-	else if ( !msg.channel.isGuild() || !pause[msg.guild.id] ) {
+	else if ( !msg.channel.isGuild() || !pause[msg.guildId] ) {
 		if ( msg.isAdmin() && msg.defaultSettings ) help_setup(lang, msg);
 		if ( msg.isAdmin() && msg.defaultSettings ) help_setup(lang, msg);
 		let textList = lang.get('test.text').filter( text => text.trim() );
 		let textList = lang.get('test.text').filter( text => text.trim() );
 		var text = ( textList[Math.floor(Math.random() * ( textList.length * 5 ))] || lang.get('test.text.0') );
 		var text = ( textList[Math.floor(Math.random() * ( textList.length * 5 ))] || lang.get('test.text.0') );
 		if ( process.env.READONLY ) text = lang.get('general.readonly') + '\n' + process.env.invite;
 		if ( process.env.READONLY ) text = lang.get('general.readonly') + '\n' + process.env.invite;
-		console.log( '- Test[' + global.shardId + ']: Fully functioning!' );
+		console.log( '- Test[' + process.env.SHARDS + ']: Fully functioning!' );
 		var now = Date.now();
 		var now = Date.now();
 		msg.replyMsg( text ).then( message => {
 		msg.replyMsg( text ).then( message => {
 			if ( !message ) return;
 			if ( !message ) return;
 			var then = Date.now();
 			var then = Date.now();
-			var embed = new MessageEmbed().setTitle( lang.get('test.time') ).setFooter( 'Shard: ' + global.shardId ).addField( 'Discord', ( then - now ).toLocaleString(lang.get('dateformat')) + 'ms' );
+			var embed = new MessageEmbed().setTitle( lang.get('test.time') ).setFooter( 'Shard: ' + process.env.SHARDS ).addField( 'Discord', ( then - now ).toLocaleString(lang.get('dateformat')) + 'ms' );
 			now = Date.now();
 			now = Date.now();
 			got.get( wiki + 'api.php?action=query&meta=siteinfo&siprop=general&format=json', {
 			got.get( wiki + 'api.php?action=query&meta=siteinfo&siprop=general&format=json', {
 				timeout: 10000
 				timeout: 10000
@@ -60,13 +60,13 @@ function cmd_test(lang, msg, args, line, wiki) {
 					}
 					}
 				}
 				}
 				else if ( ( msg.isAdmin() || msg.isOwner() ) && !wiki.isFandom() ) {
 				else if ( ( msg.isAdmin() || msg.isOwner() ) && !wiki.isFandom() ) {
-					logging(wiki, msg.guild?.id, 'test');
+					logging(wiki, msg.guildId, 'test');
 					if ( body.query.general.generator.replace( /^MediaWiki 1\.(\d\d).*$/, '$1' ) < 30 ) {
 					if ( body.query.general.generator.replace( /^MediaWiki 1\.(\d\d).*$/, '$1' ) < 30 ) {
 						console.log( '- This wiki is using ' + body.query.general.generator + '.' );
 						console.log( '- This wiki is using ' + body.query.general.generator + '.' );
 						notice.push(lang.get('test.MediaWiki', '[MediaWiki 1.30](https://www.mediawiki.org/wiki/MediaWiki_1.30)', body.query.general.generator));
 						notice.push(lang.get('test.MediaWiki', '[MediaWiki 1.30](https://www.mediawiki.org/wiki/MediaWiki_1.30)', body.query.general.generator));
 					}
 					}
 				}
 				}
-				else logging(wiki, msg.guild?.id, 'test');
+				else logging(wiki, msg.guildId, 'test');
 				if ( notice.length ) embed.addField( lang.get('test.notice'), notice.join('\n') );
 				if ( notice.length ) embed.addField( lang.get('test.notice'), notice.join('\n') );
 			}, error => {
 			}, error => {
 				then = Date.now();
 				then = Date.now();
@@ -87,15 +87,15 @@ function cmd_test(lang, msg, args, line, wiki) {
 					return '```js\n' + error + '\n```';
 					return '```js\n' + error + '\n```';
 				} ).then( shards => {
 				} ).then( shards => {
 					embed.addField( 'Shards', shards );
 					embed.addField( 'Shards', shards );
-					message.edit( message.content, {embed,allowedMentions:{users:[msg.author.id]}} ).catch(log_error);
+					message.edit( {content: message.content, embeds: [embed]} ).catch(log_error);
 				} );
 				} );
-				message.edit( message.content, {embed,allowedMentions:{users:[msg.author.id]}} ).catch(log_error);
+				message.edit( {content: message.content, embeds: [embed]} ).catch(log_error);
 			} );
 			} );
 		} );
 		} );
 	}
 	}
 	else {
 	else {
 		console.log( '- Test: Paused!' );
 		console.log( '- Test: Paused!' );
-		msg.replyMsg( lang.get('test.pause'), {}, true );
+		msg.replyMsg( lang.get('test.pause'), true );
 	}
 	}
 }
 }
 
 

+ 76 - 93
cmds/verification.js

@@ -1,8 +1,8 @@
+const {Util, MessageActionRow, MessageButton, Permissions: {FLAGS}} = require('discord.js');
 const help_setup = require('../functions/helpsetup.js');
 const help_setup = require('../functions/helpsetup.js');
 const {limit: {verification: verificationLimit}} = require('../util/default.json');
 const {limit: {verification: verificationLimit}} = require('../util/default.json');
 var db = require('../util/database.js');
 var db = require('../util/database.js');
-const {got, slashCommands} = require('../util/functions.js');
-const slashCommand = slashCommands.find( slashCommand => slashCommand.name === 'verify' );
+const {got} = require('../util/functions.js');
 
 
 /**
 /**
  * Processes the "verification" command.
  * Processes the "verification" command.
@@ -14,45 +14,32 @@ const slashCommand = slashCommands.find( slashCommand => slashCommand.name === '
  */
  */
 function cmd_verification(lang, msg, args, line, wiki) {
 function cmd_verification(lang, msg, args, line, wiki) {
 	if ( !msg.isAdmin() ) {
 	if ( !msg.isAdmin() ) {
-		if ( msg.channel.isGuild() && !pause[msg.guild.id] ) this.verify(lang, msg, args, line, wiki);
+		if ( msg.channel.isGuild() && !pause[msg.guildId] ) this.verify(lang, msg, args, line, wiki);
 		else msg.reactEmoji('❌');
 		else msg.reactEmoji('❌');
 		return;
 		return;
 	}
 	}
 	if ( msg.defaultSettings ) return help_setup(lang, msg);
 	if ( msg.defaultSettings ) return help_setup(lang, msg);
-	if ( !msg.guild.me.permissions.has('MANAGE_ROLES') ) {
-		console.log( msg.guild.id + ': Missing permissions - MANAGE_ROLES' );
+	if ( !msg.guild.me.permissions.has(FLAGS.MANAGE_ROLES) ) {
+		console.log( msg.guildId + ': Missing permissions - MANAGE_ROLES' );
 		return msg.replyMsg( lang.get('general.missingperm') + ' `MANAGE_ROLES`' );
 		return msg.replyMsg( lang.get('general.missingperm') + ' `MANAGE_ROLES`' );
 	}
 	}
 	
 	
-	db.query( 'SELECT configid, channel, role, editcount, postcount, usergroup, accountage, rename FROM verification WHERE guild = $1 ORDER BY configid ASC', [msg.guild.id] ).then( ({rows}) => {
-		var prefix = ( patreons[msg.guild.id] || process.env.prefix );
-		var button = {
-			type: 2,
-			style: 5,
-			label: lang.get('settings.button'),
-			emoji: {
-				id: '588723255972593672',
-				name: 'wikibot',
-				animated: false
-			},
-			url: new URL(`/guild/${msg.guild.id}/verification`, process.env.dashboard).href,
-			disabled: false
-		};
+	db.query( 'SELECT configid, channel, role, editcount, postcount, usergroup, accountage, rename FROM verification WHERE guild = $1 ORDER BY configid ASC', [msg.guildId] ).then( ({rows}) => {
+		var prefix = ( patreons[msg.guildId] || process.env.prefix );
+		var button = null;
 		var components = [];
 		var components = [];
-		if ( process.env.dashboard ) components.push({
-			type: 1,
-			components: [
-				button
-			]
-		});
+		if ( process.env.dashboard ) {
+			button = new MessageButton().setLabel(lang.get('settings.button')).setEmoji('<:wikibot:588723255972593672>').setStyle('LINK').setURL(new URL(`/guild/${msg.guildId}/verification`, process.env.dashboard).href);
+			components.push(new MessageActionRow().addComponents(button));
+		}
 		if ( args[0] && args[0].toLowerCase() === 'add' ) {
 		if ( args[0] && args[0].toLowerCase() === 'add' ) {
-			var limit = verificationLimit[( patreons[msg.guild.id] ? 'patreon' : 'default' )];
-			if ( rows.length >= limit ) return msg.replyMsg( lang.get('verification.max_entries'), {}, true );
-			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
-			button.url = new URL(`/guild/${msg.guild.id}/verification/new`, process.env.dashboard).href;
+			var limit = verificationLimit[( patreons[msg.guildId] ? 'patreon' : 'default' )];
+			if ( rows.length >= limit ) return msg.replyMsg( lang.get('verification.max_entries'), true );
+			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
+			button?.setURL(new URL(`/guild/${msg.guildId}/verification/new`, button.url).href);
 			var roles = args.slice(1).join(' ').split('|').map( role => role.replace( /^\s*<?\s*(.*?)\s*>?\s*$/, '$1' ) ).filter( role => role.length );
 			var roles = args.slice(1).join(' ').split('|').map( role => role.replace( /^\s*<?\s*(.*?)\s*>?\s*$/, '$1' ) ).filter( role => role.length );
-			if ( !roles.length ) return msg.replyMsg( lang.get('verification.no_role') + '\n`' + prefix + 'verification add ' + lang.get('verification.new_role') + '`', {components}, true );
-			if ( roles.length > 10 ) return msg.replyMsg( lang.get('verification.role_max'), {components}, true );
+			if ( !roles.length ) return msg.replyMsg( {content: lang.get('verification.no_role') + '\n`' + prefix + 'verification add ' + lang.get('verification.new_role') + '`', components}, true );
+			if ( roles.length > 10 ) return msg.replyMsg( {content: lang.get('verification.role_max'), components}, true );
 			roles = roles.map( role => {
 			roles = roles.map( role => {
 				var new_role = ['', null];
 				var new_role = ['', null];
 				if ( role.startsWith( '-' ) ) {
 				if ( role.startsWith( '-' ) ) {
@@ -64,120 +51,116 @@ function cmd_verification(lang, msg, args, line, wiki) {
 				if ( !new_role[1] ) new_role[1] = msg.guild.roles.cache.find( gc => gc.name.toLowerCase() === role.toLowerCase().replace( /^@/, '' ) );
 				if ( !new_role[1] ) new_role[1] = msg.guild.roles.cache.find( gc => gc.name.toLowerCase() === role.toLowerCase().replace( /^@/, '' ) );
 				return new_role;
 				return new_role;
 			} );
 			} );
-			if ( roles.some( role => !role[1] ) ) return msg.replyMsg( lang.get('verification.role_missing'), {components}, true );
-			if ( roles.some( role => role[1].managed || role[1].id === msg.guild.id ) ) return msg.replyMsg( lang.get('verification.role_managed'), {components}, true );
+			if ( roles.some( role => !role[1] ) ) return msg.replyMsg( {content: lang.get('verification.role_missing'), components}, true );
+			if ( roles.some( role => role[1].managed || role[1].id === msg.guildId ) ) return msg.replyMsg( {content: lang.get('verification.role_managed'), components}, true );
 			roles = roles.map( role => role[0] + role[1].id ).join('|');
 			roles = roles.map( role => role[0] + role[1].id ).join('|');
 			var new_configid = 1;
 			var new_configid = 1;
 			for ( let i of rows.map( row => row.configid ) ) {
 			for ( let i of rows.map( row => row.configid ) ) {
 				if ( new_configid === i ) new_configid++;
 				if ( new_configid === i ) new_configid++;
 				else break;
 				else break;
 			}
 			}
-			return db.query( 'INSERT INTO verification(guild, configid, channel, role) VALUES($1, $2, $3, $4)', [msg.guild.id, new_configid, '|' + msg.channel.id + '|', roles] ).then( () => {
+			return db.query( 'INSERT INTO verification(guild, configid, channel, role) VALUES($1, $2, $3, $4)', [msg.guildId, new_configid, '|' + ( msg.channel.isThread() ? msg.channel.parentId : msg.channelId ) + '|', roles] ).then( () => {
 				console.log( '- Verification successfully added.' );
 				console.log( '- Verification successfully added.' );
-				if ( !rows.length && slashCommand?.id ) msg.client.api.applications(msg.client.user.id).guilds(msg.guild.id).commands(slashCommand.id).permissions.put( {
-					data: {
-						permissions: [
-							{
-								id: msg.guild.id,
-								type: 1,
-								permission: true
-							}
-						]
-					}
+				if ( !rows.length ) msg.client.application.commands.cache.find( slashCommand => slashCommand.name === 'verify' )?.permissions.set( {
+					guild: msg.guildId,
+					permissions: [{
+						id: msg.guildId,
+						type: 'ROLE',
+						permission: true
+					}]
 				} ).then( () => {
 				} ).then( () => {
 					console.log( '- Slash command successfully enabled.' );
 					console.log( '- Slash command successfully enabled.' );
 				}, error => {
 				}, error => {
 					console.log( '- Error while enabling the slash command: ' + error );
 					console.log( '- Error while enabling the slash command: ' + error );
 				} );
 				} );
-				msg.replyMsg( lang.get('verification.added') + formatVerification(false, false, {configid: new_configid, role: roles}), {components}, true );
+				msg.replyMsg( {content: lang.get('verification.added') + formatVerification(false, false, {configid: new_configid, role: roles}), components}, true );
 			}, dberror => {
 			}, dberror => {
 				console.log( '- Error while adding the verification: ' + dberror );
 				console.log( '- Error while adding the verification: ' + dberror );
-				msg.replyMsg( lang.get('verification.save_failed'), {components}, true );
+				msg.replyMsg( {content: lang.get('verification.save_failed'), components}, true );
 			} );
 			} );
 		}
 		}
 		if ( !rows.some( row => row.configid.toString() === args[0] ) ) {
 		if ( !rows.some( row => row.configid.toString() === args[0] ) ) {
 			if ( args.length ) {
 			if ( args.length ) {
-				if ( !pause[msg.guild.id] ) this.verify(lang, msg, args, line, wiki);
+				if ( !pause[msg.guildId] ) this.verify(lang, msg, args, line, wiki);
 				return;
 				return;
 			}
 			}
 			var text = '';
 			var text = '';
 			if ( rows.length ) {
 			if ( rows.length ) {
 				text += lang.get('verification.current');
 				text += lang.get('verification.current');
-				if ( process.env.dashboard ) text += `\n<${button.url}>`;
+				if ( button ) text += `\n<${button.url}>`;
 				text += rows.map( row => formatVerification(false, true, row) ).join('');
 				text += rows.map( row => formatVerification(false, true, row) ).join('');
 			}
 			}
 			else {
 			else {
 				text += lang.get('verification.missing');
 				text += lang.get('verification.missing');
-				if ( process.env.dashboard ) text += `\n<${button.url}>`;
+				if ( button ) text += `\n<${button.url}>`;
 			}
 			}
 			text += '\n\n' + lang.get('verification.add_more') + '\n`' + prefix + 'verification add ' + lang.get('verification.new_role') + '`';
 			text += '\n\n' + lang.get('verification.add_more') + '\n`' + prefix + 'verification add ' + lang.get('verification.new_role') + '`';
-			return msg.sendChannel( '<@' + msg.author.id + '>, ' + text, {split:true,components}, true );
+			return Util.splitMessage( text ).forEach( textpart => msg.replyMsg( {content: textpart, components}, true ) );
 		}
 		}
 		var row = rows.find( row => row.configid.toString() === args[0] );
 		var row = rows.find( row => row.configid.toString() === args[0] );
 		if ( args[1] ) args[1] = args[1].toLowerCase();
 		if ( args[1] ) args[1] = args[1].toLowerCase();
 		if ( args[1] === 'delete' && !args.slice(2).join('') ) {
 		if ( args[1] === 'delete' && !args.slice(2).join('') ) {
-			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
-			return db.query( 'DELETE FROM verification WHERE guild = $1 AND configid = $2', [msg.guild.id, row.configid] ).then( () => {
+			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
+			return db.query( 'DELETE FROM verification WHERE guild = $1 AND configid = $2', [msg.guildId, row.configid] ).then( () => {
 				console.log( '- Verification successfully removed.' );
 				console.log( '- Verification successfully removed.' );
-				if ( rows.length === 1 && slashCommand?.id ) msg.client.api.applications(msg.client.user.id).guilds(msg.guild.id).commands(slashCommand.id).permissions.put( {
-					data: {
-						permissions: []
-					}
+				if ( rows.length === 1 ) msg.client.application.commands.cache.find( slashCommand => slashCommand.name === 'verify' )?.permissions.set( {
+					guild: msg.guildId,
+					permissions: []
 				} ).then( () => {
 				} ).then( () => {
 					console.log( '- Slash command successfully disabled.' );
 					console.log( '- Slash command successfully disabled.' );
 				}, error => {
 				}, error => {
 					console.log( '- Error while disabling the slash command: ' + error );
 					console.log( '- Error while disabling the slash command: ' + error );
 				} );
 				} );
-				msg.replyMsg( lang.get('verification.deleted'), {components}, true );
+				msg.replyMsg( {content: lang.get('verification.deleted'), components}, true );
 			}, dberror => {
 			}, dberror => {
 				console.log( '- Error while removing the verification: ' + dberror );
 				console.log( '- Error while removing the verification: ' + dberror );
-				button.url = new URL(`/guild/${msg.guild.id}/verification/${row.configid}`, process.env.dashboard).href;
-				msg.replyMsg( lang.get('verification.save_failed'), {components}, true );
+				button?.setURL(new URL(`/guild/${msg.guildId}/verification/${row.configid}`, button.url).href);
+				msg.replyMsg( {content: lang.get('verification.save_failed'), components}, true );
 			} );
 			} );
 		}
 		}
-		button.url = new URL(`/guild/${msg.guild.id}/verification/${row.configid}`, process.env.dashboard).href;
+		button?.setURL(new URL(`/guild/${msg.guildId}/verification/${row.configid}`, button.url).href);
 		if ( args[1] === 'rename' && !args.slice(2).join('') ) {
 		if ( args[1] === 'rename' && !args.slice(2).join('') ) {
-			if ( !row.rename && !msg.guild.me.permissions.has('MANAGE_NICKNAMES') ) {
-				console.log( msg.guild.id + ': Missing permissions - MANAGE_NICKNAMES' );
+			if ( !row.rename && !msg.guild.me.permissions.has(FLAGS.MANAGE_NICKNAMES) ) {
+				console.log( msg.guildId + ': Missing permissions - MANAGE_NICKNAMES' );
 				return msg.replyMsg( lang.get('general.missingperm') + ' `MANAGE_NICKNAMES`' );
 				return msg.replyMsg( lang.get('general.missingperm') + ' `MANAGE_NICKNAMES`' );
 			}
 			}
-			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
-			return db.query( 'UPDATE verification SET rename = $1 WHERE guild = $2 AND configid = $3', [( row.rename ? 0 : 1 ), msg.guild.id, row.configid] ).then( () => {
+			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
+			return db.query( 'UPDATE verification SET rename = $1 WHERE guild = $2 AND configid = $3', [( row.rename ? 0 : 1 ), msg.guildId, row.configid] ).then( () => {
 				console.log( '- Verification successfully updated.' );
 				console.log( '- Verification successfully updated.' );
 				row.rename = ( row.rename ? 0 : 1 );
 				row.rename = ( row.rename ? 0 : 1 );
-				msg.sendChannel( '<@' + msg.author.id + '>, ' + lang.get('verification.updated') + formatVerification(), {split:true,components}, true );
+				Util.splitMessage( lang.get('verification.updated') + formatVerification() ).forEach( textpart => msg.replyMsg( {content: textpart, components}, true ) );
 			}, dberror => {
 			}, dberror => {
 				console.log( '- Error while updating the verification: ' + dberror );
 				console.log( '- Error while updating the verification: ' + dberror );
-				msg.replyMsg( lang.get('verification.save_failed'), {components}, true );
+				msg.replyMsg( {content: lang.get('verification.save_failed'), components}, true );
 			} );
 			} );
 		}
 		}
 		if ( args[2] ) {
 		if ( args[2] ) {
-			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
+			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
 			args[2] = args.slice(2).join(' ').replace( /^\s*<?\s*(.*?)\s*>?\s*$/, '$1' );
 			args[2] = args.slice(2).join(' ').replace( /^\s*<?\s*(.*?)\s*>?\s*$/, '$1' );
 			if ( args[1] === 'channel' ) {
 			if ( args[1] === 'channel' ) {
 				var channels = args[2].replace( /\s*>?\s*[,|]\s*<?\s*/g, '|' ).split('|').filter( channel => channel.length );
 				var channels = args[2].replace( /\s*>?\s*[,|]\s*<?\s*/g, '|' ).split('|').filter( channel => channel.length );
-				if ( channels.length > 10 ) return msg.replyMsg( lang.get('verification.channel_max'), {components}, true );
+				if ( channels.length > 10 ) return msg.replyMsg( {content: lang.get('verification.channel_max'), components}, true );
 				channels = channels.map( channel => {
 				channels = channels.map( channel => {
 					var new_channel = '';
 					var new_channel = '';
-					if ( /^\d+$/.test(channel) ) new_channel = msg.guild.channels.cache.filter( tc => tc.isGuild() ).get(channel);
-					if ( !new_channel ) new_channel = msg.guild.channels.cache.filter( gc => gc.isGuild() ).find( gc => gc.name === channel.replace( /^#/, '' ) );
-					if ( !new_channel ) new_channel = msg.guild.channels.cache.filter( gc => gc.isGuild() ).find( gc => gc.name.toLowerCase() === channel.toLowerCase().replace( /^#/, '' ) );
+					if ( /^\d+$/.test(channel) ) new_channel = msg.guild.channels.cache.filter( tc => tc.isGuild(false) ).get(channel);
+					if ( !new_channel ) new_channel = msg.guild.channels.cache.filter( gc => gc.isGuild(false) ).find( gc => gc.name === channel.replace( /^#/, '' ) );
+					if ( !new_channel ) new_channel = msg.guild.channels.cache.filter( gc => gc.isGuild(false) ).find( gc => gc.name.toLowerCase() === channel.toLowerCase().replace( /^#/, '' ) );
 					return new_channel;
 					return new_channel;
 				} );
 				} );
-				if ( channels.some( channel => !channel ) ) return msg.replyMsg( lang.get('verification.channel_missing'), {components}, true );
+				if ( channels.some( channel => !channel ) ) return msg.replyMsg( {content: lang.get('verification.channel_missing'), components}, true );
 				channels = channels.map( channel => channel.id ).join('|');
 				channels = channels.map( channel => channel.id ).join('|');
-				if ( channels.length ) return db.query( 'UPDATE verification SET channel = $1 WHERE guild = $2 AND configid = $3', ['|' + channels + '|', msg.guild.id, row.configid] ).then( () => {
+				if ( channels.length ) return db.query( 'UPDATE verification SET channel = $1 WHERE guild = $2 AND configid = $3', ['|' + channels + '|', msg.guildId, row.configid] ).then( () => {
 					console.log( '- Verification successfully updated.' );
 					console.log( '- Verification successfully updated.' );
 					row.channel = '|' + channels + '|';
 					row.channel = '|' + channels + '|';
-					msg.sendChannel( '<@' + msg.author.id + '>, ' + lang.get('verification.updated') + formatVerification(), {split:true,components}, true );
+					Util.splitMessage( lang.get('verification.updated') + formatVerification() ).forEach( textpart => msg.replyMsg( {content: textpart, components}, true ) );
 				}, dberror => {
 				}, dberror => {
 					console.log( '- Error while updating the verification: ' + dberror );
 					console.log( '- Error while updating the verification: ' + dberror );
-					msg.replyMsg( lang.get('verification.save_failed'), {components}, true );
+					msg.replyMsg( {content: lang.get('verification.save_failed'), components}, true );
 				} );
 				} );
 			}
 			}
 			if ( args[1] === 'role' ) {
 			if ( args[1] === 'role' ) {
 				var roles = args[2].replace( /\s*>?\s*[,|]\s*<?\s*/g, '|' ).split('|').filter( role => role.length );
 				var roles = args[2].replace( /\s*>?\s*[,|]\s*<?\s*/g, '|' ).split('|').filter( role => role.length );
-				if ( roles.length > 10 ) return msg.replyMsg( lang.get('verification.role_max'), {components}, true );
+				if ( roles.length > 10 ) return msg.replyMsg( {content: lang.get('verification.role_max'), components}, true );
 				roles = roles.map( role => {
 				roles = roles.map( role => {
 					var new_role = ['', null];
 					var new_role = ['', null];
 					if ( role.startsWith( '-' ) ) {
 					if ( role.startsWith( '-' ) ) {
@@ -189,31 +172,31 @@ function cmd_verification(lang, msg, args, line, wiki) {
 					if ( !new_role[1] ) new_role[1] = msg.guild.roles.cache.find( gc => gc.name.toLowerCase() === role.toLowerCase().replace( /^@/, '' ) );
 					if ( !new_role[1] ) new_role[1] = msg.guild.roles.cache.find( gc => gc.name.toLowerCase() === role.toLowerCase().replace( /^@/, '' ) );
 					return new_role;
 					return new_role;
 				} );
 				} );
-				if ( roles.some( role => !role[1] ) ) return msg.replyMsg( lang.get('verification.role_missing'), {components}, true );
-				if ( roles.some( role => role[1].managed || role[1].id === msg.guild.id ) ) return msg.replyMsg( lang.get('verification.role_managed'), {components}, true );
+				if ( roles.some( role => !role[1] ) ) return msg.replyMsg( {content: lang.get('verification.role_missing'), components}, true );
+				if ( roles.some( role => role[1].managed || role[1].id === msg.guildId ) ) return msg.replyMsg( {content: lang.get('verification.role_managed'), components}, true );
 				roles = roles.map( role => role[0] + role[1].id ).join('|');
 				roles = roles.map( role => role[0] + role[1].id ).join('|');
-				if ( roles.length ) return db.query( 'UPDATE verification SET role = $1 WHERE guild = $2 AND configid = $3', [roles, msg.guild.id, row.configid] ).then( () => {
+				if ( roles.length ) return db.query( 'UPDATE verification SET role = $1 WHERE guild = $2 AND configid = $3', [roles, msg.guildId, row.configid] ).then( () => {
 					console.log( '- Verification successfully updated.' );
 					console.log( '- Verification successfully updated.' );
 					row.role = roles;
 					row.role = roles;
-					msg.sendChannel( '<@' + msg.author.id + '>, ' + lang.get('verification.updated') + formatVerification(), {split:true,components}, true );
+					Util.splitMessage( lang.get('verification.updated') + formatVerification() ).forEach( textpart => msg.replyMsg( {content: textpart, components}, true ) );
 				}, dberror => {
 				}, dberror => {
 					console.log( '- Error while updating the verification: ' + dberror );
 					console.log( '- Error while updating the verification: ' + dberror );
-					msg.replyMsg( lang.get('verification.save_failed'), {components}, true );
+					msg.replyMsg( {content: lang.get('verification.save_failed'), components}, true );
 				} );
 				} );
 			}
 			}
 			if ( ( ( args[1] === 'editcount' || args[1] === 'accountage' ) && /^\d+$/.test(args[2]) ) || ( args[1] === 'postcount' && /^(?:-?\d+|null)$/.test(args[2]) ) ) {
 			if ( ( ( args[1] === 'editcount' || args[1] === 'accountage' ) && /^\d+$/.test(args[2]) ) || ( args[1] === 'postcount' && /^(?:-?\d+|null)$/.test(args[2]) ) ) {
 				args[2] = parseInt(args[2], 10);
 				args[2] = parseInt(args[2], 10);
 				if ( isNaN(args[2]) ) args[2] = null;
 				if ( isNaN(args[2]) ) args[2] = null;
 				if ( args[2] > 1000000 || args[2] < -1000000 ) {
 				if ( args[2] > 1000000 || args[2] < -1000000 ) {
-					return msg.replyMsg( lang.get('verification.value_too_high'), {components}, true );
+					return msg.replyMsg( {content: lang.get('verification.value_too_high'), components}, true );
 				}
 				}
-				return db.query( 'UPDATE verification SET ' + args[1] + ' = $1 WHERE guild = $2 AND configid = $3', [args[2], msg.guild.id, row.configid] ).then( () => {
+				return db.query( 'UPDATE verification SET ' + args[1] + ' = $1 WHERE guild = $2 AND configid = $3', [args[2], msg.guildId, row.configid] ).then( () => {
 					console.log( '- Verification successfully updated.' );
 					console.log( '- Verification successfully updated.' );
 					row[args[1]] = args[2];
 					row[args[1]] = args[2];
-					msg.sendChannel( '<@' + msg.author.id + '>, ' + lang.get('verification.updated') + formatVerification(), {split:true,components}, true );
+					Util.splitMessage( lang.get('verification.updated') + formatVerification() ).forEach( textpart => msg.replyMsg( {content: textpart, components}, true ) );
 				}, dberror => {
 				}, dberror => {
 					console.log( '- Error while updating the verification: ' + dberror );
 					console.log( '- Error while updating the verification: ' + dberror );
-					msg.replyMsg( lang.get('verification.save_failed'), {components}, true );
+					msg.replyMsg( {content: lang.get('verification.save_failed'), components}, true );
 				} );
 				} );
 			}
 			}
 			if ( args[1] === 'usergroup' ) {
 			if ( args[1] === 'usergroup' ) {
@@ -223,8 +206,8 @@ function cmd_verification(lang, msg, args, line, wiki) {
 					usergroups = usergroups.slice(1);
 					usergroups = usergroups.slice(1);
 					and_or = 'AND|';
 					and_or = 'AND|';
 				}
 				}
-				if ( usergroups.length > 10 ) return msg.replyMsg( lang.get('verification.usergroup_max'), {components}, true );
-				if ( usergroups.some( usergroup => usergroup.length > 100 ) ) return msg.replyMsg( lang.get('verification.usergroup_too_long'), {components}, true );
+				if ( usergroups.length > 10 ) return msg.replyMsg( {content: lang.get('verification.usergroup_max'), components}, true );
+				if ( usergroups.some( usergroup => usergroup.length > 100 ) ) return msg.replyMsg( {content: lang.get('verification.usergroup_too_long'), components}, true );
 				if ( usergroups.length ) return msg.reactEmoji('⏳').then( reaction => got.get( wiki + 'api.php?action=query&meta=allmessages&amprefix=group-&amincludelocal=true&amenableparser=true&format=json' ).then( response => {
 				if ( usergroups.length ) return msg.reactEmoji('⏳').then( reaction => got.get( wiki + 'api.php?action=query&meta=allmessages&amprefix=group-&amincludelocal=true&amenableparser=true&format=json' ).then( response => {
 					var body = response.body;
 					var body = response.body;
 					if ( body && body.warnings ) log_warn(body.warnings);
 					if ( body && body.warnings ) log_warn(body.warnings);
@@ -257,26 +240,26 @@ function cmd_verification(lang, msg, args, line, wiki) {
 					console.log( '- Error while getting the usergroups: ' + error );
 					console.log( '- Error while getting the usergroups: ' + error );
 				} ).finally( () => {
 				} ).finally( () => {
 					usergroups = usergroups.join('|');
 					usergroups = usergroups.join('|');
-					db.query( 'UPDATE verification SET usergroup = $1 WHERE guild = $2 AND configid = $3', [and_or + usergroups, msg.guild.id, row.configid] ).then( () => {
+					db.query( 'UPDATE verification SET usergroup = $1 WHERE guild = $2 AND configid = $3', [and_or + usergroups, msg.guildId, row.configid] ).then( () => {
 						console.log( '- Verification successfully updated.' );
 						console.log( '- Verification successfully updated.' );
 						row.usergroup = and_or + usergroups;
 						row.usergroup = and_or + usergroups;
-						msg.sendChannel( '<@' + msg.author.id + '>, ' + lang.get('verification.updated') + formatVerification(), {split:true,components}, true );
+						Util.splitMessage( lang.get('verification.updated') + formatVerification() ).forEach( textpart => msg.replyMsg( {content: textpart, components}, true ) );
 						
 						
 						if ( reaction ) reaction.removeEmoji();
 						if ( reaction ) reaction.removeEmoji();
 					}, dberror => {
 					}, dberror => {
 						console.log( '- Error while updating the verification: ' + dberror );
 						console.log( '- Error while updating the verification: ' + dberror );
-						msg.replyMsg( lang.get('verification.save_failed'), {components}, true );
+						msg.replyMsg( {content: lang.get('verification.save_failed'), components}, true );
 						
 						
 						if ( reaction ) reaction.removeEmoji();
 						if ( reaction ) reaction.removeEmoji();
 					} );
 					} );
 				} ) );
 				} ) );
 			}
 			}
 		}
 		}
-		return msg.sendChannel( '<@' + msg.author.id + '>, ' + lang.get('verification.current_selected', row.configid) + ( process.env.dashboard ? `\n<${button.url}>` : '' ) + formatVerification(true) +'\n\n' + lang.get('verification.delete_current') + '\n`' + prefix + 'verification ' + row.configid + ' delete`', {split:true,components}, true );
+		return Util.splitMessage( lang.get('verification.current_selected', row.configid) + ( button ? `\n<${button.url}>` : '' ) + formatVerification(true) +'\n\n' + lang.get('verification.delete_current') + '\n`' + prefix + 'verification ' + row.configid + ' delete`' ).forEach( textpart => msg.replyMsg( {content: textpart, components}, true ) );
 		
 		
 		function formatVerification(showCommands, hideNotice, {
 		function formatVerification(showCommands, hideNotice, {
 			configid,
 			configid,
-			channel = '|' + msg.channel.id + '|',
+			channel = '|' + ( msg.channel.isThread() ? msg.channel.parentId : msg.channelId ) + '|',
 			role = '',
 			role = '',
 			editcount = 0,
 			editcount = 0,
 			postcount = 0,
 			postcount = 0,
@@ -308,7 +291,7 @@ function cmd_verification(lang, msg, args, line, wiki) {
 			if ( showCommands ) verification_text += '\n`' + prefix + 'verification ' + row.configid + ' accountage ' + lang.get('verification.new_accountage') + '`\n';
 			if ( showCommands ) verification_text += '\n`' + prefix + 'verification ' + row.configid + ' accountage ' + lang.get('verification.new_accountage') + '`\n';
 			verification_text += '\n' + lang.get('verification.rename') + ' *`' + lang.get('verification.' + ( rename ? 'enabled' : 'disabled')) + '`*';
 			verification_text += '\n' + lang.get('verification.rename') + ' *`' + lang.get('verification.' + ( rename ? 'enabled' : 'disabled')) + '`*';
 			if ( showCommands ) verification_text += ' ' + lang.get('verification.toggle') + '\n`' + prefix + 'verification ' + row.configid + ' rename`\n';
 			if ( showCommands ) verification_text += ' ' + lang.get('verification.toggle') + '\n`' + prefix + 'verification ' + row.configid + ' rename`\n';
-			if ( !hideNotice && rename && !msg.guild.me.permissions.has('MANAGE_NICKNAMES') ) {
+			if ( !hideNotice && rename && !msg.guild.me.permissions.has(FLAGS.MANAGE_NICKNAMES) ) {
 				verification_text += '\n\n' + lang.get('verification.rename_no_permission', msg.guild.me.toString());
 				verification_text += '\n\n' + lang.get('verification.rename_no_permission', msg.guild.me.toString());
 			}
 			}
 			if ( !hideNotice && role.replace( /-/g, '' ).split('|').some( role => {
 			if ( !hideNotice && role.replace( /-/g, '' ).split('|').some( role => {

+ 68 - 87
cmds/verify.js

@@ -1,5 +1,5 @@
 const {randomBytes} = require('crypto');
 const {randomBytes} = require('crypto');
-const {MessageEmbed} = require('discord.js');
+const {MessageEmbed, MessageActionRow, MessageButton, Permissions: {FLAGS}} = require('discord.js');
 var db = require('../util/database.js');
 var db = require('../util/database.js');
 var verify = require('../functions/verify.js');
 var verify = require('../functions/verify.js');
 const {got, oauthVerify, allowDelete, escapeFormatting} = require('../util/functions.js');
 const {got, oauthVerify, allowDelete, escapeFormatting} = require('../util/functions.js');
@@ -14,19 +14,19 @@ const {got, oauthVerify, allowDelete, escapeFormatting} = require('../util/funct
  */
  */
 function cmd_verify(lang, msg, args, line, wiki) {
 function cmd_verify(lang, msg, args, line, wiki) {
 	if ( !msg.channel.isGuild() || msg.defaultSettings ) return this.LINK(lang, msg, line, wiki);
 	if ( !msg.channel.isGuild() || msg.defaultSettings ) return this.LINK(lang, msg, line, wiki);
-	if ( !msg.guild.me.permissions.has('MANAGE_ROLES') ) {
+	if ( !msg.guild.me.permissions.has(FLAGS.MANAGE_ROLES) ) {
 		if ( msg.isAdmin() ) {
 		if ( msg.isAdmin() ) {
-			console.log( msg.guild.id + ': Missing permissions - MANAGE_ROLES' );
+			console.log( msg.guildId + ': Missing permissions - MANAGE_ROLES' );
 			msg.replyMsg( lang.get('general.missingperm') + ' `MANAGE_ROLES`' );
 			msg.replyMsg( lang.get('general.missingperm') + ' `MANAGE_ROLES`' );
 		}
 		}
 		else if ( !msg.onlyVerifyCommand ) this.LINK(lang, msg, line, wiki);
 		else if ( !msg.onlyVerifyCommand ) this.LINK(lang, msg, line, wiki);
 		return;
 		return;
 	}
 	}
 	
 	
-	db.query( 'SELECT logchannel, flags, onsuccess, onmatch, role, editcount, postcount, usergroup, accountage, rename FROM verification LEFT JOIN verifynotice ON verification.guild = verifynotice.guild WHERE verification.guild = $1 AND channel LIKE $2 ORDER BY configid ASC', [msg.guild.id, '%|' + msg.channel.id + '|%'] ).then( ({rows}) => {
+	db.query( 'SELECT logchannel, flags, onsuccess, onmatch, role, editcount, postcount, usergroup, accountage, rename FROM verification LEFT JOIN verifynotice ON verification.guild = verifynotice.guild WHERE verification.guild = $1 AND channel LIKE $2 ORDER BY configid ASC', [msg.guildId, '%|' + ( msg.channel.isThread() ? msg.channel.parentId : msg.channelId ) + '|%'] ).then( ({rows}) => {
 		if ( !rows.length ) {
 		if ( !rows.length ) {
 			if ( msg.onlyVerifyCommand ) return;
 			if ( msg.onlyVerifyCommand ) return;
-			return msg.replyMsg( lang.get('verify.missing') + ( msg.isAdmin() ? '\n`' + ( patreons[msg.guild.id] || process.env.prefix ) + 'verification`' : '' ) );
+			return msg.replyMsg( lang.get('verify.missing') + ( msg.isAdmin() ? '\n`' + ( patreons[msg.guildId] || process.env.prefix ) + 'verification`' : '' ) );
 		}
 		}
 		
 		
 		if ( wiki.hasOAuth2() && process.env.dashboard ) {
 		if ( wiki.hasOAuth2() && process.env.dashboard ) {
@@ -54,10 +54,11 @@ function cmd_verify(lang, msg, args, line, wiki) {
 							console.log( '- Dashboard: Error while updating the OAuth2 token for ' + msg.author.id + ': ' + dberror );
 							console.log( '- Dashboard: Error while updating the OAuth2 token for ' + msg.author.id + ': ' + dberror );
 						} );
 						} );
 						return global.verifyOauthUser('', body.access_token, {
 						return global.verifyOauthUser('', body.access_token, {
-							wiki: wiki.href,
-							channel: msg.channel,
-							user: msg.author.id,
-							sourceMessage: msg
+							wiki: wiki.href, channel: msg.channel,
+							user: msg.author.id, sourceMessage: msg,
+							fail: () => msg.replyMsg( lang.get('verify.error_reply'), false, false ).then( message => {
+								if ( message ) message.reactEmoji('error');
+							} )
 						});
 						});
 					}, error => {
 					}, error => {
 						console.log( '- Error while refreshing the mediawiki token: ' + error );
 						console.log( '- Error while refreshing the mediawiki token: ' + error );
@@ -76,9 +77,9 @@ function cmd_verify(lang, msg, args, line, wiki) {
 							console.log( '- Dashboard: Error while deleting the OAuth2 token for ' + msg.author.id + ': ' + dberror );
 							console.log( '- Dashboard: Error while deleting the OAuth2 token for ' + msg.author.id + ': ' + dberror );
 						} );
 						} );
 					}
 					}
-					let state = `${oauth[0]} ${global.shardId}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( oauth[1] ? ` ${oauth[1]}` : '' );
+					let state = `${oauth[0]} ${process.env.SHARDS}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( oauth[1] ? ` ${oauth[1]}` : '' );
 					while ( oauthVerify.has(state) ) {
 					while ( oauthVerify.has(state) ) {
-						state = `${oauth[0]} ${global.shardId}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( oauth[1] ? ` ${oauth[1]}` : '' );
+						state = `${oauth[0]} ${process.env.SHARDS}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( oauth[1] ? ` ${oauth[1]}` : '' );
 					}
 					}
 					oauthVerify.set(state, {
 					oauthVerify.set(state, {
 						state, wiki: wiki.href,
 						state, wiki: wiki.href,
@@ -90,26 +91,15 @@ function cmd_verify(lang, msg, args, line, wiki) {
 						response_type: 'code', redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
 						response_type: 'code', redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
 						client_id: process.env['oauth_' + ( oauth[1] || oauth[0] )], state
 						client_id: process.env['oauth_' + ( oauth[1] || oauth[0] )], state
 					}).toString();
 					}).toString();
-					return msg.member.send( lang.get('verify.oauth_message_dm', escapeFormatting(msg.guild.name)) + '\n<' + oauthURL + '>', {
-						components: [
-							{
-								type: 1,
-								components: [
-									{
-										type: 2,
-										style: 5,
-										label: lang.get('verify.oauth_button'),
-										emoji: {id: null, name: '🔗'},
-										url: oauthURL,
-										disabled: false
-									}
-								]
-							}
-						]
+					return msg.member.send( {
+						content: lang.get('verify.oauth_message_dm', escapeFormatting(msg.guild.name)) + '\n<' + oauthURL + '>',
+						components: [new MessageActionRow().addComponents(
+							new MessageButton().setLabel(lang.get('verify.oauth_button')).setEmoji('🔗').setStyle('LINK').setURL(oauthURL)
+						)]
 					} ).then( message => {
 					} ).then( message => {
 						msg.reactEmoji('📩');
 						msg.reactEmoji('📩');
 						allowDelete(message, msg.author.id);
 						allowDelete(message, msg.author.id);
-						msg.delete({timeout: 60000, reason: lang.get('verify.footer')}).catch(log_error);
+						setTimeout( () => msg.delete().catch(log_error), 60000 ).unref();
 					}, error => {
 					}, error => {
 						if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
 						if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
 							return msg.replyMsg( lang.get('verify.oauth_private') );
 							return msg.replyMsg( lang.get('verify.oauth_private') );
@@ -155,10 +145,11 @@ function cmd_verify(lang, msg, args, line, wiki) {
 								console.log( '- Dashboard: Error while updating the OAuth2 token for ' + msg.author.id + ': ' + dberror );
 								console.log( '- Dashboard: Error while updating the OAuth2 token for ' + msg.author.id + ': ' + dberror );
 							} );
 							} );
 							return global.verifyOauthUser('', body.access_token, {
 							return global.verifyOauthUser('', body.access_token, {
-								wiki: wiki.href,
-								channel: msg.channel,
-								user: msg.author.id,
-								sourceMessage: msg
+								wiki: wiki.href, channel: msg.channel,
+								user: msg.author.id, sourceMessage: msg,
+								fail: () => msg.replyMsg( lang.get('verify.error_reply'), false, false ).then( message => {
+									if ( message ) message.reactEmoji('error');
+								} )
 							});
 							});
 						}, error => {
 						}, error => {
 							console.log( '- Error while refreshing the mediawiki token: ' + error );
 							console.log( '- Error while refreshing the mediawiki token: ' + error );
@@ -177,9 +168,9 @@ function cmd_verify(lang, msg, args, line, wiki) {
 								console.log( '- Dashboard: Error while deleting the OAuth2 token for ' + msg.author.id + ': ' + dberror );
 								console.log( '- Dashboard: Error while deleting the OAuth2 token for ' + msg.author.id + ': ' + dberror );
 							} );
 							} );
 						}
 						}
-						let state = `${result.oauth[0]} ${global.shardId}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( result.oauth[1] ? ` ${result.oauth[1]}` : '' );
+						let state = `${result.oauth[0]} ${process.env.SHARDS}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( result.oauth[1] ? ` ${result.oauth[1]}` : '' );
 						while ( oauthVerify.has(state) ) {
 						while ( oauthVerify.has(state) ) {
-							state = `${result.oauth[0]} ${global.shardId}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( result.oauth[1] ? ` ${result.oauth[1]}` : '' );
+							state = `${result.oauth[0]} ${process.env.SHARDS}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( result.oauth[1] ? ` ${result.oauth[1]}` : '' );
 						}
 						}
 						oauthVerify.set(state, {
 						oauthVerify.set(state, {
 							state, wiki: wiki.href,
 							state, wiki: wiki.href,
@@ -191,26 +182,15 @@ function cmd_verify(lang, msg, args, line, wiki) {
 							response_type: 'code', redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
 							response_type: 'code', redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
 							client_id: process.env['oauth_' + ( result.oauth[1] || result.oauth[0] )], state
 							client_id: process.env['oauth_' + ( result.oauth[1] || result.oauth[0] )], state
 						}).toString();
 						}).toString();
-						msg.member.send( lang.get('verify.oauth_message_dm', escapeFormatting(msg.guild.name)) + '\n<' + oauthURL + '>', {
-							components: [
-								{
-									type: 1,
-									components: [
-										{
-											type: 2,
-											style: 5,
-											label: lang.get('verify.oauth_button'),
-											emoji: {id: null, name: '🔗'},
-											url: oauthURL,
-											disabled: false
-										}
-									]
-								}
-							]
+						msg.member.send( {
+							content: lang.get('verify.oauth_message_dm', escapeFormatting(msg.guild.name)) + '\n<' + oauthURL + '>',
+							components: [new MessageActionRow().addComponents(
+								new MessageButton().setLabel(lang.get('verify.oauth_button')).setEmoji('🔗').setStyle('LINK').setURL(oauthURL)
+							)]
 						} ).then( message => {
 						} ).then( message => {
 							msg.reactEmoji('📩');
 							msg.reactEmoji('📩');
 							allowDelete(message, msg.author.id);
 							allowDelete(message, msg.author.id);
-							msg.delete({timeout: 60000, reason: lang.get('verify.footer')}).catch(log_error);
+							setTimeout( () => msg.delete().catch(log_error), 60000 ).unref();
 						}, error => {
 						}, error => {
 							if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
 							if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
 								return msg.replyMsg( lang.get('verify.oauth_private') );
 								return msg.replyMsg( lang.get('verify.oauth_private') );
@@ -222,69 +202,70 @@ function cmd_verify(lang, msg, args, line, wiki) {
 				}
 				}
 				else if ( result.reaction ) msg.reactEmoji(result.reaction);
 				else if ( result.reaction ) msg.reactEmoji(result.reaction);
 				else {
 				else {
-					var options = {embed: result.embed, components: []};
-					if ( result.add_button ) options.components.push({
-						type: 1,
-						components: [
-							{
-								type: 2,
-								style: 1,
-								label: lang.get('verify.button_again'),
-								emoji: {id: null, name: '🔂'},
-								custom_id: 'verify_again',
-								disabled: false
-							}
-						]
-					});
+					var options = {
+						content: msg.member.toString() + ', ' + result.content,
+						embeds: [result.embed],
+						components: [],
+						allowedMentions: {
+							users: [msg.author.id],
+							repliedUser: true
+						}
+					};
+					if ( result.add_button ) options.components.push(new MessageActionRow().addComponents(
+						new MessageButton().setLabel(lang.get('verify.button_again')).setEmoji('🔂').setStyle('PRIMARY').setCustomId('verify_again')
+					));
 					if ( result.send_private ) {
 					if ( result.send_private ) {
-						let dmEmbed = new MessageEmbed(options.embed);
-						dmEmbed.fields.forEach( field => {
-							field.value = field.value.replace( /<@&(\d+)>/g, (mention, id) => {
-								if ( !msg.guild.roles.cache.has(id) ) return mention;
-								return escapeFormatting('@' + msg.guild.roles.cache.get(id)?.name);
+						let dmEmbeds = [new MessageEmbed(result.embed)];
+						if ( options.embeds[0] ) {
+							dmEmbeds.push(new MessageEmbed(options.embeds[0]));
+							dmEmbeds[0].fields.forEach( field => {
+								field.value = field.value.replace( /<@&(\d+)>/g, (mention, id) => {
+									if ( !msg.guild.roles.cache.has(id) ) return mention;
+									return escapeFormatting('@' + msg.guild.roles.cache.get(id)?.name);
+								} );
 							} );
 							} );
-						} );
-						msg.member.send( msg.channel.toString() + '; ' + result.content, {embed: dmEmbed, components: []} ).then( message => {
+						}
+						msg.member.send( {content: msg.channel.toString() + '; ' + result.content, embeds: dmEmbeds, components: []} ).then( message => {
 							msg.reactEmoji('📩');
 							msg.reactEmoji('📩');
 							allowDelete(message, msg.author.id);
 							allowDelete(message, msg.author.id);
-							msg.delete({timeout: 60000, reason: lang.get('verify.footer')}).catch(log_error);
+							setTimeout( () => msg.delete().catch(log_error), 60000 ).unref();
 						}, error => {
 						}, error => {
 							if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
 							if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
-								return msg.replyMsg( result.content, options, false, false );
+								return msg.replyMsg( options, false, false );
 							}
 							}
 							log_error(error);
 							log_error(error);
 							msg.reactEmoji('error');
 							msg.reactEmoji('error');
 						} );
 						} );
 						if ( result.logging.channel && msg.guild.channels.cache.has(result.logging.channel) ) {
 						if ( result.logging.channel && msg.guild.channels.cache.has(result.logging.channel) ) {
-							msg.guild.channels.cache.get(result.logging.channel).send(result.logging.content, {
-								embed: result.logging.embed,
-								allowedMentions: {parse: []}
-							}).catch(log_error);
+							msg.guild.channels.cache.get(result.logging.channel).send( {
+								content: result.logging.content,
+								embeds: [result.logging.embed]
+							} ).catch(log_error);
 						}
 						}
 					}
 					}
-					else msg.replyMsg( result.content, options, false, false ).then( message => {
+					else msg.replyMsg( options, false, false ).then( message => {
 						if ( !result.logging.channel || !msg.guild.channels.cache.has(result.logging.channel) ) return;
 						if ( !result.logging.channel || !msg.guild.channels.cache.has(result.logging.channel) ) return;
 						if ( message ) {
 						if ( message ) {
-							if ( result.logging.embed ) result.logging.embed.addField(message.url, '<#' + msg.channel.id + '>');
-							else result.logging.content += '\n<#' + msg.channel.id + '> – <' + message.url + '>';
+							if ( result.logging.embed ) result.logging.embed.addField(message.url, '<#' + msg.channelId + '>');
+							else result.logging.content += '\n<#' + msg.channelId + '> – <' + message.url + '>';
 						}
 						}
-						msg.guild.channels.cache.get(result.logging.channel).send(result.logging.content, {
-							embed: result.logging.embed,
-							allowedMentions: {parse: []}
-						}).catch(log_error);
+						msg.guild.channels.cache.get(result.logging.channel).send( {
+							content: result.logging.content,
+							embeds: [result.logging.embed]
+						} ).catch(log_error);
 					} );
 					} );
 				}
 				}
 				if ( reaction ) reaction.removeEmoji();
 				if ( reaction ) reaction.removeEmoji();
 			}, error => {
 			}, error => {
 				console.log( '- Error during the verifications: ' + error );
 				console.log( '- Error during the verifications: ' + error );
-				msg.replyMsg( lang.get('verify.error_reply'), {}, false, false ).then( message => {
+				msg.replyMsg( lang.get('verify.error_reply'), false, false ).then( message => {
 					if ( message ) message.reactEmoji('error');
 					if ( message ) message.reactEmoji('error');
 				} );
 				} );
 			} );
 			} );
 		} );
 		} );
 	}, dberror => {
 	}, dberror => {
 		console.log( '- Error while getting the verifications: ' + dberror );
 		console.log( '- Error while getting the verifications: ' + dberror );
-		msg.replyMsg( lang.get('verify.error_reply'), {}, false, false ).then( message => {
+		msg.replyMsg( lang.get('verify.error_reply'), false, false ).then( message => {
 			if ( message ) message.reactEmoji('error');
 			if ( message ) message.reactEmoji('error');
 		} );
 		} );
 	} );
 	} );

+ 13 - 13
cmds/voice.js

@@ -13,37 +13,37 @@ function cmd_voice(lang, msg, args, line, wiki) {
 	if ( msg.isAdmin() ) {
 	if ( msg.isAdmin() ) {
 		if ( !args.join('') ) {
 		if ( !args.join('') ) {
 			var text = lang.get('voice.text') + '\n`' + lang.get('voice.channel') + ' – <' + lang.get('voice.name') + '>`\n';
 			var text = lang.get('voice.text') + '\n`' + lang.get('voice.channel') + ' – <' + lang.get('voice.name') + '>`\n';
-			text += lang.get('voice.' + ( voice[msg.guild.id] ? 'disable' : 'enable' ), ( patreons[msg.guild.id] || process.env.prefix ) + 'voice toggle');
-			return msg.replyMsg( text, {}, true );
+			text += lang.get('voice.' + ( voice[msg.guildId] ? 'disable' : 'enable' ), ( patreons[msg.guildId] || process.env.prefix ) + 'voice toggle');
+			return msg.replyMsg( text, true );
 		}
 		}
 		args[1] = args.slice(1).join(' ').trim()
 		args[1] = args.slice(1).join(' ').trim()
 		if ( args[0].toLowerCase() === 'toggle' && !args[1] ) {
 		if ( args[0].toLowerCase() === 'toggle' && !args[1] ) {
 			if ( msg.defaultSettings ) return help_setup(lang, msg);
 			if ( msg.defaultSettings ) return help_setup(lang, msg);
-			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, {}, true );
-			var value = ( voice[msg.guild.id] ? null : 1 );
-			return db.query( 'UPDATE discord SET voice = $1 WHERE guild = $2 AND channel IS NULL', [value, msg.guild.id] ).then( () => {
+			if ( process.env.READONLY ) return msg.replyMsg( lang.get('general.readonly') + '\n' + process.env.invite, true );
+			var value = ( voice[msg.guildId] ? null : 1 );
+			return db.query( 'UPDATE discord SET voice = $1 WHERE guild = $2 AND channel IS NULL', [value, msg.guildId] ).then( () => {
 				console.log( '- Voice settings successfully updated.' );
 				console.log( '- Voice settings successfully updated.' );
 				if ( value ) {
 				if ( value ) {
-					voice[msg.guild.id] = lang.lang;
-					db.query( 'SELECT lang FROM discord WHERE guild = $1 AND channel IS NULL', [msg.guild.id] ).then( ({rows:[row]}) => {
+					voice[msg.guildId] = lang.lang;
+					db.query( 'SELECT lang FROM discord WHERE guild = $1 AND channel IS NULL', [msg.guildId] ).then( ({rows:[row]}) => {
 						console.log( '- Voice language successfully updated.' );
 						console.log( '- Voice language successfully updated.' );
-						voice[msg.guild.id] = row.lang;
+						voice[msg.guildId] = row.lang;
 					}, dberror => {
 					}, dberror => {
 						console.log( '- Error while getting the voice language: ' + dberror );
 						console.log( '- Error while getting the voice language: ' + dberror );
 					} );
 					} );
-					msg.replyMsg( lang.get('voice.enabled') + '\n`' + lang.get('voice.channel') + ' – <' + lang.get('voice.name') + '>`', {}, true );
+					msg.replyMsg( lang.get('voice.enabled') + '\n`' + lang.get('voice.channel') + ' – <' + lang.get('voice.name') + '>`', true );
 				}
 				}
 				else {
 				else {
-					delete voice[msg.guild.id];
-					msg.replyMsg( lang.get('voice.disabled'), {}, true );
+					delete voice[msg.guildId];
+					msg.replyMsg( lang.get('voice.disabled'), true );
 				}
 				}
 			}, dberror => {
 			}, dberror => {
 				console.log( '- Error while editing the voice settings: ' + dberror );
 				console.log( '- Error while editing the voice settings: ' + dberror );
-				msg.replyMsg( lang.get('settings.save_failed'), {}, true );
+				msg.replyMsg( lang.get('settings.save_failed'), true );
 			} );
 			} );
 		}
 		}
 	}
 	}
-	if ( !msg.channel.isGuild() || !pause[msg.guild.id] ) this.LINK(lang, msg, line, wiki);
+	if ( !msg.channel.isGuild() || !pause[msg.guildId] ) this.LINK(lang, msg, line, wiki);
 }
 }
 
 
 module.exports = {
 module.exports = {

+ 6 - 6
cmds/wiki/diff.js

@@ -82,7 +82,7 @@ function gamepedia_diff(lang, msg, args, wiki, reaction, spoiler, noEmbed, embed
 						msg.reactEmoji('nowiki');
 						msg.reactEmoji('nowiki');
 					}
 					}
 					else if ( noerror ) {
 					else if ( noerror ) {
-						msg.replyMsg( lang.get('diff.badrev') );
+						msg.replyMsg( {content: lang.get('diff.badrev'), allowedMentions: {repliedUser: false}} );
 					}
 					}
 					else {
 					else {
 						console.log( '- ' + response.statusCode + ': Error while getting the search results: ' + ( body && body.error && body.error.info ) );
 						console.log( '- ' + response.statusCode + ': Error while getting the search results: ' + ( body && body.error && body.error.info ) );
@@ -130,7 +130,7 @@ function gamepedia_diff(lang, msg, args, wiki, reaction, spoiler, noEmbed, embed
 		}
 		}
 	}
 	}
 	else {
 	else {
-		if ( embed ) msg.sendChannel( spoiler + '<' + embed.url + '>' + spoiler, ( noEmbed ? {} : {embed} ) );
+		if ( embed ) msg.sendChannel( {content: spoiler + '<' + embed.url + '>' + spoiler, embeds: ( noEmbed ? [] : [embed] )} );
 		else msg.reactEmoji('error');
 		else msg.reactEmoji('error');
 		
 		
 		if ( reaction ) reaction.removeEmoji();
 		if ( reaction ) reaction.removeEmoji();
@@ -165,13 +165,13 @@ function gamepedia_diff_send(lang, msg, args, wiki, reaction, spoiler, noEmbed,
 			if ( reaction ) reaction.removeEmoji();
 			if ( reaction ) reaction.removeEmoji();
 		}
 		}
 		else if ( body.query.badrevids ) {
 		else if ( body.query.badrevids ) {
-			msg.replyMsg( lang.get('diff.badrev') );
+			msg.replyMsg( {content: lang.get('diff.badrev'), allowedMentions: {repliedUser: false}} );
 			
 			
 			if ( reaction ) reaction.removeEmoji();
 			if ( reaction ) reaction.removeEmoji();
 		}
 		}
 		else if ( body.query.pages && !body.query.pages['-1'] ) {
 		else if ( body.query.pages && !body.query.pages['-1'] ) {
 			wiki.updateWiki(body.query.general);
 			wiki.updateWiki(body.query.general);
-			logging(wiki, msg.guild?.id, 'diff');
+			logging(wiki, msg.guildId, 'diff');
 			var pages = Object.values(body.query.pages);
 			var pages = Object.values(body.query.pages);
 			if ( pages.length !== 1 ) {
 			if ( pages.length !== 1 ) {
 				msg.sendChannel( spoiler + '<' + wiki.toLink('Special:Diff/' + ( args[1] ? args[1] + '/' : '' ) + args[0]) + '>' + spoiler );
 				msg.sendChannel( spoiler + '<' + wiki.toLink('Special:Diff/' + ( args[1] ? args[1] + '/' : '' ) + args[0]) + '>' + spoiler );
@@ -246,7 +246,7 @@ function gamepedia_diff_send(lang, msg, args, wiki, reaction, spoiler, noEmbed,
 					console.log( '- Error while getting the diff: ' + error );
 					console.log( '- Error while getting the diff: ' + error );
 				} ).finally( () => {
 				} ).finally( () => {
 					if ( tags?.[1] ) embed.addField( tags[0], htmlToDiscord(tags[1], pagelink) );
 					if ( tags?.[1] ) embed.addField( tags[0], htmlToDiscord(tags[1], pagelink) );
-					msg.sendChannel( spoiler + text + spoiler, {embed} );
+					msg.sendChannel( {content: spoiler + text + spoiler, embeds: [embed]} );
 					
 					
 					if ( reaction ) reaction.removeEmoji();
 					if ( reaction ) reaction.removeEmoji();
 				} );
 				} );
@@ -268,7 +268,7 @@ function gamepedia_diff_send(lang, msg, args, wiki, reaction, spoiler, noEmbed,
 					}
 					}
 					if ( tags?.[1] ) embed.addField( tags[0], htmlToDiscord(tags[1], pagelink) );
 					if ( tags?.[1] ) embed.addField( tags[0], htmlToDiscord(tags[1], pagelink) );
 					
 					
-					msg.sendChannel( spoiler + text + spoiler, {embed} );
+					msg.sendChannel( {content: spoiler + text + spoiler, embeds: [embed]} );
 					
 					
 					if ( reaction ) reaction.removeEmoji();
 					if ( reaction ) reaction.removeEmoji();
 				}
 				}

+ 16 - 20
cmds/wiki/general.js

@@ -108,15 +108,15 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 		}
 		}
 		wiki.updateWiki(body.query.general);
 		wiki.updateWiki(body.query.general);
 		if ( aliasInvoke === 'search' ) {
 		if ( aliasInvoke === 'search' ) {
-			logging(wiki, msg.guild?.id, 'search');
+			logging(wiki, msg.guildId, 'search');
 			return fn.search(lang, msg, full_title.split(' ').slice(1).join(' '), wiki, body.query, reaction, spoiler, noEmbed);
 			return fn.search(lang, msg, full_title.split(' ').slice(1).join(' '), wiki, body.query, reaction, spoiler, noEmbed);
 		}
 		}
 		if ( aliasInvoke === 'discussion' && wiki.isFandom(false) && !querystring.toString() && !fragment ) {
 		if ( aliasInvoke === 'discussion' && wiki.isFandom(false) && !querystring.toString() && !fragment ) {
-			logging(wiki, msg.guild?.id, 'discussion');
+			logging(wiki, msg.guildId, 'discussion');
 			return fn.discussion(lang, msg, wiki, args.join(' '), body.query.general.sitename, reaction, spoiler, noEmbed);
 			return fn.discussion(lang, msg, wiki, args.join(' '), body.query.general.sitename, reaction, spoiler, noEmbed);
 		}
 		}
 		if ( !msg.notMinecraft && mcw.hasOwnProperty(wiki.href) && ( minecraft.hasOwnProperty(aliasInvoke) || invoke.startsWith( '/' ) ) && !querystring.toString() && !fragment ) {
 		if ( !msg.notMinecraft && mcw.hasOwnProperty(wiki.href) && ( minecraft.hasOwnProperty(aliasInvoke) || invoke.startsWith( '/' ) ) && !querystring.toString() && !fragment ) {
-			logging(wiki, msg.guild?.id, 'minecraft', ( minecraft.hasOwnProperty(aliasInvoke) ? aliasInvoke : 'command' ));
+			logging(wiki, msg.guildId, 'minecraft', ( minecraft.hasOwnProperty(aliasInvoke) ? aliasInvoke : 'command' ));
 			minecraft.WIKI = this;
 			minecraft.WIKI = this;
 			if ( minecraft.hasOwnProperty(aliasInvoke) ) minecraft[aliasInvoke](lang, msg, wiki, args, title, cmd, reaction, spoiler, noEmbed);
 			if ( minecraft.hasOwnProperty(aliasInvoke) ) minecraft[aliasInvoke](lang, msg, wiki, args, title, cmd, reaction, spoiler, noEmbed);
 			else minecraft.SYNTAX(lang, msg, wiki, invoke.substring(1), args, title, cmd, reaction, spoiler, noEmbed);
 			else minecraft.SYNTAX(lang, msg, wiki, invoke.substring(1), args, title, cmd, reaction, spoiler, noEmbed);
@@ -183,11 +183,11 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 				} );
 				} );
 			}
 			}
 			if ( wiki.isMiraheze() && querypage.ns === 0 && /^Mh:[a-z\d]+:/.test(querypage.title) ) {
 			if ( wiki.isMiraheze() && querypage.ns === 0 && /^Mh:[a-z\d]+:/.test(querypage.title) ) {
-				logging(wiki, msg.guild?.id, 'interwiki', 'miraheze');
+				logging(wiki, msg.guildId, 'interwiki', 'miraheze');
 				var iw_parts = querypage.title.split(':');
 				var iw_parts = querypage.title.split(':');
 				var iw = new Wiki('https://' + iw_parts[1] + '.miraheze.org/w/');
 				var iw = new Wiki('https://' + iw_parts[1] + '.miraheze.org/w/');
 				var iw_link = iw.toLink(iw_parts.slice(2).join(':'), querystring, fragment);
 				var iw_link = iw.toLink(iw_parts.slice(2).join(':'), querystring, fragment);
-				var maxselfcall = interwikiLimit[( patreons[msg.guild?.id] ? 'patreon' : 'default' )];
+				var maxselfcall = interwikiLimit[( patreons[msg.guildId] ? 'patreon' : 'default' )];
 				if ( selfcall < maxselfcall ) {
 				if ( selfcall < maxselfcall ) {
 					selfcall++;
 					selfcall++;
 					return this.general(lang, msg, iw_parts.slice(2).join(':'), iw, '!!' + iw.hostname + ' ', reaction, spoiler, noEmbed, querystring, fragment, iw_link, selfcall);
 					return this.general(lang, msg, iw_parts.slice(2).join(':'), iw, '!!' + iw.hostname + ' ', reaction, spoiler, noEmbed, querystring, fragment, iw_link, selfcall);
@@ -199,7 +199,7 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 				return;
 				return;
 			}
 			}
 			if ( ( querypage.missing !== undefined && querypage.known === undefined && !( noRedirect || querypage.categoryinfo ) ) || querypage.invalid !== undefined ) return got.get( wiki + 'api.php?uselang=' + uselang + '&action=query&prop=categoryinfo|info|pageprops|pageimages|extracts&piprop=original|name&ppprop=description|displaytitle|page_image_free|disambiguation|infoboxes&explaintext=true&exsectionformat=raw&exlimit=1&generator=search&gsrnamespace=4|12|14|' + ( querypage.ns >= 0 ? querypage.ns + '|' : '' ) + Object.values(body.query.namespaces).filter( ns => ns.content !== undefined ).map( ns => ns.id ).join('|') + '&gsrlimit=1&gsrsearch=' + encodeURIComponent( title ) + '&format=json' ).then( srresponse => {
 			if ( ( querypage.missing !== undefined && querypage.known === undefined && !( noRedirect || querypage.categoryinfo ) ) || querypage.invalid !== undefined ) return got.get( wiki + 'api.php?uselang=' + uselang + '&action=query&prop=categoryinfo|info|pageprops|pageimages|extracts&piprop=original|name&ppprop=description|displaytitle|page_image_free|disambiguation|infoboxes&explaintext=true&exsectionformat=raw&exlimit=1&generator=search&gsrnamespace=4|12|14|' + ( querypage.ns >= 0 ? querypage.ns + '|' : '' ) + Object.values(body.query.namespaces).filter( ns => ns.content !== undefined ).map( ns => ns.id ).join('|') + '&gsrlimit=1&gsrsearch=' + encodeURIComponent( title ) + '&format=json' ).then( srresponse => {
-				logging(wiki, msg.guild?.id, 'general', 'search');
+				logging(wiki, msg.guildId, 'general', 'search');
 				var srbody = srresponse.body;
 				var srbody = srresponse.body;
 				if ( srbody?.warnings ) log_warn(srbody.warnings);
 				if ( srbody?.warnings ) log_warn(srbody.warnings);
 				if ( srresponse.statusCode !== 200 || !srbody || srbody.batchcomplete === undefined ) {
 				if ( srresponse.statusCode !== 200 || !srbody || srbody.batchcomplete === undefined ) {
@@ -215,7 +215,7 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 					} ).then( hresponse => {
 					} ).then( hresponse => {
 						if ( hresponse.statusCode === 301 && /^https:\/\/[a-z\d-]{1,50}\.fandom\.com\/(?:(?!wiki\/)[a-z-]{2,12}\/)?wiki\/Help:/.test( hresponse.headers?.location ) ) {
 						if ( hresponse.statusCode === 301 && /^https:\/\/[a-z\d-]{1,50}\.fandom\.com\/(?:(?!wiki\/)[a-z-]{2,12}\/)?wiki\/Help:/.test( hresponse.headers?.location ) ) {
 							var location = hresponse.headers.location.split('wiki/');
 							var location = hresponse.headers.location.split('wiki/');
-							var maxselfcall = interwikiLimit[( patreons[msg.guild?.id] ? 'patreon' : 'default' )];
+							var maxselfcall = interwikiLimit[( patreons[msg.guildId] ? 'patreon' : 'default' )];
 							if ( selfcall < maxselfcall ) {
 							if ( selfcall < maxselfcall ) {
 								selfcall++;
 								selfcall++;
 								return this.general(lang, msg, location.slice(1).join('wiki/'), new Wiki(location[0]), cmd, reaction, spoiler, noEmbed, querystring, fragment, '', selfcall);
 								return this.general(lang, msg, location.slice(1).join('wiki/'), new Wiki(location[0]), cmd, reaction, spoiler, noEmbed, querystring, fragment, '', selfcall);
@@ -286,9 +286,7 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 					if ( msg.showEmbed() && /\.(?:png|jpg|jpeg|gif)$/.test(querypage.title.toLowerCase()) ) embed.setImage( pageimage );
 					if ( msg.showEmbed() && /\.(?:png|jpg|jpeg|gif)$/.test(querypage.title.toLowerCase()) ) embed.setImage( pageimage );
 					else if ( querypage.title.toLowerCase().endsWith( '.svg' ) && querypage?.original?.width && msg.showEmbed() ) {
 					else if ( querypage.title.toLowerCase().endsWith( '.svg' ) && querypage?.original?.width && msg.showEmbed() ) {
 						embed.setImage( wiki.toLink('Special:FilePath/' + querypage.title, {width:querypage.original.width,version:Date.now()}) );
 						embed.setImage( wiki.toLink('Special:FilePath/' + querypage.title, {width:querypage.original.width,version:Date.now()}) );
-						if ( msg.uploadFiles() ) embed.attachFiles( [{attachment:pageimage,name:( spoiler ? 'SPOILER ' : '' ) + querypage.title}] );
 					}
 					}
-					else if ( msg.uploadFiles() ) embed.attachFiles( [{attachment:pageimage,name:( spoiler ? 'SPOILER ' : '' ) + querypage.title}] );
 				}
 				}
 				else if ( querypage.title === body.query.general.mainpage ) {
 				else if ( querypage.title === body.query.general.mainpage ) {
 					embed.setThumbnail( new URL(body.query.general.logo, wiki).href );
 					embed.setThumbnail( new URL(body.query.general.logo, wiki).href );
@@ -301,7 +299,7 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 				}
 				}
 				else embed.setThumbnail( new URL(body.query.general.logo, wiki).href );
 				else embed.setThumbnail( new URL(body.query.general.logo, wiki).href );
 				
 				
-				var prefix = ( msg.channel.isGuild() && patreons[msg.guild.id] || process.env.prefix );
+				var prefix = ( msg.channel.isGuild() && patreons[msg.guildId] || process.env.prefix );
 				var linksuffix = ( querystring.toString() ? '?' + querystring : '' ) + ( fragment ? '#' + fragment : '' );
 				var linksuffix = ( querystring.toString() ? '?' + querystring : '' ) + ( fragment ? '#' + fragment : '' );
 				if ( title.replace( /[_-]/g, ' ' ).toLowerCase() === querypage.title.replace( /-/g, ' ' ).toLowerCase() ) {
 				if ( title.replace( /[_-]/g, ' ' ).toLowerCase() === querypage.title.replace( /-/g, ' ' ).toLowerCase() ) {
 					text = '';
 					text = '';
@@ -333,7 +331,7 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 
 
 				return parse_page(lang, msg, spoiler + '<' + pagelink + '>' + text + spoiler, ( noEmbed ? null : embed ), wiki, reaction, querypage, ( querypage.title === body.query.general.mainpage ? '' : new URL(body.query.general.logo, wiki).href ), fragment, pagelink);
 				return parse_page(lang, msg, spoiler + '<' + pagelink + '>' + text + spoiler, ( noEmbed ? null : embed ), wiki, reaction, querypage, ( querypage.title === body.query.general.mainpage ? '' : new URL(body.query.general.logo, wiki).href ), fragment, pagelink);
 			}, error => {
 			}, error => {
-				logging(wiki, msg.guild?.id, 'general', 'search');
+				logging(wiki, msg.guildId, 'general', 'search');
 				console.log( '- Error while getting the search results: ' + error );
 				console.log( '- Error while getting the search results: ' + error );
 				msg.sendChannelError( spoiler + '<' + wiki.toLink('Special:Search', {search:title}) + '>' + spoiler );
 				msg.sendChannelError( spoiler + '<' + wiki.toLink('Special:Search', {search:title}) + '>' + spoiler );
 				
 				
@@ -347,22 +345,21 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 				}
 				}
 			}
 			}
 			if ( querypage.ns === -2 ) {
 			if ( querypage.ns === -2 ) {
-				logging(wiki, msg.guild?.id, 'general', 'media');
+				logging(wiki, msg.guildId, 'general', 'media');
 				var filepath = body.query.specialpagealiases.find( sp => sp.realname === 'Filepath' );
 				var filepath = body.query.specialpagealiases.find( sp => sp.realname === 'Filepath' );
 				var pagelink = wiki.toLink(body.query.namespaces['-1']['*'] + ':' + ( filepath?.aliases?.[0] || 'FilePath' ) + querypage.title.replace( body.query.namespaces['-2']['*'] + ':', '/' ), querystring, fragment);
 				var pagelink = wiki.toLink(body.query.namespaces['-1']['*'] + ':' + ( filepath?.aliases?.[0] || 'FilePath' ) + querypage.title.replace( body.query.namespaces['-2']['*'] + ':', '/' ), querystring, fragment);
 				var embed = null;
 				var embed = null;
 				if ( !noEmbed ) {
 				if ( !noEmbed ) {
 					embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( escapeFormatting(querypage.title) ).setURL( pagelink ).setDescription( '[' + lang.get('search.media') + '](' + wiki.toLink(querypage.title, '', '', true) + ')' );
 					embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( escapeFormatting(querypage.title) ).setURL( pagelink ).setDescription( '[' + lang.get('search.media') + '](' + wiki.toLink(querypage.title, '', '', true) + ')' );
 					if ( msg.showEmbed() && /\.(?:png|jpg|jpeg|gif)$/.test(querypage.title.toLowerCase()) ) embed.setImage( pagelink );
 					if ( msg.showEmbed() && /\.(?:png|jpg|jpeg|gif)$/.test(querypage.title.toLowerCase()) ) embed.setImage( pagelink );
-					else if ( msg.uploadFiles() ) embed.attachFiles( [{attachment:pagelink,name:( spoiler ? 'SPOILER ' : '' ) + querypage.title}] );
 				}
 				}
 				
 				
-				msg.sendChannel( spoiler + '<' + pagelink + '>' + spoiler, {embed} );
+				msg.sendChannel( {content: spoiler + '<' + pagelink + '>' + spoiler, embeds: [embed]} );
 				
 				
 				if ( reaction ) reaction.removeEmoji();
 				if ( reaction ) reaction.removeEmoji();
 				return;
 				return;
 			}
 			}
-			logging(wiki, msg.guild?.id, 'general');
+			logging(wiki, msg.guildId, 'general');
 			var pagelink = wiki.toLink(querypage.title, querystring, ( fragment || ( body.query.redirects && body.query.redirects[0].tofragment ) || '' ));
 			var pagelink = wiki.toLink(querypage.title, querystring, ( fragment || ( body.query.redirects && body.query.redirects[0].tofragment ) || '' ));
 			var text = '';
 			var text = '';
 			var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( escapeFormatting(querypage.title) ).setURL( pagelink );
 			var embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( escapeFormatting(querypage.title) ).setURL( pagelink );
@@ -386,7 +383,6 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 			if ( querypage.ns === 6 ) {
 			if ( querypage.ns === 6 ) {
 				var pageimage = ( querypage?.original?.source || wiki.toLink('Special:FilePath/' + querypage.title, {version:Date.now()}) );
 				var pageimage = ( querypage?.original?.source || wiki.toLink('Special:FilePath/' + querypage.title, {version:Date.now()}) );
 				if ( msg.showEmbed() && /\.(?:png|jpg|jpeg|gif)$/.test(querypage.title.toLowerCase()) ) embed.setImage( pageimage );
 				if ( msg.showEmbed() && /\.(?:png|jpg|jpeg|gif)$/.test(querypage.title.toLowerCase()) ) embed.setImage( pageimage );
-				else if ( msg.uploadFiles() ) embed.attachFiles( [{attachment:pageimage,name:( spoiler ? 'SPOILER ' : '' ) + querypage.title}] );
 			}
 			}
 			else if ( querypage.title === body.query.general.mainpage ) {
 			else if ( querypage.title === body.query.general.mainpage ) {
 				embed.setThumbnail( new URL(body.query.general.logo, wiki).href );
 				embed.setThumbnail( new URL(body.query.general.logo, wiki).href );
@@ -419,7 +415,7 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 			return parse_page(lang, msg, spoiler + '<' + pagelink + '>' + text + spoiler, ( noEmbed ? null : embed ), wiki, reaction, querypage, ( querypage.title === body.query.general.mainpage ? '' : new URL(body.query.general.logo, wiki).href ), ( fragment || ( body.query.redirects && body.query.redirects[0].tofragment ) || '' ), pagelink);
 			return parse_page(lang, msg, spoiler + '<' + pagelink + '>' + text + spoiler, ( noEmbed ? null : embed ), wiki, reaction, querypage, ( querypage.title === body.query.general.mainpage ? '' : new URL(body.query.general.logo, wiki).href ), ( fragment || ( body.query.redirects && body.query.redirects[0].tofragment ) || '' ), pagelink);
 		}
 		}
 		if ( body.query.interwiki ) {
 		if ( body.query.interwiki ) {
-			if ( msg.channel.isGuild() && pause[msg.guild.id] ) {
+			if ( msg.channel.isGuild() && pause[msg.guildId] ) {
 				if ( reaction ) reaction.removeEmoji();
 				if ( reaction ) reaction.removeEmoji();
 				console.log( '- Aborted, paused.' );
 				console.log( '- Aborted, paused.' );
 				return;
 				return;
@@ -433,8 +429,8 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 			if ( /^phabricator\.(wikimedia|miraheze)\.org$/.test(iw.hostname) ) {
 			if ( /^phabricator\.(wikimedia|miraheze)\.org$/.test(iw.hostname) ) {
 				return phabricator(lang, msg, wiki, iw, reaction, spoiler, noEmbed);
 				return phabricator(lang, msg, wiki, iw, reaction, spoiler, noEmbed);
 			}
 			}
-			logging(wiki, msg.guild?.id, 'interwiki');
-			var maxselfcall = interwikiLimit[( patreons[msg.guild?.id] ? 'patreon' : 'default' )];
+			logging(wiki, msg.guildId, 'interwiki');
+			var maxselfcall = interwikiLimit[( patreons[msg.guildId] ? 'patreon' : 'default' )];
 			if ( selfcall < maxselfcall && ['http:','https:'].includes( iw.protocol ) ) {
 			if ( selfcall < maxselfcall && ['http:','https:'].includes( iw.protocol ) ) {
 				selfcall++;
 				selfcall++;
 				if ( iw.hostname.endsWith( '.gamepedia.com' ) ) {
 				if ( iw.hostname.endsWith( '.gamepedia.com' ) ) {
@@ -467,7 +463,7 @@ function gamepedia_check_wiki(lang, msg, title, wiki, cmd, reaction, spoiler = '
 			if ( reaction ) reaction.removeEmoji();
 			if ( reaction ) reaction.removeEmoji();
 			return;
 			return;
 		}
 		}
-		logging(wiki, msg.guild?.id, 'general');
+		logging(wiki, msg.guildId, 'general');
 		var querypage = {
 		var querypage = {
 			title: body.query.general.mainpage,
 			title: body.query.general.mainpage,
 			contentmodel: 'wikitext',
 			contentmodel: 'wikitext',

+ 3 - 3
cmds/wiki/overview.js

@@ -33,7 +33,7 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler, noEmbed, queryst
 			return;
 			return;
 		}
 		}
 		wiki.updateWiki(body.query.general);
 		wiki.updateWiki(body.query.general);
-		logging(wiki, msg.guild?.id, 'overview');
+		logging(wiki, msg.guildId, 'overview');
 		var version = [lang.get('overview.version'), body.query.general.generator];
 		var version = [lang.get('overview.version'), body.query.general.generator];
 		var creation_date = null;
 		var creation_date = null;
 		var created = [lang.get('overview.created'), lang.get('overview.unknown'), ''];
 		var created = [lang.get('overview.created'), lang.get('overview.unknown'), ''];
@@ -234,7 +234,7 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler, noEmbed, queryst
 					text += '\n\n*' + lang.get('overview.inaccurate') + '*';
 					text += '\n\n*' + lang.get('overview.inaccurate') + '*';
 				}
 				}
 				
 				
-				msg.sendChannel( spoiler + text + spoiler, {embed} );
+				msg.sendChannel( {content: spoiler + text + spoiler, embeds: [embed]} );
 				
 				
 				if ( reaction ) reaction.removeEmoji();
 				if ( reaction ) reaction.removeEmoji();
 			} );
 			} );
@@ -253,7 +253,7 @@ function gamepedia_overview(lang, msg, wiki, reaction, spoiler, noEmbed, queryst
 			text += '\n\n*' + lang.get('overview.inaccurate') + '*';
 			text += '\n\n*' + lang.get('overview.inaccurate') + '*';
 		}
 		}
 		
 		
-		msg.sendChannel( spoiler + text + spoiler, {embed} );
+		msg.sendChannel( {content: spoiler + text + spoiler, embeds: [embed]} );
 		
 		
 		if ( reaction ) reaction.removeEmoji();
 		if ( reaction ) reaction.removeEmoji();
 	}, error => {
 	}, error => {

+ 2 - 3
cmds/wiki/random.js

@@ -34,7 +34,7 @@ function gamepedia_random(lang, msg, wiki, reaction, spoiler, noEmbed, namespace
 			return;
 			return;
 		}
 		}
 		wiki.updateWiki(body.query.general);
 		wiki.updateWiki(body.query.general);
-		logging(wiki, msg.guild?.id, 'random');
+		logging(wiki, msg.guildId, 'random');
 		if ( !body.query.pages ) {
 		if ( !body.query.pages ) {
 			var title = 'Special:Random';
 			var title = 'Special:Random';
 			if ( namespace[0] !== '0' && namespace[0].split('|').length === 1 ) title += '/' + namespace[1];
 			if ( namespace[0] !== '0' && namespace[0].split('|').length === 1 ) title += '/' + namespace[1];
@@ -53,7 +53,7 @@ function gamepedia_random(lang, msg, wiki, reaction, spoiler, noEmbed, namespace
 					embed.setDescription( description );
 					embed.setDescription( description );
 				}
 				}
 			}
 			}
-			msg.sendChannel( spoiler + '<' + pagelink + '>' + spoiler, {embed} );
+			msg.sendChannel( {content: spoiler + '<' + pagelink + '>' + spoiler, embeds: [embed]} );
 			
 			
 			if ( reaction ) reaction.removeEmoji();
 			if ( reaction ) reaction.removeEmoji();
 			return;
 			return;
@@ -82,7 +82,6 @@ function gamepedia_random(lang, msg, wiki, reaction, spoiler, noEmbed, namespace
 		if ( querypage.ns === 6 ) {
 		if ( querypage.ns === 6 ) {
 			var pageimage = ( querypage?.original?.source || wiki.toLink('Special:FilePath/' + querypage.title, {version:Date.now()}) );
 			var pageimage = ( querypage?.original?.source || wiki.toLink('Special:FilePath/' + querypage.title, {version:Date.now()}) );
 			if ( msg.showEmbed() && /\.(?:png|jpg|jpeg|gif)$/.test(querypage.title.toLowerCase()) ) embed.setImage( pageimage );
 			if ( msg.showEmbed() && /\.(?:png|jpg|jpeg|gif)$/.test(querypage.title.toLowerCase()) ) embed.setImage( pageimage );
-			else if ( msg.uploadFiles() ) embed.attachFiles( [{attachment:pageimage,name:( spoiler ? 'SPOILER ' : '' ) + querypage.title}] );
 		}
 		}
 		else if ( querypage.title === body.query.general.mainpage ) {
 		else if ( querypage.title === body.query.general.mainpage ) {
 			embed.setThumbnail( new URL(body.query.general.logo, wiki).href );
 			embed.setThumbnail( new URL(body.query.general.logo, wiki).href );

+ 2 - 2
cmds/wiki/search.js

@@ -25,7 +25,7 @@ function gamepedia_search(lang, msg, searchterm, wiki, query, reaction, spoiler,
 	if ( msg.showEmbed() && !noEmbed ) embed = new MessageEmbed().setAuthor( query.general.sitename ).setTitle( '`' + searchterm + '`' ).setURL( pagelink );
 	if ( msg.showEmbed() && !noEmbed ) embed = new MessageEmbed().setAuthor( query.general.sitename ).setTitle( '`' + searchterm + '`' ).setURL( pagelink );
 	else resultText += '\n\n**`' + searchterm + '`**';
 	else resultText += '\n\n**`' + searchterm + '`**';
 	var querypage = ( Object.values(( query.pages || {} ))?.[0] || {title:'',ns:0,invalid:''} );
 	var querypage = ( Object.values(( query.pages || {} ))?.[0] || {title:'',ns:0,invalid:''} );
-	var limit = searchLimit[( patreons[msg.guild?.id] ? 'patreon' : 'default' )];
+	var limit = searchLimit[( patreons[msg.guildId] ? 'patreon' : 'default' )];
 	got.get( wiki + 'api.php?action=query&titles=Special:Search&list=search&srinfo=totalhits&srprop=redirecttitle|sectiontitle&srnamespace=4|12|14|' + ( querypage.ns >= 0 ? querypage.ns + '|' : '' ) + Object.values(query.namespaces).filter( ns => ns.content !== undefined ).map( ns => ns.id ).join('|') + '&srlimit=' + limit + '&srsearch=' + encodeURIComponent( searchterm ) + '&format=json' ).then( response => {
 	got.get( wiki + 'api.php?action=query&titles=Special:Search&list=search&srinfo=totalhits&srprop=redirecttitle|sectiontitle&srnamespace=4|12|14|' + ( querypage.ns >= 0 ? querypage.ns + '|' : '' ) + Object.values(query.namespaces).filter( ns => ns.content !== undefined ).map( ns => ns.id ).join('|') + '&srlimit=' + limit + '&srsearch=' + encodeURIComponent( searchterm ) + '&format=json' ).then( response => {
 		var body = response.body;
 		var body = response.body;
 		if ( body?.warnings ) log_warn(body.warnings);
 		if ( body?.warnings ) log_warn(body.warnings);
@@ -144,7 +144,7 @@ function gamepedia_search(lang, msg, searchterm, wiki, query, reaction, spoiler,
 	}, error => {
 	}, error => {
 		console.log( '- Error while getting the search results.' + error );
 		console.log( '- Error while getting the search results.' + error );
 	} ).then( () => {
 	} ).then( () => {
-		msg.sendChannel( '🔍 ' + spoiler + resultText + spoiler, {embed} );
+		msg.sendChannel( {content: '🔍 ' + spoiler + resultText + spoiler, embeds: [embed]} );
 		
 		
 		if ( reaction ) reaction.removeEmoji();
 		if ( reaction ) reaction.removeEmoji();
 	} );
 	} );

+ 5 - 5
cmds/wiki/user.js

@@ -24,7 +24,7 @@ const {got, toMarkdown, toPlaintext, htmlToDiscord, escapeFormatting} = require(
  */
  */
 function gamepedia_user(lang, msg, namespace, username, wiki, querystring, fragment, querypage, contribs, reaction, spoiler, noEmbed) {
 function gamepedia_user(lang, msg, namespace, username, wiki, querystring, fragment, querypage, contribs, reaction, spoiler, noEmbed) {
 	if ( /^(?:(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{2})?|(?:[\dA-F]{1,4}:){7}[\dA-F]{1,4}(?:\/\d{2,3})?)$/.test(username) ) return got.get( wiki + 'api.php?action=query&meta=siteinfo&siprop=general&list=blocks&bkprop=user|by|timestamp|expiry|reason&bkip=' + encodeURIComponent( username ) + '&format=json' ).then( response => {
 	if ( /^(?:(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{2})?|(?:[\dA-F]{1,4}:){7}[\dA-F]{1,4}(?:\/\d{2,3})?)$/.test(username) ) return got.get( wiki + 'api.php?action=query&meta=siteinfo&siprop=general&list=blocks&bkprop=user|by|timestamp|expiry|reason&bkip=' + encodeURIComponent( username ) + '&format=json' ).then( response => {
-		logging(wiki, msg.guild?.id, 'user', 'ip');
+		logging(wiki, msg.guildId, 'user', 'ip');
 		var body = response.body;
 		var body = response.body;
 		if ( body && body.warnings ) log_warn(body.warnings);
 		if ( body && body.warnings ) log_warn(body.warnings);
 		if ( response.statusCode !== 200 || !body || body.batchcomplete === undefined || !body.query || !body.query.blocks || fragment ) {
 		if ( response.statusCode !== 200 || !body || body.batchcomplete === undefined || !body.query || !body.query.blocks || fragment ) {
@@ -215,7 +215,7 @@ function gamepedia_user(lang, msg, namespace, username, wiki, querystring, fragm
 				} );
 				} );
 			}
 			}
 			
 			
-			if ( msg.channel.isGuild() && patreons[msg.guild?.id] && wiki.isFandom() ) {
+			if ( msg.channel.isGuild() && patreons[msg.guildId] && wiki.isFandom() ) {
 				if ( msg.showEmbed() && !noEmbed ) embed.addField( '\u200b', '<a:loading:641343250661113886> **' + lang.get('user.info.loading') + '**' );
 				if ( msg.showEmbed() && !noEmbed ) embed.addField( '\u200b', '<a:loading:641343250661113886> **' + lang.get('user.info.loading') + '**' );
 				else text += '\n\n<a:loading:641343250661113886> **' + lang.get('user.info.loading') + '**';
 				else text += '\n\n<a:loading:641343250661113886> **' + lang.get('user.info.loading') + '**';
 
 
@@ -229,14 +229,14 @@ function gamepedia_user(lang, msg, namespace, username, wiki, querystring, fragm
 			if ( reaction ) reaction.removeEmoji();
 			if ( reaction ) reaction.removeEmoji();
 		} );
 		} );
 	}, error => {
 	}, error => {
-		logging(wiki, msg.guild?.id, 'user', 'ip');
+		logging(wiki, msg.guildId, 'user', 'ip');
 		console.log( '- Error while getting the search results: ' + error );
 		console.log( '- Error while getting the search results: ' + error );
 		msg.sendChannelError( spoiler + '<' + wiki.toLink(( querypage.noRedirect ? namespace : contribs ) + username, querystring, fragment) + '>' + spoiler );
 		msg.sendChannelError( spoiler + '<' + wiki.toLink(( querypage.noRedirect ? namespace : contribs ) + username, querystring, fragment) + '>' + spoiler );
 		
 		
 		if ( reaction ) reaction.removeEmoji();
 		if ( reaction ) reaction.removeEmoji();
 	} );
 	} );
 
 
-	logging(wiki, msg.guild?.id, 'user');
+	logging(wiki, msg.guildId, 'user');
 	got.get( wiki + 'api.php?action=query&meta=siteinfo' + ( wiki.hasCentralAuth() ? '|globaluserinfo&guiprop=groups|editcount|merged&guiuser=' + encodeURIComponent( username ) + '&' : '' ) + '&siprop=general&prop=revisions&rvprop=content|user&rvslots=main&titles=User:' + encodeURIComponent( username ) + '/Discord&list=users&usprop=blockinfo|groups|editcount|registration|gender&ususers=' + encodeURIComponent( username ) + '&format=json' ).then( response => {
 	got.get( wiki + 'api.php?action=query&meta=siteinfo' + ( wiki.hasCentralAuth() ? '|globaluserinfo&guiprop=groups|editcount|merged&guiuser=' + encodeURIComponent( username ) + '&' : '' ) + '&siprop=general&prop=revisions&rvprop=content|user&rvslots=main&titles=User:' + encodeURIComponent( username ) + '/Discord&list=users&usprop=blockinfo|groups|editcount|registration|gender&ususers=' + encodeURIComponent( username ) + '&format=json' ).then( response => {
 		var body = response.body;
 		var body = response.body;
 		if ( body && body.warnings ) log_warn(body.warnings);
 		if ( body && body.warnings ) log_warn(body.warnings);
@@ -564,7 +564,7 @@ function gamepedia_user(lang, msg, namespace, username, wiki, querystring, fragm
 					else text += '\n\n**' + block.header + '**\n' + block.text;
 					else text += '\n\n**' + block.header + '**\n' + block.text;
 				}
 				}
 				
 				
-				if ( msg.channel.isGuild() && patreons[msg.guild?.id] ) {
+				if ( msg.channel.isGuild() && patreons[msg.guildId] ) {
 					if ( msg.showEmbed() && !noEmbed ) embed.addField( '\u200b', '<a:loading:641343250661113886> **' + lang.get('user.info.loading') + '**' );
 					if ( msg.showEmbed() && !noEmbed ) embed.addField( '\u200b', '<a:loading:641343250661113886> **' + lang.get('user.info.loading') + '**' );
 					else text += '\n\n<a:loading:641343250661113886> **' + lang.get('user.info.loading') + '**';
 					else text += '\n\n<a:loading:641343250661113886> **' + lang.get('user.info.loading') + '**';
 					
 					

+ 2 - 2
dashboard/settings.js

@@ -321,7 +321,7 @@ function update_settings(res, userSettings, guild, type, settings) {
 			console.log( `- Dashboard: Settings successfully removed: ${guild}#${type}` );
 			console.log( `- Dashboard: Settings successfully removed: ${guild}#${type}` );
 			res(`/guild/${guild}/settings`, 'save');
 			res(`/guild/${guild}/settings`, 'save');
 			if ( !channel ) return;
 			if ( !channel ) return;
-			db.query( 'SELECT channel, wiki, lang, role, inline FROM discord WHERE guild = $1 AND ( channel = $2 OR channel IS NULL ) ORDER BY channel DESC NULLS LAST', [guild, '#' + response.parentID] ).then( ({rows:[row, {lang: guildlang} = {}]}) => {
+			db.query( 'SELECT channel, wiki, lang, role, inline FROM discord WHERE guild = $1 AND ( channel = $2 OR channel IS NULL ) ORDER BY channel DESC NULLS LAST', [guild, '#' + response.parentId] ).then( ({rows:[row, {lang: guildlang} = {}]}) => {
 				var lang = new Lang(( guildlang || row.lang ));
 				var lang = new Lang(( guildlang || row.lang ));
 				var text = lang.get('settings.dashboard.removed', `<@${userSettings.user.id}>`, `<#${type}>`);
 				var text = lang.get('settings.dashboard.removed', `<@${userSettings.user.id}>`, `<#${type}>`);
 				if ( channel.wiki !== row.wiki ) text += `\n${lang.get('settings.currentwiki')} <${channel.wiki}>`;
 				if ( channel.wiki !== row.wiki ) text += `\n${lang.get('settings.currentwiki')} <${channel.wiki}>`;
@@ -362,7 +362,7 @@ function update_settings(res, userSettings, guild, type, settings) {
 			}
 			}
 			return fresponse;
 			return fresponse;
 		} ).then( fresponse => {
 		} ).then( fresponse => {
-			return db.query( 'SELECT channel, wiki, lang, role, inline, prefix FROM discord WHERE guild = $1 AND ( channel = $2 OR channel IS NULL ) ORDER BY channel DESC NULLS LAST', [guild, '#' + response.parentID] ).then( ({rows:[row, {lang: guildlang} = {}]}) => {
+			return db.query( 'SELECT channel, wiki, lang, role, inline, prefix FROM discord WHERE guild = $1 AND ( channel = $2 OR channel IS NULL ) ORDER BY channel DESC NULLS LAST', [guild, '#' + response.parentId] ).then( ({rows:[row, {lang: guildlang} = {}]}) => {
 				if ( row ) row.guildlang = ( guildlang || row.lang );
 				if ( row ) row.guildlang = ( guildlang || row.lang );
 				var body = fresponse.body;
 				var body = fresponse.body;
 				if ( fresponse.statusCode !== 200 || body?.batchcomplete === undefined || !body?.query?.general ) {
 				if ( fresponse.statusCode !== 200 || body?.batchcomplete === undefined || !body?.query?.general ) {

+ 3 - 3
functions/discussion.js

@@ -15,7 +15,7 @@ const {got, htmlToDiscord, escapeFormatting} = require('../util/functions.js');
  * @param {Boolean} noEmbed - If the response should be without an embed.
  * @param {Boolean} noEmbed - If the response should be without an embed.
  */
  */
 function fandom_discussion(lang, msg, wiki, title, sitename, reaction, spoiler, noEmbed) {
 function fandom_discussion(lang, msg, wiki, title, sitename, reaction, spoiler, noEmbed) {
-	var limit = discussionLimit[( patreons[msg.guild?.id] ? 'patreon' : 'default' )];
+	var limit = discussionLimit[( patreons[msg.guildId] ? 'patreon' : 'default' )];
 	if ( !title ) {
 	if ( !title ) {
 		var pagelink = wiki + 'f';
 		var pagelink = wiki + 'f';
 		if ( !msg.showEmbed() || noEmbed ) {
 		if ( !msg.showEmbed() || noEmbed ) {
@@ -52,7 +52,7 @@ function fandom_discussion(lang, msg, wiki, title, sitename, reaction, spoiler,
 		}, error => {
 		}, error => {
 			console.log( '- Error while getting the description: ' + error );
 			console.log( '- Error while getting the description: ' + error );
 		} ).finally( () => {
 		} ).finally( () => {
-			msg.sendChannel( spoiler + '<' + pagelink + '>' + spoiler, {embed} );
+			msg.sendChannel( {content: spoiler + '<' + pagelink + '>' + spoiler, embeds: [embed]} );
 			
 			
 			if ( reaction ) reaction.removeEmoji();
 			if ( reaction ) reaction.removeEmoji();
 		} );
 		} );
@@ -322,7 +322,7 @@ function discussion_send(lang, msg, wiki, discussion, embed, spoiler, noEmbed) {
 		embed.addField( lang.get('discussion.tags'), Util.splitMessage( discussion.tags.map( tag => '[' + escapeFormatting(tag.articleTitle) + '](' + wiki.toLink(tag.articleTitle, '', '', true) + ')' ).join(', '), {char:', ',maxLength:1000} )[0], false );
 		embed.addField( lang.get('discussion.tags'), Util.splitMessage( discussion.tags.map( tag => '[' + escapeFormatting(tag.articleTitle) + '](' + wiki.toLink(tag.articleTitle, '', '', true) + ')' ).join(', '), {char:', ',maxLength:1000} )[0], false );
 	}
 	}
 	
 	
-	msg.sendChannel( spoiler + '<' + pagelink + '>' + spoiler, {embed} );
+	msg.sendChannel( {content: spoiler + '<' + pagelink + '>' + spoiler, embeds: [embed]} );
 }
 }
 
 
 /**
 /**

+ 2 - 2
functions/global_block.js

@@ -13,7 +13,7 @@ const {got, escapeFormatting} = require('../util/functions.js');
  * @param {String} [gender] - The gender of the user.
  * @param {String} [gender] - The gender of the user.
  */
  */
 function global_block(lang, msg, username, text, embed, wiki, spoiler, gender) {
 function global_block(lang, msg, username, text, embed, wiki, spoiler, gender) {
-	if ( !msg || !msg.channel.isGuild() || !patreons[msg.guild?.id] || !wiki.isFandom() ) return;
+	if ( !msg || !msg.channel.isGuild() || !patreons[msg.guildId] || !wiki.isFandom() ) return;
 	
 	
 	var isUser = true;
 	var isUser = true;
 	if ( !gender ) {
 	if ( !gender ) {
@@ -98,7 +98,7 @@ function global_block(lang, msg, username, text, embed, wiki, spoiler, gender) {
 			console.log( '- Error while getting the global edit count: ' + error );
 			console.log( '- Error while getting the global edit count: ' + error );
 		} ) : undefined )
 		} ) : undefined )
 	]).finally( () => {
 	]).finally( () => {
-		msg.edit( spoiler + text + spoiler, {embed,allowedMentions:{parse:[]}} ).catch(log_error);
+		msg.edit( {content: spoiler + text + spoiler, embeds: [embed]} ).catch(log_error);
 	} );
 	} );
 }
 }
 
 

+ 1 - 1
functions/helpsetup.js

@@ -5,7 +5,7 @@
  */
  */
 function help_setup(lang, msg) {
 function help_setup(lang, msg) {
 	msg.defaultSettings = false;
 	msg.defaultSettings = false;
-	msg.replyMsg( lang.get('general.default', '`' + process.env.prefix + 'settings`') + ( process.env.dashboard ? '\n' + new URL(`/guild/${msg.guild.id}/settings`, process.env.dashboard).href : '' ) );
+	msg.replyMsg( lang.get('general.default', '`' + process.env.prefix + 'settings`') + ( process.env.dashboard ? '\n' + new URL(`/guild/${msg.guildId}/settings`, process.env.dashboard).href : '' ) );
 }
 }
 
 
 module.exports = help_setup;
 module.exports = help_setup;

+ 6 - 5
functions/parse_page.js

@@ -104,10 +104,11 @@ function parse_page(lang, msg, content, embed, wiki, reaction, {title, contentmo
 				embed.setDescription( embed.backupDescription );
 				embed.setDescription( embed.backupDescription );
 			}
 			}
 		}
 		}
-		return msg.sendChannel( content, {embed} );
+		return msg.sendChannel( {content: content, embeds: [embed]} );
 	}
 	}
-	return msg.sendChannel( content, {
-		embed: new MessageEmbed(embed).setDescription( '<a:loading:641343250661113886> **' + lang.get('search.loading') + '**' )
+	return msg.sendChannel( {
+		content,
+		embeds: [new MessageEmbed(embed).setDescription( '<a:loading:641343250661113886> **' + lang.get('search.loading') + '**' )]
 	} ).then( message => {
 	} ).then( message => {
 		if ( !message ) return;
 		if ( !message ) return;
 		if ( !parsedContentModels.includes( contentmodel ) ) return got.get( wiki + 'api.php?action=query&prop=revisions&rvprop=content&rvslots=main&converttitles=true&titles=%1F' + encodeURIComponent( title ) + '&format=json', {
 		if ( !parsedContentModels.includes( contentmodel ) ) return got.get( wiki + 'api.php?action=query&prop=revisions&rvprop=content&rvslots=main&converttitles=true&titles=%1F' + encodeURIComponent( title ) + '&format=json', {
@@ -160,7 +161,7 @@ function parse_page(lang, msg, content, embed, wiki, reaction, {title, contentmo
 				embed.setDescription( embed.backupDescription );
 				embed.setDescription( embed.backupDescription );
 			}
 			}
 		} ).then( () => {
 		} ).then( () => {
-			return message.edit( content, {embed,allowedMentions:{users:[msg.author.id]}} ).catch(log_error);
+			return message.edit( {content, embeds: [embed]} ).catch(log_error);
 		} );
 		} );
 		if ( !fragment && !embed.fields.length && infoboxes ) {
 		if ( !fragment && !embed.fields.length && infoboxes ) {
 			try {
 			try {
@@ -393,7 +394,7 @@ function parse_page(lang, msg, content, embed, wiki, reaction, {title, contentmo
 				embed.spliceFields( 0, 0, embed.backupField );
 				embed.spliceFields( 0, 0, embed.backupField );
 			}
 			}
 		} ).then( () => {
 		} ).then( () => {
-			return message.edit( content, {embed,allowedMentions:{users:[msg.author.id]}} ).catch(log_error);
+			return message.edit( {content, embeds: [embed]} ).catch(log_error);
 		} );
 		} );
 	} );
 	} );
 }
 }

+ 3 - 3
functions/phabricator.js

@@ -15,13 +15,13 @@ const {got, escapeFormatting, limitLength} = require('../util/functions.js');
 function phabricator_task(lang, msg, wiki, link, reaction, spoiler = '', noEmbed = false) {
 function phabricator_task(lang, msg, wiki, link, reaction, spoiler = '', noEmbed = false) {
 	var regex = /^(?:https?:)?\/\/phabricator\.(wikimedia|miraheze)\.org\/T(\d+)(?:#|$)/.exec(link.href);
 	var regex = /^(?:https?:)?\/\/phabricator\.(wikimedia|miraheze)\.org\/T(\d+)(?:#|$)/.exec(link.href);
 	if ( !regex || !process.env['phabricator_' + regex[1]] ) {
 	if ( !regex || !process.env['phabricator_' + regex[1]] ) {
-		logging(wiki, msg.guild?.id, 'interwiki');
+		logging(wiki, msg.guildId, 'interwiki');
 		msg.sendChannel( spoiler + ( noEmbed ? '<' : ' ' ) + link + ( noEmbed ? '>' : ' ' ) + spoiler );
 		msg.sendChannel( spoiler + ( noEmbed ? '<' : ' ' ) + link + ( noEmbed ? '>' : ' ' ) + spoiler );
 		if ( reaction ) reaction.removeEmoji();
 		if ( reaction ) reaction.removeEmoji();
 		return;
 		return;
 	}
 	}
 	var site = 'https://phabricator.' + regex[1] + '.org/';
 	var site = 'https://phabricator.' + regex[1] + '.org/';
-	logging(site, msg.guild?.id, 'phabricator', regex[1]);
+	logging(site, msg.guildId, 'phabricator', regex[1]);
 	got.get( site + 'api/maniphest.search?api.token=' + process.env['phabricator_' + regex[1]] + '&attachments[projects]=1&constraints[ids][0]=' + regex[2] ).then( response => {
 	got.get( site + 'api/maniphest.search?api.token=' + process.env['phabricator_' + regex[1]] + '&attachments[projects]=1&constraints[ids][0]=' + regex[2] ).then( response => {
 		var body = response.body;
 		var body = response.body;
 		if ( response.statusCode !== 200 || !body?.result?.data || body.error_code ) {
 		if ( response.statusCode !== 200 || !body?.result?.data || body.error_code ) {
@@ -87,7 +87,7 @@ function phabricator_task(lang, msg, wiki, link, reaction, spoiler = '', noEmbed
 				console.log( '- Error while getting the task transactions: ' + error );
 				console.log( '- Error while getting the task transactions: ' + error );
 			} ) : undefined )
 			} ) : undefined )
 		]).finally( () => {
 		]).finally( () => {
-			msg.sendChannel( spoiler + status + '<' + link + '>' + spoiler, {embed} );
+			msg.sendChannel( {content: spoiler + status + '<' + link + '>' + spoiler, embeds: [embed]} );
 			
 			
 			if ( reaction ) reaction.removeEmoji();
 			if ( reaction ) reaction.removeEmoji();
 		} );
 		} );

+ 4 - 4
functions/special_page.js

@@ -167,7 +167,7 @@ function special_page(lang, msg, {title, uselang = lang.lang}, specialpage, quer
 		overwrites[specialpage](this, lang, msg, wiki, querystring, fragment, reaction, spoiler, noEmbed, args, embed, query);
 		overwrites[specialpage](this, lang, msg, wiki, querystring, fragment, reaction, spoiler, noEmbed, args, embed, query);
 		return;
 		return;
 	}
 	}
-	logging(wiki, msg.guild?.id, 'general', 'special');
+	logging(wiki, msg.guildId, 'general', 'special');
 	if ( !msg.showEmbed() || noEmbed ) {
 	if ( !msg.showEmbed() || noEmbed ) {
 		msg.sendChannel( spoiler + '<' + pagelink + '>' + spoiler );
 		msg.sendChannel( spoiler + '<' + pagelink + '>' + spoiler );
 		
 		
@@ -175,7 +175,7 @@ function special_page(lang, msg, {title, uselang = lang.lang}, specialpage, quer
 		return;
 		return;
 	}
 	}
 	if ( specialpage === 'recentchanges' && msg.isAdmin() ) {
 	if ( specialpage === 'recentchanges' && msg.isAdmin() ) {
-		embed.addField( lang.get('rcscript.title'), lang.get('rcscript.ad', ( patreons[msg?.guild?.id] || process.env.prefix ), '[RcGcDw](https://gitlab.com/piotrex43/RcGcDw)') );
+		embed.addField( lang.get('rcscript.title'), lang.get('rcscript.ad', ( patreons[msg.guildId] || process.env.prefix ), '[RcGcDw](https://gitlab.com/piotrex43/RcGcDw)') );
 	}
 	}
 	got.get( wiki + 'api.php?uselang=' + uselang + '&action=query&meta=allmessages|siteinfo&siprop=general&amenableparser=true&amtitle=' + encodeURIComponent( title ) + '&ammessages=' + encodeURIComponent( specialpage ) + '|' + ( descriptions.hasOwnProperty(specialpage) ? descriptions[specialpage] : encodeURIComponent( specialpage ) + '-summary' ) + ( querypages.hasOwnProperty(specialpage) ? querypages[specialpage][0] : '' ) + '&converttitles=true&titles=%1F' + encodeURIComponent( title ) + '&format=json' ).then( response => {
 	got.get( wiki + 'api.php?uselang=' + uselang + '&action=query&meta=allmessages|siteinfo&siprop=general&amenableparser=true&amtitle=' + encodeURIComponent( title ) + '&ammessages=' + encodeURIComponent( specialpage ) + '|' + ( descriptions.hasOwnProperty(specialpage) ? descriptions[specialpage] : encodeURIComponent( specialpage ) + '-summary' ) + ( querypages.hasOwnProperty(specialpage) ? querypages[specialpage][0] : '' ) + '&converttitles=true&titles=%1F' + encodeURIComponent( title ) + '&format=json' ).then( response => {
 		var body = response.body;
 		var body = response.body;
@@ -199,7 +199,7 @@ function special_page(lang, msg, {title, uselang = lang.lang}, specialpage, quer
 			if ( description.length > 1000 ) description = description.substring(0, 1000) + '\u2026';
 			if ( description.length > 1000 ) description = description.substring(0, 1000) + '\u2026';
 			embed.setDescription( description );
 			embed.setDescription( description );
 		}
 		}
-		if ( msg.channel.isGuild() && patreons[msg.guild?.id] && querypages.hasOwnProperty(specialpage) ) {
+		if ( msg.channel.isGuild() && patreons[msg.guildId] && querypages.hasOwnProperty(specialpage) ) {
 			var text = Util.splitMessage( querypages[specialpage][1](body.query, wiki, lang), {maxLength:1000} )[0];
 			var text = Util.splitMessage( querypages[specialpage][1](body.query, wiki, lang), {maxLength:1000} )[0];
 			embed.addField( lang.get('search.special'), ( text || lang.get('search.empty') ) );
 			embed.addField( lang.get('search.special'), ( text || lang.get('search.empty') ) );
 			if ( body.query.querypage.cached !== undefined ) {
 			if ( body.query.querypage.cached !== undefined ) {
@@ -209,7 +209,7 @@ function special_page(lang, msg, {title, uselang = lang.lang}, specialpage, quer
 	}, error => {
 	}, error => {
 		console.log( '- Error while getting the special page: ' + error );
 		console.log( '- Error while getting the special page: ' + error );
 	} ).finally( () => {
 	} ).finally( () => {
-		msg.sendChannel( spoiler + '<' + pagelink + '>' + spoiler, {embed} );
+		msg.sendChannel( {content: spoiler + '<' + pagelink + '>' + spoiler, embeds: [embed]} );
 		
 		
 		if ( reaction ) reaction.removeEmoji();
 		if ( reaction ) reaction.removeEmoji();
 	} );
 	} );

+ 135 - 141
functions/verify.js

@@ -1,5 +1,5 @@
 const cheerio = require('cheerio');
 const cheerio = require('cheerio');
-const {MessageEmbed} = require('discord.js');
+const {MessageEmbed, MessageActionRow, MessageButton, Permissions: {FLAGS}} = require('discord.js');
 var db = require('../util/database.js');
 var db = require('../util/database.js');
 const Lang = require('../util/i18n.js');
 const Lang = require('../util/i18n.js');
 const Wiki = require('../util/wiki.js');
 const Wiki = require('../util/wiki.js');
@@ -27,17 +27,17 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 		onmatch: rows[0].onmatch
 		onmatch: rows[0].onmatch
 	};
 	};
 	verifynotice.logchannel = ( verifynotice.logchannel ? channel.guild.channels.cache.filter( logchannel => {
 	verifynotice.logchannel = ( verifynotice.logchannel ? channel.guild.channels.cache.filter( logchannel => {
-		return ( logchannel.isGuild() && logchannel.permissionsFor(channel.guild.me).has(['VIEW_CHANNEL', 'SEND_MESSAGES']) );
+		return ( logchannel.isGuild() && logchannel.permissionsFor(channel.guild.me).has([FLAGS.VIEW_CHANNEL, FLAGS.SEND_MESSAGES]) );
 	} ).get(verifynotice.logchannel) : null );
 	} ).get(verifynotice.logchannel) : null );
 	var embed = new MessageEmbed().setFooter( lang.get('verify.footer') ).setTimestamp();
 	var embed = new MessageEmbed().setFooter( lang.get('verify.footer') ).setTimestamp();
 	var result = {
 	var result = {
 		content: '', embed,
 		content: '', embed,
-		add_button: channel.permissionsFor(channel.guild.me).has('EMBED_LINKS'),
+		add_button: channel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS),
 		send_private: ( (verifynotice.flags & 1 << 0) === 1 << 0 ),
 		send_private: ( (verifynotice.flags & 1 << 0) === 1 << 0 ),
 		reaction: '', oauth: [],
 		reaction: '', oauth: [],
 		logging: {
 		logging: {
 			channel: '',
 			channel: '',
-			content: '',
+			content: null,
 			embed: null
 			embed: null
 		}
 		}
 	};
 	};
@@ -51,7 +51,7 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 			}
 			}
 			else if ( body?.error?.code === 'us400' || body?.error?.code === 'baduser_ucuser' ) {
 			else if ( body?.error?.code === 'us400' || body?.error?.code === 'baduser_ucuser' ) {
 				// special catch for Fandom
 				// special catch for Fandom
-				if ( !old_username ) logging(wiki, channel.guild.id, 'verification');
+				if ( !old_username ) logging(wiki, channel.guildId, 'verification');
 				embed.setTitle( escapeFormatting( old_username || username ) ).setColor('#0000FF').setDescription( lang.get('verify.user_missing', escapeFormatting( old_username || username )) ).addField( lang.get('verify.notice'), lang.get('verify.help_missing') );
 				embed.setTitle( escapeFormatting( old_username || username ) ).setColor('#0000FF').setDescription( lang.get('verify.user_missing', escapeFormatting( old_username || username )) ).addField( lang.get('verify.notice'), lang.get('verify.help_missing') );
 				result.content = lang.get('verify.user_missing_reply', escapeFormatting( old_username || username ));
 				result.content = lang.get('verify.user_missing_reply', escapeFormatting( old_username || username ));
 			}
 			}
@@ -73,7 +73,7 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 				return;
 				return;
 			}
 			}
 		}
 		}
-		if ( !old_username ) logging(wiki, channel.guild.id, 'verification');
+		if ( !old_username ) logging(wiki, channel.guildId, 'verification');
 		var queryuser = body.query.users[0];
 		var queryuser = body.query.users[0];
 		embed.setAuthor( body.query.general.sitename );
 		embed.setAuthor( body.query.general.sitename );
 		if ( body.query.users.length !== 1 || queryuser.missing !== undefined || queryuser.invalid !== undefined ) {
 		if ( body.query.users.length !== 1 || queryuser.missing !== undefined || queryuser.invalid !== undefined ) {
@@ -101,7 +101,7 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 			result.content = lang.get('verify.user_blocked_reply', escapeFormatting(username), queryuser.gender);
 			result.content = lang.get('verify.user_blocked_reply', escapeFormatting(username), queryuser.gender);
 			if ( (verifynotice.flags & 1 << 1) === 1 << 1 && verifynotice.logchannel ) {
 			if ( (verifynotice.flags & 1 << 1) === 1 << 1 && verifynotice.logchannel ) {
 				result.logging.channel = verifynotice.logchannel.id;
 				result.logging.channel = verifynotice.logchannel.id;
-				if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) {
+				if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) {
 					let logembed = new MessageEmbed(embed);
 					let logembed = new MessageEmbed(embed);
 					logembed.addField( lang.get('verify.discord', 'unknown'), escapeFormatting(member.user.tag) + ` (${member.toString()})`, true );
 					logembed.addField( lang.get('verify.discord', 'unknown'), escapeFormatting(member.user.tag) + ` (${member.toString()})`, true );
 					result.logging.embed = logembed;
 					result.logging.embed = logembed;
@@ -179,7 +179,7 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 					embed.setColor('#FFFF00').setDescription( lang.get('verify.user_failed', member.toString(), '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) );
 					embed.setColor('#FFFF00').setDescription( lang.get('verify.user_failed', member.toString(), '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) );
 					if ( (verifynotice.flags & 1 << 1) === 1 << 1 && verifynotice.logchannel ) {
 					if ( (verifynotice.flags & 1 << 1) === 1 << 1 && verifynotice.logchannel ) {
 						result.logging.channel = verifynotice.logchannel.id;
 						result.logging.channel = verifynotice.logchannel.id;
-						if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) {
+						if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) {
 							result.logging.embed = new MessageEmbed(embed);
 							result.logging.embed = new MessageEmbed(embed);
 						}
 						}
 						else {
 						else {
@@ -189,8 +189,8 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 						}
 						}
 					}
 					}
 					var help_link = '';
 					var help_link = '';
-					if ( wiki.isGamepedia() ) help_link = lang.get('verify.help_gamepedia') + '?c=' + ( patreons[channel.guild.id] && patreons[channel.guild.id] !== process.env.prefix ? encodeURIComponent( patreons[channel.guild.id] + 'verify' ) : 'wb' ) + ( channel.name !== 'verification' ? '&ch=' + encodeURIComponent( channel.name ) : '' ) + '&user=' + toTitle(username) + '&discord=' + encodeURIComponent( member.user.username ) + '&tag=' + member.user.discriminator + '&useskin=fandomdesktop';
-					else if ( wiki.isFandom() ) help_link = lang.get('verify.help_fandom') + '/' + toTitle(username) + '?c=' + ( patreons[channel.guild.id] && patreons[channel.guild.id] !== process.env.prefix ? encodeURIComponent( patreons[channel.guild.id] + 'verify' ) : 'wb' ) + ( channel.name !== 'verification' ? '&ch=' + encodeURIComponent( channel.name ) : '' ) + '&user=' + encodeURIComponent( member.user.username ) + '&tag=' + member.user.discriminator + '&useskin=fandomdesktop';
+					if ( wiki.isGamepedia() ) help_link = lang.get('verify.help_gamepedia') + '?c=' + ( patreons[channel.guildId] && patreons[channel.guildId] !== process.env.prefix ? encodeURIComponent( patreons[channel.guildId] + 'verify' ) : 'wb' ) + ( channel.name !== 'verification' ? '&ch=' + encodeURIComponent( channel.name ) : '' ) + '&user=' + toTitle(username) + '&discord=' + encodeURIComponent( member.user.username ) + '&tag=' + member.user.discriminator + '&useskin=fandomdesktop';
+					else if ( wiki.isFandom() ) help_link = lang.get('verify.help_fandom') + '/' + toTitle(username) + '?c=' + ( patreons[channel.guildId] && patreons[channel.guildId] !== process.env.prefix ? encodeURIComponent( patreons[channel.guildId] + 'verify' ) : 'wb' ) + ( channel.name !== 'verification' ? '&ch=' + encodeURIComponent( channel.name ) : '' ) + '&user=' + encodeURIComponent( member.user.username ) + '&tag=' + member.user.discriminator + '&useskin=fandomdesktop';
 					if ( help_link.length ) embed.addField( lang.get('verify.notice'), lang.get('verify.help_guide', help_link, queryuser.gender) + '\n' + help_link );
 					if ( help_link.length ) embed.addField( lang.get('verify.notice'), lang.get('verify.help_guide', help_link, queryuser.gender) + '\n' + help_link );
 					result.content = lang.get('verify.user_failed_reply', escapeFormatting(username), queryuser.gender);
 					result.content = lang.get('verify.user_failed_reply', escapeFormatting(username), queryuser.gender);
 					return;
 					return;
@@ -278,7 +278,7 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 						if ( verifynotice.logchannel ) {
 						if ( verifynotice.logchannel ) {
 							useLogging = true;
 							useLogging = true;
 							result.logging.channel = verifynotice.logchannel.id;
 							result.logging.channel = verifynotice.logchannel.id;
-							if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) {
+							if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) {
 								let logembed = new MessageEmbed(embed);
 								let logembed = new MessageEmbed(embed);
 								if ( addRolesMentions[0].length ) logembed.addField( lang.get('verify.qualified_add'), addRolesMentions[0].join('\n') );
 								if ( addRolesMentions[0].length ) logembed.addField( lang.get('verify.qualified_add'), addRolesMentions[0].join('\n') );
 								if ( addRolesMentions[1].length ) logembed.setColor('#008800').addField( lang.get('verify.qualified_add_error'), addRolesMentions[1].join('\n') );
 								if ( addRolesMentions[1].length ) logembed.setColor('#008800').addField( lang.get('verify.qualified_add_error'), addRolesMentions[1].join('\n') );
@@ -305,7 +305,7 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 							accountage: Math.trunc(accountage),
 							accountage: Math.trunc(accountage),
 							dateformat: lang.get('dateformat')
 							dateformat: lang.get('dateformat')
 						}).trim() : '' );
 						}).trim() : '' );
-						if ( channel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) {
+						if ( channel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) {
 							if ( addRolesMentions[0].length ) embed.addField( lang.get('verify.qualified_add'), addRolesMentions[0].join('\n') );
 							if ( addRolesMentions[0].length ) embed.addField( lang.get('verify.qualified_add'), addRolesMentions[0].join('\n') );
 							if ( addRolesMentions[1].length && !useLogging ) embed.setColor('#008800').addField( lang.get('verify.qualified_add_error'), addRolesMentions[1].join('\n') );
 							if ( addRolesMentions[1].length && !useLogging ) embed.setColor('#008800').addField( lang.get('verify.qualified_add_error'), addRolesMentions[1].join('\n') );
 							if ( removeRolesMentions[0].length ) embed.addField( lang.get('verify.qualified_remove'), removeRolesMentions[0].join('\n') );
 							if ( removeRolesMentions[0].length ) embed.addField( lang.get('verify.qualified_remove'), removeRolesMentions[0].join('\n') );
@@ -332,7 +332,7 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 
 
 				if ( (verifynotice.flags & 1 << 1) === 1 << 1 && verifynotice.logchannel ) {
 				if ( (verifynotice.flags & 1 << 1) === 1 << 1 && verifynotice.logchannel ) {
 					result.logging.channel = verifynotice.logchannel.id;
 					result.logging.channel = verifynotice.logchannel.id;
-					if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) {
+					if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) {
 						result.logging.embed = new MessageEmbed(embed);
 						result.logging.embed = new MessageEmbed(embed);
 					}
 					}
 					else {
 					else {
@@ -350,7 +350,7 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 					dateformat: lang.get('dateformat')
 					dateformat: lang.get('dateformat')
 				});
 				});
 				if ( !onmatch.trim() ) return;
 				if ( !onmatch.trim() ) return;
-				if ( channel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) embed.addField( lang.get('verify.notice'), onmatch );
+				if ( channel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) embed.addField( lang.get('verify.notice'), onmatch );
 				else result.content += '\n\n**' + lang.get('verify.notice') + '** ' + onmatch;
 				else result.content += '\n\n**' + lang.get('verify.notice') + '** ' + onmatch;
 			}, error => {
 			}, error => {
 				if ( error ) console.log( '- Error while getting the Discord tag: ' + error );
 				if ( error ) console.log( '- Error while getting the Discord tag: ' + error );
@@ -363,7 +363,7 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 			result.content = error.reply;
 			result.content = error.reply;
 			if ( (verifynotice.flags & 1 << 1) === 1 << 1 && verifynotice.logchannel ) {
 			if ( (verifynotice.flags & 1 << 1) === 1 << 1 && verifynotice.logchannel ) {
 				result.logging.channel = verifynotice.logchannel.id;
 				result.logging.channel = verifynotice.logchannel.id;
-				if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) {
+				if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) {
 					let logembed = new MessageEmbed(embed);
 					let logembed = new MessageEmbed(embed);
 					logembed.addField( lang.get('verify.discord', 'unknown'), escapeFormatting(member.user.tag) + ` (${member.toString()})`, true );
 					logembed.addField( lang.get('verify.discord', 'unknown'), escapeFormatting(member.user.tag) + ` (${member.toString()})`, true );
 					result.logging.embed = logembed;
 					result.logging.embed = logembed;
@@ -392,7 +392,7 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 					result.content = lang.get('verify.user_gblocked_reply', escapeFormatting(username), queryuser.gender);
 					result.content = lang.get('verify.user_gblocked_reply', escapeFormatting(username), queryuser.gender);
 					if ( (verifynotice.flags & 1 << 1) === 1 << 1 && verifynotice.logchannel ) {
 					if ( (verifynotice.flags & 1 << 1) === 1 << 1 && verifynotice.logchannel ) {
 						result.logging.channel = verifynotice.logchannel.id;
 						result.logging.channel = verifynotice.logchannel.id;
-						if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) {
+						if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) {
 							let logembed = new MessageEmbed(embed);
 							let logembed = new MessageEmbed(embed);
 							logembed.addField( lang.get('verify.discord', 'unknown'), escapeFormatting(member.user.tag) + ` (${member.toString()})`, true );
 							logembed.addField( lang.get('verify.discord', 'unknown'), escapeFormatting(member.user.tag) + ` (${member.toString()})`, true );
 							result.logging.embed = logembed;
 							result.logging.embed = logembed;
@@ -421,7 +421,7 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 				embed.setColor('#FFFF00').setDescription( lang.get('verify.user_failed', member.toString(), '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) );
 				embed.setColor('#FFFF00').setDescription( lang.get('verify.user_failed', member.toString(), '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) );
 				if ( (verifynotice.flags & 1 << 1) === 1 << 1 && verifynotice.logchannel ) {
 				if ( (verifynotice.flags & 1 << 1) === 1 << 1 && verifynotice.logchannel ) {
 					result.logging.channel = verifynotice.logchannel.id;
 					result.logging.channel = verifynotice.logchannel.id;
-					if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) {
+					if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) {
 						result.logging.embed = new MessageEmbed(embed);
 						result.logging.embed = new MessageEmbed(embed);
 					}
 					}
 					else {
 					else {
@@ -509,7 +509,7 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 					if ( verifynotice.logchannel ) {
 					if ( verifynotice.logchannel ) {
 						useLogging = true;
 						useLogging = true;
 						result.logging.channel = verifynotice.logchannel.id;
 						result.logging.channel = verifynotice.logchannel.id;
-						if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) {
+						if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) {
 							var logembed = new MessageEmbed(embed);
 							var logembed = new MessageEmbed(embed);
 							if ( addRolesMentions[0].length ) logembed.addField( lang.get('verify.qualified_add'), addRolesMentions[0].join('\n') );
 							if ( addRolesMentions[0].length ) logembed.addField( lang.get('verify.qualified_add'), addRolesMentions[0].join('\n') );
 							if ( addRolesMentions[1].length ) logembed.setColor('#008800').addField( lang.get('verify.qualified_add_error'), addRolesMentions[1].join('\n') );
 							if ( addRolesMentions[1].length ) logembed.setColor('#008800').addField( lang.get('verify.qualified_add_error'), addRolesMentions[1].join('\n') );
@@ -535,7 +535,7 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 						accountage: Math.trunc(accountage),
 						accountage: Math.trunc(accountage),
 						dateformat: lang.get('dateformat')
 						dateformat: lang.get('dateformat')
 					}).trim() : '' );
 					}).trim() : '' );
-					if ( channel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) {
+					if ( channel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) {
 						if ( addRolesMentions[0].length ) embed.addField( lang.get('verify.qualified_add'), addRolesMentions[0].join('\n') );
 						if ( addRolesMentions[0].length ) embed.addField( lang.get('verify.qualified_add'), addRolesMentions[0].join('\n') );
 						if ( addRolesMentions[1].length && !useLogging ) embed.setColor('#008800').addField( lang.get('verify.qualified_add_error'), addRolesMentions[1].join('\n') );
 						if ( addRolesMentions[1].length && !useLogging ) embed.setColor('#008800').addField( lang.get('verify.qualified_add_error'), addRolesMentions[1].join('\n') );
 						if ( removeRolesMentions[0].length ) embed.addField( lang.get('verify.qualified_remove'), removeRolesMentions[0].join('\n') );
 						if ( removeRolesMentions[0].length ) embed.addField( lang.get('verify.qualified_remove'), removeRolesMentions[0].join('\n') );
@@ -567,7 +567,7 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
 				dateformat: lang.get('dateformat')
 				dateformat: lang.get('dateformat')
 			});
 			});
 			if ( !onmatch.trim() ) return;
 			if ( !onmatch.trim() ) return;
-			if ( channel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) embed.addField( lang.get('verify.notice'), onmatch );
+			if ( channel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) embed.addField( lang.get('verify.notice'), onmatch );
 			else result.content += '\n\n**' + lang.get('verify.notice') + '** ' + onmatch;
 			else result.content += '\n\n**' + lang.get('verify.notice') + '** ' + onmatch;
 		}, error => {
 		}, error => {
 			console.log( '- Error while getting the Discord tag: ' + error );
 			console.log( '- Error while getting the Discord tag: ' + error );
@@ -593,10 +593,9 @@ function verify(lang, channel, member, username, wiki, rows, old_username = '')
  * @param {Object} [settings] - Settings to skip oauth.
  * @param {Object} [settings] - Settings to skip oauth.
  * @param {import('discord.js').TextChannel} settings.channel - The channel.
  * @param {import('discord.js').TextChannel} settings.channel - The channel.
  * @param {String} settings.user - The user id.
  * @param {String} settings.user - The user id.
- * @param {String} [settings.wiki] - The OAuth2 wiki.
- * @param {String} [settings.username] - The username.
- * @param {String} [settings.token] - The webhook token.
- * @param {Function} [settings.send] - The function to edit the message.
+ * @param {String} settings.wiki - The OAuth2 wiki.
+ * @param {import('discord.js').CommandInteraction|import('discord.js').ButtonInteraction} [settings.interaction] - The interaction.
+ * @param {Function} [settings.fail] - The function to call when the verifiction errors.
  * @param {import('discord.js').Message} [settings.sourceMessage] - The source message with the command.
  * @param {import('discord.js').Message} [settings.sourceMessage] - The source message with the command.
  */
  */
 global.verifyOauthUser = function(state, access_token, settings) {
 global.verifyOauthUser = function(state, access_token, settings) {
@@ -604,14 +603,16 @@ global.verifyOauthUser = function(state, access_token, settings) {
 		settings = oauthVerify.get(state);
 		settings = oauthVerify.get(state);
 		oauthVerify.delete(state);
 		oauthVerify.delete(state);
 	}
 	}
-	if ( !settings?.channel ) return;
+	if ( !settings?.channel ) return settings?.fail?.();
 	var channel = settings.channel;
 	var channel = settings.channel;
-	var username = settings.username;
-	if ( !username && !channel.permissionsFor(channel.guild.me).has(['VIEW_CHANNEL', 'SEND_MESSAGES']) ) return;
+	if ( !channel.permissionsFor(channel.guild.me).has([FLAGS.VIEW_CHANNEL, FLAGS.SEND_MESSAGES]) ) return settings.fail?.();
 	Promise.all([
 	Promise.all([
-		db.query( 'SELECT logchannel, flags, onsuccess, onmatch, role, editcount, postcount, usergroup, accountage, rename FROM verification LEFT JOIN verifynotice ON verification.guild = verifynotice.guild WHERE verification.guild = $1 AND channel LIKE $2 ORDER BY configid ASC', [channel.guild.id, '%|' + channel.id + '|%'] ).then( ({rows}) => {
+		db.query( 'SELECT logchannel, flags, onsuccess, onmatch, role, editcount, postcount, usergroup, accountage, rename FROM verification LEFT JOIN verifynotice ON verification.guild = verifynotice.guild WHERE verification.guild = $1 AND channel LIKE $2 ORDER BY configid ASC', [channel.guildId, '%|' + ( channel.isThread() ? channel.parentId : channel.id ) + '|%'] ).then( ({rows}) => {
 			if ( !rows.length ) return Promise.reject();
 			if ( !rows.length ) return Promise.reject();
-			return db.query( 'SELECT wiki, lang FROM discord WHERE guild = $1 AND (channel = $2 OR channel = $3 OR channel IS NULL) ORDER BY channel DESC NULLS LAST LIMIT 1', [channel.guild.id, channel.id, '#' + channel.parentID] ).then( ({rows: [row]}) => {
+			let sqlargs = [channel.guildId];
+			if ( channel.isThread() ) sqlargs.push(channel.parentId, '#' + channel.parent?.parentId);
+			else sqlargs.push(channel.id, '#' + channel.parentId);
+			return db.query( 'SELECT wiki, lang FROM discord WHERE guild = $1 AND (channel = $2 OR channel = $3 OR channel IS NULL) ORDER BY channel DESC NULLS LAST LIMIT 1', sqlargs ).then( ({rows: [row]}) => {
 				return {
 				return {
 					rows, wiki: new Wiki(row?.wiki),
 					rows, wiki: new Wiki(row?.wiki),
 					lang: new Lang(( row?.lang || channel?.guild?.preferredLocale ))
 					lang: new Lang(( row?.lang || channel?.guild?.preferredLocale ))
@@ -619,7 +620,7 @@ global.verifyOauthUser = function(state, access_token, settings) {
 			} );
 			} );
 		} ),
 		} ),
 		channel.guild.members.fetch(settings.user),
 		channel.guild.members.fetch(settings.user),
-		( !username ? got.get( settings.wiki + 'rest.php/oauth2/resource/profile', {
+		got.get( settings.wiki + 'rest.php/oauth2/resource/profile', {
 			headers: {
 			headers: {
 				Authorization: `Bearer ${access_token}`
 				Authorization: `Bearer ${access_token}`
 			}
 			}
@@ -629,17 +630,17 @@ global.verifyOauthUser = function(state, access_token, settings) {
 				console.log( '- ' + response.statusCode + ': Error while getting the mediawiki profile: ' + ( body?.message || body?.error ) );
 				console.log( '- ' + response.statusCode + ': Error while getting the mediawiki profile: ' + ( body?.message || body?.error ) );
 				return;
 				return;
 			}
 			}
-			username = body.username;
-			console.log( channel.guild.id + ': OAuth2: ' + username );
+			console.log( channel.guildId + ': OAuth2: ' + body.username );
+			return body.username;
 		}, error => {
 		}, error => {
 			console.log( '- Error while getting the mediawiki profile: ' + error );
 			console.log( '- Error while getting the mediawiki profile: ' + error );
-		} ) : null )
-	]).then( ([{rows, wiki, lang}, member]) => {
-		if ( !username || ( settings.wiki && settings.wiki !== wiki.href ) ) return settings.send?.();
+		} )
+	]).then( ([{rows, wiki, lang}, member, username]) => {
+		if ( !username || settings.wiki !== wiki.href ) return settings.fail?.();
 		/** @type {{logchannel:import('discord.js').TextChannel,flags:Number,onsuccess:String,onmatch:String}} */
 		/** @type {{logchannel:import('discord.js').TextChannel,flags:Number,onsuccess:String,onmatch:String}} */
 		var verifynotice = ( rows[0] || {} );
 		var verifynotice = ( rows[0] || {} );
 		verifynotice.logchannel = ( verifynotice.logchannel ? channel.guild.channels.cache.filter( logchannel => {
 		verifynotice.logchannel = ( verifynotice.logchannel ? channel.guild.channels.cache.filter( logchannel => {
-			return ( logchannel.isGuild() && logchannel.permissionsFor(channel.guild.me).has(['VIEW_CHANNEL', 'SEND_MESSAGES']) );
+			return ( logchannel.isGuild() && logchannel.permissionsFor(channel.guild.me).has([FLAGS.VIEW_CHANNEL, FLAGS.SEND_MESSAGES]) );
 		} ).get(verifynotice.logchannel) : null );
 		} ).get(verifynotice.logchannel) : null );
 		got.get( wiki + 'api.php?action=query&meta=siteinfo|globaluserinfo&siprop=general&guiprop=groups&guiuser=' + encodeURIComponent( username ) + '&list=users&usprop=blockinfo|groups|editcount|registration|gender&ususers=' + encodeURIComponent( username ) + '&format=json' ).then( response => {
 		got.get( wiki + 'api.php?action=query&meta=siteinfo|globaluserinfo&siprop=general&guiprop=groups&guiuser=' + encodeURIComponent( username ) + '&list=users&usprop=blockinfo|groups|editcount|registration|gender&ususers=' + encodeURIComponent( username ) + '&format=json' ).then( response => {
 			var body = response.body;
 			var body = response.body;
@@ -651,27 +652,22 @@ global.verifyOauthUser = function(state, access_token, settings) {
 				else {
 				else {
 					console.log( '- ' + response.statusCode + ': Error while getting the user: ' + body?.error?.info );
 					console.log( '- ' + response.statusCode + ': Error while getting the user: ' + body?.error?.info );
 				}
 				}
-				return settings.send?.();
+				return settings.fail?.();
 			}
 			}
 			wiki.updateWiki(body.query.general);
 			wiki.updateWiki(body.query.general);
-			logging(wiki, channel.guild.id, 'verification');
+			logging(wiki, channel.guildId, 'verification');
 			var queryuser = body.query.users[0];
 			var queryuser = body.query.users[0];
-			if ( body.query.users.length !== 1 || queryuser.missing !== undefined || queryuser.invalid !== undefined ) return settings.send?.();
-			var allowedMentions = {
-				users: [
-					member.id
-				]
-			};
+			if ( body.query.users.length !== 1 || queryuser.missing !== undefined || queryuser.invalid !== undefined ) return settings.fail?.();
 			var embed = new MessageEmbed().setFooter( lang.get('verify.footer') ).setTimestamp().setAuthor( body.query.general.sitename ).addField( lang.get('verify.discord', queryuser.gender), escapeFormatting(member.user.tag), true ).addField( lang.get('verify.wiki', queryuser.gender), lang.get('verify.oauth_used'), true );
 			var embed = new MessageEmbed().setFooter( lang.get('verify.footer') ).setTimestamp().setAuthor( body.query.general.sitename ).addField( lang.get('verify.discord', queryuser.gender), escapeFormatting(member.user.tag), true ).addField( lang.get('verify.wiki', queryuser.gender), lang.get('verify.oauth_used'), true );
 			var pagelink = wiki.toLink('User:' + username, '', '', true);
 			var pagelink = wiki.toLink('User:' + username, '', '', true);
 			embed.setTitle( escapeFormatting(username) ).setURL( pagelink );
 			embed.setTitle( escapeFormatting(username) ).setURL( pagelink );
 			if ( queryuser.blockexpiry ) {
 			if ( queryuser.blockexpiry ) {
 				embed.setColor('#FF0000').setDescription( lang.get('verify.user_blocked', '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) );
 				embed.setColor('#FF0000').setDescription( lang.get('verify.user_blocked', '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) );
-				return sendMessage(lang.get('verify.user_blocked_reply', escapeFormatting(username), queryuser.gender), {embed, allowedMentions}).then( msg => {
+				return sendMessage( {content: lang.get('verify.user_blocked_reply', escapeFormatting(username), queryuser.gender), embeds: [embed]} ).then( msg => {
 					if ( (verifynotice.flags & 1 << 1) !== 1 << 1 || !verifynotice.logchannel ) return;
 					if ( (verifynotice.flags & 1 << 1) !== 1 << 1 || !verifynotice.logchannel ) return;
 					let logembed;
 					let logembed;
-					let logtext = '';
-					if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) {
+					let logtext;
+					if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) {
 						logembed = new MessageEmbed(embed);
 						logembed = new MessageEmbed(embed);
 						logembed.addField( lang.get('verify.discord', 'unknown'), escapeFormatting(member.user.tag) + ` (${member.toString()})`, true );
 						logembed.addField( lang.get('verify.discord', 'unknown'), escapeFormatting(member.user.tag) + ` (${member.toString()})`, true );
 						if ( msg ) logembed.addField(msg.url, '<#' + channel.id + '>');
 						if ( msg ) logembed.addField(msg.url, '<#' + channel.id + '>');
@@ -681,19 +677,19 @@ global.verifyOauthUser = function(state, access_token, settings) {
 						logtext += '\n<' + pagelink + '>';
 						logtext += '\n<' + pagelink + '>';
 						if ( msg ) logtext += '\n<#' + channel.id + '> – <' + msg.url + '>';
 						if ( msg ) logtext += '\n<#' + channel.id + '> – <' + msg.url + '>';
 					}
 					}
-					verifynotice.logchannel.send(logtext, {
-						embed: logembed,
-						allowedMentions: {parse: []}
-					}).catch(log_error);
+					verifynotice.logchannel.send( {
+						content: logtext,
+						embeds: [logembed]
+					} ).catch(log_error);
 				}, log_error );
 				}, log_error );
 			}
 			}
 			if ( body.query.globaluserinfo.locked !== undefined ) {
 			if ( body.query.globaluserinfo.locked !== undefined ) {
 				embed.setColor('#FF0000').setDescription( lang.get('verify.user_gblocked', '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) );
 				embed.setColor('#FF0000').setDescription( lang.get('verify.user_gblocked', '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) );
-				return sendMessage(lang.get('verify.user_gblocked_reply', escapeFormatting(username), queryuser.gender), {embed, allowedMentions}).then( msg => {
+				return sendMessage( {content: lang.get('verify.user_gblocked_reply', escapeFormatting(username), queryuser.gender), embeds: [embed]} ).then( msg => {
 					if ( (verifynotice.flags & 1 << 1) !== 1 << 1 || !verifynotice.logchannel ) return;
 					if ( (verifynotice.flags & 1 << 1) !== 1 << 1 || !verifynotice.logchannel ) return;
 					let logembed;
 					let logembed;
-					let logtext = '';
-					if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) {
+					let logtext;
+					if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) {
 						logembed = new MessageEmbed(embed);
 						logembed = new MessageEmbed(embed);
 						logembed.addField( lang.get('verify.discord', 'unknown'), escapeFormatting(member.user.tag) + ` (${member.toString()})`, true );
 						logembed.addField( lang.get('verify.discord', 'unknown'), escapeFormatting(member.user.tag) + ` (${member.toString()})`, true );
 						if ( msg ) logembed.addField(msg.url, '<#' + channel.id + '>');
 						if ( msg ) logembed.addField(msg.url, '<#' + channel.id + '>');
@@ -703,10 +699,10 @@ global.verifyOauthUser = function(state, access_token, settings) {
 						logtext += '\n<' + pagelink + '>';
 						logtext += '\n<' + pagelink + '>';
 						if ( msg ) logtext += '\n<#' + channel.id + '> – <' + msg.url + '>';
 						if ( msg ) logtext += '\n<#' + channel.id + '> – <' + msg.url + '>';
 					}
 					}
-					verifynotice.logchannel.send(logtext, {
-						embed: logembed,
-						allowedMentions: {parse: []}
-					}).catch(log_error);
+					verifynotice.logchannel.send( {
+						content: logtext,
+						embeds: [logembed]
+					} ).catch(log_error);
 				}, log_error );
 				}, log_error );
 			}
 			}
 			queryuser.groups.push(...body.query.globaluserinfo.groups);
 			queryuser.groups.push(...body.query.globaluserinfo.groups);
@@ -784,10 +780,10 @@ global.verifyOauthUser = function(state, access_token, settings) {
 					];
 					];
 					var useLogging = false;
 					var useLogging = false;
 					var logembed;
 					var logembed;
-					var logtext = '';
+					var logtext;
 					if ( verifynotice.logchannel ) {
 					if ( verifynotice.logchannel ) {
 						useLogging = true;
 						useLogging = true;
-						if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) {
+						if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) {
 							logembed = new MessageEmbed(embed);
 							logembed = new MessageEmbed(embed);
 							if ( addRolesMentions[0].length ) logembed.addField( lang.get('verify.qualified_add'), addRolesMentions[0].join('\n') );
 							if ( addRolesMentions[0].length ) logembed.addField( lang.get('verify.qualified_add'), addRolesMentions[0].join('\n') );
 							if ( addRolesMentions[1].length ) logembed.setColor('#008800').addField( lang.get('verify.qualified_add_error'), addRolesMentions[1].join('\n') );
 							if ( addRolesMentions[1].length ) logembed.setColor('#008800').addField( lang.get('verify.qualified_add_error'), addRolesMentions[1].join('\n') );
@@ -812,7 +808,7 @@ global.verifyOauthUser = function(state, access_token, settings) {
 						accountage: Math.trunc(accountage),
 						accountage: Math.trunc(accountage),
 						dateformat: lang.get('dateformat')
 						dateformat: lang.get('dateformat')
 					}).trim() : '' );
 					}).trim() : '' );
-					if ( channel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) {
+					if ( channel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) {
 						if ( addRolesMentions[0].length ) embed.addField( lang.get('verify.qualified_add'), addRolesMentions[0].join('\n') );
 						if ( addRolesMentions[0].length ) embed.addField( lang.get('verify.qualified_add'), addRolesMentions[0].join('\n') );
 						if ( addRolesMentions[1].length && !useLogging ) embed.setColor('#008800').addField( lang.get('verify.qualified_add_error'), addRolesMentions[1].join('\n') );
 						if ( addRolesMentions[1].length && !useLogging ) embed.setColor('#008800').addField( lang.get('verify.qualified_add_error'), addRolesMentions[1].join('\n') );
 						if ( removeRolesMentions[0].length ) embed.addField( lang.get('verify.qualified_remove'), removeRolesMentions[0].join('\n') );
 						if ( removeRolesMentions[0].length ) embed.addField( lang.get('verify.qualified_remove'), removeRolesMentions[0].join('\n') );
@@ -829,16 +825,16 @@ global.verifyOauthUser = function(state, access_token, settings) {
 						if ( comment.length && !useLogging ) text += '\n\n' + comment.join('\n');
 						if ( comment.length && !useLogging ) text += '\n\n' + comment.join('\n');
 						if ( onsuccess ) text += '\n\n**' + lang.get('verify.notice') + '** ' + onsuccess;
 						if ( onsuccess ) text += '\n\n**' + lang.get('verify.notice') + '** ' + onsuccess;
 					}
 					}
-					return sendMessage(text, {embed, allowedMentions}).then( msg => {
+					return sendMessage( {content: text, embeds: [embed]} ).then( msg => {
 						if ( !useLogging ) return;
 						if ( !useLogging ) return;
 						if ( msg ) {
 						if ( msg ) {
 							if ( logembed ) logembed.addField(msg.url, '<#' + channel.id + '>');
 							if ( logembed ) logembed.addField(msg.url, '<#' + channel.id + '>');
 							else logtext += '\n<#' + channel.id + '> – <' + msg.url + '>';
 							else logtext += '\n<#' + channel.id + '> – <' + msg.url + '>';
 						}
 						}
-						verifynotice.logchannel.send(logtext, {
-							embed: logembed,
-							allowedMentions: {parse: []}
-						}).catch(log_error);
+						verifynotice.logchannel.send( {
+							content: logtext,
+							embeds: [logembed]
+						} ).catch(log_error);
 					}, log_error );
 					}, log_error );
 				}, log_error );
 				}, log_error );
 			}
 			}
@@ -846,9 +842,9 @@ global.verifyOauthUser = function(state, access_token, settings) {
 			embed.setColor('#FFFF00').setDescription( lang.get('verify.user_matches', member.toString(), '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) );
 			embed.setColor('#FFFF00').setDescription( lang.get('verify.user_matches', member.toString(), '[' + escapeFormatting(username) + '](' + pagelink + ')', queryuser.gender) );
 
 
 			let logembed;
 			let logembed;
-			let logtext = '';
+			let logtext;
 			if ( (verifynotice.flags & 1 << 1) === 1 << 1 && verifynotice.logchannel ) {
 			if ( (verifynotice.flags & 1 << 1) === 1 << 1 && verifynotice.logchannel ) {
-				if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) {
+				if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) {
 					logembed = new MessageEmbed(embed);
 					logembed = new MessageEmbed(embed);
 				}
 				}
 				else {
 				else {
@@ -865,116 +861,114 @@ global.verifyOauthUser = function(state, access_token, settings) {
 					dateformat: lang.get('dateformat')
 					dateformat: lang.get('dateformat')
 				});
 				});
 				if ( onmatch.trim() ) {
 				if ( onmatch.trim() ) {
-					if ( channel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) embed.addField( lang.get('verify.notice'), onmatch );
+					if ( channel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) embed.addField( lang.get('verify.notice'), onmatch );
 					else noticeContent = '\n\n**' + lang.get('verify.notice') + '** ' + onmatch;
 					else noticeContent = '\n\n**' + lang.get('verify.notice') + '** ' + onmatch;
 				}
 				}
 			}
 			}
-			var components = [
-				{
-					type: 1,
-					components: [
-						{
-							type: 2,
-							style: 1,
-							label: lang.get('verify.button_again'),
-							emoji: {id: null, name: '🔂'},
-							custom_id: 'verify_again',
-							disabled: false
-						}
-					]
-				}
-			];
-			return sendMessage(lang.get('verify.user_matches_reply', escapeFormatting(username), queryuser.gender) + noticeContent, {embed, allowedMentions, components}).then( msg => {
+			return sendMessage( {
+				content: lang.get('verify.user_matches_reply', escapeFormatting(username), queryuser.gender) + noticeContent,
+				embeds: [embed], components: [new MessageActionRow().addComponents(
+					new MessageButton().setLabel(lang.get('verify.button_again')).setEmoji('🔂').setStyle('PRIMARY').setCustomId('verify_again')
+				)]
+			} ).then( msg => {
 				if ( !logtext && !logembed ) return;
 				if ( !logtext && !logembed ) return;
 				if ( msg ) {
 				if ( msg ) {
-					if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has('EMBED_LINKS') ) {
+					if ( verifynotice.logchannel.permissionsFor(channel.guild.me).has(FLAGS.EMBED_LINKS) ) {
 						logembed.addField(msg.url, '<#' + channel.id + '>');
 						logembed.addField(msg.url, '<#' + channel.id + '>');
 					}
 					}
 					else logtext += '\n<#' + channel.id + '> – <' + msg.url + '>';
 					else logtext += '\n<#' + channel.id + '> – <' + msg.url + '>';
 				}
 				}
-				verifynotice.logchannel.send(logtext, {
-					embed: logembed,
-					allowedMentions: {parse: []}
-				}).catch(log_error);
+				verifynotice.logchannel.send( {
+					content: logtext,
+					embeds: [logembed]
+				} ).catch(log_error);
 			}, log_error );
 			}, log_error );
 
 
 			/**
 			/**
 			 * Send the message responding to the OAuth2 verification.
 			 * Send the message responding to the OAuth2 verification.
-			 * @param {String} content - The message content.
 			 * @param {import('discord.js').MessageOptions} options - The message options.
 			 * @param {import('discord.js').MessageOptions} options - The message options.
-			 * @returns {Promise<import('discord.js').Message?>}
 			 */
 			 */
-			function sendMessage(content, options) {
-				var msg = Promise.resolve();
-				if ( settings.send ) msg = settings.send(member.toString() + ', ' + content, options);
-				else if ( settings.token ) {
-					msg = channel.client.api.webhooks(channel.client.user.id, settings.token).post( {
-						data: {
-							content: member.toString() + ', ' + content,
-							allowed_mentions: options.allowedMentions,
-							embeds: ( options.embed ? [options.embed] : [] ),
-							components: ( options.components || [] ),
-							flags: ( (verifynotice.flags & 1 << 0) === 1 << 0 ? 64 : 0 )
-						}
-					} ).then( message => {
-						if ( (verifynotice.flags & 1 << 0) === 1 << 0 ) return;
-						return channel.messages.add(message);
-					}, () => {
-						if ( (verifynotice.flags & 1 << 0) === 1 << 0 ) {
-							let dmEmbed = new MessageEmbed(options.embed);
-							dmEmbed.fields.forEach( field => {
+			function sendMessage(options) {
+				var message = {
+					content: member.toString() + ', ' + options.content,
+					embeds: ( options.embeds?.[0] ? options.embeds : [] ),
+					components: ( options.components || [] ),
+					allowedMentions: {
+						users: [member.id],
+						repliedUser: true
+					},
+					ephemeral: ( (verifynotice.flags & 1 << 0) === 1 << 0 )
+				}
+				if ( settings.interaction ) return settings.interaction.editReply( message ).then( msg => {
+					if ( settings.interaction.isButton() ) settings.interaction.followUp( {
+						content: message.content,
+						embeds: message.embeds,
+						components: [],
+						ephemeral: true
+					} ).catch(log_error);
+					if ( message.ephemeral ) return;
+					return msg;
+				}, error => {
+					log_error(error);
+					if ( message.ephemeral ) {
+						let dmEmbeds = [];
+						if ( message.embeds[0] ) {
+							dmEmbeds.push(new MessageEmbed(message.embeds[0]));
+							dmEmbeds[0].fields.forEach( field => {
 								field.value = field.value.replace( /<@&(\d+)>/g, (mention, id) => {
 								field.value = field.value.replace( /<@&(\d+)>/g, (mention, id) => {
 									if ( !channel.guild.roles.cache.has(id) ) return mention;
 									if ( !channel.guild.roles.cache.has(id) ) return mention;
 									return escapeFormatting('@' + channel.guild.roles.cache.get(id)?.name);
 									return escapeFormatting('@' + channel.guild.roles.cache.get(id)?.name);
 								} );
 								} );
 							} );
 							} );
-							member.send(channel.toString() + '; ' + content, Object.assign({}, options, {embed: dmEmbed})).then( message => {
-								allowDelete(message, member.id);
-								if ( settings.sourceMessage ) {
-									settings.sourceMessage.reactEmoji('📩');
-									settings.sourceMessage.delete({timeout: 60000, reason: lang.get('verify.footer')}).catch(log_error);
-								}
-							}, error => {
-								if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
-									return channel.send(member.toString() + ', ' + content, options).catch(log_error);
-								}
-								log_error(error);
-							} );
 						}
 						}
-						else return channel.send(member.toString() + ', ' + content, options).catch(log_error);
-					} );
-				}
-				else if ( (verifynotice.flags & 1 << 0) === 1 << 0 ) {
-					let dmEmbed = new MessageEmbed(options.embed);
-					dmEmbed.fields.forEach( field => {
-						field.value = field.value.replace( /<@&(\d+)>/g, (mention, id) => {
-							if ( !channel.guild.roles.cache.has(id) ) return mention;
-							return escapeFormatting('@' + channel.guild.roles.cache.get(id)?.name);
+						return member.send( {content: channel.toString() + '; ' + options.content, embeds: dmEmbeds} ).then( msg => {
+							allowDelete(msg, member.id);
+							if ( settings.sourceMessage ) {
+								settings.sourceMessage.reactEmoji('📩');
+								setTimeout( () => settings.sourceMessage.delete().catch(log_error), 60000 ).unref();
+							}
+						}, error => {
+							if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
+								return channel.send( message ).catch(log_error);
+							}
+							log_error(error);
 						} );
 						} );
-					} );
-					member.send(channel.toString() + '; ' + content, Object.assign({}, options, {embed: dmEmbed})).then( message => {
-						allowDelete(message, member.id);
+					}
+					return channel.send( message ).catch(log_error);
+				} );
+				if ( message.ephemeral ) {
+					let dmEmbeds = [];
+					if ( message.embeds[0] ) {
+						dmEmbeds.push(new MessageEmbed(message.embeds[0]));
+						dmEmbeds[0].fields.forEach( field => {
+							field.value = field.value.replace( /<@&(\d+)>/g, (mention, id) => {
+								if ( !channel.guild.roles.cache.has(id) ) return mention;
+								return escapeFormatting('@' + channel.guild.roles.cache.get(id)?.name);
+							} );
+						} );
+					}
+					return member.send( {content: channel.toString() + '; ' + options.content, embeds: dmEmbeds} ).then( msg => {
+						allowDelete(msg, member.id);
 						if ( settings.sourceMessage ) {
 						if ( settings.sourceMessage ) {
 							settings.sourceMessage.reactEmoji('📩');
 							settings.sourceMessage.reactEmoji('📩');
-							settings.sourceMessage.delete({timeout: 60000, reason: lang.get('verify.footer')}).catch(log_error);
+							setTimeout( () => settings.sourceMessage.delete().catch(log_error), 60000 ).unref();
 						}
 						}
 					}, error => {
 					}, error => {
 						if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
 						if ( error?.code === 50007 ) { // CANNOT_MESSAGE_USER
-							return channel.send(member.toString() + ', ' + content, options).catch(log_error);
+							return channel.send( message ).catch(log_error);
 						}
 						}
 						log_error(error);
 						log_error(error);
 					} );
 					} );
 				}
 				}
-				else msg = channel.send(member.toString() + ', ' + content, options).catch(log_error);
-				return msg;
+				return channel.send( message ).catch(log_error);
 			}
 			}
 		}, error => {
 		}, error => {
 			console.log( '- Error while getting the user: ' + error );
 			console.log( '- Error while getting the user: ' + error );
-			settings.send?.();
+			settings.fail?.();
 		} );
 		} );
 	}, error => {
 	}, error => {
 		if ( error ) console.log( '- Error while preparing oauth verification: ' + error );
 		if ( error ) console.log( '- Error while preparing oauth verification: ' + error );
-		settings.send?.();
+		settings.fail?.();
 	} );
 	} );
 }
 }
 
 

+ 87 - 87
i18n/en.json

@@ -113,7 +113,7 @@
     },
     },
     "dateformat": "en-US",
     "dateformat": "en-US",
     "diff": {
     "diff": {
-        "badrev": "at least one revision doesn't exist!",
+        "badrev": "At least one revision doesn't exist!",
         "hidden": "*hidden*",
         "hidden": "*hidden*",
         "info": {
         "info": {
             "added": "Added:",
             "added": "Added:",
@@ -146,15 +146,15 @@
     ],
     ],
     "general": {
     "general": {
         "database": "⚠️ **Limited Functionality** ⚠️\nNo settings found, please contact the bot owner!",
         "database": "⚠️ **Limited Functionality** ⚠️\nNo settings found, please contact the bot owner!",
-        "default": "this server isn't set up yet. Use $1 or the dashboard to change the settings.",
+        "default": "This server isn't set up yet. Use $1 or the dashboard to change the settings.",
         "disclaimer": "I am a small bot with the purpose to easily link and search MediaWiki sites like Wikipedia and Fandom wikis. I show short descriptions and additional info about pages and am able to resolve redirects and follow interwiki links. $1 wrote me in JavaScript.\n\nYou can support me on Patreon:",
         "disclaimer": "I am a small bot with the purpose to easily link and search MediaWiki sites like Wikipedia and Fandom wikis. I show short descriptions and additional info about pages and am able to resolve redirects and follow interwiki links. $1 wrote me in JavaScript.\n\nYou can support me on Patreon:",
         "experimental": "**This feature is experimental! It is not guaranteed to work correctly and may be removed in the future.**",
         "experimental": "**This feature is experimental! It is not guaranteed to work correctly and may be removed in the future.**",
         "helpserver": "For questions and problems please visit my support server:",
         "helpserver": "For questions and problems please visit my support server:",
         "limit": "🚨 **Stop, you hit a limit!** 🚨\n\n$1, your message contained too many commands!",
         "limit": "🚨 **Stop, you hit a limit!** 🚨\n\n$1, your message contained too many commands!",
         "missingperm": "I'm missing some permissions for this command:",
         "missingperm": "I'm missing some permissions for this command:",
-        "patreon": "this is a Patreon only feature!\nYou can support me on Patreon to get access to this feature:",
-        "prefix": "the prefix for this server is `$1`. You can change the prefix with `$1settings prefix`. For a list of all commands see `$1help`.",
-        "readonly": "**the database is currently in read-only mode, you can't change any settings right now!**"
+        "patreon": "This is a Patreon only feature!\nYou can support me on Patreon to get access to this feature:",
+        "prefix": "The prefix for this server is `$1`. You can change the prefix with `$1settings prefix`. For a list of all commands see `$1help`.",
+        "readonly": "**The database is currently in read-only mode, you can't change any settings right now!**"
     },
     },
     "help": {
     "help": {
         "admin": "These commands can only be performed by administrators:",
         "admin": "These commands can only be performed by administrators:",
@@ -389,7 +389,7 @@
                 "desc": "I will answer with a link to a matching article in the named Wikia wiki: `https://<wiki>.wikia.org/`"
                 "desc": "I will answer with a link to a matching article in the named Wikia wiki: `https://<wiki>.wikia.org/`"
             }
             }
         },
         },
-        "noadmin": "you need the `Manage Server` permission for these commands!",
+        "noadmin": "You need the `Manage Server` permission for these commands!",
         "pause": "**I'm currently paused on this server!**\nOnly these commands can be performed:"
         "pause": "**I'm currently paused on this server!**\nOnly these commands can be performed:"
     },
     },
     "interaction": {
     "interaction": {
@@ -490,34 +490,34 @@
     "rcscript": {
     "rcscript": {
         "ad": "You want recent changes directly in Discord? Use `$1rcscript` to add a recent changes webhook based on **$2** to your Discord server!",
         "ad": "You want recent changes directly in Discord? Use `$1rcscript` to add a recent changes webhook based on **$2** to your Discord server!",
         "add_more": "Add more recent changes webhooks:",
         "add_more": "Add more recent changes webhooks:",
-        "added": "a recent changes webhook has been added for:",
-        "all_inactive": "you can't have wiki changes and feeds based changes disabled at the same time.",
+        "added": "A recent changes webhook has been added for:",
+        "all_inactive": "You can't have wiki changes and feeds based changes disabled at the same time.",
         "audit_reason": "Recent changes webhook for \"$1\"",
         "audit_reason": "Recent changes webhook for \"$1\"",
         "audit_reason_delete": "Removed recent changes webhook",
         "audit_reason_delete": "Removed recent changes webhook",
         "audit_reason_edit": "Updated recent changes webhook",
         "audit_reason_edit": "Updated recent changes webhook",
         "avatar": "Webhook avatar:",
         "avatar": "Webhook avatar:",
-        "blocked": "this wiki has been blocked from being added as a recent changes webhook!",
-        "blocked_reason": "this wiki has been blocked from being added as a recent changes webhook for `$1`!",
+        "blocked": "This wiki has been blocked from being added as a recent changes webhook!",
+        "blocked_reason": "This wiki has been blocked from being added as a recent changes webhook for `$1`!",
         "channel": "Channel:",
         "channel": "Channel:",
-        "current": "these are the current recent changes webhooks for this server:",
-        "current_display": "the display mode for this webhook is:",
-        "current_lang": "the language for this webhook is:",
-        "current_selected": "this is the recent changes webhook `$1` for this server:",
-        "current_wiki": "the wiki for this webhook is:",
+        "current": "These are the current recent changes webhooks for this server:",
+        "current_display": "The display mode for this webhook is:",
+        "current_lang": "The language for this webhook is:",
+        "current_selected": "This is the recent changes webhook `$1` for this server:",
+        "current_wiki": "The wiki for this webhook is:",
         "dashboard": {
         "dashboard": {
             "added": "$1 added the recent changes webhook with id `$2`.",
             "added": "$1 added the recent changes webhook with id `$2`.",
             "removed": "$1 removed the recent changes webhook with id `$2`.",
             "removed": "$1 removed the recent changes webhook with id `$2`.",
             "updated": "$1 updated the recent changes webhook with id `$2`."
             "updated": "$1 updated the recent changes webhook with id `$2`."
         },
         },
         "delete": "Delete this recent changes webhook:",
         "delete": "Delete this recent changes webhook:",
-        "deleted": "the recent changes webhook has been deleted.",
+        "deleted": "The recent changes webhook has been deleted.",
         "disabled": "disabled",
         "disabled": "disabled",
-        "disabled_feeds": "the feeds based changes, like discussions, message walls and article comments, for this webhook have been disabled.",
-        "disabled_rc": "the wiki changes for this webhook have been disabled.",
+        "disabled_feeds": "The feeds based changes, like discussions, message walls and article comments, for this webhook have been disabled.",
+        "disabled_rc": "The wiki changes for this webhook have been disabled.",
         "display": "Display mode:",
         "display": "Display mode:",
         "enabled": "enabled",
         "enabled": "enabled",
-        "enabled_feeds": "the feeds based changes, like discussions, message walls and article comments, for this webhook have been enabled.",
-        "enabled_rc": "the wiki changes for this webhook have been enabled.",
+        "enabled_feeds": "The feeds based changes, like discussions, message walls and article comments, for this webhook have been enabled.",
+        "enabled_rc": "The wiki changes for this webhook have been enabled.",
         "feeds": "Feeds based changes:",
         "feeds": "Feeds based changes:",
         "help_display_compact": "Compact text messages with inline links.",
         "help_display_compact": "Compact text messages with inline links.",
         "help_display_diff": "Embed messages with image previews and edit differences.",
         "help_display_diff": "Embed messages with image previews and edit differences.",
@@ -527,20 +527,20 @@
         "help_lang": "Currently supported languages are:",
         "help_lang": "Currently supported languages are:",
         "help_wiki": "Link to a MediaWiki site like `https://<wiki>.fandom.com/`",
         "help_wiki": "Link to a MediaWiki site like `https://<wiki>.fandom.com/`",
         "lang": "Language:",
         "lang": "Language:",
-        "max_entries": "you already reached the maximal amount of recent changes webhooks.",
-        "missing": "there are no recent changes webhooks for this server yet.",
+        "max_entries": "You already reached the maximal amount of recent changes webhooks.",
+        "missing": "There are no recent changes webhooks for this server yet.",
         "name": "Webhook name:",
         "name": "Webhook name:",
         "new_lang": "<new language>",
         "new_lang": "<new language>",
         "new_wiki": "<link to wiki>",
         "new_wiki": "<link to wiki>",
-        "no_feeds": "the wiki for this webhook has no feeds based features, like discussions, message walls or article comments, enabled.",
-        "noadmin": "you need the `Manage Webhooks` permission for this command!",
+        "no_feeds": "The wiki for this webhook has no feeds based features, like discussions, message walls or article comments, enabled.",
+        "noadmin": "You need the `Manage Webhooks` permission for this command!",
         "rc": "Wiki changes:",
         "rc": "Wiki changes:",
-        "sysmessage": "the system message `$1` has to be the server id `$2` to add a recent changes webhook.",
+        "sysmessage": "The system message `$1` has to be the server id `$2` to add a recent changes webhook.",
         "title": "Recent changes webhook",
         "title": "Recent changes webhook",
         "toggle": "(toggle)",
         "toggle": "(toggle)",
-        "updated_display": "the display mode for this webhook has been changed to:",
-        "updated_lang": "the language for this webhook has been changed to:",
-        "updated_wiki": "the wiki for this webhook has been changed to:",
+        "updated_display": "The display mode for this webhook has been changed to:",
+        "updated_lang": "The language for this webhook has been changed to:",
+        "updated_wiki": "The wiki for this webhook has been changed to:",
         "webhook": {
         "webhook": {
             "blocked": "This recent changes webhook will be deleted because the wiki has been blocked!",
             "blocked": "This recent changes webhook will be deleted because the wiki has been blocked!",
             "blocked_help": "You can ask for more details on the [support server]($1).",
             "blocked_help": "You can ask for more details on the [support server]($1).",
@@ -574,7 +574,7 @@
             "updated_lang": "The language has been changed to `$1` for this recent changes webhook.",
             "updated_lang": "The language has been changed to `$1` for this recent changes webhook.",
             "updated_wiki": "The wiki has been changed to $1 for this recent changes webhook."
             "updated_wiki": "The wiki has been changed to $1 for this recent changes webhook."
         },
         },
-        "webhook_failed": "sadly the webhook couldn't be created, please try again later.",
+        "webhook_failed": "Sadly the webhook couldn't be created, please try again later.",
         "wiki": "Wiki:"
         "wiki": "Wiki:"
     },
     },
     "search": {
     "search": {
@@ -596,14 +596,14 @@
     },
     },
     "settings": {
     "settings": {
         "button": "Use the Dashboard",
         "button": "Use the Dashboard",
-        "channel current": "these are the current settings for this channel:",
-        "channel lang": "the language for this channel is:",
-        "channel langchanged": "you changed the language for this channel to:",
-        "channel role": "the minimal required role for this channel is:",
-        "channel rolechanged": "you changed the minimal required role for this channel to:",
-        "channel wiki": "the default wiki for this channel is:",
-        "channel wikichanged": "you changed the default wiki for this channel to:",
-        "current": "these are the current settings for this server:",
+        "channel current": "These are the current settings for this channel:",
+        "channel lang": "The language for this channel is:",
+        "channel langchanged": "You changed the language for this channel to:",
+        "channel role": "The minimal required role for this channel is:",
+        "channel rolechanged": "You changed the minimal required role for this channel to:",
+        "channel wiki": "The default wiki for this channel is:",
+        "channel wikichanged": "You changed the default wiki for this channel to:",
+        "current": "These are the current settings for this server:",
         "currentchannel": "Channel overwrites:",
         "currentchannel": "Channel overwrites:",
         "currentinline": "Inline commands:",
         "currentinline": "Inline commands:",
         "currentlang": "Language:",
         "currentlang": "Language:",
@@ -617,42 +617,42 @@
         },
         },
         "foundwikis": "Do you mean any of these wikis?",
         "foundwikis": "Do you mean any of these wikis?",
         "inline disabled": {
         "inline disabled": {
-            "channel inline": "inline commands are currently disabled for this channel.",
-            "channel inlinechanged": "you disabled inline commands for this channel.",
+            "channel inline": "Inline commands are currently disabled for this channel.",
+            "channel inlinechanged": "You disabled inline commands for this channel.",
             "help": "Use `$1` to enable inline commands like `[[$2]]` and `{{$2}}`.",
             "help": "Use `$1` to enable inline commands like `[[$2]]` and `{{$2}}`.",
-            "inline": "inline commands are currently disabled for this server.",
-            "inlinechanged": "you disabled inline commands for this server."
+            "inline": "Inline commands are currently disabled for this server.",
+            "inlinechanged": "You disabled inline commands for this server."
         },
         },
         "inline enabled": {
         "inline enabled": {
-            "channel inline": "inline commands are currently enabled for this channel.",
-            "channel inlinechanged": "you enabled inline commands for this channel.",
+            "channel inline": "Inline commands are currently enabled for this channel.",
+            "channel inlinechanged": "You enabled inline commands for this channel.",
             "help": "Use `$1` to disable inline commands like `[[$2]]` and `{{$2}}`.",
             "help": "Use `$1` to disable inline commands like `[[$2]]` and `{{$2}}`.",
-            "inline": "inline commands are currently enabled for this server.",
-            "inlinechanged": "you enabled inline commands for this server."
+            "inline": "Inline commands are currently enabled for this server.",
+            "inlinechanged": "You enabled inline commands for this server."
         },
         },
-        "lang": "the language for this server is:",
-        "langchanged": "you changed the language for this server to:",
+        "lang": "The language for this server is:",
+        "langchanged": "You changed the language for this server to:",
         "langhelp": "Use `$1 <language>` to change the language.\nCurrently supported languages are:",
         "langhelp": "Use `$1 <language>` to change the language.\nCurrently supported languages are:",
-        "langinvalid": "the specified language is not supported!",
-        "missing": "this server isn't set up yet. Use $1 and $2 to change the settings.",
+        "langinvalid": "The specified language is not supported!",
+        "missing": "This server isn't set up yet. Use $1 and $2 to change the settings.",
         "nochannels": "*No channel overwrites yet*",
         "nochannels": "*No channel overwrites yet*",
-        "prefix": "the prefix for this server is:",
-        "prefixchanged": "you changed the prefix for this server to:",
+        "prefix": "The prefix for this server is:",
+        "prefixchanged": "You changed the prefix for this server to:",
         "prefixhelp": "Use `$1 <prefix>` to change the prefix.\nUse `_` at the end to indicate a space at the end of the prefix.\nThe prefix may not include mentions!",
         "prefixhelp": "Use `$1 <prefix>` to change the prefix.\nUse `_` at the end to indicate a space at the end of the prefix.\nThe prefix may not include mentions!",
-        "prefixinvalid": "the specified prefix is not supported!",
-        "role": "the minimal required role for this server is:",
-        "rolechanged": "you changed the minimal required role for this server to:",
+        "prefixinvalid": "The specified prefix is not supported!",
+        "role": "The minimal required role for this server is:",
+        "rolechanged": "You changed the minimal required role for this server to:",
         "rolehelp": "Use `$1 <role>` to change the minimal required role.",
         "rolehelp": "Use `$1 <role>` to change the minimal required role.",
-        "roleinvalid": "the specified role does not exist!",
-        "save_failed": "sadly the settings couldn't be saved, please try again later.",
-        "wiki": "the default wiki for this server is:",
-        "wikichanged": "you changed the default wiki for this server to:",
+        "roleinvalid": "The specified role does not exist!",
+        "save_failed": "Sadly the settings couldn't be saved, please try again later.",
+        "wiki": "The default wiki for this server is:",
+        "wikichanged": "You changed the default wiki for this server to:",
         "wikihelp": "Use `$1 <link>` to change the default wiki.\nLink to a MediaWiki site like `https://<wiki>.fandom.com/`",
         "wikihelp": "Use `$1 <link>` to change the default wiki.\nLink to a MediaWiki site like `https://<wiki>.fandom.com/`",
-        "wikiinvalid": "please provide a valid link to a MediaWiki site, like Wikipedia or a Fandom wiki!",
-        "wikiinvalid_http": "the provided website doesn't have a valid TLS/SSL certificate! For security reasons only wikis using HTTPS are supported.\nIf you are a site administrator, you can get a certificate from a certificate authority like *Let’s Encrypt*:\n<https://letsencrypt.org/getting-started/>",
-        "wikiinvalid_private": "the provided wiki is private! Only public wikis that can be read by everyone are supported.",
-        "wikiinvalid_timeout": "the provided link took too long to respond!",
-        "wikimissing": "no default wiki is set for this server yet!"
+        "wikiinvalid": "Please provide a valid link to a MediaWiki site, like Wikipedia or a Fandom wiki!",
+        "wikiinvalid_http": "The provided website doesn't have a valid TLS/SSL certificate! For security reasons only wikis using HTTPS are supported.\nIf you are a site administrator, you can get a certificate from a certificate authority like *Let’s Encrypt*:\n<https://letsencrypt.org/getting-started/>",
+        "wikiinvalid_private": "The provided wiki is private! Only public wikis that can be read by everyone are supported.",
+        "wikiinvalid_timeout": "The provided link took too long to respond!",
+        "wikimissing": "No default wiki is set for this server yet!"
     },
     },
     "test": {
     "test": {
         "MediaWiki": "Requires at least $1 for full functionality, found `$2`.",
         "MediaWiki": "Requires at least $1 for full functionality, found `$2`.",
@@ -661,7 +661,7 @@
         "text": [
         "text": [
             "I'm fully functional!",
             "I'm fully functional!",
             "I'm still alive!",
             "I'm still alive!",
-            "and believe me, I am still alive.",
+            "And believe me, I am still alive.",
             "I'm doing science and I'm still alive.",
             "I'm doing science and I'm still alive.",
             "I feel fantastic and I'm still alive.",
             "I feel fantastic and I'm still alive.",
             " ",
             " ",
@@ -736,13 +736,13 @@
     "verification": {
     "verification": {
         "accountage": "Account age:",
         "accountage": "Account age:",
         "add_more": "Add more verifications:",
         "add_more": "Add more verifications:",
-        "added": "the verification has been added:",
+        "added": "The verification has been added:",
         "and": "and",
         "and": "and",
         "channel": "Channel:",
         "channel": "Channel:",
-        "channel_max": "you provided too many channels.",
-        "channel_missing": "the provided channel does not exist.",
-        "current": "these are the current verifications for this server:",
-        "current_selected": "this is the verification `$1` for this server:",
+        "channel_max": "You provided too many channels.",
+        "channel_missing": "The provided channel does not exist.",
+        "current": "These are the current verifications for this server:",
+        "current_selected": "This is the verification `$1` for this server:",
         "dashboard": {
         "dashboard": {
             "added": "$1 added the verification with id `$2`.",
             "added": "$1 added the verification with id `$2`.",
             "added_notice": "$1 added some verification notices.",
             "added_notice": "$1 added some verification notices.",
@@ -751,7 +751,7 @@
             "updated_notice": "$1 updated some verification notices."
             "updated_notice": "$1 updated some verification notices."
         },
         },
         "delete_current": "Delete this verification:",
         "delete_current": "Delete this verification:",
-        "deleted": "the verification has been deleted.",
+        "deleted": "The verification has been deleted.",
         "disabled": "disabled",
         "disabled": "disabled",
         "editcount": "Edit count:",
         "editcount": "Edit count:",
         "enabled": "enabled",
         "enabled": "enabled",
@@ -760,15 +760,15 @@
         "indays": "(in days)",
         "indays": "(in days)",
         "logging": "Logging channel:",
         "logging": "Logging channel:",
         "match": "Missing requirements notice:",
         "match": "Missing requirements notice:",
-        "max_entries": "you already reached the maximal amount of verifications.",
-        "missing": "there are no verifications for this server yet.",
+        "max_entries": "You already reached the maximal amount of verifications.",
+        "missing": "There are no verifications for this server yet.",
         "new_accountage": "<new account age>",
         "new_accountage": "<new account age>",
         "new_channel": "<new channel>",
         "new_channel": "<new channel>",
         "new_editcount": "<new edit count>",
         "new_editcount": "<new edit count>",
         "new_postcount": "<new post count>",
         "new_postcount": "<new post count>",
         "new_role": "<new role>",
         "new_role": "<new role>",
         "new_usergroup": "<new user group>",
         "new_usergroup": "<new user group>",
-        "no_role": "please provide a role for the new verification.",
+        "no_role": "Please provide a role for the new verification.",
         "notice_embed": "Some notices include masked markdown links. Make sure the bot has the `Embed Links` permissions in all verification channels for them to work properly.",
         "notice_embed": "Some notices include masked markdown links. Make sure the bot has the `Embed Links` permissions in all verification channels for them to work properly.",
         "or": "or",
         "or": "or",
         "postcount": "Post count (only Fandom wikis):",
         "postcount": "Post count (only Fandom wikis):",
@@ -778,20 +778,20 @@
         "rename_no_permission": "**$1 is missing the `Manage Nicknames` permission to force wiki usernames!**",
         "rename_no_permission": "**$1 is missing the `Manage Nicknames` permission to force wiki usernames!**",
         "role_add": "Role to add:",
         "role_add": "Role to add:",
         "role_deleted": "**The role $1 doesn't seem to exist anymore!**",
         "role_deleted": "**The role $1 doesn't seem to exist anymore!**",
-        "role_managed": "the provided role can't be assigned.",
-        "role_max": "you provided too many roles.",
-        "role_missing": "the provided role does not exist.",
+        "role_managed": "The provided role can't be assigned.",
+        "role_max": "You provided too many roles.",
+        "role_missing": "The provided role does not exist.",
         "role_none": "none",
         "role_none": "none",
         "role_remove": "Role to remove:",
         "role_remove": "Role to remove:",
         "role_too_high": "**The role $1 is too high for $2 to assign!**",
         "role_too_high": "**The role $1 is too high for $2 to assign!**",
-        "save_failed": "sadly the verification couldn't be saved, please try again later.",
+        "save_failed": "Sadly the verification couldn't be saved, please try again later.",
         "success": "Success notice:",
         "success": "Success notice:",
         "toggle": "(toggle)",
         "toggle": "(toggle)",
-        "updated": "the verification has been updated:",
+        "updated": "The verification has been updated:",
         "usergroup": "User group:",
         "usergroup": "User group:",
-        "usergroup_max": "you provided too many user groups.",
-        "usergroup_too_long": "the provided user group is too long.",
-        "value_too_high": "the provided value is too high."
+        "usergroup_max": "You provided too many user groups.",
+        "usergroup_too_long": "The provided user group is too long.",
+        "value_too_high": "The provided value is too high."
     },
     },
     "verify": {
     "verify": {
         "audit_reason": "Verified as \"$1\"",
         "audit_reason": "Verified as \"$1\"",
@@ -800,7 +800,7 @@
         "discord": "Discord user:",
         "discord": "Discord user:",
         "empty": "*empty*",
         "empty": "*empty*",
         "error": "The verification failed due to an error.",
         "error": "The verification failed due to an error.",
-        "error_reply": "the verification failed due to an error, please try again.",
+        "error_reply": "The verification failed due to an error, please try again.",
         "failed_gblock": "**Check for global block failed!**",
         "failed_gblock": "**Check for global block failed!**",
         "failed_rename": "**Changing {{GENDER:$1|his|her|their}} Discord nickname failed!**",
         "failed_rename": "**Changing {{GENDER:$1|his|her|their}} Discord nickname failed!**",
         "failed_roles": "**Adding roles failed!**",
         "failed_roles": "**Adding roles failed!**",
@@ -810,12 +810,12 @@
         "help_guide": "Follow [this guide]($1) to add your Discord tag to your wiki profile:",
         "help_guide": "Follow [this guide]($1) to add your Discord tag to your wiki profile:",
         "help_missing": "Please make sure you are using your wiki username and the caseing is correct.",
         "help_missing": "Please make sure you are using your wiki username and the caseing is correct.",
         "help_subpage": "Please add your Discord tag ($1) to your Discord subpage on the wiki:",
         "help_subpage": "Please add your Discord tag ($1) to your Discord subpage on the wiki:",
-        "missing": "there are no verifications set up for this channel.",
+        "missing": "There are no verifications set up for this channel.",
         "notice": "Notice:",
         "notice": "Notice:",
         "oauth_button": "Authenticate",
         "oauth_button": "Authenticate",
-        "oauth_message": "please use [this link]($1) to authenticate your wiki account.",
+        "oauth_message": "Please use [this link]($1) to authenticate your wiki account.",
         "oauth_message_dm": "Please use this link to authenticate your wiki account for $1.",
         "oauth_message_dm": "Please use this link to authenticate your wiki account for $1.",
-        "oauth_private": "the wiki uses OAuth2 for verification. Please enable direct messages from this server or use the `/verify` command so I can send you an authentication link privately.",
+        "oauth_private": "The wiki uses OAuth2 for verification. Please enable direct messages from this server or use the `/verify` command so I can send you an authentication link privately.",
         "oauth_used": "*Verified using OAuth2*",
         "oauth_used": "*Verified using OAuth2*",
         "qualified_add": "Added to:",
         "qualified_add": "Added to:",
         "qualified_add_error": "Can't be added to:",
         "qualified_add_error": "Can't be added to:",
@@ -841,9 +841,9 @@
     "voice": {
     "voice": {
         "channel": "Voice channel",
         "channel": "Voice channel",
         "disable": "Use `$1` to disable this function.",
         "disable": "Use `$1` to disable this function.",
-        "disabled": "you disabled the function to add roles for voice channels.",
+        "disabled": "You disabled the function to add roles for voice channels.",
         "enable": "Use `$1` to enable this function.",
         "enable": "Use `$1` to enable this function.",
-        "enabled": "you enabled the function to add roles for voice channels.",
+        "enabled": "You enabled the function to add roles for voice channels.",
         "join": "$1 joined the voice channel \"$2\".",
         "join": "$1 joined the voice channel \"$2\".",
         "left": "$1 left the voice channel \"$2\".",
         "left": "$1 left the voice channel \"$2\".",
         "name": "voice channel name",
         "name": "voice channel name",

+ 30 - 50
interactions/inline.js

@@ -1,45 +1,33 @@
+const {Permissions: {FLAGS}} = require('discord.js');
 const logging = require('../util/logging.js');
 const logging = require('../util/logging.js');
 const Wiki = require('../util/wiki.js');
 const Wiki = require('../util/wiki.js');
 const {got, limitLength, partialURIdecode, sendMessage} = require('../util/functions.js');
 const {got, limitLength, partialURIdecode, sendMessage} = require('../util/functions.js');
 
 
 /**
 /**
  * Post a message with inline wiki links.
  * Post a message with inline wiki links.
- * @param {Object} interaction - The interaction.
- * @param {import('discord.js').Client} interaction.client - The client of the interaction.
+ * @param {import('discord.js').CommandInteraction} interaction - The interaction.
  * @param {import('../util/i18n.js')} lang - The user language.
  * @param {import('../util/i18n.js')} lang - The user language.
  * @param {import('../util/wiki.js')} wiki - The wiki for the interaction.
  * @param {import('../util/wiki.js')} wiki - The wiki for the interaction.
- * @param {import('discord.js').TextChannel} [channel] - The channel for the interaction.
  */
  */
-function slash_inline(interaction, lang, wiki, channel) {
-	var text = ( interaction.data.options?.[0]?.value || '' ).replace( /\]\(/g, ']\\(' );
+function slash_inline(interaction, lang, wiki) {
+	var text = ( interaction.options.getString('text') || '' ).replace( /\]\(/g, ']\\(' );
 	text = text.replace( /\x1F/g, '' ).replace( /(?<!@)\u200b/g, '' ).trim();
 	text = text.replace( /\x1F/g, '' ).replace( /(?<!@)\u200b/g, '' ).trim();
 	if ( !text.includes( '{{' ) && !( text.includes( '[[' ) && text.includes( ']]' ) ) && !text.includes( 'PMID' ) && !text.includes( 'RFC' ) && !text.includes( 'ISBN' ) ) {
 	if ( !text.includes( '{{' ) && !( text.includes( '[[' ) && text.includes( ']]' ) ) && !text.includes( 'PMID' ) && !text.includes( 'RFC' ) && !text.includes( 'ISBN' ) ) {
-		return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-			data: {
-				type: 4,
-				data: {
-					content: lang.get('interaction.inline'),
-					allowed_mentions: {
-						parse: []
-					},
-					flags: 64
-				}
-			}
-		} ).catch(log_error);
+		return interaction.reply( {content: lang.get('interaction.inline'), ephemeral: true} ).catch(log_error);
 	}
 	}
-	var allowed_mentions = {
+	var allowedMentions = {
 		parse: ['users']
 		parse: ['users']
 	};
 	};
-	if ( interaction.guild_id ) {
-		if ( interaction.member.permissions.has('MENTION_EVERYONE') ) {
-			allowed_mentions.parse = ['users', 'roles', 'everyone'];
+	if ( interaction.inGuild() ) {
+		if ( interaction.member.permissions.has(FLAGS.MENTION_EVERYONE) ) {
+			allowedMentions.parse = ['users', 'roles', 'everyone'];
 		}
 		}
-		else if ( channel?.guild ) {
-			allowed_mentions.roles = channel.guild.roles.cache.filter( role => role.mentionable ).map( role => role.id ).slice(0, 100);
+		else if ( interaction.guild ) {
+			allowedMentions.roles = interaction.guild.roles.cache.filter( role => role.mentionable ).map( role => role.id ).slice(0, 100);
 		}
 		}
-		if ( channel?.guild && !interaction.member.permissions.has('USE_EXTERNAL_EMOJIS') ) {
+		if ( interaction.guild && !interaction.member.permissions.has(FLAGS.USE_EXTERNAL_EMOJIS) ) {
 			text = text.replace( /(?<!\\)<a?(:\w+:)\d+>/g, (replacement, emoji, id) => {
 			text = text.replace( /(?<!\\)<a?(:\w+:)\d+>/g, (replacement, emoji, id) => {
-				if ( channel.guild.emojis.cache.has(id) ) {
+				if ( interaction.guild.emojis.cache.has(id) ) {
 					return replacement;
 					return replacement;
 				}
 				}
 				return emoji;
 				return emoji;
@@ -49,22 +37,14 @@ function slash_inline(interaction, lang, wiki, channel) {
 	if ( text.length > 1800 ) text = text.substring(0, 1800) + '\u2026';
 	if ( text.length > 1800 ) text = text.substring(0, 1800) + '\u2026';
 	var message = {
 	var message = {
 		content: text.replace( /(?<!\\)<a?(:\w+:)\d+>/g, (replacement, emoji, id) => {
 		content: text.replace( /(?<!\\)<a?(:\w+:)\d+>/g, (replacement, emoji, id) => {
-			if ( channel?.guild?.emojis.cache.has(id) ) {
+			if ( interaction.guild?.emojis.cache.has(id) ) {
 				return replacement;
 				return replacement;
 			}
 			}
 			return emoji;
 			return emoji;
 		} ),
 		} ),
-		allowed_mentions
+		allowedMentions
 	};
 	};
-	return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-		data: {
-			type: 5,
-			data: {
-				allowed_mentions,
-				flags: 0
-			}
-		}
-	} ).then( () => {
+	return interaction.deferReply().then( () => {
 		var textReplacement = [];
 		var textReplacement = [];
 		var magiclinks = [];
 		var magiclinks = [];
 		var replacedText = text.replace( /(?<!\\)(?:<a?(:\w+:)\d+>|<#(\d+)>|<@!?(\d+)>|<@&(\d+)>|```.+?```|``.+?``|`.+?`)/gs, (replacement, emoji, textchannel, user, role) => {
 		var replacedText = text.replace( /(?<!\\)(?:<a?(:\w+:)\d+>|<#(\d+)>|<@!?(\d+)>|<@&(\d+)>|```.+?```|``.+?``|`.+?`)/gs, (replacement, emoji, textchannel, user, role) => {
@@ -73,18 +53,18 @@ function slash_inline(interaction, lang, wiki, channel) {
 			if ( emoji ) arg = emoji;
 			if ( emoji ) arg = emoji;
 			if ( textchannel ) {
 			if ( textchannel ) {
 				let tempchannel = interaction.client.channels.cache.get(textchannel);
 				let tempchannel = interaction.client.channels.cache.get(textchannel);
-				if ( tempchannel ) arg = '#' + tempchannel.name;
+				if ( tempchannel ) arg = '#' + ( tempchannel.name || 'deleted-channel' );
 			}
 			}
 			if ( user ) {
 			if ( user ) {
-				let tempuser = channel?.guild?.members.cache.get(user);
-				if ( tempuser ) arg = '@' + tempuser.displayName;
+				let tempmember = interaction.guild?.members.cache.get(user);
+				if ( tempmember ) arg = '@' + tempmember.displayName;
 				else {
 				else {
-					tempuser = interaction.client.users.cache.get(user);
+					let tempuser = interaction.client.users.cache.get(user);
 					if ( tempuser ) arg = '@' + tempuser.username;
 					if ( tempuser ) arg = '@' + tempuser.username;
 				}
 				}
 			}
 			}
 			if ( role ) {
 			if ( role ) {
-				let temprole = channel?.guild?.roles.cache.get(role);
+				let temprole = interaction.guild?.roles.cache.get(role);
 				if ( temprole ) arg = '@' + temprole.name;
 				if ( temprole ) arg = '@' + temprole.name;
 			}
 			}
 			return '\x1F<replacement\x1F' + textReplacement.length + ( arg ? '\x1F' + arg : '' ) + '>\x1F';
 			return '\x1F<replacement\x1F' + textReplacement.length + ( arg ? '\x1F' + arg : '' ) + '>\x1F';
@@ -127,7 +107,7 @@ function slash_inline(interaction, lang, wiki, channel) {
 			}
 			}
 		} );
 		} );
 		if ( !templates.length && !links.length && !magiclinks.length ) {
 		if ( !templates.length && !links.length && !magiclinks.length ) {
-			return sendMessage(interaction, message, channel);
+			return sendMessage(interaction, message);
 		}
 		}
 		return got.get( wiki + 'api.php?action=query&meta=siteinfo' + ( magiclinks.length ? '|allmessages&ammessages=pubmedurl|rfcurl&amenableparser=true' : '' ) + '&siprop=general&iwurl=true&titles=' + encodeURIComponent( [
 		return got.get( wiki + 'api.php?action=query&meta=siteinfo' + ( magiclinks.length ? '|allmessages&ammessages=pubmedurl|rfcurl&amenableparser=true' : '' ) + '&siprop=general&iwurl=true&titles=' + encodeURIComponent( [
 			...templates.map( link => link.title + '|' + link.template ),
 			...templates.map( link => link.title + '|' + link.template ),
@@ -142,9 +122,9 @@ function slash_inline(interaction, lang, wiki, channel) {
 				else {
 				else {
 					console.log( '- ' + response.statusCode + ': Error while following the links: ' + body?.error?.info );
 					console.log( '- ' + response.statusCode + ': Error while following the links: ' + body?.error?.info );
 				}
 				}
-				return sendMessage(interaction, message, channel);
+				return sendMessage(interaction, message);
 			}
 			}
-			logging(wiki, interaction.guild_id, 'slash', 'inline');
+			logging(wiki, interaction.guildId, 'slash', 'inline');
 			wiki.updateWiki(body.query.general);
 			wiki.updateWiki(body.query.general);
 			if ( body.query.normalized ) {
 			if ( body.query.normalized ) {
 				body.query.normalized.forEach( title => {
 				body.query.normalized.forEach( title => {
@@ -211,7 +191,7 @@ function slash_inline(interaction, lang, wiki, channel) {
 						link.url = wiki.toLink(title + '/' + link.isbn, '', '', true);
 						link.url = wiki.toLink(title + '/' + link.isbn, '', '', true);
 					}
 					}
 					if ( link.url ) {
 					if ( link.url ) {
-						console.log( ( interaction.guild_id || '@' + interaction.user.id ) + ': Slash: ' + link.type + ' ' + link.id );
+						console.log( ( interaction.guildId || '@' + interaction.user.id ) + ': Slash: ' + link.type + ' ' + link.id );
 						textReplacement[link.replacementId] = '[' + link.type + ' ' + link.id + '](<' + link.url + '>)';
 						textReplacement[link.replacementId] = '[' + link.type + ' ' + link.id + '](<' + link.url + '>)';
 					}
 					}
 				} );
 				} );
@@ -229,7 +209,7 @@ function slash_inline(interaction, lang, wiki, channel) {
 							title = title.replace( /(?:%[\dA-F]{2})+/g, partialURIdecode ).replace( /\x1F<replacement\x1F\d+\x1F(.+?)>\x1F/g, '$1' ).trim();
 							title = title.replace( /(?:%[\dA-F]{2})+/g, partialURIdecode ).replace( /\x1F<replacement\x1F\d+\x1F(.+?)>\x1F/g, '$1' ).trim();
 							let link = templates.find( link => link.raw === title );
 							let link = templates.find( link => link.raw === title );
 							if ( !link ) return fullLink;
 							if ( !link ) return fullLink;
-							console.log( ( interaction.guild_id || '@' + interaction.user.id ) + ': Slash: ' + fullLink );
+							console.log( ( interaction.guildId || '@' + interaction.user.id ) + ': Slash: ' + fullLink );
 							if ( title.startsWith( 'int:' ) ) {
 							if ( title.startsWith( 'int:' ) ) {
 								title = title.replace( /^int:\s*/, replacement => {
 								title = title.replace( /^int:\s*/, replacement => {
 									linkprefix += replacement;
 									linkprefix += replacement;
@@ -245,7 +225,7 @@ function slash_inline(interaction, lang, wiki, channel) {
 							title = title.replace( /(?:%[\dA-F]{2})+/g, partialURIdecode ).replace( /\x1F<replacement\x1F\d+\x1F(.+?)>\x1F/g, '$1' ).split('#')[0].trim();
 							title = title.replace( /(?:%[\dA-F]{2})+/g, partialURIdecode ).replace( /\x1F<replacement\x1F\d+\x1F(.+?)>\x1F/g, '$1' ).split('#')[0].trim();
 							let link = links.find( link => link.raw === title );
 							let link = links.find( link => link.raw === title );
 							if ( !link ) return fullLink;
 							if ( !link ) return fullLink;
-							console.log( ( interaction.guild_id || '@' + interaction.user.id ) + ': Slash: ' + fullLink );
+							console.log( ( interaction.guildId || '@' + interaction.user.id ) + ': Slash: ' + fullLink );
 							if ( display === undefined ) display = title.replace( /^\s*:?/, '' );
 							if ( display === undefined ) display = title.replace( /^\s*:?/, '' );
 							if ( !display.trim() ) {
 							if ( !display.trim() ) {
 								display = title.replace( /^\s*:/, '' );
 								display = title.replace( /^\s*:/, '' );
@@ -267,9 +247,9 @@ function slash_inline(interaction, lang, wiki, channel) {
 				} );
 				} );
 				if ( text.length > 1900 ) text = limitLength(text, 1900, 100);
 				if ( text.length > 1900 ) text = limitLength(text, 1900, 100);
 				message.content = text;
 				message.content = text;
-				return sendMessage(interaction, message, channel);
+				return sendMessage(interaction, message);
 			}
 			}
-			else return sendMessage(interaction, message, channel);
+			else return sendMessage(interaction, message);
 		}, error => {
 		}, error => {
 			if ( wiki.noWiki(error.message) ) {
 			if ( wiki.noWiki(error.message) ) {
 				console.log( '- This wiki doesn\'t exist!' );
 				console.log( '- This wiki doesn\'t exist!' );
@@ -277,7 +257,7 @@ function slash_inline(interaction, lang, wiki, channel) {
 			else {
 			else {
 				console.log( '- Error while following the links: ' + error );
 				console.log( '- Error while following the links: ' + error );
 			}
 			}
-			return sendMessage(interaction, message, channel);
+			return sendMessage(interaction, message);
 		} );
 		} );
 	}, log_error );
 	}, log_error );
 }
 }

+ 341 - 600
interactions/verify.js

@@ -1,164 +1,109 @@
 const {randomBytes} = require('crypto');
 const {randomBytes} = require('crypto');
+const {MessageActionRow, MessageButton, Permissions: {FLAGS}} = require('discord.js');
 var db = require('../util/database.js');
 var db = require('../util/database.js');
 var verify = require('../functions/verify.js');
 var verify = require('../functions/verify.js');
 const {got, oauthVerify, sendMessage} = require('../util/functions.js');
 const {got, oauthVerify, sendMessage} = require('../util/functions.js');
 
 
 /**
 /**
  * Wiki user verification.
  * Wiki user verification.
- * @param {Object} interaction - The interaction.
- * @param {import('discord.js').Client} interaction.client - The client of the interaction.
+ * @param {import('discord.js').CommandInteraction} interaction - The interaction.
  * @param {import('../util/i18n.js')} lang - The user language.
  * @param {import('../util/i18n.js')} lang - The user language.
  * @param {import('../util/wiki.js')} wiki - The wiki for the interaction.
  * @param {import('../util/wiki.js')} wiki - The wiki for the interaction.
- * @param {import('discord.js').TextChannel} [channel] - The channel for the interaction.
  */
  */
-function slash_verify(interaction, lang, wiki, channel) {
-	var reply = '<@' + ( interaction.member?.nick ? '!' : '' ) + interaction.user.id + '>, ';
-	var allowed_mentions = {
-		users: [interaction.user.id]
-	};
-	if ( !channel?.guild ) return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-		data: {
-			type: 4,
-			data: {
-				content: reply + lang.get('verify.missing'),
-				allowed_mentions,
-				flags: 64
-			}
-		}
-	} ).catch(log_error);
-	if ( !channel.guild.me.permissions.has('MANAGE_ROLES') ) {
-		console.log( channel.guild.id + ': Missing permissions - MANAGE_ROLES' );
-		return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-			data: {
-				type: 4,
-				data: {
-					content: reply + lang.get('general.missingperm') + ' `MANAGE_ROLES`',
-					allowed_mentions,
-					flags: 64
-				}
-			}
-		} ).catch(log_error);
+function slash_verify(interaction, lang, wiki) {
+	if ( !interaction.guild ) return interaction.reply( {content: lang.get('verify.missing'), ephemeral: true} ).catch(log_error);
+	if ( !interaction.guild.me.permissions.has(FLAGS.MANAGE_ROLES) ) {
+		console.log( interaction.guildId + ': Missing permissions - MANAGE_ROLES' );
+		return interaction.reply( {content: lang.get('general.missingperm') + ' `MANAGE_ROLES`', ephemeral: true} ).catch(log_error);
 	}
 	}
 	
 	
-	return db.query( 'SELECT logchannel, flags, onsuccess, onmatch, role, editcount, postcount, usergroup, accountage, rename FROM verification LEFT JOIN verifynotice ON verification.guild = verifynotice.guild WHERE verification.guild = $1 AND channel LIKE $2 ORDER BY configid ASC', [interaction.guild_id, '%|' + interaction.channel_id + '|%'] ).then( ({rows}) => {
-		if ( !rows.length ) return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-			data: {
-				type: 4,
-				data: {
-					content: reply + lang.get('verify.missing') + ( interaction.member.permissions.has('MANAGE_GUILD') && process.env.dashboard ? '\n' + new URL(`/guild/${interaction.guild_id}/verification`, process.env.dashboard).href : '' ),
-					allowed_mentions,
-					flags: 64
-				}
-			}
-		} ).catch(log_error);
+	return db.query( 'SELECT logchannel, flags, onsuccess, onmatch, role, editcount, postcount, usergroup, accountage, rename FROM verification LEFT JOIN verifynotice ON verification.guild = verifynotice.guild WHERE verification.guild = $1 AND channel LIKE $2 ORDER BY configid ASC', [interaction.guildId, '%|' + ( interaction.channel?.isThread() ? interaction.channel.parentId : interaction.channelId ) + '|%'] ).then( ({rows}) => {
+		if ( !rows.length ) return interaction.reply( {content: lang.get('verify.missing') + ( interaction.member.permissions.has(FLAGS.MANAGE_GUILD) && process.env.dashboard ? '\n' + new URL(`/guild/${interaction.guildId}/verification`, process.env.dashboard).href : '' ), ephemeral: true} ).catch(log_error);
 
 
 		if ( wiki.hasOAuth2() && process.env.dashboard ) {
 		if ( wiki.hasOAuth2() && process.env.dashboard ) {
 			let oauth = [wiki.hostname + wiki.pathname.slice(0, -1)];
 			let oauth = [wiki.hostname + wiki.pathname.slice(0, -1)];
 			if ( wiki.isWikimedia() ) oauth.push('wikimedia');
 			if ( wiki.isWikimedia() ) oauth.push('wikimedia');
 			if ( wiki.isMiraheze() ) oauth.push('miraheze');
 			if ( wiki.isMiraheze() ) oauth.push('miraheze');
 			if ( process.env['oauth_' + ( oauth[1] || oauth[0] )] && process.env['oauth_' + ( oauth[1] || oauth[0] ) + '_secret'] ) {
 			if ( process.env['oauth_' + ( oauth[1] || oauth[0] )] && process.env['oauth_' + ( oauth[1] || oauth[0] ) + '_secret'] ) {
-				return db.query( 'SELECT token FROM oauthusers WHERE userid = $1 AND site = $2', [interaction.user.id, ( oauth[1] || oauth[0] )] ).then( ({rows: [row]}) => {
-					if ( row?.token ) return got.post( wiki + 'rest.php/oauth2/access_token', {
-						form: {
-							grant_type: 'refresh_token', refresh_token: row.token,
-							redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
-							client_id: process.env['oauth_' + ( oauth[1] || oauth[0] )],
-							client_secret: process.env['oauth_' + ( oauth[1] || oauth[0] ) + '_secret']
-						}
-					} ).then( response => {
-						var body = response.body;
-						if ( response.statusCode !== 200 || !body?.access_token ) {
-							console.log( '- ' + response.statusCode + ': Error while refreshing the mediawiki token: ' + ( body?.message || body?.error ) );
-							return Promise.reject(row);
-						}
-						if ( body?.refresh_token ) db.query( 'UPDATE oauthusers SET token = $1 WHERE userid = $2 AND site = $3', [body.refresh_token, interaction.user.id, ( oauth[1] || oauth[0] )] ).then( () => {
-							console.log( '- Dashboard: OAuth2 token for ' + interaction.user.id + ' successfully updated.' );
-						}, dberror => {
-							console.log( '- Dashboard: Error while updating the OAuth2 token for ' + interaction.user.id + ': ' + dberror );
-						} );
-						return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-							data: {
-								type: 5,
-								data: {
-									allowed_mentions,
-									flags: ( (rows[0].flags & 1 << 0) === 1 << 0 ? 64 : 0 )
-								}
+				return interaction.deferReply( {ephemeral: ( (rows[0].flags & 1 << 0) === 1 << 0 )} ).then( () => {
+					return db.query( 'SELECT token FROM oauthusers WHERE userid = $1 AND site = $2', [interaction.user.id, ( oauth[1] || oauth[0] )] ).then( ({rows: [row]}) => {
+						if ( row?.token ) return got.post( wiki + 'rest.php/oauth2/access_token', {
+							form: {
+								grant_type: 'refresh_token', refresh_token: row.token,
+								redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
+								client_id: process.env['oauth_' + ( oauth[1] || oauth[0] )],
+								client_secret: process.env['oauth_' + ( oauth[1] || oauth[0] ) + '_secret']
 							}
 							}
-						} ).then( () => {
+						} ).then( response => {
+							var body = response.body;
+							if ( response.statusCode !== 200 || !body?.access_token ) {
+								console.log( '- ' + response.statusCode + ': Error while refreshing the mediawiki token: ' + ( body?.message || body?.error ) );
+								return Promise.reject(row);
+							}
+							if ( body?.refresh_token ) db.query( 'UPDATE oauthusers SET token = $1 WHERE userid = $2 AND site = $3', [body.refresh_token, interaction.user.id, ( oauth[1] || oauth[0] )] ).then( () => {
+								console.log( '- Dashboard: OAuth2 token for ' + interaction.user.id + ' successfully updated.' );
+							}, dberror => {
+								console.log( '- Dashboard: Error while updating the OAuth2 token for ' + interaction.user.id + ': ' + dberror );
+							} );
 							return global.verifyOauthUser('', body.access_token, {
 							return global.verifyOauthUser('', body.access_token, {
-								wiki: wiki.href, channel,
-								user: interaction.user.id,
-								token: interaction.token
+								wiki: wiki.href, channel: interaction.channel,
+								user: interaction.user.id, interaction,
+								fail: () => sendMessage(interaction, lang.get('verify.error_reply'))
 							});
 							});
-						}, log_error );
-					}, error => {
-						console.log( '- Error while refreshing the mediawiki token: ' + error );
-						return Promise.reject(row);
-					} );
-					return Promise.reject(row);
-				}, dberror => {
-					console.log( '- Error while getting the OAuth2 token: ' + dberror );
-					return Promise.reject();
-				} ).catch( row => {
-					if ( row ) {
-						if ( !row?.hasOwnProperty?.('token') ) console.log( '- Error while checking the OAuth2 refresh token: ' + row );
-						else if ( row.token ) db.query( 'DELETE FROM oauthusers WHERE userid = $1 AND site = $2', [interaction.user.id, ( oauth[1] || oauth[0] )] ).then( () => {
-							console.log( '- Dashboard: OAuth2 token for ' + interaction.user.id + ' successfully deleted.' );
-						}, dberror => {
-							console.log( '- Dashboard: Error while deleting the OAuth2 token for ' + interaction.user.id + ': ' + dberror );
+						}, error => {
+							console.log( '- Error while refreshing the mediawiki token: ' + error );
+							return Promise.reject(row);
 						} );
 						} );
-					}
-					let state = `${oauth[0]} ${global.shardId}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( oauth[1] ? ` ${oauth[1]}` : '' );
-					while ( oauthVerify.has(state) ) {
-						state = `${oauth[0]} ${global.shardId}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( oauth[1] ? ` ${oauth[1]}` : '' );
-					}
-					oauthVerify.set(state, {
-						state, wiki: wiki.href, channel,
-						user: interaction.user.id,
-						token: interaction.token
-					});
-					interaction.client.shard.send({id: 'verifyUser', state, user: ( row?.token === null ? '' : interaction.user.id )});
-					let oauthURL = wiki + 'rest.php/oauth2/authorize?' + new URLSearchParams({
-						response_type: 'code', redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
-						client_id: process.env['oauth_' + ( oauth[1] || oauth[0] )], state
-					}).toString();
-					return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-						data: {
-							type: 4,
-							data: {
-								content: reply + lang.get('verify.oauth_message', '<' + oauthURL + '>'),
-								allowed_mentions,
-								components: [
-									{
-										type: 1,
-										components: [
-											{
-												type: 2,
-												style: 5,
-												label: lang.get('verify.oauth_button'),
-												emoji: {id: null, name: '🔗'},
-												url: oauthURL,
-												disabled: false
-											}
-										]
-									}
-								],
-								flags: 64
-							}
+						return Promise.reject(row);
+					}, dberror => {
+						console.log( '- Error while getting the OAuth2 token: ' + dberror );
+						return Promise.reject();
+					} ).catch( row => {
+						if ( row ) {
+							if ( !row?.hasOwnProperty?.('token') ) console.log( '- Error while checking the OAuth2 refresh token: ' + row );
+							else if ( row.token ) db.query( 'DELETE FROM oauthusers WHERE userid = $1 AND site = $2', [interaction.user.id, ( oauth[1] || oauth[0] )] ).then( () => {
+								console.log( '- Dashboard: OAuth2 token for ' + interaction.user.id + ' successfully deleted.' );
+							}, dberror => {
+								console.log( '- Dashboard: Error while deleting the OAuth2 token for ' + interaction.user.id + ': ' + dberror );
+							} );
 						}
 						}
-					} ).catch(log_error);
-				} );
+						let state = `${oauth[0]} ${process.env.SHARDS}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( oauth[1] ? ` ${oauth[1]}` : '' );
+						while ( oauthVerify.has(state) ) {
+							state = `${oauth[0]} ${process.env.SHARDS}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( oauth[1] ? ` ${oauth[1]}` : '' );
+						}
+						oauthVerify.set(state, {
+							state, wiki: wiki.href, channel: interaction.channel,
+							user: interaction.user.id, interaction
+						});
+						interaction.client.shard.send({id: 'verifyUser', state, user: ( row?.token === null ? '' : interaction.user.id )});
+						let oauthURL = wiki + 'rest.php/oauth2/authorize?' + new URLSearchParams({
+							response_type: 'code', redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
+							client_id: process.env['oauth_' + ( oauth[1] || oauth[0] )], state
+						}).toString();
+						let message = {
+							content: lang.get('verify.oauth_message', '<' + oauthURL + '>'),
+							components: [new MessageActionRow().addComponents(
+								new MessageButton().setLabel(lang.get('verify.oauth_button')).setEmoji('🔗').setStyle('LINK').setURL(oauthURL)
+							)],
+							ephemeral: true
+						};
+						if ( (rows[0].flags & 1 << 0) === 1 << 0 ) return sendMessage(interaction, message, false);
+						return interaction.deleteReply().then( () => {
+							return interaction.followUp( message ).catch(log_error);
+						}, log_error );
+					} );
+				}, log_error );
 			}
 			}
 		}
 		}
 		
 		
-		var username = ( interaction.data.options?.[0]?.value || '' ).replace( /^\s*<@!?(\d+)>\s*$/, (mention, id) => {
+		var username = ( interaction.options.getString('username') || '' ).replace( /^\s*<@!?(\d+)>\s*$/, (mention, id) => {
 			if ( id === interaction.user.id ) {
 			if ( id === interaction.user.id ) {
-				return ( interaction.member?.nick || interaction.user.username );
+				return interaction.member.displayName;
 			}
 			}
-			let user = channel.guild.members.cache.get(id);
-			if ( user ) return user.displayName;
+			let member = interaction.guild.members.cache.get(id);
+			if ( member ) return member.displayName;
 			else {
 			else {
-				user = interaction.client.users.cache.get(user);
+				let user = interaction.client.users.cache.get(id);
 				if ( user ) return user.username;
 				if ( user ) return user.username;
 			}
 			}
 			return mention;
 			return mention;
@@ -168,524 +113,320 @@ function slash_verify(interaction, lang, wiki, channel) {
 		}
 		}
 		if ( wiki.isGamepedia() ) username = username.replace( /^userprofile\s*:\s*/i, '' );
 		if ( wiki.isGamepedia() ) username = username.replace( /^userprofile\s*:\s*/i, '' );
 		
 		
-		if ( !username.trim() ) return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-			data: {
-				type: 4,
-				data: {
-					content: lang.get('interaction.verify'),
-					allowed_mentions,
-					flags: 64
-				}
-			}
-		} ).catch(log_error);
+		if ( !username.trim() ) return interaction.reply( {content: lang.get('interaction.verify'), ephemeral: true} ).catch(log_error);
 
 
-		return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-			data: {
-				type: 5,
-				data: {
-					allowed_mentions,
-					flags: ( (rows[0].flags & 1 << 0) === 1 << 0 ? 64 : 0 )
-				}
-			}
-		} ).then( () => {
-			return channel.guild.members.fetch(interaction.user.id).then( member => {
-				return verify(lang, channel, member, username, wiki, rows).then( result => {
-					if ( result.oauth.length ) {
-						return db.query( 'SELECT token FROM oauthusers WHERE userid = $1 AND site = $2', [interaction.user.id, ( result.oauth[1] || result.oauth[0] )] ).then( ({rows: [row]}) => {
-							if ( row?.token ) return got.post( wiki + 'rest.php/oauth2/access_token', {
-								form: {
-									grant_type: 'refresh_token', refresh_token: row.token,
-									redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
-									client_id: process.env['oauth_' + ( result.oauth[1] || result.oauth[0] )],
-									client_secret: process.env['oauth_' + ( result.oauth[1] || result.oauth[0] ) + '_secret']
-								}
-							} ).then( response => {
-								var body = response.body;
-								if ( response.statusCode !== 200 || !body?.access_token ) {
-									console.log( '- ' + response.statusCode + ': Error while refreshing the mediawiki token: ' + ( body?.message || body?.error ) );
-									return Promise.reject(row);
-								}
-								if ( body?.refresh_token ) db.query( 'UPDATE oauthusers SET token = $1 WHERE userid = $2 AND site = $3', [body.refresh_token, interaction.user.id, ( result.oauth[1] || result.oauth[0] )] ).then( () => {
-									console.log( '- Dashboard: OAuth2 token for ' + interaction.user.id + ' successfully updated.' );
-								}, dberror => {
-									console.log( '- Dashboard: Error while updating the OAuth2 token for ' + interaction.user.id + ': ' + dberror );
-								} );
-								return global.verifyOauthUser('', body.access_token, {
-									wiki: wiki.href, channel,
-									user: interaction.user.id,
-									token: interaction.token
-								});
-							}, error => {
-								console.log( '- Error while refreshing the mediawiki token: ' + error );
-								return Promise.reject(row);
-							} );
-							return Promise.reject(row);
-						}, dberror => {
-							console.log( '- Error while getting the OAuth2 token: ' + dberror );
-							return Promise.reject();
-						} ).catch( row => {
-							if ( row ) {
-								if ( !row?.hasOwnProperty?.('token') ) console.log( '- Error while checking the OAuth2 refresh token: ' + row );
-								else if ( row.token ) db.query( 'DELETE FROM oauthusers WHERE userid = $1 AND site = $2', [interaction.user.id, ( result.oauth[1] || result.oauth[0] )] ).then( () => {
-									console.log( '- Dashboard: OAuth2 token for ' + interaction.user.id + ' successfully deleted.' );
-								}, dberror => {
-									console.log( '- Dashboard: Error while deleting the OAuth2 token for ' + interaction.user.id + ': ' + dberror );
-								} );
+		return interaction.deferReply( {ephemeral: ( (rows[0].flags & 1 << 0) === 1 << 0 )} ).then( () => {
+			return verify(lang, interaction.channel, interaction.member, username, wiki, rows).then( result => {
+				if ( result.oauth.length ) {
+					return db.query( 'SELECT token FROM oauthusers WHERE userid = $1 AND site = $2', [interaction.user.id, ( result.oauth[1] || result.oauth[0] )] ).then( ({rows: [row]}) => {
+						if ( row?.token ) return got.post( wiki + 'rest.php/oauth2/access_token', {
+							form: {
+								grant_type: 'refresh_token', refresh_token: row.token,
+								redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
+								client_id: process.env['oauth_' + ( result.oauth[1] || result.oauth[0] )],
+								client_secret: process.env['oauth_' + ( result.oauth[1] || result.oauth[0] ) + '_secret']
 							}
 							}
-							let state = `${result.oauth[0]} ${global.shardId}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( result.oauth[1] ? ` ${result.oauth[1]}` : '' );
-							while ( oauthVerify.has(state) ) {
-								state = `${result.oauth[0]} ${global.shardId}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( result.oauth[1] ? ` ${result.oauth[1]}` : '' );
+						} ).then( response => {
+							var body = response.body;
+							if ( response.statusCode !== 200 || !body?.access_token ) {
+								console.log( '- ' + response.statusCode + ': Error while refreshing the mediawiki token: ' + ( body?.message || body?.error ) );
+								return Promise.reject(row);
 							}
 							}
-							oauthVerify.set(state, {
-								state, wiki: wiki.href, channel,
-								user: interaction.user.id,
-								token: interaction.token
+							if ( body?.refresh_token ) db.query( 'UPDATE oauthusers SET token = $1 WHERE userid = $2 AND site = $3', [body.refresh_token, interaction.user.id, ( result.oauth[1] || result.oauth[0] )] ).then( () => {
+								console.log( '- Dashboard: OAuth2 token for ' + interaction.user.id + ' successfully updated.' );
+							}, dberror => {
+								console.log( '- Dashboard: Error while updating the OAuth2 token for ' + interaction.user.id + ': ' + dberror );
+							} );
+							return global.verifyOauthUser('', body.access_token, {
+								wiki: wiki.href, channel: interaction.channel,
+								user: interaction.user.id, interaction,
+								fail: () => sendMessage(interaction, lang.get('verify.error_reply'))
 							});
 							});
-							interaction.client.shard.send({id: 'verifyUser', state, user: ( row?.token === null ? '' : interaction.user.id )});
-							let oauthURL = wiki + 'rest.php/oauth2/authorize?' + new URLSearchParams({
-								response_type: 'code', redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
-								client_id: process.env['oauth_' + ( result.oauth[1] || result.oauth[0] )], state
-							}).toString();
-							let message = {
-								content: reply + lang.get('verify.oauth_message', '<' + oauthURL + '>'),
-								allowed_mentions,
-								components: [
-									{
-										type: 1,
-										components: [
-											{
-												type: 2,
-												style: 5,
-												label: lang.get('verify.oauth_button'),
-												emoji: {id: null, name: '🔗'},
-												url: oauthURL,
-												disabled: false
-											}
-										]
-									}
-								]
-							}
-							if ( result.send_private ) return sendMessage(interaction, message, channel, false);
-							message.flags = 64;
-							return interaction.client.api.webhooks(interaction.application_id, interaction.token).messages('@original').delete().then( () => {
-								return interaction.client.api.webhooks(interaction.application_id, interaction.token).post( {
-									data: message
-								} ).catch(log_error);
-							}, log_error );
+						}, error => {
+							console.log( '- Error while refreshing the mediawiki token: ' + error );
+							return Promise.reject(row);
 						} );
 						} );
-					}
-					var message = {
-						content: reply + result.content,
-						embeds: [result.embed],
-						allowed_mentions,
-						components: []
-					};
-					if ( result.add_button && !result.send_private ) message.components.push({
-						type: 1,
-						components: [
-							{
-								type: 2,
-								style: 1,
-								label: lang.get('verify.button_again'),
-								emoji: {id: null, name: '🔂'},
-								custom_id: 'verify_again',
-								disabled: false
-							}
-						]
-					});
-					if ( result.reaction ) {
-						if ( result.reaction === 'nowiki' ) message.content = lang.get('interaction.nowiki');
-						else message.content = reply + lang.get('verify.error_reply');
-						message.embeds = [];
-					}
-					return sendMessage(interaction, message, channel, false).then( msg => {
-						if ( !result.logging.channel || !channel.guild.channels.cache.has(result.logging.channel) ) return;
-						if ( msg && !result.send_private ) {
-							if ( result.logging.embed ) result.logging.embed.addField(msg.url, '<#' + channel.id + '>');
-							else result.logging.content += '\n<#' + channel.id + '> – <' + msg.url + '>';
+						return Promise.reject(row);
+					}, dberror => {
+						console.log( '- Error while getting the OAuth2 token: ' + dberror );
+						return Promise.reject();
+					} ).catch( row => {
+						if ( row ) {
+							if ( !row?.hasOwnProperty?.('token') ) console.log( '- Error while checking the OAuth2 refresh token: ' + row );
+							else if ( row.token ) db.query( 'DELETE FROM oauthusers WHERE userid = $1 AND site = $2', [interaction.user.id, ( result.oauth[1] || result.oauth[0] )] ).then( () => {
+								console.log( '- Dashboard: OAuth2 token for ' + interaction.user.id + ' successfully deleted.' );
+							}, dberror => {
+								console.log( '- Dashboard: Error while deleting the OAuth2 token for ' + interaction.user.id + ': ' + dberror );
+							} );
 						}
 						}
-						channel.guild.channels.cache.get(result.logging.channel).send(result.logging.content, {
-							embed: result.logging.embed,
-							allowedMentions: {parse: []}
-						}).catch(log_error);
+						let state = `${result.oauth[0]} ${process.env.SHARDS}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( result.oauth[1] ? ` ${result.oauth[1]}` : '' );
+						while ( oauthVerify.has(state) ) {
+							state = `${result.oauth[0]} ${process.env.SHARDS}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( result.oauth[1] ? ` ${result.oauth[1]}` : '' );
+						}
+						oauthVerify.set(state, {
+							state, wiki: wiki.href, channel: interaction.channel,
+							user: interaction.user.id, interaction
+						});
+						interaction.client.shard.send({id: 'verifyUser', state, user: ( row?.token === null ? '' : interaction.user.id )});
+						let oauthURL = wiki + 'rest.php/oauth2/authorize?' + new URLSearchParams({
+							response_type: 'code', redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
+							client_id: process.env['oauth_' + ( result.oauth[1] || result.oauth[0] )], state
+						}).toString();
+						let message = {
+							content: lang.get('verify.oauth_message', '<' + oauthURL + '>'),
+							components: [new MessageActionRow().addComponents(
+								new MessageButton().setLabel(lang.get('verify.oauth_button')).setEmoji('🔗').setStyle('LINK').setURL(oauthURL)
+							)],
+							ephemeral: true
+						}
+						if ( result.send_private ) return sendMessage(interaction, message, false);
+						return interaction.deleteReply().then( () => {
+							return interaction.followUp( message ).catch(log_error);
+						}, log_error );
 					} );
 					} );
-				}, error => {
-					console.log( '- Error during the verifications: ' + error );
-					return sendMessage(interaction, {
-						content: reply + lang.get('verify.error_reply'),
-						allowed_mentions
-					}, channel);
+				}
+				var message = {
+					content: interaction.member.toString() + ', ' + result.content,
+					embeds: [result.embed],
+					components: [],
+					allowedMentions: {
+						users: [interaction.user.id],
+						repliedUser: true
+					}
+				};
+				if ( result.reaction ) {
+					if ( result.reaction === 'nowiki' ) message.content = lang.get('interaction.nowiki');
+					else message.content = lang.get('verify.error_reply');
+					message.embeds = [];
+				}
+				else if ( result.add_button && !result.send_private ) message.components.push(new MessageActionRow().addComponents(
+					new MessageButton().setLabel(lang.get('verify.button_again')).setEmoji('🔂').setStyle('PRIMARY').setCustomId('verify_again')
+				));
+				return sendMessage(interaction, message, false).then( msg => {
+					if ( !result.logging.channel || !interaction.guild.channels.cache.has(result.logging.channel) ) return;
+					if ( msg && !result.send_private ) {
+						if ( result.logging.embed ) result.logging.embed.addField(msg.url, '<#' + interaction.channelId + '>');
+						else result.logging.content += '\n<#' + interaction.channelId + '> – <' + msg.url + '>';
+					}
+					interaction.guild.channels.cache.get(result.logging.channel).send( {
+						content: result.logging.content,
+						embeds: [result.logging.embed]
+					} ).catch(log_error);
 				} );
 				} );
 			}, error => {
 			}, error => {
-				console.log( '- Error while getting the member: ' + error );
-				return sendMessage(interaction, {
-					content: reply + lang.get('verify.error_reply'),
-					allowed_mentions
-				}, channel);
+				console.log( '- Error during the verifications: ' + error );
+				return sendMessage(interaction, lang.get('verify.error_reply'));
 			} );
 			} );
 		}, log_error );
 		}, log_error );
 	}, dberror => {
 	}, dberror => {
 		console.log( '- Error while getting the verifications: ' + dberror );
 		console.log( '- Error while getting the verifications: ' + dberror );
-		return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-			data: {
-				type: 4,
-				data: {
-					content: reply + lang.get('verify.error_reply'),
-					allowed_mentions,
-					flags: 64
-				}
-			}
-		} ).catch(log_error);
+		return interaction.reply( {content: lang.get('verify.error_reply'), ephemeral: true} ).catch(log_error);
 	} );
 	} );
 }
 }
 
 
 /**
 /**
  * Wiki user verification.
  * Wiki user verification.
- * @param {Object} interaction - The interaction.
- * @param {import('discord.js').Client} interaction.client - The client of the interaction.
+ * @param {import('discord.js').ButtonInteraction} interaction - The interaction.
  * @param {import('../util/i18n.js')} lang - The user language.
  * @param {import('../util/i18n.js')} lang - The user language.
  * @param {import('../util/wiki.js')} wiki - The wiki for the interaction.
  * @param {import('../util/wiki.js')} wiki - The wiki for the interaction.
- * @param {import('discord.js').TextChannel} [channel] - The channel for the interaction.
  */
  */
- function button_verify(interaction, lang, wiki, channel) {
-	var username = interaction?.message?.embeds?.[0]?.title?.replace( /\\(\\)?/g, '$1' );
-	if ( !username || !channel?.guild || !interaction.message?.mentions?.[0]?.id ) {
-		interaction.message.allowed_mentions = {
-			users: [interaction.user.id]
-		};
-		interaction.message.components = [];
-		return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-			data: {
-				type: 7,
-				data: interaction.message
-			}
-		} ).catch(log_error);
+ function button_verify(interaction, lang, wiki) {
+	var username = interaction.message?.embeds?.[0]?.title?.replace( /\\(\\)?/g, '$1' );
+	if ( !username || !interaction.guild || !interaction.message.mentions?.users?.size ) {
+		return interaction.update( {components: []} ).catch(log_error);
 	}
 	}
-	if ( interaction.user.id !== interaction.message.mentions[0].id ) {
-		return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-			data: {type: 6}
-		} ).then( () => {
-			interaction.client.api.webhooks(interaction.application_id, interaction.token).post( {
-				data: {
-					content: lang.get('verify.button_wrong_user', `<@${interaction.message.mentions[0].id}>`),
-					allowed_mentions: {
-						parse: []
-					},
-					flags: 64
-				}
-			} ).catch(log_error);
-		}, log_error);
+	if ( !interaction.message.mentions.users.has(interaction.user.id) ) {
+		return interaction.reply( {content: lang.get('verify.button_wrong_user', interaction.message.mentions.users.first().toString()), ephemeral: true} ).catch(log_error);
 	}
 	}
-	return db.query( 'SELECT logchannel, flags, onsuccess, onmatch, role, editcount, postcount, usergroup, accountage, rename FROM verification LEFT JOIN verifynotice ON verification.guild = verifynotice.guild WHERE verification.guild = $1 AND channel LIKE $2 ORDER BY configid ASC', [interaction.guild_id, '%|' + interaction.channel_id + '|%'] ).then( ({rows}) => {
-		if ( !rows.length || !channel.guild.me.permissions.has('MANAGE_ROLES') ) {
-			return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-				data: {type: 6}
-			} ).catch(log_error);
-		}
-		var reply = '<@' + ( interaction.member?.nick ? '!' : '' ) + interaction.user.id + '>, ';
-		var allowed_mentions = {
-			users: [interaction.user.id]
-		};
-		interaction.message.allowed_mentions = allowed_mentions;
+	return db.query( 'SELECT logchannel, flags, onsuccess, onmatch, role, editcount, postcount, usergroup, accountage, rename FROM verification LEFT JOIN verifynotice ON verification.guild = verifynotice.guild WHERE verification.guild = $1 AND channel LIKE $2 ORDER BY configid ASC', [interaction.guildId, '%|' + ( interaction.channel?.isThread() ? interaction.channel.parentId : interaction.channelId ) + '|%'] ).then( ({rows}) => {
+		if ( !rows.length || !interaction.guild.me.permissions.has(FLAGS.MANAGE_ROLES) ) return interaction.update( {components: []} ).catch(log_error);
 
 
-		if ( interaction?.message?.embeds?.[0]?.fields?.[1]?.value === lang.get('verify.oauth_used') && interaction?.message?.embeds?.[0]?.url?.startsWith( wiki.origin ) ) {
-			console.log( interaction.guild_id + ': Button: ' + interaction.data.custom_id + ': OAuth2: ' + username );
-			interaction.message.components[0].components[0].disabled = true;
-			return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-				data: {
-					type: 7,
-					data: interaction.message
-				}
-			} ).then( () => {
-				return global.verifyOauthUser('', '', {
-					channel, username, user: interaction.user.id,
-					send: function(content, options) {
-						if ( !content && !options ) {
-							interaction.message.components = [];
-							return sendMessage(interaction, interaction.message, channel, false);
-						}
-						var message = {
-							content, allowed_mentions,
-							embeds: ( options.embed ? [options.embed] : [] ),
-							components: ( options.components ? options.components : [] )
-						};
-						var msg = sendMessage(interaction, message, channel, false);
-						interaction.client.api.webhooks(interaction.application_id, interaction.token).post( {
-							data: {
-								content, allowed_mentions,
-								embeds: ( options.embed ? [options.embed] : [] ),
-								components: [],
-								flags: 64
-							}
-						} ).catch(log_error);
-						return msg;
-					}
-				});
-			}, log_error );
-		}
 		if ( wiki.hasOAuth2() && process.env.dashboard ) {
 		if ( wiki.hasOAuth2() && process.env.dashboard ) {
 			let oauth = [wiki.hostname + wiki.pathname.slice(0, -1)];
 			let oauth = [wiki.hostname + wiki.pathname.slice(0, -1)];
 			if ( wiki.isWikimedia() ) oauth.push('wikimedia');
 			if ( wiki.isWikimedia() ) oauth.push('wikimedia');
 			if ( wiki.isMiraheze() ) oauth.push('miraheze');
 			if ( wiki.isMiraheze() ) oauth.push('miraheze');
 			if ( process.env['oauth_' + ( oauth[1] || oauth[0] )] && process.env['oauth_' + ( oauth[1] || oauth[0] ) + '_secret'] ) {
 			if ( process.env['oauth_' + ( oauth[1] || oauth[0] )] && process.env['oauth_' + ( oauth[1] || oauth[0] ) + '_secret'] ) {
-				console.log( interaction.guild_id + ': Button: ' + interaction.data.custom_id + ': OAuth2' );
-				return db.query( 'SELECT token FROM oauthusers WHERE userid = $1 AND site = $2', [interaction.user.id, ( oauth[1] || oauth[0] )] ).then( ({rows: [row]}) => {
-					if ( row?.token ) return got.post( wiki + 'rest.php/oauth2/access_token', {
-						form: {
-							grant_type: 'refresh_token', refresh_token: row.token,
-							redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
-							client_id: process.env['oauth_' + ( oauth[1] || oauth[0] )],
-							client_secret: process.env['oauth_' + ( oauth[1] || oauth[0] ) + '_secret']
-						}
-					} ).then( response => {
-						var body = response.body;
-						if ( response.statusCode !== 200 || !body?.access_token ) {
-							console.log( '- ' + response.statusCode + ': Error while refreshing the mediawiki token: ' + ( body?.message || body?.error ) );
-							return Promise.reject(row);
-						}
-						if ( body?.refresh_token ) db.query( 'UPDATE oauthusers SET token = $1 WHERE userid = $2 AND site = $3', [body.refresh_token, interaction.user.id, ( oauth[1] || oauth[0] )] ).then( () => {
-							console.log( '- Dashboard: OAuth2 token for ' + interaction.user.id + ' successfully updated.' );
-						}, dberror => {
-							console.log( '- Dashboard: Error while updating the OAuth2 token for ' + interaction.user.id + ': ' + dberror );
-						} );
-						return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-							data: {
-								type: 7,
-								data: interaction.message
+				console.log( interaction.guildId + ': Button: ' + interaction.customId + ': OAuth2' );
+				return interaction.update( {components: [new MessageActionRow().addComponents(
+					new MessageButton(interaction.message.components[0].components[0]).setDisabled()
+				)]} ).then( () => {
+					return db.query( 'SELECT token FROM oauthusers WHERE userid = $1 AND site = $2', [interaction.user.id, ( oauth[1] || oauth[0] )] ).then( ({rows: [row]}) => {
+						if ( row?.token ) return got.post( wiki + 'rest.php/oauth2/access_token', {
+							form: {
+								grant_type: 'refresh_token', refresh_token: row.token,
+								redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
+								client_id: process.env['oauth_' + ( oauth[1] || oauth[0] )],
+								client_secret: process.env['oauth_' + ( oauth[1] || oauth[0] ) + '_secret']
+							}
+						} ).then( response => {
+							var body = response.body;
+							if ( response.statusCode !== 200 || !body?.access_token ) {
+								console.log( '- ' + response.statusCode + ': Error while refreshing the mediawiki token: ' + ( body?.message || body?.error ) );
+								return Promise.reject(row);
 							}
 							}
-						} ).then( () => {
+							if ( body?.refresh_token ) db.query( 'UPDATE oauthusers SET token = $1 WHERE userid = $2 AND site = $3', [body.refresh_token, interaction.user.id, ( oauth[1] || oauth[0] )] ).then( () => {
+								console.log( '- Dashboard: OAuth2 token for ' + interaction.user.id + ' successfully updated.' );
+							}, dberror => {
+								console.log( '- Dashboard: Error while updating the OAuth2 token for ' + interaction.user.id + ': ' + dberror );
+							} );
 							return global.verifyOauthUser('', body.access_token, {
 							return global.verifyOauthUser('', body.access_token, {
-								wiki: wiki.href, channel,
-								user: interaction.user.id,
-								token: interaction.token
+								wiki: wiki.href, channel: interaction.channel,
+								user: interaction.user.id, interaction,
+								fail: () => sendMessage(interaction, {components: []}, false)
 							});
 							});
-						}, log_error );
-					}, error => {
-						console.log( '- Error while refreshing the mediawiki token: ' + error );
-						return Promise.reject(row);
-					} );
-					return Promise.reject(row);
-				}, dberror => {
-					console.log( '- Error while getting the OAuth2 token: ' + dberror );
-					return Promise.reject();
-				} ).catch( row => {
-					if ( row ) {
-						if ( !row?.hasOwnProperty?.('token') ) console.log( '- Error while checking the OAuth2 refresh token: ' + row );
-						else if ( row.token ) db.query( 'DELETE FROM oauthusers WHERE userid = $1 AND site = $2', [interaction.user.id, ( oauth[1] || oauth[0] )] ).then( () => {
-							console.log( '- Dashboard: OAuth2 token for ' + interaction.user.id + ' successfully deleted.' );
-						}, dberror => {
-							console.log( '- Dashboard: Error while deleting the OAuth2 token for ' + interaction.user.id + ': ' + dberror );
+						}, error => {
+							console.log( '- Error while refreshing the mediawiki token: ' + error );
+							return Promise.reject(row);
 						} );
 						} );
-					}
-					let state = `${oauth[0]} ${global.shardId}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( oauth[1] ? ` ${oauth[1]}` : '' );
-					while ( oauthVerify.has(state) ) {
-						state = `${oauth[0]} ${global.shardId}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( oauth[1] ? ` ${oauth[1]}` : '' );
-					}
-					oauthVerify.set(state, {
-						state, wiki: wiki.href, channel,
-						user: interaction.user.id,
-						token: interaction.token
-					});
-					interaction.client.shard.send({id: 'verifyUser', state, user: ( row?.token === null ? '' : interaction.user.id )});
-					let oauthURL = wiki + 'rest.php/oauth2/authorize?' + new URLSearchParams({
-						response_type: 'code', redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
-						client_id: process.env['oauth_' + ( oauth[1] || oauth[0] )], state
-					}).toString();
-					interaction.message.components = [];
-					interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-						data: {
-							type: 7,
-							data: interaction.message
+						return Promise.reject(row);
+					}, dberror => {
+						console.log( '- Error while getting the OAuth2 token: ' + dberror );
+						return Promise.reject();
+					} ).catch( row => {
+						if ( row ) {
+							if ( !row?.hasOwnProperty?.('token') ) console.log( '- Error while checking the OAuth2 refresh token: ' + row );
+							else if ( row.token ) db.query( 'DELETE FROM oauthusers WHERE userid = $1 AND site = $2', [interaction.user.id, ( oauth[1] || oauth[0] )] ).then( () => {
+								console.log( '- Dashboard: OAuth2 token for ' + interaction.user.id + ' successfully deleted.' );
+							}, dberror => {
+								console.log( '- Dashboard: Error while deleting the OAuth2 token for ' + interaction.user.id + ': ' + dberror );
+							} );
 						}
 						}
-					} ).catch(log_error);
-					return interaction.client.api.webhooks(interaction.application_id, interaction.token).post( {
-						data: {
-							content: reply + lang.get('verify.oauth_message', '<' + oauthURL + '>'),
-							allowed_mentions,
-							components: [
-								{
-									type: 1,
-									components: [
-										{
-											type: 2,
-											style: 5,
-											label: lang.get('verify.oauth_button'),
-											emoji: {id: null, name: '🔗'},
-											url: oauthURL,
-											disabled: false
-										}
-									]
-								}
-							],
-							flags: 64
+						let state = `${oauth[0]} ${process.env.SHARDS}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( oauth[1] ? ` ${oauth[1]}` : '' );
+						while ( oauthVerify.has(state) ) {
+							state = `${oauth[0]} ${process.env.SHARDS}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( oauth[1] ? ` ${oauth[1]}` : '' );
 						}
 						}
-					} ).catch(log_error);
-				} );
+						oauthVerify.set(state, {
+							state, wiki: wiki.href, channel: interaction.channel,
+							user: interaction.user.id, interaction
+						});
+						interaction.client.shard.send({id: 'verifyUser', state, user: ( row?.token === null ? '' : interaction.user.id )});
+						let oauthURL = wiki + 'rest.php/oauth2/authorize?' + new URLSearchParams({
+							response_type: 'code', redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
+							client_id: process.env['oauth_' + ( oauth[1] || oauth[0] )], state
+						}).toString();
+						sendMessage(interaction, {components: []}, false);
+						return interaction.followUp( {
+							content: lang.get('verify.oauth_message', '<' + oauthURL + '>'),
+							components: [new MessageActionRow().addComponents(
+								new MessageButton().setLabel(lang.get('verify.oauth_button')).setEmoji('🔗').setStyle('LINK').setURL(oauthURL)
+							)],
+							ephemeral: true
+						} ).catch(log_error);
+					} );
+				}, log_error );
 			}
 			}
 		}
 		}
 
 
-		interaction.message.components[0].components[0].disabled = true;
-		return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-			data: {
-				type: 7,
-				data: interaction.message
-			}
-		} ).then( () => {
-			return channel.guild.members.fetch(interaction.user.id).then( member => {
-				console.log( interaction.guild_id + ': Button: ' + interaction.data.custom_id + ' ' + username );
-				return verify(lang, channel, member, username, wiki, rows).then( result => {
-					if ( result.oauth.length ) {
-						return db.query( 'SELECT token FROM oauthusers WHERE userid = $1 AND site = $2', [interaction.user.id, ( result.oauth[1] || result.oauth[0] )] ).then( ({rows: [row]}) => {
-							if ( row?.token ) return got.post( wiki + 'rest.php/oauth2/access_token', {
-								form: {
-									grant_type: 'refresh_token', refresh_token: row.token,
-									redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
-									client_id: process.env['oauth_' + ( result.oauth[1] || result.oauth[0] )],
-									client_secret: process.env['oauth_' + ( result.oauth[1] || result.oauth[0] ) + '_secret']
-								}
-							} ).then( response => {
-								var body = response.body;
-								if ( response.statusCode !== 200 || !body?.access_token ) {
-									console.log( '- ' + response.statusCode + ': Error while refreshing the mediawiki token: ' + ( body?.message || body?.error ) );
-									return Promise.reject(row);
-								}
-								if ( body?.refresh_token ) db.query( 'UPDATE oauthusers SET token = $1 WHERE userid = $2 AND site = $3', [body.refresh_token, interaction.user.id, ( result.oauth[1] || result.oauth[0] )] ).then( () => {
-									console.log( '- Dashboard: OAuth2 token for ' + interaction.user.id + ' successfully updated.' );
-								}, dberror => {
-									console.log( '- Dashboard: Error while updating the OAuth2 token for ' + interaction.user.id + ': ' + dberror );
-								} );
-								return global.verifyOauthUser('', body.access_token, {
-									wiki: wiki.href, channel,
-									user: interaction.user.id,
-									token: interaction.token
-								});
-							}, error => {
-								console.log( '- Error while refreshing the mediawiki token: ' + error );
-								return Promise.reject(row);
-							} );
-							return Promise.reject(row);
-						}, dberror => {
-							console.log( '- Error while getting the OAuth2 token: ' + dberror );
-							return Promise.reject();
-						} ).catch( row => {
-							if ( row ) {
-								if ( !row?.hasOwnProperty?.('token') ) console.log( '- Error while checking the OAuth2 refresh token: ' + row );
-								else if ( row.token ) db.query( 'DELETE FROM oauthusers WHERE userid = $1 AND site = $2', [interaction.user.id, ( result.oauth[1] || result.oauth[0] )] ).then( () => {
-									console.log( '- Dashboard: OAuth2 token for ' + interaction.user.id + ' successfully deleted.' );
-								}, dberror => {
-									console.log( '- Dashboard: Error while deleting the OAuth2 token for ' + interaction.user.id + ': ' + dberror );
-								} );
+		return interaction.update( {components: [new MessageActionRow().addComponents(
+			new MessageButton(interaction.message.components[0].components[0]).setDisabled()
+		)]} ).then( () => {
+			console.log( interaction.guildId + ': Button: ' + interaction.customId + ' ' + username );
+			return verify(lang, interaction.channel, interaction.member, username, wiki, rows).then( result => {
+				if ( result.oauth.length ) {
+					return db.query( 'SELECT token FROM oauthusers WHERE userid = $1 AND site = $2', [interaction.user.id, ( result.oauth[1] || result.oauth[0] )] ).then( ({rows: [row]}) => {
+						if ( row?.token ) return got.post( wiki + 'rest.php/oauth2/access_token', {
+							form: {
+								grant_type: 'refresh_token', refresh_token: row.token,
+								redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
+								client_id: process.env['oauth_' + ( result.oauth[1] || result.oauth[0] )],
+								client_secret: process.env['oauth_' + ( result.oauth[1] || result.oauth[0] ) + '_secret']
 							}
 							}
-							let state = `${result.oauth[0]} ${global.shardId}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( result.oauth[1] ? ` ${result.oauth[1]}` : '' );
-							while ( oauthVerify.has(state) ) {
-								state = `${result.oauth[0]} ${global.shardId}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( result.oauth[1] ? ` ${result.oauth[1]}` : '' );
+						} ).then( response => {
+							var body = response.body;
+							if ( response.statusCode !== 200 || !body?.access_token ) {
+								console.log( '- ' + response.statusCode + ': Error while refreshing the mediawiki token: ' + ( body?.message || body?.error ) );
+								return Promise.reject(row);
 							}
 							}
-							oauthVerify.set(state, {
-								state, wiki: wiki.href, channel,
-								user: interaction.user.id,
-								token: interaction.token
+							if ( body?.refresh_token ) db.query( 'UPDATE oauthusers SET token = $1 WHERE userid = $2 AND site = $3', [body.refresh_token, interaction.user.id, ( result.oauth[1] || result.oauth[0] )] ).then( () => {
+								console.log( '- Dashboard: OAuth2 token for ' + interaction.user.id + ' successfully updated.' );
+							}, dberror => {
+								console.log( '- Dashboard: Error while updating the OAuth2 token for ' + interaction.user.id + ': ' + dberror );
+							} );
+							return global.verifyOauthUser('', body.access_token, {
+								wiki: wiki.href, channel: interaction.channel,
+								user: interaction.user.id, interaction,
+								fail: () => sendMessage(interaction, {components: []}, false)
 							});
 							});
-							interaction.client.shard.send({id: 'verifyUser', state, user: ( row?.token === null ? '' : interaction.user.id )});
-							let oauthURL = wiki + 'rest.php/oauth2/authorize?' + new URLSearchParams({
-								response_type: 'code', redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
-								client_id: process.env['oauth_' + ( result.oauth[1] || result.oauth[0] )], state
-							}).toString();
-							interaction.message.components = [];
-							interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-								data: {
-									type: 7,
-									data: interaction.message
-								}
-							} ).catch(log_error);
-							return interaction.client.api.webhooks(interaction.application_id, interaction.token).post( {
-								data: {
-									content: reply + lang.get('verify.oauth_message', '<' + oauthURL + '>'),
-									allowed_mentions,
-									components: [
-										{
-											type: 1,
-											components: [
-												{
-													type: 2,
-													style: 5,
-													label: lang.get('verify.oauth_button'),
-													emoji: {id: null, name: '🔗'},
-													url: oauthURL,
-													disabled: false
-												}
-											]
-										}
-									],
-									flags: 64
-								}
-							} ).catch(log_error);
+						}, error => {
+							console.log( '- Error while refreshing the mediawiki token: ' + error );
+							return Promise.reject(row);
 						} );
 						} );
-					}
-					var message = {
-						content: reply + result.content,
-						embeds: [result.embed],
-						allowed_mentions,
-						components: []
-					};
-					if ( result.reaction ) {
-						if ( result.reaction === 'nowiki' ) message.content = lang.get('interaction.nowiki');
-						else message.content = reply + lang.get('verify.error_reply');
-						message.embeds = [];
-					}
-					else if ( result.add_button ) message.components.push({
-						type: 1,
-						components: [
-							{
-								type: 2,
-								style: 1,
-								label: lang.get('verify.button_again'),
-								emoji: {id: null, name: '🔂'},
-								custom_id: 'verify_again',
-								disabled: false
-							}
-						]
-					});
-					sendMessage(interaction, message, channel, false);
-					if ( result.logging.channel && channel.guild.channels.cache.has(result.logging.channel) ) {
-						if ( !result.send_private ) {
-							let msg_url = `https://discord.com/channels/${channel.guild.id}/${channel.id}/${interaction.message.id}`;
-							if ( result.logging.embed ) result.logging.embed.addField(msg_url, '<#' + channel.id + '>');
-							else result.logging.content += '\n<#' + channel.id + '> – <' + msg_url + '>';
+						return Promise.reject(row);
+					}, dberror => {
+						console.log( '- Error while getting the OAuth2 token: ' + dberror );
+						return Promise.reject();
+					} ).catch( row => {
+						if ( row ) {
+							if ( !row?.hasOwnProperty?.('token') ) console.log( '- Error while checking the OAuth2 refresh token: ' + row );
+							else if ( row.token ) db.query( 'DELETE FROM oauthusers WHERE userid = $1 AND site = $2', [interaction.user.id, ( result.oauth[1] || result.oauth[0] )] ).then( () => {
+								console.log( '- Dashboard: OAuth2 token for ' + interaction.user.id + ' successfully deleted.' );
+							}, dberror => {
+								console.log( '- Dashboard: Error while deleting the OAuth2 token for ' + interaction.user.id + ': ' + dberror );
+							} );
 						}
 						}
-						channel.guild.channels.cache.get(result.logging.channel).send(result.logging.content, {
-							embed: result.logging.embed,
-							allowedMentions: {parse: []}
-						}).catch(log_error);
-					}
-					interaction.client.api.webhooks(interaction.application_id, interaction.token).post( {
-						data: {
-							content: message.content,
-							embeds: message.embeds,
-							allowed_mentions,
-							components: [],
-							flags: 64
+						let state = `${result.oauth[0]} ${process.env.SHARDS}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( result.oauth[1] ? ` ${result.oauth[1]}` : '' );
+						while ( oauthVerify.has(state) ) {
+							state = `${result.oauth[0]} ${process.env.SHARDS}` + Date.now().toString(16) + randomBytes(16).toString('hex') + ( result.oauth[1] ? ` ${result.oauth[1]}` : '' );
 						}
 						}
+						oauthVerify.set(state, {
+							state, wiki: wiki.href, channel: interaction.channel,
+							user: interaction.user.id, interaction
+						});
+						interaction.client.shard.send({id: 'verifyUser', state, user: ( row?.token === null ? '' : interaction.user.id )});
+						let oauthURL = wiki + 'rest.php/oauth2/authorize?' + new URLSearchParams({
+							response_type: 'code', redirect_uri: new URL('/oauth/mw', process.env.dashboard).href,
+							client_id: process.env['oauth_' + ( result.oauth[1] || result.oauth[0] )], state
+						}).toString();
+						sendMessage(interaction, {components: []}, false);
+						return interaction.followUp( {
+							content: lang.get('verify.oauth_message', '<' + oauthURL + '>'),
+							components: [new MessageActionRow().addComponents(
+								new MessageButton().setLabel(lang.get('verify.oauth_button')).setEmoji('🔗').setStyle('LINK').setURL(oauthURL)
+							)],
+							ephemeral: true
+						} ).catch(log_error);
+					} );
+				}
+				var message = {
+					content: interaction.member.toString() + ', ' + result.content,
+					embeds: [result.embed],
+					components: [],
+					allowedMentions: {
+						users: [interaction.user.id],
+						repliedUser: true
+					}
+				};
+				if ( result.reaction ) {
+					if ( result.reaction === 'nowiki' ) message.content = lang.get('interaction.nowiki');
+					else message.content = lang.get('verify.error_reply');
+					message.embeds = [];
+				}
+				else if ( result.add_button ) message.components.push(new MessageActionRow().addComponents(
+					new MessageButton().setLabel(lang.get('verify.button_again')).setEmoji('🔂').setStyle('PRIMARY').setCustomId('verify_again')
+				));
+				sendMessage(interaction, message, false);
+				if ( result.logging.channel && interaction.guild.channels.cache.has(result.logging.channel) ) {
+					if ( result.logging.embed ) result.logging.embed.addField(interaction.message.url, '<#' + interaction.channelId + '>');
+					else result.logging.content += '\n<#' + interaction.channelId + '> – <' + interaction.message.url + '>';
+					interaction.guild.channels.cache.get(result.logging.channel).send( {
+						content: result.logging.content,
+						embeds: [result.logging.embed]
 					} ).catch(log_error);
 					} ).catch(log_error);
-				}, error => {
-					console.log( '- Error during the verifications: ' + error );
-					return sendMessage(interaction, {
-						content: reply + lang.get('verify.error_reply'),
-						allowed_mentions
-					}, channel);
-				} );
+				}
+				interaction.followUp( {
+					content: message.content,
+					embeds: message.embeds,
+					components: [],
+					ephemeral: true
+				} ).catch(log_error);
 			}, error => {
 			}, error => {
-				console.log( '- Error while getting the member: ' + error );
-				return sendMessage(interaction, {
-					content: reply + lang.get('verify.error_reply'),
-					allowed_mentions
-				}, channel);
+				console.log( '- Error during the verifications: ' + error );
+				return sendMessage(interaction, {components: []});
 			} );
 			} );
 		}, log_error);
 		}, log_error);
 	}, dberror => {
 	}, dberror => {
 		console.log( '- Error while getting the verifications: ' + dberror );
 		console.log( '- Error while getting the verifications: ' + dberror );
-		return interaction.client.api.interactions(interaction.id, interaction.token).callback.post( {
-			data: {type: 6}
-		} ).catch(log_error);
+		return interaction.reply( {content: lang.get('verify.error_reply'), ephemeral: true} ).catch(log_error);
 	} );
 	} );
 }
 }
 
 

+ 159 - 150
main.js

@@ -15,7 +15,7 @@ const got = require('got').extend( {
 	},
 	},
 	responseType: 'json'
 	responseType: 'json'
 } );
 } );
-const {ShardingManager, ShardClientUtil: {shardIDForGuildID}} = require('discord.js');
+const {ShardingManager, ShardClientUtil: {shardIdForGuildId}} = require('discord.js');
 const manager = new ShardingManager( './bot.js', {
 const manager = new ShardingManager( './bot.js', {
 	execArgv: ['--icu-data-dir=node_modules/full-icu'],
 	execArgv: ['--icu-data-dir=node_modules/full-icu'],
 	shardArgs: ( isDebug ? ['debug'] : [] ),
 	shardArgs: ( isDebug ? ['debug'] : [] ),
@@ -28,11 +28,6 @@ manager.on( 'shardCreate', shard => {
 	
 	
 	shard.on( 'spawn', () => {
 	shard.on( 'spawn', () => {
 		console.log( `- Shard[${shard.id}]: Spawned` );
 		console.log( `- Shard[${shard.id}]: Spawned` );
-		shard.send( {
-			shard: {
-				id: shard.id
-			}
-		} );
 	} );
 	} );
 	
 	
 	shard.on( 'message', message => {
 	shard.on( 'message', message => {
@@ -47,7 +42,9 @@ manager.on( 'shardCreate', shard => {
 		if ( message === 'toggleDebug' ) {
 		if ( message === 'toggleDebug' ) {
 			console.log( '\n- Toggle debug logging for all shards!\n' );
 			console.log( '\n- Toggle debug logging for all shards!\n' );
 			isDebug = !isDebug;
 			isDebug = !isDebug;
-			manager.broadcastEval( `global.isDebug = !global.isDebug` );
+			manager.broadcastEval( () => {
+				global.isDebug = !global.isDebug;
+			} );
 			if ( typeof server !== 'undefined' ) server.send( 'toggleDebug' );
 			if ( typeof server !== 'undefined' ) server.send( 'toggleDebug' );
 		}
 		}
 		if ( message === 'postStats' && process.env.botlist ) postStats();
 		if ( message === 'postStats' && process.env.botlist ) postStats();
@@ -65,7 +62,7 @@ manager.on( 'shardCreate', shard => {
 	} );
 	} );
 } );
 } );
 
 
-manager.spawn(manager.totalShards, 5500, 60000).then( shards => {
+manager.spawn({timeout: 60000}).then( shards => {
 	if ( !isDebug && process.env.botlist ) {
 	if ( !isDebug && process.env.botlist ) {
 		var botList = JSON.parse(process.env.botlist);
 		var botList = JSON.parse(process.env.botlist);
 		for ( let [key, value] of Object.entries(botList) ) {
 		for ( let [key, value] of Object.entries(botList) ) {
@@ -83,7 +80,7 @@ manager.spawn(manager.totalShards, 5500, 60000).then( shards => {
 		if ( typeof server !== 'undefined' && !server.killed ) server.kill();
 		if ( typeof server !== 'undefined' && !server.killed ) server.kill();
 		process.exit(1);
 		process.exit(1);
 	}
 	}
-	else manager.spawn(manager.totalShards, 5500, -1).catch( error2 => {
+	else manager.spawn({timeout: -1}).catch( error2 => {
 		console.error( '- Error while spawning the shards: ' + error2 );
 		console.error( '- Error while spawning the shards: ' + error2 );
 		manager.respawn = false;
 		manager.respawn = false;
 		manager.shards.filter( shard => shard.process && !shard.process.killed ).forEach( shard => shard.kill() );
 		manager.shards.filter( shard => shard.process && !shard.process.killed ).forEach( shard => shard.kill() );
@@ -97,6 +94,147 @@ if ( process.env.dashboard ) {
 	const dashboard = child_process.fork('./dashboard/index.js', ( isDebug ? ['debug'] : [] ));
 	const dashboard = child_process.fork('./dashboard/index.js', ( isDebug ? ['debug'] : [] ));
 	server = dashboard;
 	server = dashboard;
 
 
+	const evalFunctions = {
+		getGuilds: (discordClient, evalData) => {
+			return Promise.all(
+				evalData.guilds.map( id => {
+					if ( discordClient.guilds.cache.has(id) ) {
+						let guild = discordClient.guilds.cache.get(id);
+						return guild.members.fetch(evalData.member).then( member => {
+							return {
+								patreon: global.patreons.hasOwnProperty(guild.id),
+								memberCount: guild.memberCount,
+								botPermissions: guild.me.permissions.bitfield.toString(),
+								channels: guild.channels.cache.filter( channel => {
+									return ( channel.isGuild(false) || channel.type === 'GUILD_CATEGORY' );
+								} ).sort( (a, b) => {
+									let aVal = a.rawPosition + 1;
+									if ( a.type === 'GUILD_CATEGORY' ) aVal *= 1000;
+									else if ( !a.parent ) aVal -= 1000;
+									else aVal += ( a.parent.rawPosition + 1 ) * 1000;
+									let bVal = b.rawPosition + 1;
+									if ( b.type === 'GUILD_CATEGORY' ) bVal *= 1000;
+									else if ( !b.parent ) bVal -= 1000;
+									else bVal += ( b.parent.rawPosition + 1 ) * 1000;
+									return aVal - bVal;
+								} ).map( channel => {
+									return {
+										id: channel.id,
+										name: channel.name,
+										isCategory: ( channel.type === 'GUILD_CATEGORY' ),
+										userPermissions: member.permissionsIn(channel).bitfield.toString(),
+										botPermissions: guild.me.permissionsIn(channel).bitfield.toString()
+									};
+								} ),
+								roles: guild.roles.cache.filter( role => {
+									return ( role.id !== guild.id );
+								} ).sort( (a, b) => {
+									return b.rawPosition - a.rawPosition;
+								} ).map( role => {
+									return {
+										id: role.id,
+										name: role.name,
+										lower: ( guild.me.roles.highest.comparePositionTo(role) > 0 && !role.managed )
+									};
+								} ),
+								locale: guild.preferredLocale
+							};
+						}, error => {
+							return 'noMember';
+						} );
+					}
+				} )
+			)
+		},
+		getMember: (discordClient, evalData) => {
+			if ( discordClient.guilds.cache.has(evalData.guild) ) {
+				let guild = discordClient.guilds.cache.get(evalData.guild);
+				return guild.members.fetch(evalData.member).then( member => {
+					var response = {
+						patreon: global.patreons.hasOwnProperty(guild.id),
+						userPermissions: member.permissions.bitfield.toString(),
+						botPermissions: guild.me.permissions.bitfield.toString()
+					};
+					if ( evalData.channel ) {
+						let channel = guild.channels.cache.get(evalData.channel);
+						if ( channel?.isGuild(false) || ( response.patreon && evalData.allowCategory && channel?.type === 'GUILD_CATEGORY' ) ) {
+							response.userPermissions = channel.permissionsFor(member).bitfield.toString();
+							response.botPermissions = channel.permissionsFor(guild.me).bitfield.toString();
+							response.isCategory = ( channel.type === 'GUILD_CATEGORY' );
+							response.parentId = channel.parentId;
+						}
+						else response.message = 'noChannel';
+					}
+					if ( evalData.newchannel ) {
+						let newchannel = guild.channels.cache.get(evalData.newchannel);
+						if ( newchannel?.isGuild(false) ) {
+							response.userPermissionsNew = newchannel.permissionsFor(member).bitfield.toString();
+							response.botPermissionsNew = newchannel.permissionsFor(guild.me).bitfield.toString();
+						}
+						else response.message = 'noChannel';
+					}
+					return response;
+				}, error => {
+					return 'noMember';
+				} );
+			}
+		},
+		notifyGuild: (discordClient, evalData) => {
+			if ( evalData.prefix ) {
+				global.patreons[evalData.guild] = evalData.prefix;
+			}
+			if ( evalData.voice && global.voice.hasOwnProperty(evalData.guild) ) {
+				global.voice[evalData.guild] = evalData.voice;
+			}
+			if ( discordClient.guilds.cache.has(evalData.guild) ) {
+				let channel = discordClient.guilds.cache.get(evalData.guild).publicUpdatesChannel;
+				if ( channel ) channel.send( {
+					content: evalData.text,
+					embeds: [evalData.embed],
+					files: evalData.file,
+					allowedMentions: {parse: []}
+				} ).catch(log_error);
+			}
+		},
+		createWebhook: (discordClient, evalData) => {
+			if ( discordClient.guilds.cache.has(evalData.guild) ) {
+				let channel = discordClient.guilds.cache.get(evalData.guild).channels.cache.get(evalData.channel);
+				if ( channel ) return channel.createWebhook( evalData.name, {
+					avatar: ( evalData.avatar || discordClient.user.displayAvatarURL({format:'png',size:4096}) ),
+					reason: evalData.reason
+				} ).then( webhook => {
+					console.log( `- Dashboard: Webhook successfully created: ${evalData.guild}#${evalData.channel}` );
+					webhook.send( evalData.text ).catch(log_error);
+					return webhook.id + '/' + webhook.token;
+				}, error => {
+					console.log( '- Dashboard: Error while creating the webhook: ' + error );
+				} );
+			}
+		},
+		editWebhook: (discordClient, evalData) => {
+			if ( discordClient.guilds.cache.has(evalData.guild) ) {
+				return discordClient.fetchWebhook(...evalData.webhook.split('/')).then( webhook => {
+					var changes = {};
+					if ( evalData.channel ) changes.channel = evalData.channel;
+					if ( evalData.name ) changes.name = evalData.name;
+					if ( evalData.avatar ) changes.avatar = evalData.avatar;
+					return webhook.edit( changes, evalData.reason ).then( newwebhook => {
+						console.log( `- Dashboard: Webhook successfully edited: ${evalData.guild}#` + ( evalData.channel || webhook.channelId ) );
+						webhook.send( evalData.text ).catch(log_error);
+						return true;
+					}, error => {
+						console.log( '- Dashboard: Error while editing the webhook: ' + error );
+					} );
+				}, error => {
+					console.log( '- Dashboard: Error while editing the webhook: ' + error );
+				} );
+			}
+		},
+		verifyUser: (discordClient, evalData) => {
+			global.verifyOauthUser(evalData.state, evalData.access_token);
+		}
+	};
+
 	dashboard.on( 'message', message => {
 	dashboard.on( 'message', message => {
 		if ( message.id ) {
 		if ( message.id ) {
 			var data = {
 			var data = {
@@ -106,55 +244,7 @@ if ( process.env.dashboard ) {
 			};
 			};
 			switch ( message.data.type ) {
 			switch ( message.data.type ) {
 				case 'getGuilds':
 				case 'getGuilds':
-					return manager.broadcastEval(`Promise.all(
-						${JSON.stringify(message.data.guilds)}.map( id => {
-							if ( this.guilds.cache.has(id) ) {
-								let guild = this.guilds.cache.get(id);
-								return guild.members.fetch(${JSON.stringify(message.data.member)}).then( member => {
-									return {
-										patreon: global.patreons.hasOwnProperty(guild.id),
-										memberCount: guild.memberCount,
-										botPermissions: guild.me.permissions.bitfield,
-										channels: guild.channels.cache.filter( channel => {
-											return ( channel.isGuild() || channel.type === 'category' );
-										} ).sort( (a, b) => {
-											let aVal = a.rawPosition + 1;
-											if ( a.type === 'category' ) aVal *= 1000;
-											else if ( !a.parent ) aVal -= 1000;
-											else aVal += ( a.parent.rawPosition + 1 ) * 1000;
-											let bVal = b.rawPosition + 1;
-											if ( b.type === 'category' ) bVal *= 1000;
-											else if ( !b.parent ) bVal -= 1000;
-											else bVal += ( b.parent.rawPosition + 1 ) * 1000;
-											return aVal - bVal;
-										} ).map( channel => {
-											return {
-												id: channel.id,
-												name: channel.name,
-												isCategory: ( channel.type === 'category' ),
-												userPermissions: member.permissionsIn(channel).bitfield,
-												botPermissions: guild.me.permissionsIn(channel).bitfield
-											};
-										} ),
-										roles: guild.roles.cache.filter( role => {
-											return ( role.id !== guild.id );
-										} ).sort( (a, b) => {
-											return b.rawPosition - a.rawPosition;
-										} ).map( role => {
-											return {
-												id: role.id,
-												name: role.name,
-												lower: ( guild.me.roles.highest.comparePositionTo(role) > 0 && !role.managed )
-											};
-										} ),
-										locale: guild.preferredLocale
-									};
-								}, error => {
-									return 'noMember';
-								} )
-							}
-						} )
-					)`).then( results => {
+					return manager.broadcastEval( evalFunctions.getGuilds, {context: message.data} ).then( results => {
 						data.response = message.data.guilds.map( (guild, i) => {
 						data.response = message.data.guilds.map( (guild, i) => {
 							return results.find( result => result[i] )?.[i];
 							return results.find( result => result[i] )?.[i];
 						} );
 						} );
@@ -165,78 +255,12 @@ if ( process.env.dashboard ) {
 					} );
 					} );
 					break;
 					break;
 				case 'getMember':
 				case 'getMember':
-					return manager.broadcastEval(`if ( this.guilds.cache.has(${JSON.stringify(message.data.guild)}) ) {
-						let guild = this.guilds.cache.get(${JSON.stringify(message.data.guild)});
-						guild.members.fetch(${JSON.stringify(message.data.member)}).then( member => {
-							var response = {
-								patreon: global.patreons.hasOwnProperty(guild.id),
-								userPermissions: member.permissions.bitfield,
-								botPermissions: guild.me.permissions.bitfield
-							};
-							if ( ${JSON.stringify(message.data.channel)} ) {
-								let channel = guild.channels.cache.get(${JSON.stringify(message.data.channel)});
-								if ( channel?.isText() || ( response.patreon && ${JSON.stringify(message.data.allowCategory)} && channel?.type === 'category' ) ) {
-									response.userPermissions = channel.permissionsFor(member).bitfield;
-									response.botPermissions = channel.permissionsFor(guild.me).bitfield;
-									response.isCategory = ( channel.type === 'category' );
-									response.parentID = channel.parentID;
-								}
-								else response.message = 'noChannel';
-							}
-							if ( ${JSON.stringify(message.data.newchannel)} ) {
-								let newchannel = guild.channels.cache.get(${JSON.stringify(message.data.newchannel)});
-								if ( newchannel?.isText() ) {
-									response.userPermissionsNew = newchannel.permissionsFor(member).bitfield;
-									response.botPermissionsNew = newchannel.permissionsFor(guild.me).bitfield;
-								}
-								else response.message = 'noChannel';
-							}
-							return response;
-						}, error => {
-							return 'noMember';
-						} );
-					}`, shardIDForGuildID(message.data.guild, manager.totalShards)).then( result => {
-						data.response = result;
-					}, error => {
-						data.error = error.toString();
-					} ).finally( () => {
-						return dashboard.send( {id: message.id, data} );
-					} );
-					break;
-				case 'notifyGuild':
-					return manager.broadcastEval(`if ( ${JSON.stringify(message.data.prefix)} ) {
-						global.patreons[${JSON.stringify(message.data.guild)}] = ${JSON.stringify(message.data.prefix)};
-					}
-					if ( ${JSON.stringify(message.data.voice)} && global.voice.hasOwnProperty(${JSON.stringify(message.data.guild)}) ) {
-						global.voice[${JSON.stringify(message.data.guild)}] = ${JSON.stringify(message.data.voice)};
-					}
-					if ( this.guilds.cache.has(${JSON.stringify(message.data.guild)}) ) {
-						let channel = this.guilds.cache.get(${JSON.stringify(message.data.guild)}).publicUpdatesChannel;
-						if ( channel ) channel.send( ${JSON.stringify(message.data.text)}, {
-							embed: ${JSON.stringify(message.data.embed)},
-							files: ${JSON.stringify(message.data.file)},
-							allowedMentions: {parse: []}, split: true
-						} ).catch( error => {} );
-					}`).catch( error => {
-						data.error = error.toString();
-					} ).finally( () => {
-						return dashboard.send( {id: message.id, data} );
-					} );
-					break;
 				case 'createWebhook':
 				case 'createWebhook':
-					return manager.broadcastEval(`if ( this.guilds.cache.has(${JSON.stringify(message.data.guild)}) ) {
-						let channel = this.guilds.cache.get(${JSON.stringify(message.data.guild)}).channels.cache.get(${JSON.stringify(message.data.channel)});
-						if ( channel ) channel.createWebhook( ${JSON.stringify(message.data.name)}, {
-							avatar: ( ${JSON.stringify(message.data.avatar)} || this.user.displayAvatarURL({format:'png',size:4096}) ),
-							reason: ${JSON.stringify(message.data.reason)}
-						} ).then( webhook => {
-							console.log( '- Dashboard: Webhook successfully created: ${message.data.guild}#${message.data.channel}' );
-							webhook.send( ${JSON.stringify(message.data.text)} ).catch(log_error);
-							return webhook.id + '/' + webhook.token;
-						}, error => {
-							console.log( '- Dashboard: Error while creating the webhook: ' + error );
-						} );
-					}`, shardIDForGuildID(message.data.guild, manager.totalShards)).then( result => {
+				case 'editWebhook':
+					return manager.broadcastEval( evalFunctions[message.data.type], {
+						context: message.data,
+						shard: shardIdForGuildId(message.data.guild, manager.totalShards)
+					} ).then( result => {
 						data.response = result;
 						data.response = result;
 					}, error => {
 					}, error => {
 						data.error = error.toString();
 						data.error = error.toString();
@@ -244,33 +268,18 @@ if ( process.env.dashboard ) {
 						return dashboard.send( {id: message.id, data} );
 						return dashboard.send( {id: message.id, data} );
 					} );
 					} );
 					break;
 					break;
-				case 'editWebhook':
-					return manager.broadcastEval(`if ( this.guilds.cache.has(${JSON.stringify(message.data.guild)}) ) {
-						this.fetchWebhook(...${JSON.stringify(message.data.webhook.split('/'))}).then( webhook => {
-							var changes = {};
-							if ( ${JSON.stringify(message.data.channel)} ) changes.channel = ${JSON.stringify(message.data.channel)};
-							if ( ${JSON.stringify(message.data.name)} ) changes.name = ${JSON.stringify(message.data.name)};
-							if ( ${JSON.stringify(message.data.avatar)} ) changes.avatar = ${JSON.stringify(message.data.avatar)};
-							return webhook.edit( changes, ${JSON.stringify(message.data.reason)} ).then( newwebhook => {
-								console.log( '- Dashboard: Webhook successfully edited: ${message.data.guild}#' + ( ${JSON.stringify(message.data.channel)} || webhook.channelID ) );
-								webhook.send( ${JSON.stringify(message.data.text)} ).catch(log_error);
-								return true;
-							}, error => {
-								console.log( '- Dashboard: Error while editing the webhook: ' + error );
-							} );
-						}, error => {
-							console.log( '- Dashboard: Error while editing the webhook: ' + error );
-						} );
-					}`, shardIDForGuildID(message.data.guild, manager.totalShards)).then( result => {
-						data.response = result;
-					}, error => {
+				case 'notifyGuild':
+					return manager.broadcastEval( evalFunctions.notifyGuild, {context: message.data} ).catch( error => {
 						data.error = error.toString();
 						data.error = error.toString();
 					} ).finally( () => {
 					} ).finally( () => {
 						return dashboard.send( {id: message.id, data} );
 						return dashboard.send( {id: message.id, data} );
 					} );
 					} );
 					break;
 					break;
 				case 'verifyUser':
 				case 'verifyUser':
-					return manager.broadcastEval(`global.verifyOauthUser(${JSON.stringify(message.data.state)}, ${JSON.stringify(message.data.access_token)})`, message.data.state.split(' ')[1][0]).catch( error => {
+					return manager.broadcastEval( evalFunctions.verifyUser, {
+						context: message.data,
+						shard: message.data.state.split(' ')[1][0]
+					} ).catch( error => {
 						data.error = error.toString();
 						data.error = error.toString();
 					} ).finally( () => {
 					} ).finally( () => {
 						return dashboard.send( {id: message.id, data} );
 						return dashboard.send( {id: message.id, data} );

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 329 - 203
package-lock.json


+ 6 - 6
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "discord-wiki-bot",
   "name": "discord-wiki-bot",
-  "version": "4.1.0",
+  "version": "4.2.0",
   "description": "Wiki-Bot is a bot with the purpose to easily search for and link to wiki pages. Wiki-Bot shows short descriptions and additional info about pages and is able to resolve redirects and follow interwiki links.",
   "description": "Wiki-Bot is a bot with the purpose to easily search for and link to wiki pages. Wiki-Bot shows short descriptions and additional info about pages and is able to resolve redirects and follow interwiki links.",
   "main": "main.js",
   "main": "main.js",
   "scripts": {
   "scripts": {
@@ -12,19 +12,19 @@
   "author": "MarkusRost",
   "author": "MarkusRost",
   "license": "ISC",
   "license": "ISC",
   "engines": {
   "engines": {
-    "node": ">=14.0.0"
+    "node": ">=16.6.0"
   },
   },
   "dependencies": {
   "dependencies": {
     "cheerio": "^1.0.0-rc.10",
     "cheerio": "^1.0.0-rc.10",
     "datetime-difference": "^1.0.2",
     "datetime-difference": "^1.0.2",
-    "discord-oauth2": "^2.6.0",
-    "discord.js": "^12.5.3",
+    "discord-oauth2": "^2.7.1",
+    "discord.js": "^13.1.0",
     "dotenv": "^10.0.0",
     "dotenv": "^10.0.0",
     "full-icu": "^1.3.4",
     "full-icu": "^1.3.4",
     "got": "^11.8.2",
     "got": "^11.8.2",
     "htmlparser2": "^6.1.0",
     "htmlparser2": "^6.1.0",
-    "npm": "^7.17.0",
-    "pg": "^8.6.0"
+    "npm": "^7.20.6",
+    "pg": "^8.7.1"
   },
   },
   "repository": {
   "repository": {
     "type": "git",
     "type": "git",

+ 5 - 5
util/database.js

@@ -1,24 +1,24 @@
 const {Pool} = require('pg');
 const {Pool} = require('pg');
 const db = new Pool();
 const db = new Pool();
 db.on( 'error', dberror => {
 db.on( 'error', dberror => {
-	console.log( '- ' + shardId + ': Error while connecting to the database: ' + dberror );
+	console.log( '- ' + process.env.SHARDS + ': Error while connecting to the database: ' + dberror );
 } );
 } );
 
 
 db.query( 'SELECT guild, prefix FROM discord WHERE patreon IS NOT NULL' ).then( ({rows}) => {
 db.query( 'SELECT guild, prefix FROM discord WHERE patreon IS NOT NULL' ).then( ({rows}) => {
-	console.log( '- ' + shardId + ': Patreons successfully loaded.' );
+	console.log( '- ' + process.env.SHARDS + ': Patreons successfully loaded.' );
 	rows.forEach( row => {
 	rows.forEach( row => {
 		patreons[row.guild] = row.prefix;
 		patreons[row.guild] = row.prefix;
 	} );
 	} );
 }, dberror => {
 }, dberror => {
-	console.log( '- ' + shardId + ': Error while getting the patreons: ' + dberror );
+	console.log( '- ' + process.env.SHARDS + ': Error while getting the patreons: ' + dberror );
 } );
 } );
 db.query( 'SELECT guild, lang FROM discord WHERE voice IS NOT NULL' ).then( ({rows}) => {
 db.query( 'SELECT guild, lang FROM discord WHERE voice IS NOT NULL' ).then( ({rows}) => {
-	console.log( '- ' + shardId + ': Voice channels successfully loaded.' );
+	console.log( '- ' + process.env.SHARDS + ': Voice channels successfully loaded.' );
 	rows.forEach( row => {
 	rows.forEach( row => {
 		voice[row.guild] = row.lang;
 		voice[row.guild] = row.lang;
 	} );
 	} );
 }, dberror => {
 }, dberror => {
-	console.log( '- ' + shardId + ': Error while getting the voice channels: ' + dberror );
+	console.log( '- ' + process.env.SHARDS + ': Error while getting the voice channels: ' + dberror );
 } );
 } );
 
 
 module.exports = db;
 module.exports = db;

+ 1 - 1
util/default.json

@@ -26,7 +26,7 @@
 			"display": 2
 			"display": 2
 		}
 		}
 	},
 	},
-	"defaultPermissions": 104019119168,
+	"defaultPermissions": "104019119168",
 	"defaultSettings": {
 	"defaultSettings": {
 		"lang": "en",
 		"lang": "en",
 		"wiki": "https://en.wikipedia.org/w/"
 		"wiki": "https://en.wikipedia.org/w/"

+ 8 - 17
util/functions.js

@@ -8,8 +8,6 @@ const got = require('got').extend( {
 	responseType: 'json'
 	responseType: 'json'
 } );
 } );
 
 
-const slashCommands = require('../interactions/commands.json');
-
 /**
 /**
  * @type {Map<String, {state: String, wiki: String, channel: import('discord.js').TextChannel, user: String}>}
  * @type {Map<String, {state: String, wiki: String, channel: import('discord.js').TextChannel, user: String}>}
  */
  */
@@ -432,7 +430,7 @@ function partialURIdecode(m) {
  * @param {String} author - The user id.
  * @param {String} author - The user id.
  */
  */
 function allowDelete(msg, author) {
 function allowDelete(msg, author) {
-	msg.awaitReactions( (reaction, user) => reaction.emoji.name === '🗑️' && user.id === author, {max:1,time:300000} ).then( reaction => {
+	msg?.awaitReactions?.( {filter: (reaction, user) => ( reaction.emoji.name === '🗑️' && user.id === author ), max: 1, time: 300000} ).then( reaction => {
 		if ( reaction.size ) {
 		if ( reaction.size ) {
 			msg.delete().catch(log_error);
 			msg.delete().catch(log_error);
 		}
 		}
@@ -441,28 +439,21 @@ function allowDelete(msg, author) {
 
 
 /**
 /**
  * Sends an interaction response.
  * Sends an interaction response.
- * @param {Object} interaction - The interaction.
- * @param {Object} message - The message.
- * @param {String} message.content - The message content.
- * @param {{parse: String[], roles?: String[], users?: String[]}} message.allowed_mentions - The allowed mentions.
- * @param {import('discord.js').TextChannel} channel - The channel for the interaction.
+ * @param {import('discord.js').CommandInteraction|import('discord.js').ButtonInteraction} interaction - The interaction.
+ * @param {import('discord.js').MessageOptions} message - The message.
  * @param {Boolean} [letDelete] - Let the interaction user delete the message.
  * @param {Boolean} [letDelete] - Let the interaction user delete the message.
  * @returns {Promise<import('discord.js').Message?>}
  * @returns {Promise<import('discord.js').Message?>}
  */
  */
-function sendMessage(interaction, message, channel, letDelete = true) {
-	return interaction.client.api.webhooks(interaction.application_id, interaction.token).messages('@original').patch( {
-		data: message
-	} ).then( msg => {
-		if ( !channel ) return;
-		var responseMessage = channel.messages.add(msg);
-		if ( letDelete ) allowDelete(responseMessage, ( interaction.member?.user.id || interaction.user.id ));
-		return responseMessage;
+function sendMessage(interaction, message, letDelete = true) {
+	if ( message?.embeds?.length && !message.embeds[0] ) message.embeds = [];
+	return interaction.editReply( message ).then( msg => {
+		if ( letDelete && (msg.flags & 64) !== 64 ) allowDelete(msg, interaction.user.id);
+		return msg;
 	}, log_error );
 	}, log_error );
 };
 };
 
 
 module.exports = {
 module.exports = {
 	got,
 	got,
-	slashCommands,
 	oauthVerify,
 	oauthVerify,
 	parse_infobox,
 	parse_infobox,
 	toFormatting,
 	toFormatting,

+ 3 - 3
util/logging.js

@@ -7,7 +7,7 @@ const fs = require('fs');
 const usageLog = fs.createWriteStream(process.env.usagelog, {flags:'a'});
 const usageLog = fs.createWriteStream(process.env.usagelog, {flags:'a'});
 
 
 usageLog.on( 'error', (error) => {
 usageLog.on( 'error', (error) => {
-	console.log( '- ' + shardId + ': Error while logging the usage: ' + error );
+	console.log( '- ' + process.env.SHARDS + ': Error while logging the usage: ' + error );
 } );
 } );
 
 
 /**
 /**
@@ -16,8 +16,8 @@ usageLog.on( 'error', (error) => {
  * @param {String} [guild] - The guild.
  * @param {String} [guild] - The guild.
  * @param {String[]} [notes] - The notes about the usage.
  * @param {String[]} [notes] - The notes about the usage.
  */
  */
-function logging(wiki, guild = 'DM', ...notes) {
-	usageLog.write( [new Date().toISOString(), wiki.href, guild, ...notes].join('\t') + '\n', 'utf8' );
+function logging(wiki, guild, ...notes) {
+	usageLog.write( [new Date().toISOString(), wiki.href, ( guild || 'DM' ), ...notes].join('\t') + '\n', 'utf8' );
 }
 }
 
 
 module.exports = logging;
 module.exports = logging;

+ 29 - 24
util/newMessage.js

@@ -45,12 +45,12 @@ function newMessage(msg, lang, wiki = defaultSettings.wiki, prefix = process.env
 			cont = cont.substring(prefix.length);
 			cont = cont.substring(prefix.length);
 			let args = cont.split(' ').slice(1);
 			let args = cont.split(' ').slice(1);
 			if ( cont.split(' ')[0].split('\n')[1] ) args.unshift( '', cont.split(' ')[0].split('\n')[1] );
 			if ( cont.split(' ')[0].split('\n')[1] ) args.unshift( '', cont.split(' ')[0].split('\n')[1] );
-			console.log( ( channel.isGuild() ? msg.guild.id : '@' + author.id ) + ': ' + prefix + cont );
+			console.log( ( channel.isGuild() ? msg.guildId : '@' + author.id ) + ': ' + prefix + cont );
 			return ownercmdmap[aliasInvoke](lang, msg, args, cont, wiki);
 			return ownercmdmap[aliasInvoke](lang, msg, args, cont, wiki);
 		}
 		}
 	}
 	}
 	var count = 0;
 	var count = 0;
-	var maxcount = commandLimit[( patreons[msg.guild?.id] ? 'patreon' : 'default' )];
+	var maxcount = commandLimit[( patreons[msg.guildId] ? 'patreon' : 'default' )];
 	var breakLines = false;
 	var breakLines = false;
 	cleanCont.replace( /\u200b/g, '' ).replace( /<a?(:\w+:)\d+>/g, '$1' ).replace( /(?<!\\)```.+?```/gs, '<codeblock>' ).split('\n').forEach( line => {
 	cleanCont.replace( /\u200b/g, '' ).replace( /<a?(:\w+:)\d+>/g, '$1' ).replace( /(?<!\\)```.+?```/gs, '<codeblock>' ).split('\n').forEach( line => {
 		if ( line.startsWith( '>>> ' ) ) breakLines = true;
 		if ( line.startsWith( '>>> ' ) ) breakLines = true;
@@ -59,7 +59,14 @@ function newMessage(msg, lang, wiki = defaultSettings.wiki, prefix = process.env
 			count++;
 			count++;
 			console.log( '- Message contains too many commands!' );
 			console.log( '- Message contains too many commands!' );
 			msg.reactEmoji('⚠️');
 			msg.reactEmoji('⚠️');
-			msg.sendChannelError( lang.get('general.limit', '<@' + author.id + '>'), {allowedMentions:{users:[author.id]}} );
+			msg.sendChannelError( {
+				content: lang.get('general.limit', author.toString()),
+				reply: {messageReference: msg.id},
+				allowedMentions: {
+					users: [author.id],
+					repliedUser: true
+				}
+			} );
 			return;
 			return;
 		}
 		}
 		count++;
 		count++;
@@ -68,12 +75,12 @@ function newMessage(msg, lang, wiki = defaultSettings.wiki, prefix = process.env
 		var args = line.split(' ').slice(1);
 		var args = line.split(' ').slice(1);
 		var aliasInvoke = ( lang.aliases[invoke] || invoke );
 		var aliasInvoke = ( lang.aliases[invoke] || invoke );
 		var ownercmd = ( msg.isOwner() && ownercmdmap.hasOwnProperty(aliasInvoke) );
 		var ownercmd = ( msg.isOwner() && ownercmdmap.hasOwnProperty(aliasInvoke) );
-		var pausecmd = ( msg.isAdmin() && pause[msg.guild.id] && pausecmdmap.hasOwnProperty(aliasInvoke) );
+		var pausecmd = ( msg.isAdmin() && pause[msg.guildId] && pausecmdmap.hasOwnProperty(aliasInvoke) );
 		if ( msg.onlyVerifyCommand && !( aliasInvoke === 'verify' || pausecmd || ownercmd ) ) return;
 		if ( msg.onlyVerifyCommand && !( aliasInvoke === 'verify' || pausecmd || ownercmd ) ) return;
-		if ( channel.isGuild() && pause[msg.guild.id] && !( pausecmd || ownercmd ) ) {
-			return console.log( msg.guild.id + ': Paused' );
+		if ( channel.isGuild() && pause[msg.guildId] && !( pausecmd || ownercmd ) ) {
+			return console.log( msg.guildId + ': Paused' );
 		}
 		}
-		console.log( ( channel.isGuild() ? msg.guild.id : '@' + author.id ) + ': ' + prefix + line );
+		console.log( ( channel.isGuild() ? msg.guildId : '@' + author.id ) + ': ' + prefix + line );
 		if ( ownercmd ) return ownercmdmap[aliasInvoke](lang, msg, args, line, wiki);
 		if ( ownercmd ) return ownercmdmap[aliasInvoke](lang, msg, args, line, wiki);
 		if ( pausecmd ) return pausecmdmap[aliasInvoke](lang, msg, args, line, wiki);
 		if ( pausecmd ) return pausecmdmap[aliasInvoke](lang, msg, args, line, wiki);
 		if ( cmdmap.hasOwnProperty(aliasInvoke) ) return cmdmap[aliasInvoke](lang, msg, args, line, wiki);
 		if ( cmdmap.hasOwnProperty(aliasInvoke) ) return cmdmap[aliasInvoke](lang, msg, args, line, wiki);
@@ -103,7 +110,7 @@ function newMessage(msg, lang, wiki = defaultSettings.wiki, prefix = process.env
 	} );
 	} );
 	if ( msg.onlyVerifyCommand ) return;
 	if ( msg.onlyVerifyCommand ) return;
 	
 	
-	if ( ( !channel.isGuild() || !pause[msg.guild.id] ) && !noInline && ( cont.includes( '[[' ) || cont.includes( '{{' ) ) ) {
+	if ( ( !channel.isGuild() || !pause[msg.guildId] ) && !noInline && ( cont.includes( '[[' ) || cont.includes( '{{' ) ) ) {
 		var links = [];
 		var links = [];
 		var embeds = [];
 		var embeds = [];
 		var linkcount = 0;
 		var linkcount = 0;
@@ -120,7 +127,7 @@ function newMessage(msg, lang, wiki = defaultSettings.wiki, prefix = process.env
 				while ( ( entry = regex.exec(line) ) !== null ) {
 				while ( ( entry = regex.exec(line) ) !== null ) {
 					if ( linkcount < linkmaxcount ) {
 					if ( linkcount < linkmaxcount ) {
 						linkcount++;
 						linkcount++;
-						console.log( ( channel.isGuild() ? msg.guild.id : '@' + author.id ) + ': ' + entry[0] );
+						console.log( ( channel.isGuild() ? msg.guildId : '@' + author.id ) + ': ' + entry[0] );
 						let title = entry[2].split('#')[0];
 						let title = entry[2].split('#')[0];
 						let section = entry[2].split('#').slice(1).join('#');
 						let section = entry[2].split('#').slice(1).join('#');
 						links.push({title,section,spoiler:entry[1]});
 						links.push({title,section,spoiler:entry[1]});
@@ -140,7 +147,7 @@ function newMessage(msg, lang, wiki = defaultSettings.wiki, prefix = process.env
 				while ( ( entry = regex.exec(line) ) !== null ) {
 				while ( ( entry = regex.exec(line) ) !== null ) {
 					if ( count < maxcount ) {
 					if ( count < maxcount ) {
 						count++;
 						count++;
-						console.log( ( channel.isGuild() ? msg.guild.id : '@' + author.id ) + ': ' + entry[0] );
+						console.log( ( channel.isGuild() ? msg.guildId : '@' + author.id ) + ': ' + entry[0] );
 						let title = entry[2].split('#')[0];
 						let title = entry[2].split('#')[0];
 						let section = entry[2].split('#').slice(1).join('#');
 						let section = entry[2].split('#').slice(1).join('#');
 						embeds.push({title,section,spoiler:entry[1]});
 						embeds.push({title,section,spoiler:entry[1]});
@@ -172,7 +179,7 @@ function newMessage(msg, lang, wiki = defaultSettings.wiki, prefix = process.env
 			}
 			}
 			if ( body.query.interwiki ) {
 			if ( body.query.interwiki ) {
 				body.query.interwiki.forEach( interwiki => links.filter( link => link.title === interwiki.title ).forEach( link => {
 				body.query.interwiki.forEach( interwiki => links.filter( link => link.title === interwiki.title ).forEach( link => {
-					logging(wiki, msg.guild?.id, 'inline', 'interwiki');
+					logging(wiki, msg.guildId, 'inline', 'interwiki');
 					link.url = ( link.section ? decodeURI(interwiki.url.split('#')[0]) + Wiki.toSection(link.section) : decodeURI(interwiki.url) );
 					link.url = ( link.section ? decodeURI(interwiki.url.split('#')[0]) + Wiki.toSection(link.section) : decodeURI(interwiki.url) );
 				} ) );
 				} ) );
 			}
 			}
@@ -184,20 +191,20 @@ function newMessage(msg, lang, wiki = defaultSettings.wiki, prefix = process.env
 				querypages.filter( page => page.missing !== undefined && page.known === undefined ).forEach( page => links.filter( link => link.title === page.title ).forEach( link => {
 				querypages.filter( page => page.missing !== undefined && page.known === undefined ).forEach( page => links.filter( link => link.title === page.title ).forEach( link => {
 					if ( ( page.ns === 2 || page.ns === 202 ) && !page.title.includes( '/' ) ) return;
 					if ( ( page.ns === 2 || page.ns === 202 ) && !page.title.includes( '/' ) ) return;
 					if ( wiki.isMiraheze() && page.ns === 0 && /^Mh:[a-z\d]+:/.test(page.title) ) {
 					if ( wiki.isMiraheze() && page.ns === 0 && /^Mh:[a-z\d]+:/.test(page.title) ) {
-						logging(wiki, msg.guild?.id, 'inline', 'interwiki');
+						logging(wiki, msg.guildId, 'inline', 'interwiki');
 						var iw_parts = page.title.split(':');
 						var iw_parts = page.title.split(':');
 						var iw = new Wiki('https://' + iw_parts[1] + '.miraheze.org/w/');
 						var iw = new Wiki('https://' + iw_parts[1] + '.miraheze.org/w/');
 						link.url = iw.toLink(iw_parts.slice(2).join(':'), '', link.section);
 						link.url = iw.toLink(iw_parts.slice(2).join(':'), '', link.section);
 						return;
 						return;
 					}
 					}
-					logging(wiki, msg.guild?.id, 'inline', 'redlink');
+					logging(wiki, msg.guildId, 'inline', 'redlink');
 					link.url = wiki.toLink(link.title, 'action=edit&redlink=1');
 					link.url = wiki.toLink(link.title, 'action=edit&redlink=1');
 				} ) );
 				} ) );
 			}
 			}
-			if ( links.length ) msg.sendChannel( links.map( link => {
-				if ( !link.url ) logging(wiki, msg.guild?.id, 'inline');
+			if ( links.length ) Util.splitMessage( links.map( link => {
+				if ( !link.url ) logging(wiki, msg.guildId, 'inline');
 				return link.spoiler + '<' + ( link.url || wiki.toLink(link.title, '', link.section) ) + '>' + link.spoiler;
 				return link.spoiler + '<' + ( link.url || wiki.toLink(link.title, '', link.section) ) + '>' + link.spoiler;
-			} ).join('\n'), {split:true} );
+			} ).join('\n') ).forEach( textpart => msg.sendChannel( textpart ) );
 		}, error => {
 		}, error => {
 			if ( wiki.noWiki(error.message) ) {
 			if ( wiki.noWiki(error.message) ) {
 				console.log( '- This wiki doesn\'t exist!' );
 				console.log( '- This wiki doesn\'t exist!' );
@@ -239,16 +246,14 @@ function newMessage(msg, lang, wiki = defaultSettings.wiki, prefix = process.env
 					}
 					}
 					if ( embed.template || !body.query.variables || !body.query.variables.some( variable => variable.toUpperCase() === embed.title ) ) missing.push(embed);
 					if ( embed.template || !body.query.variables || !body.query.variables.some( variable => variable.toUpperCase() === embed.title ) ) missing.push(embed);
 				} ) );
 				} ) );
-				if ( missing.length ) {
-					msg.sendChannel( missing.map( embed => {
-						if ( embed.template ) logging(wiki, msg.guild?.id, 'inline', 'template');
-						else logging(wiki, msg.guild?.id, 'inline', 'redlink');
-						return embed.spoiler + '<' + ( embed.template || wiki.toLink(embed.title, 'action=edit&redlink=1') ) + '>' + embed.spoiler;
-					} ).join('\n'), {split:true} );
-				}
+				if ( missing.length ) Util.splitMessage( missing.map( embed => {
+					if ( embed.template ) logging(wiki, msg.guildId, 'inline', 'template');
+					else logging(wiki, msg.guildId, 'inline', 'redlink');
+					return embed.spoiler + '<' + ( embed.template || wiki.toLink(embed.title, 'action=edit&redlink=1') ) + '>' + embed.spoiler;
+				} ).join('\n') ).forEach( textpart => msg.sendChannel( textpart ) );
 			}
 			}
 			if ( embeds.length ) embeds.forEach( embed => msg.reactEmoji('⏳').then( reaction => {
 			if ( embeds.length ) embeds.forEach( embed => msg.reactEmoji('⏳').then( reaction => {
-				logging(wiki, msg.guild?.id, 'inline', 'embed');
+				logging(wiki, msg.guildId, 'inline', 'embed');
 				check_wiki.general(lang, msg, embed.title, wiki, '', reaction, embed.spoiler, false, new URLSearchParams(), embed.section);
 				check_wiki.general(lang, msg, embed.title, wiki, '', reaction, embed.spoiler, false, new URLSearchParams(), embed.section);
 			} ) );
 			} ) );
 		}, error => {
 		}, error => {

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio