Skip to content
This repository has been archived by the owner on Jul 8, 2024. It is now read-only.

Commit

Permalink
Start upgrading to Discord.js v13
Browse files Browse the repository at this point in the history
  • Loading branch information
HoeenCoder committed Apr 6, 2022
1 parent 48117b8 commit c14fb01
Show file tree
Hide file tree
Showing 12 changed files with 1,010 additions and 430 deletions.
1,336 changes: 948 additions & 388 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@
"@types/node": "^12.7.8",
"@types/pg": "^7.14.1",
"@types/ws": "^7.2.3",
"discord.js": "^12.1.1",
"discord.js": "^13.2.0",
"dotenv": "^8.1.0",
"eslint-plugin-jest": "^24.3.5",
"pg": "^8.0.3",
"pg-mem": "^1.9.6",
"pg-mem": "^1.8.6",
"postgrator": "^4.0.1",
"sqlutils": "^1.2.1",
"typescript": "^4.1.5"
"typescript": "^4.4.4"
},
"devDependencies": {
"@pkmn/eslint-config": "^1.1.0",
Expand Down
23 changes: 19 additions & 4 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,22 @@ interface IDatabaseInsert {
channel?: DiscordChannel;
}

export const client = new Discord.Client();
export const client = new Discord.Client({
intents: [
// For reporting ban info
Discord.Intents.FLAGS.GUILD_BANS,
// For checking if a user is set as offline
Discord.Intents.FLAGS.GUILD_PRESENCES,
// For reading messages
Discord.Intents.FLAGS.GUILD_MESSAGES,
Discord.Intents.FLAGS.DIRECT_MESSAGES,
// For checking reactions on messages
Discord.Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
Discord.Intents.FLAGS.DIRECT_MESSAGE_REACTIONS,
// TODO determine if this is needed
//Discord.Intents.FLAGS.GUILDS,
],
});

// Necessary to match process.on('uncaughtException')
// eslint-disable-next-line @typescript-eslint/ban-types
Expand Down Expand Up @@ -195,7 +210,7 @@ client.on('ready', () => void (async () => {

// Fires when we get a new message from discord. We ignore messages that aren't commands or are from a bot.
client.on('message', (m) => void (async msg => {
if (msg.webhookID) return;
if (msg.webhookId) return;
await verifyData(msg);
if (msg.author.bot) return;
if (!msg.content.startsWith(prefix)) {
Expand All @@ -209,7 +224,7 @@ client.on('message', (m) => void (async msg => {
await monitor.execute();
}
} catch (e) {
await onError(e, 'A chat monitor crashed: ');
await onError(<Error>e, 'A chat monitor crashed: ');
}
}
return;
Expand All @@ -230,7 +245,7 @@ client.on('message', (m) => void (async msg => {
try {
await cmd.execute();
} catch (e) {
await onError(e, 'A chat command crashed: ');
await onError(<Error>e, 'A chat command crashed: ');
await msg.channel.send(
'\u274C - An error occured while trying to run your command. The error has been logged, and we will fix it soon.'
);
Expand Down
13 changes: 9 additions & 4 deletions src/command_base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export abstract class BaseCommand {

// All custom permissions need to resolve above.
if (!permissions.includes(permission)) throw new Error(`Unhandled custom permission: ${permission}.`);
return member.hasPermission((permission as Discord.PermissionResolvable), {checkAdmin: true, checkOwner: true});
return member.permissions.has((permission as Discord.PermissionResolvable));
}

/**
Expand Down Expand Up @@ -143,7 +143,7 @@ export abstract class BaseCommand {
if (channel.guild && channel.guild.id !== this.guild.id) return;
}
if (authorVisibilitity) {
const guildMember = channel.guild.member(this.author.id);
const guildMember = channel.guild.members.cache.get(this.author.id);
if (!guildMember) return; // User not in guild and cannot see channel
const permissions = channel.permissionsFor(guildMember);
if (!permissions) {
Expand Down Expand Up @@ -271,6 +271,11 @@ export abstract class BaseCommand {
return channel.send('\u274C ' + msg);
}

protected embedReply(embeds: Discord.MessageEmbedOptions[], channel?: DiscordChannel): Promise<Discord.Message> | void {
if (!channel) channel = this.channel;
return channel.send({embeds: embeds});
}

/**
* Send a reply in a code block
* @param msg The message to reply with
Expand All @@ -288,7 +293,7 @@ export abstract class BaseCommand {
* If one is not setup, the message is dropped.
* @param msg The message to send
*/
protected async sendLog(msg: string | Discord.MessageEmbed): Promise<Discord.Message | void> {
protected async sendLog(msg: string | Discord.MessageOptions): Promise<Discord.Message | void> {
if (!toID(msg) || !this.guild) return;
const res = await database.queryWithResults('SELECT logchannel FROM servers WHERE serverid = $1', [this.guild.id]);
const channel = this.getChannel(res[0].logchannel, false, false);
Expand Down Expand Up @@ -353,7 +358,7 @@ export abstract class ReactionPageTurner {
async initialize(messageOrChannel: Discord.Message | DiscordChannel): Promise<void> {
if (this.message) throw new Error('Reaction Page Turner already initialized.');
if (!(messageOrChannel instanceof Discord.Message)) {
this.message = await messageOrChannel.send(this.buildPage());
this.message = await messageOrChannel.send({embeds: [this.buildPage()]});
} else {
this.message = messageOrChannel;
}
Expand Down
4 changes: 2 additions & 2 deletions src/commands/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class Eval extends BaseCommand {
result = await eval(this.target);
if (result === '') result = '""';
} catch (e) {
result = `An error occured: ${e.toString()}`;
result = `An error occured: ${(e as Error).toString()}`;
}
await this.sendCode(result);
}
Expand All @@ -60,7 +60,7 @@ export class Query extends BaseCommand {
const res = await database.queryWithResults(this.target, undefined);
await this.sendCode(this.formatResponse(res));
} catch (err) {
await this.sendCode(`An error occured: ${err.toString()}`);
await this.sendCode(`An error occured: ${(err as Error).toString()}`);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/commands/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export class Help extends BaseCommand {
timestamp: Date.now(),
};

await this.channel.send({embed: embed});
await this.embedReply([embed])
} else {
// General help
const data: {[key: string]: string}[] = [];
Expand Down
9 changes: 4 additions & 5 deletions src/commands/moderation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ export class Whois extends BaseCommand {
private async getJoinPosition(user: Discord.GuildMember): Promise<string> {
const guild = user.guild;
await guild.members.fetch();
const orderedList = guild.members.cache
.array()
const orderedList = [...guild.members.cache.values()]
.sort((a, b) => (a.joinedTimestamp || Date.now()) - (b.joinedTimestamp || Date.now()));

return `${orderedList.indexOf(user) + 1} of ${orderedList.length}`;
Expand Down Expand Up @@ -82,7 +81,7 @@ export class Whois extends BaseCommand {
},
};

await this.channel.send({embed: embed});
await this.embedReply([embed]);
}

static help(): string {
Expand Down Expand Up @@ -124,7 +123,7 @@ export class WhoHas extends BaseCommand {
},
};

void this.channel.send({embed: embed});
void this.embedReply([embed]);
}

static help(): string {
Expand Down Expand Up @@ -152,7 +151,7 @@ abstract class StickyCommand extends BaseCommand {
if (await this.can('EVAL', user.user)) return true;

// Server owner override
if (this.guild.ownerID === user.user.id) return true;
if (this.guild.ownerId === user.user.id) return true;

await this.guild.roles.fetch();
const highestRole = [...user.roles.cache.values()].sort((a, b) => b.comparePositionTo(a))[0];
Expand Down
2 changes: 1 addition & 1 deletion src/commands/rmt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class RaterList extends ReactionPageTurner {

private buildFormat(): Discord.EmbedFieldData[] {
return [{
name: this.format,
name: this.format || "List of Team Raters",
value: this.data.map(v => `${v.name}#${v.discriminator}`).join(', ') || 'No Team Raters Found.',
}];
}
Expand Down
34 changes: 17 additions & 17 deletions src/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ async function fetchAuditLog(
type: Discord.GuildAuditLogsAction,
guild: Discord.Guild
): Promise<Discord.GuildAuditLogsEntry | void> {
if (!guild.me?.hasPermission('VIEW_AUDIT_LOG')) return;
if (!guild.me?.permissions.has('VIEW_AUDIT_LOG')) return;

const log = (await guild.fetchAuditLogs({
limit: 1,
Expand Down Expand Up @@ -56,15 +56,14 @@ client.on('messageDelete', (oldMsg: Discord.Message | Discord.PartialMessage) =>
if (!logChannel) return; // Nowhere to log to

const log = await fetchAuditLog('MESSAGE_DELETE', oldMessage.guild);
if (!log || log.executor.id === oldMessage.author.id) return; // Not a mod delete
if (!log || !log.executor || log.executor.id === oldMessage.author.id) return; // Not a mod delete or unable to tell

// Don't report for private channels
await oldMessage.guild.roles.fetch();
const everyone = oldMessage.guild.roles.everyone; // everyone is always a role
if (!everyone) throw new Error('Unable to find the everyone role in the messageDelete event');
const permissions = (oldMessage.channel as Discord.TextChannel | Discord.NewsChannel)
.permissionOverwrites
.get(everyone.id);
.permissionOverwrites.cache.get(everyone.id);
if (permissions?.deny.has('VIEW_CHANNEL')) {
// There are custom permissions for @everyone on this channel, and @everyone cannot view the channel.
return;
Expand Down Expand Up @@ -98,7 +97,7 @@ client.on('messageDelete', (oldMsg: Discord.Message | Discord.PartialMessage) =>
timestamp: Date.now(),
};

await logChannel.send({embed: embed});
await logChannel.send({embeds: [embed]});
})(oldMsg);
});

Expand All @@ -110,7 +109,7 @@ client.on('guildMemberRemove', (u: Discord.GuildMember | Discord.PartialGuildMem

const log = await fetchAuditLog('MEMBER_KICK', user.guild);

if (!log || log.executor.id === user.user.id) return; // No log or user left of their own will
if (!log || !log.executor || log.executor.id === user.user.id) return; // No log or user left of their own will

const embed: Discord.MessageEmbedOptions = {
color: 0x6194fd,
Expand All @@ -131,12 +130,13 @@ client.on('guildMemberRemove', (u: Discord.GuildMember | Discord.PartialGuildMem
],
};

await logChannel.send({embed: embed});
await logChannel.send({embeds: [embed]});
})(u);
});

async function banChange(guild: Discord.Guild, user: Discord.User | Discord.PartialUser, unbanned = false) {
user = (user as Discord.User);
async function banChange(ban: Discord.GuildBan, unbanned = false) {
const user = ban.user;
const guild = ban.guild;
const logChannel = await getLogChannel(guild);
if (!logChannel) return; // Nowhere to log to

Expand All @@ -152,25 +152,25 @@ async function banChange(guild: Discord.Guild, user: Discord.User | Discord.Part
fields: [
{
name: user.tag,
value: log ? `by <@${log.executor.id}>` : 'by Unknown',
value: log && log.executor ? `by <@${log.executor.id}>` : 'by Unknown',
},
{
name: 'Reason',
value: log ? log.reason || 'N/A' : 'N/A',
value: typeof ban.reason === "string" ? ban.reason : 'N/A',
},
],
timestamp: Date.now(),
};

await logChannel.send({embed: embed});
await logChannel.send({embeds: [embed]});
}

client.on('guildBanAdd', (guild: Discord.Guild, user: Discord.User | Discord.PartialUser) => {
void banChange(guild, user);
client.on('guildBanAdd', (ban: Discord.GuildBan) => {
void banChange(ban);
});

client.on('guildBanRemove', (guild: Discord.Guild, user: Discord.User | Discord.PartialUser) => {
void banChange(guild, user, true);
client.on('guildBanRemove', (ban: Discord.GuildBan) => {
void banChange(ban, true);
});

client.on('guildMemberAdd', (m: Discord.GuildMember | Discord.PartialGuildMember) => {
Expand All @@ -189,7 +189,7 @@ client.on('guildMemberAdd', (m: Discord.GuildMember | Discord.PartialGuildMember
if (!sticky.length) return; // User rejoined and had 0 sticky roles.

// Re-assign sticky roles
if (!bot.hasPermission('MANAGE_ROLES')) {
if (!bot.permissions.has('MANAGE_ROLES')) {
// Bot can't assign roles due to lack of permissions
const channel = await getLogChannel(guild);
const msg = '[WARN] Bot tried to assign sticky (persistant) roles to a user joining the server, but lacks the MANAGE_ROLES permission.';
Expand Down
2 changes: 1 addition & 1 deletion src/monitors/activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class ActivityMonitor extends BaseMonitor {
await this.guild.roles.fetch();
const everyone = this.guild.roles.everyone; // everyone is always a role
if (!everyone) throw new Error('Unable to find the everyone role when logging linecounts.');
const permissions = this.channel.permissionOverwrites.get(everyone.id);
const permissions = this.channel.permissionOverwrites.resolve(everyone.id);
if (permissions?.deny.has('VIEW_CHANNEL')) {
// There are custom permissions for @everyone on this channel, and @everyone cannot view the channel.
return false;
Expand Down
7 changes: 4 additions & 3 deletions src/monitors/rmt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export class TeamRatingMonitor extends BaseMonitor {
}

async shouldExecute() {
if (!this.guild) return false;
let res = await database.queryWithResults('SELECT channelid FROM teamraters WHERE channelid = $1', [this.channel.id]);
if (!res.length) return false; // This channel isn't setup for team rating.

Expand All @@ -74,9 +75,9 @@ export class TeamRatingMonitor extends BaseMonitor {
if (!res.length) {
return false; // No results
} else {
res = res.filter(r => {
const user = this.getUser(r.userid);
if (!user || user.presence.status === 'offline') return false;
res = res.filter(async (r) => {
const user = await this.guild?.members.fetch(r.userid);
if (!user || !user.presence || user.presence.status === 'offline') return false;
return true;
});

Expand Down
2 changes: 1 addition & 1 deletion src/test/fake-discord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import OriginalDiscord = require('discord.js');

export class Client extends OriginalDiscord.Client {
constructor(options?: OriginalDiscord.ClientOptions) {
constructor(options: OriginalDiscord.ClientOptions) {
super(options);
this.token = 'not a real token';
}
Expand Down

0 comments on commit c14fb01

Please sign in to comment.