aboutsummaryrefslogtreecommitdiff
path: root/src/listeners
diff options
context:
space:
mode:
authorIRONM00N <64110067+IRONM00N@users.noreply.github.com>2021-08-25 14:47:07 -0400
committerIRONM00N <64110067+IRONM00N@users.noreply.github.com>2021-08-25 14:47:07 -0400
commit0af0be5ab4ea0d972d9c406b28b81ee41a06cbdb (patch)
treecb5d6f06a115d7e9c3d38ea44995161f6c158082 /src/listeners
parent76622cfcd13727949ef3a0baa30bf72007132cd2 (diff)
downloadtanzanite-0af0be5ab4ea0d972d9c406b28b81ee41a06cbdb.tar.gz
tanzanite-0af0be5ab4ea0d972d9c406b28b81ee41a06cbdb.tar.bz2
tanzanite-0af0be5ab4ea0d972d9c406b28b81ee41a06cbdb.zip
join roles, sticky roles, join messages, support threads etc
Diffstat (limited to 'src/listeners')
-rw-r--r--src/listeners/client/interactionCreate.ts4
-rw-r--r--src/listeners/guild/guildCreate.ts18
-rw-r--r--src/listeners/guild/guildDelete.ts16
-rw-r--r--src/listeners/guild/guildMemberAdd.ts103
-rw-r--r--src/listeners/guild/guildMemberRemove.ts67
-rw-r--r--src/listeners/guild/syncUnban.ts7
-rw-r--r--src/listeners/message/automodCreate.ts14
-rw-r--r--src/listeners/message/supportThreads.ts43
8 files changed, 261 insertions, 11 deletions
diff --git a/src/listeners/client/interactionCreate.ts b/src/listeners/client/interactionCreate.ts
index 7dc20ec..d76a484 100644
--- a/src/listeners/client/interactionCreate.ts
+++ b/src/listeners/client/interactionCreate.ts
@@ -1,5 +1,5 @@
import { BushListener } from '@lib';
-import { ClientEvents } from 'discord.js';
+import { BushClientEvents } from '../../lib/extensions/discord.js/BushClientEvents';
export default class InteractionCreateListener extends BushListener {
public constructor() {
@@ -10,7 +10,7 @@ export default class InteractionCreateListener extends BushListener {
});
}
- public override async exec(...[interaction]: ClientEvents['interactionCreate']): Promise<unknown> {
+ public override async exec(...[interaction]: BushClientEvents['interactionCreate']): Promise<unknown> {
if (!interaction) return;
if (interaction.isCommand()) {
void client.console.info(
diff --git a/src/listeners/guild/guildCreate.ts b/src/listeners/guild/guildCreate.ts
new file mode 100644
index 0000000..21a7ab0
--- /dev/null
+++ b/src/listeners/guild/guildCreate.ts
@@ -0,0 +1,18 @@
+import { BushListener, Guild } from '../../lib';
+import { BushClientEvents } from '../../lib/extensions/discord.js/BushClientEvents';
+
+export default class GuildCreateListener extends BushListener {
+ public constructor() {
+ super('guildCreate', {
+ emitter: 'client',
+ event: 'guildCreate', // when the bot joins a guild
+ category: 'client'
+ });
+ }
+
+ public override async exec(...[guild]: BushClientEvents['guildCreate']): Promise<void> {
+ void client.console.info('JoinGuild', `Joined <<${guild.name}>> with <<${guild.memberCount?.toLocaleString()}>> members.`);
+ const g = await Guild.findByPk(guild.id);
+ if (!g) void Guild.create({ id: guild.id });
+ }
+}
diff --git a/src/listeners/guild/guildDelete.ts b/src/listeners/guild/guildDelete.ts
new file mode 100644
index 0000000..a59f45e
--- /dev/null
+++ b/src/listeners/guild/guildDelete.ts
@@ -0,0 +1,16 @@
+import { BushListener } from '../../lib';
+import { BushClientEvents } from '../../lib/extensions/discord.js/BushClientEvents';
+
+export default class GuildDeleteListener extends BushListener {
+ public constructor() {
+ super('guildDelete', {
+ emitter: 'client',
+ event: 'guildDelete', //when the bot leaves a guild
+ category: 'client'
+ });
+ }
+
+ public override exec(...[guild]: BushClientEvents['guildDelete']): void {
+ void client.console.info('LeaveGuild', `Left <<${guild.name}>> with <<${guild.memberCount?.toLocaleString()}>> members.`);
+ }
+}
diff --git a/src/listeners/guild/guildMemberAdd.ts b/src/listeners/guild/guildMemberAdd.ts
new file mode 100644
index 0000000..bf6e0b6
--- /dev/null
+++ b/src/listeners/guild/guildMemberAdd.ts
@@ -0,0 +1,103 @@
+import { MessageEmbed, Snowflake, Util } from 'discord.js';
+import { BushGuildMember, BushListener, BushTextChannel, StickyRole } from '../../lib';
+import { BushClientEvents } from '../../lib/extensions/discord.js/BushClientEvents';
+
+export default class GuildMemberAddListener extends BushListener {
+ public constructor() {
+ super('guildMemberAdd', {
+ emitter: 'client',
+ event: 'guildMemberAdd',
+ category: 'client'
+ });
+ }
+
+ public override async exec(...[member]: BushClientEvents['guildMemberAdd']): Promise<void> {
+ void this.sendWelcomeMessage(member);
+ void this.joinAndStickyRoles(member);
+ }
+
+ public async sendWelcomeMessage(member: BushGuildMember): Promise<void> {
+ if (client.config.isDevelopment) return;
+ const welcomeChannel = await member.guild.getSetting('welcomeChannel');
+ if (!welcomeChannel) return;
+ const welcome = this.client.channels.cache.get(welcomeChannel) as BushTextChannel | undefined;
+ if (!welcome) return;
+ if (member.guild.id !== welcome?.guild.id) throw new Error('Welcome channel must be in the guild.');
+ const embed = new MessageEmbed()
+ .setDescription(
+ `${this.client.util.emojis.join} **${Util.escapeMarkdown(
+ member.user.tag
+ )}** joined the server. There are now ${member.guild.memberCount.toLocaleString()} members.`
+ )
+ .setColor(this.client.util.colors.green);
+ await welcome
+ .send({ embeds: [embed] })
+ .then(() => this.client.console.info('OnJoin', `Sent a message for <<${member.user.tag}>> in <<${member.guild.name}>>.`))
+ .catch(() =>
+ this.client.console.warn('OnJoin', `Failed to send message for <<${member.user.tag}>> in <<${member.guild.name}>>.`)
+ );
+ }
+
+ public async joinAndStickyRoles(member: BushGuildMember): Promise<void> {
+ if (client.config.isDevelopment) return;
+ if (await member.guild.hasFeature('stickyRoles')) {
+ const hadRoles = await StickyRole.findOne({ where: { guild: member.guild.id, user: member.id } });
+ if (hadRoles?.roles?.length) {
+ const rolesArray = hadRoles.roles
+ .map((roleID: Snowflake) => {
+ const role = member.guild.roles.cache.get(roleID);
+ if (role && !member.roles.cache.has(roleID)) {
+ if (role.name !== '@everyone' || !role.managed) return role.id;
+ }
+ })
+ .filter((role) => role) as Snowflake[];
+ if (hadRoles.nickname && member.manageable) {
+ void member.setNickname(hadRoles.nickname).catch(() => {});
+ }
+ if (rolesArray?.length) {
+ const addedRoles = await member.roles
+ .add(rolesArray, "Returning member's previous roles.")
+ .catch(
+ () => void this.client.console.warn('ReturnRoles', `There was an error returning <<${member.user.tag}>>'s roles.`)
+ );
+ if (addedRoles) {
+ void this.client.console.info(
+ 'RoleData',
+ `Assigned sticky roles to <<${member.user.tag}>> in <<${member.guild.name}>>.`
+ );
+ } else if (!addedRoles) {
+ const failedRoles: string[] = [];
+ for (let i = 0; i < rolesArray.length; i++) {
+ await member.roles
+ .add(rolesArray[i], "[Fallback] Returning member's previous roles.")
+ .catch(() => failedRoles.push(rolesArray[i]));
+ }
+ if (failedRoles.length) {
+ void this.client.console.warn('RoleData', 'Failed assigning the following roles on Fallback:' + failedRoles);
+ } else {
+ void this.client.console.info(
+ 'RoleData',
+ `[Fallback] Assigned sticky roles to <<${member.user.tag}>> in <<${member.guild.name}>>.`
+ );
+ }
+ }
+ }
+ }
+ } else {
+ const joinRoles = await member.guild.getSetting('joinRoles');
+ if (!joinRoles) return;
+ await member.roles
+ .add(joinRoles, 'Join roles.')
+ .then(() =>
+ this.client.console.info('RoleData', `Assigned join roles to <<${member.user.tag}>> in <<${member.guild.name}>>.`)
+ )
+ .catch(
+ () =>
+ void this.client.console.warn(
+ 'OnJoin',
+ `Failed to assign join roles to <<${member.user.tag}>>, in <<${member.guild.name}>>.`
+ )
+ );
+ }
+ }
+}
diff --git a/src/listeners/guild/guildMemberRemove.ts b/src/listeners/guild/guildMemberRemove.ts
new file mode 100644
index 0000000..f25108f
--- /dev/null
+++ b/src/listeners/guild/guildMemberRemove.ts
@@ -0,0 +1,67 @@
+import { MessageEmbed, Util } from 'discord.js';
+import { BushGuildMember, BushListener, BushTextChannel, PartialBushGuildMember, StickyRole } from '../../lib';
+import { BushClientEvents } from '../../lib/extensions/discord.js/BushClientEvents';
+
+export default class GuildMemberRemoveListener extends BushListener {
+ public constructor() {
+ super('guildMemberRemove', {
+ emitter: 'client',
+ event: 'guildMemberRemove',
+ category: 'guild'
+ });
+ }
+
+ public override async exec(...[member]: BushClientEvents['guildMemberRemove']): Promise<void> {
+ void this.sendWelcomeMessage(member);
+ void this.stickyRoles(member);
+ }
+
+ public async sendWelcomeMessage(member: BushGuildMember | PartialBushGuildMember): Promise<void> {
+ if (client.config.isDevelopment) return;
+ const user = member.partial ? await client.users.fetch(member.id) : member.user;
+ await util.sleep(0.05); // ban usually triggers after member leave
+ const isBan = member.guild.bans.cache.has(member.id);
+ const welcomeChannel = await member.guild.getSetting('welcomeChannel');
+ if (!welcomeChannel) return;
+ const welcome = this.client.channels.cache.get(welcomeChannel) as BushTextChannel | undefined;
+ if (member.guild.id !== welcome?.guild.id) throw new Error('Welcome channel must be in the guild.');
+ const embed: MessageEmbed = new MessageEmbed()
+ .setDescription(
+ `${this.client.util.emojis.leave} **${Util.escapeBold(user.tag)}** ${
+ isBan ? 'banned from' : 'left'
+ } the server. There are now ${welcome.guild.memberCount.toLocaleString()} members.`
+ )
+ .setColor(isBan ? util.colors.orange : util.colors.red);
+ welcome
+ .send({ embeds: [embed] })
+ .then(() => client.console.info('OnLeave', `Sent a message for <<${user.tag}>> in <<${member.guild.name}>>.`))
+ .catch(() =>
+ this.client.console.warn('OnLeave', `Failed to send message for <<${user.tag}>> in <<${member.guild.name}>>.`)
+ );
+ }
+
+ public async stickyRoles(member: BushGuildMember | PartialBushGuildMember): Promise<void> {
+ if (!(await member.guild.hasFeature('stickyRoles'))) return;
+ if (member.partial) throw new Error('Partial member, cannot save sticky roles.');
+ const rolesArray = member.roles.cache.filter((role) => role.name !== '@everyone').map((role) => role.id);
+ const nickname = member.nickname;
+ if (rolesArray) {
+ const [row, isNew] = await StickyRole.findOrBuild({
+ where: {
+ user: member.user.id,
+ guild: member.guild.id
+ },
+ defaults: {
+ user: member.user.id,
+ guild: member.guild.id,
+ roles: rolesArray
+ }
+ });
+ row.roles = rolesArray;
+ if (nickname) row.nickname = nickname;
+ await row
+ .save()
+ .then(() => this.client.console.info('RoleData', `${isNew ? 'Created' : 'Updated'} info for <<${member.user.tag}>>.`));
+ }
+ }
+}
diff --git a/src/listeners/guild/syncUnban.ts b/src/listeners/guild/syncUnban.ts
index b1e4fd9..9a6a607 100644
--- a/src/listeners/guild/syncUnban.ts
+++ b/src/listeners/guild/syncUnban.ts
@@ -1,15 +1,16 @@
import { ActivePunishment, ActivePunishmentType, BushListener } from '@lib';
-import { ClientEvents } from 'discord.js';
+import { BushClientEvents } from '../../lib/extensions/discord.js/BushClientEvents';
export default class SyncUnbanListener extends BushListener {
public constructor() {
super('guildBanRemove', {
emitter: 'client',
- event: 'guildBanRemove'
+ event: 'guildBanRemove',
+ category: 'guild'
});
}
- public override async exec(...[ban]: ClientEvents['guildBanRemove']): Promise<void> {
+ public override async exec(...[ban]: BushClientEvents['guildBanRemove']): Promise<void> {
const bans = await ActivePunishment.findAll({
where: {
user: ban.user.id,
diff --git a/src/listeners/message/automodCreate.ts b/src/listeners/message/automodCreate.ts
index ff87513..ca61dd0 100644
--- a/src/listeners/message/automodCreate.ts
+++ b/src/listeners/message/automodCreate.ts
@@ -59,7 +59,7 @@ export default class AutomodMessageCreateListener extends BushListener {
void message.delete().catch(() => {});
void message.member?.warn({
moderator: message.guild.me!,
- reason: 'Saying a blacklisted word.'
+ reason: 'Saying a blacklisted word'
});
break;
@@ -68,7 +68,7 @@ export default class AutomodMessageCreateListener extends BushListener {
void message.delete().catch(() => {});
void message.member?.mute({
moderator: message.guild.me!,
- reason: 'Saying a blacklisted word.',
+ reason: 'Saying a blacklisted word',
duration: 900_000 // 15 minutes
});
break;
@@ -77,7 +77,7 @@ export default class AutomodMessageCreateListener extends BushListener {
void message.delete().catch(() => {});
void message.member?.mute({
moderator: message.guild.me!,
- reason: 'Saying a blacklisted word.',
+ reason: 'Saying a blacklisted word',
duration: 0 // perm
});
break;
@@ -102,9 +102,11 @@ export default class AutomodMessageCreateListener extends BushListener {
new MessageEmbed()
.setTitle(`[Severity ${highestOffence}] Automod Action Performed`)
.setDescription(
- `**User:** ${message.author} (${message.author.tag})\n**Sent From**: <#${message.channel.id}> [Jump to context](${
- message.url
- })\n**Blacklisted Words:** ${util.surroundArray(Object.keys(offences), '`').join(', ')}`
+ `**User:** ${message.author.tag} (${message.author.tag})\n**Sent From**: <#${
+ message.channel.id
+ }> [Jump to context](${message.url})\n**Blacklisted Words:** ${util
+ .surroundArray(Object.keys(offences), '`')
+ .join(', ')}`
)
.addField('Message Content', `${await util.codeblock(message.content, 1024)}`)
.setColor(color)
diff --git a/src/listeners/message/supportThreads.ts b/src/listeners/message/supportThreads.ts
new file mode 100644
index 0000000..ce2aa0d
--- /dev/null
+++ b/src/listeners/message/supportThreads.ts
@@ -0,0 +1,43 @@
+import { GuildTextBasedChannels } from 'discord-akairo';
+import { MessageEmbed } from 'discord.js';
+import { BushListener, BushTextChannel } from '../../lib';
+import { BushClientEvents } from '../../lib/extensions/discord.js/BushClientEvents';
+
+export default class MessageVerboseListener extends BushListener {
+ public constructor() {
+ super('supportThreads', {
+ emitter: 'client',
+ event: 'messageCreate',
+ category: 'message'
+ });
+ }
+
+ public override async exec(...[message]: BushClientEvents['messageCreate']): Promise<Promise<void> | undefined> {
+ if (!message.guild || !message.channel) return;
+ // todo: make these configurable etc...
+ if (message.guild.id !== '516977525906341928') return; // mb
+ if (message.channel.id !== '714332750156660756') return; // neu-support-1
+ if (!(message.channel as BushTextChannel).permissionsFor(message.guild.me!).has('USE_PUBLIC_THREADS')) return;
+ const thread = await message.startThread({
+ name: `Support - ${message.author.username}#${message.author.discriminator}`,
+ autoArchiveDuration: 1440,
+ reason: 'Support Thread'
+ });
+ const embed = new MessageEmbed()
+ .setTitle('NotEnoughUpdates Support')
+ .setDescription(
+ `Welcome to Moulberry Bush Support:tm:\n\nPlease make sure you have the latest prerelease found in <#693586404256645231>.\nAdditionally if you need help installing the mod be sure to read <#737444942724726915> for a guide on how to do so.`
+ )
+ .setColor('BLURPLE');
+ void thread
+ .send({ embeds: [embed] })
+ .then(() =>
+ client.console.info(
+ 'supportThread',
+ `opened a support thread for <<${message.author.tag}>> in <<${
+ (message.channel as GuildTextBasedChannels).name
+ }>> in <<${message.guild!.name}>>.`
+ )
+ );
+ }
+}