mirror of
https://github.com/veganhacktivists/arabot.git
synced 2025-12-03 11:18:06 +01:00
Compare commits
19 Commits
coolify
...
616334f123
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
616334f123 | ||
|
|
cd319609b0 | ||
|
|
a1469e0596 | ||
|
|
ca0e43a70e | ||
|
|
dc16dee92c | ||
|
|
71f0ee9f01 | ||
|
|
881f9bfc24 | ||
|
|
98b9ac6fde | ||
|
|
1f92bf5d68 | ||
|
|
d9f04e8d49 | ||
|
|
b4c8f0785c | ||
|
|
7918f73e7d | ||
|
|
ea211a9111 | ||
|
|
32776a2311 | ||
|
|
d72b66f988 | ||
|
|
e03bd6e85e | ||
|
|
a400cf9507 | ||
|
|
2fbb6c9265 | ||
|
|
fc8c12b346 |
24
package.json
24
package.json
@@ -34,30 +34,30 @@
|
||||
"pnpm": ">=9"
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "^5.18.0",
|
||||
"@sapphire/discord.js-utilities": "^7.3.0",
|
||||
"@sapphire/framework": "^5.2.1",
|
||||
"@prisma/client": "^5.22.0",
|
||||
"@sapphire/discord.js-utilities": "^7.3.2",
|
||||
"@sapphire/framework": "^5.3.2",
|
||||
"@sapphire/plugin-logger": "^4.0.2",
|
||||
"@sapphire/plugin-scheduled-tasks": "^10.0.1",
|
||||
"@sapphire/plugin-scheduled-tasks": "^10.0.2",
|
||||
"@sapphire/plugin-subcommands": "^6.0.3",
|
||||
"@sapphire/stopwatch": "^1.5.2",
|
||||
"@sapphire/time-utilities": "^1.7.12",
|
||||
"@sapphire/stopwatch": "^1.5.4",
|
||||
"@sapphire/time-utilities": "^1.7.14",
|
||||
"@sapphire/ts-config": "^5.0.1",
|
||||
"@sapphire/utilities": "^3.17.0",
|
||||
"bullmq": "^5.12.10",
|
||||
"discord.js": "^14.15.3",
|
||||
"ioredis": "^5.4.1",
|
||||
"@sapphire/utilities": "^3.18.1",
|
||||
"bullmq": "^5.34.10",
|
||||
"discord.js": "^14.17.3",
|
||||
"ioredis": "^5.4.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "~5.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.16.1",
|
||||
"@types/node": "^20.17.13",
|
||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||
"@typescript-eslint/parser": "^6.21.0",
|
||||
"eslint": "8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"prettier": "3.2.4",
|
||||
"prisma": "^5.18.0"
|
||||
"prisma": "^5.22.0"
|
||||
},
|
||||
"packageManager": "pnpm@9.12.2+sha512.22721b3a11f81661ae1ec68ce1a7b879425a1ca5b991c975b074ac220b187ce56c708fe5db69f4c962c989452eee76c82877f4ee80f474cebd61ee13461b6228"
|
||||
}
|
||||
|
||||
618
pnpm-lock.yaml
generated
618
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@
|
||||
*/
|
||||
|
||||
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
|
||||
import type { Message } from 'discord.js';
|
||||
import { Message, MessageFlagsBitField } from 'discord.js';
|
||||
import { ChannelType, TextChannel } from 'discord.js';
|
||||
|
||||
export class AnonymousCommand extends Command {
|
||||
@@ -67,8 +67,8 @@ export class AnonymousCommand extends Command {
|
||||
if (guild === null) {
|
||||
await interaction.reply({
|
||||
content: 'Error fetching guild!',
|
||||
ephemeral: true,
|
||||
fetchReply: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -77,8 +77,17 @@ export class AnonymousCommand extends Command {
|
||||
if (interaction.channel === null) {
|
||||
await interaction.reply({
|
||||
content: 'Error getting the channel!',
|
||||
ephemeral: true,
|
||||
fetchReply: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!interaction.channel.isSendable()) {
|
||||
await interaction.reply({
|
||||
content: `I do not have sufficient permissions to send a message in ${interaction.channel}!`,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -86,8 +95,8 @@ export class AnonymousCommand extends Command {
|
||||
await interaction.channel.send(message);
|
||||
await interaction.reply({
|
||||
content: 'Sent the message',
|
||||
ephemeral: true,
|
||||
fetchReply: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -95,8 +104,8 @@ export class AnonymousCommand extends Command {
|
||||
if (channel.type !== ChannelType.GuildText) {
|
||||
await interaction.reply({
|
||||
content: 'Could not send, unsupported text channel!',
|
||||
ephemeral: true,
|
||||
fetchReply: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -105,8 +114,8 @@ export class AnonymousCommand extends Command {
|
||||
|
||||
await interaction.reply({
|
||||
content: 'Sent the message',
|
||||
ephemeral: true,
|
||||
fetchReply: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -121,7 +130,7 @@ export class AnonymousCommand extends Command {
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel.isTextBased()) {
|
||||
if (channel.isSendable()) {
|
||||
await channel.send(text);
|
||||
} else {
|
||||
await message.react('❌');
|
||||
|
||||
@@ -30,9 +30,9 @@ import {
|
||||
TextChannel,
|
||||
GuildMember,
|
||||
Snowflake,
|
||||
MessageFlagsBitField,
|
||||
} from 'discord.js';
|
||||
import type { Message } from 'discord.js';
|
||||
import { isMessageInstance } from '@sapphire/discord.js-utilities';
|
||||
import {
|
||||
addSusNoteDB,
|
||||
findNotes,
|
||||
@@ -157,10 +157,10 @@ export class SusCommand extends Subcommand {
|
||||
const { guild } = interaction;
|
||||
|
||||
// Checks if all the variables are of the right type
|
||||
if (!(guild instanceof Guild)) {
|
||||
if (guild === null) {
|
||||
await interaction.reply({
|
||||
content: 'Error fetching guild!',
|
||||
ephemeral: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -169,7 +169,7 @@ export class SusCommand extends Subcommand {
|
||||
|
||||
await interaction.reply({
|
||||
content: info.message,
|
||||
ephemeral: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ export class SusCommand extends Subcommand {
|
||||
|
||||
const guild = message.guild;
|
||||
|
||||
if (!(guild instanceof Guild)) {
|
||||
if (guild === null) {
|
||||
await message.react('❌');
|
||||
await message.reply(
|
||||
'Could not find guild! Make sure you run this command in a server.',
|
||||
@@ -292,7 +292,7 @@ export class SusCommand extends Subcommand {
|
||||
if (guild == null) {
|
||||
await interaction.reply({
|
||||
content: 'Error fetching guild!',
|
||||
ephemeral: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -306,8 +306,8 @@ export class SusCommand extends Subcommand {
|
||||
if (notes.length === 0) {
|
||||
await interaction.reply({
|
||||
content: `${user} has no sus notes!`,
|
||||
ephemeral: true,
|
||||
fetchReply: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -318,8 +318,8 @@ export class SusCommand extends Subcommand {
|
||||
// Sends the notes to the user
|
||||
await interaction.reply({
|
||||
embeds: [noteEmbed],
|
||||
ephemeral: !staffChannel,
|
||||
fetchReply: true,
|
||||
flags: staffChannel ? undefined : MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -333,8 +333,8 @@ export class SusCommand extends Subcommand {
|
||||
if (guild === null || channel === null) {
|
||||
await interaction.reply({
|
||||
content: 'Error fetching guild or channel!',
|
||||
ephemeral: true,
|
||||
fetchReply: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -346,8 +346,8 @@ export class SusCommand extends Subcommand {
|
||||
if (note === null) {
|
||||
await interaction.reply({
|
||||
content: 'Error fetching note from database!',
|
||||
ephemeral: true,
|
||||
fetchReply: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -363,8 +363,8 @@ export class SusCommand extends Subcommand {
|
||||
if (user === undefined) {
|
||||
await interaction.reply({
|
||||
content: 'Error fetching user!',
|
||||
ephemeral: true,
|
||||
fetchReply: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -407,16 +407,21 @@ export class SusCommand extends Subcommand {
|
||||
const message = await interaction.reply({
|
||||
embeds: [noteEmbed],
|
||||
components: [buttons],
|
||||
ephemeral: true,
|
||||
fetchReply: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
|
||||
// Checks if the message is not an APIMessage
|
||||
if (!isMessageInstance(message)) {
|
||||
if (message.resource === null) {
|
||||
await interaction.editReply('Failed to retrieve the message :(');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel.isSendable()) {
|
||||
await interaction.editReply('Cannot send messages in this channel!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Listen for the button presses
|
||||
const collector = channel.createMessageComponentCollector({
|
||||
max: 1, // Maximum of 1 button press
|
||||
@@ -470,10 +475,10 @@ export class SusCommand extends Subcommand {
|
||||
) {
|
||||
// Find user
|
||||
let user = guild.client.users.cache.get(userId);
|
||||
if (!(user instanceof User)) {
|
||||
if (user === undefined) {
|
||||
user = await guild.client.users.fetch(userId).catch(() => undefined);
|
||||
}
|
||||
if (!(user instanceof User)) return;
|
||||
if (user === undefined) return;
|
||||
|
||||
// Log the sus note
|
||||
let logChannel = guild.channels.cache.get(IDs.channels.logs.sus) as
|
||||
@@ -519,8 +524,8 @@ export class SusCommand extends Subcommand {
|
||||
if (guild === null || channel === null) {
|
||||
await interaction.reply({
|
||||
content: 'Error fetching guild or channel!',
|
||||
ephemeral: true,
|
||||
fetchReply: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -531,8 +536,8 @@ export class SusCommand extends Subcommand {
|
||||
if (member === undefined) {
|
||||
await interaction.reply({
|
||||
content: 'Error fetching user!',
|
||||
ephemeral: true,
|
||||
fetchReply: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -545,8 +550,8 @@ export class SusCommand extends Subcommand {
|
||||
if (notes.length === 0) {
|
||||
await interaction.reply({
|
||||
content: `${user} had no notes!`,
|
||||
ephemeral: true,
|
||||
fetchReply: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -596,16 +601,21 @@ export class SusCommand extends Subcommand {
|
||||
const message = await interaction.reply({
|
||||
embeds: [noteEmbed],
|
||||
components: [buttons],
|
||||
ephemeral: true,
|
||||
fetchReply: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
|
||||
// Checks if the message is not an APIMessage
|
||||
if (!isMessageInstance(message)) {
|
||||
if (message.resource === null) {
|
||||
await interaction.editReply('Failed to retrieve the message :(');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel.isSendable()) {
|
||||
await interaction.editReply('Cannot send messages in this channel!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Listen for the button presses
|
||||
const collector = channel.createMessageComponentCollector({
|
||||
max: 1, // Maximum of 1 button press
|
||||
|
||||
@@ -17,9 +17,8 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { isMessageInstance } from '@sapphire/discord.js-utilities';
|
||||
import { Command } from '@sapphire/framework';
|
||||
import type { Message } from 'discord.js';
|
||||
import { Message, MessageFlagsBitField } from 'discord.js';
|
||||
|
||||
export class PingCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext, options: Command.Options) {
|
||||
@@ -41,12 +40,13 @@ export class PingCommand extends Command {
|
||||
public async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
|
||||
const msg = await interaction.reply({
|
||||
content: 'Ping?',
|
||||
ephemeral: true,
|
||||
fetchReply: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
withResponse: true,
|
||||
});
|
||||
|
||||
if (isMessageInstance(msg)) {
|
||||
const diff = msg.createdTimestamp - interaction.createdTimestamp;
|
||||
if (msg.resource !== null && msg.resource.message !== null) {
|
||||
const diff =
|
||||
msg.resource.message.createdTimestamp - interaction.createdTimestamp;
|
||||
const ping = Math.round(this.container.client.ws.ping);
|
||||
return interaction.editReply(
|
||||
`Pong 🏓! (Round trip took: ${diff}ms. Heartbeat: ${ping}ms.)`,
|
||||
@@ -57,6 +57,11 @@ export class PingCommand extends Command {
|
||||
}
|
||||
|
||||
public async messageRun(message: Message) {
|
||||
if (!message.channel.isSendable()) {
|
||||
// TODO manage logging/errors properly
|
||||
return;
|
||||
}
|
||||
|
||||
const msg = await message.channel.send('Ping?');
|
||||
|
||||
const diff = msg.createdTimestamp - message.createdTimestamp;
|
||||
|
||||
@@ -21,8 +21,14 @@ import {
|
||||
InteractionHandler,
|
||||
InteractionHandlerTypes,
|
||||
} from '@sapphire/framework';
|
||||
import type { ButtonInteraction, GuildMember, TextChannel } from 'discord.js';
|
||||
import {
|
||||
ButtonInteraction,
|
||||
GuildMember,
|
||||
MessageFlagsBitField,
|
||||
TextChannel,
|
||||
} from 'discord.js';
|
||||
import IDs from '#utils/ids';
|
||||
import { checkActive } from '#utils/database/moderation/restriction';
|
||||
|
||||
export class WelcomeButtonHandler extends InteractionHandler {
|
||||
public constructor(
|
||||
@@ -54,7 +60,7 @@ export class WelcomeButtonHandler extends InteractionHandler {
|
||||
await interaction.reply({
|
||||
content:
|
||||
'There was an error giving you the role, please try again later or contact ModMail to be let into this server.',
|
||||
ephemeral: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -62,6 +68,16 @@ export class WelcomeButtonHandler extends InteractionHandler {
|
||||
try {
|
||||
member = member as GuildMember;
|
||||
|
||||
// Checks if the user is currently restricted
|
||||
if (await checkActive(member.id)) {
|
||||
await interaction.reply({
|
||||
content: `You are currently restricted from this server! Contact the moderators by sending a DM to <@${IDs.modMail}>.`,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Give non-vegan role
|
||||
if (!member.voice.channel) {
|
||||
await member.roles.add(IDs.roles.nonvegan.nonvegan);
|
||||
@@ -78,13 +94,13 @@ export class WelcomeButtonHandler extends InteractionHandler {
|
||||
await interaction.reply({
|
||||
content:
|
||||
"You're currently in a verification, you'll have to leave the verification or get verified before being able to access the server again.",
|
||||
ephemeral: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
});
|
||||
} catch (error) {
|
||||
await interaction.reply({
|
||||
content:
|
||||
'There was an error giving you the role, please try again later or contact ModMail to be let into this server.',
|
||||
ephemeral: true,
|
||||
flags: MessageFlagsBitField.Flags.Ephemeral,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,11 @@ export class XpListener extends Listener {
|
||||
// If no counts exist on the database, then create the first count from the bot
|
||||
if (lastCount === null) {
|
||||
if (this.container.client.id === null) {
|
||||
if (!message.channel.isSendable()) {
|
||||
// TODO manage logging/errors properly
|
||||
return;
|
||||
}
|
||||
|
||||
message.channel.send(
|
||||
'An unexpected error occurred trying to set up the counting channel, please contact a developer!',
|
||||
);
|
||||
@@ -63,6 +68,11 @@ export class XpListener extends Listener {
|
||||
|
||||
lastCount = await getLastCount();
|
||||
if (lastCount === null) {
|
||||
if (!message.channel.isSendable()) {
|
||||
// TODO manage logging/errors properly
|
||||
return;
|
||||
}
|
||||
|
||||
message.channel.send(
|
||||
'An unexpected error occurred, please contact a developer!',
|
||||
);
|
||||
|
||||
195
src/listeners/fixRoles.ts
Normal file
195
src/listeners/fixRoles.ts
Normal file
@@ -0,0 +1,195 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
/*
|
||||
Animal Rights Advocates Discord Bot
|
||||
Copyright (C) 2025 Anthony Berg
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
I used the Sapphire documentation and parts of the code from the Sapphire CLI to
|
||||
create this file.
|
||||
*/
|
||||
|
||||
import { Listener } from '@sapphire/framework';
|
||||
import { DurationFormatter } from '@sapphire/time-utilities';
|
||||
import { Client } from 'discord.js';
|
||||
import IDs from '#utils/ids';
|
||||
import { fetchRoles } from '#utils/database/dbExistingUser';
|
||||
import { checkActive } from '#utils/database/moderation/restriction';
|
||||
import { getUser } from '#utils/database/fun/xp';
|
||||
|
||||
export class FixRolesOnReady extends Listener {
|
||||
public constructor(
|
||||
context: Listener.LoaderContext,
|
||||
options: Listener.Options,
|
||||
) {
|
||||
super(context, {
|
||||
...options,
|
||||
once: true,
|
||||
event: 'ready',
|
||||
// !!!!!!!!!!!! WARNING !!!!!!!!!!!!
|
||||
// THIS SHOULD BE DISABLED BY DEFAULT
|
||||
// THIS IS ONLY USED FOR RESTORING ROLES TO THE SERVER!
|
||||
// ENABLING THIS UNINTENTIONALLY WILL CAUSE SLOWDOWNS TO THE BOT DUE TO RATE LIMITING!
|
||||
enabled: true,
|
||||
});
|
||||
}
|
||||
|
||||
public async run(client: Client) {
|
||||
this.container.logger.info(
|
||||
'FixRolesOnReady: Preparation before starting to fix the roles for nonvegans...',
|
||||
);
|
||||
|
||||
// Fetching the Guild
|
||||
const guild = await client.guilds.fetch(IDs.guild).catch(() => undefined);
|
||||
|
||||
if (guild === undefined) {
|
||||
this.container.logger.error('FixRolesOnReady: Could not find the server');
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetching the channel for the logs
|
||||
// Leave the snowflake parameter empty for no logs
|
||||
const logChannel = await client.channels
|
||||
.fetch('1329152627312824320')
|
||||
.catch(() => null);
|
||||
const sendLogs = logChannel !== null;
|
||||
|
||||
if (!sendLogs) {
|
||||
this.container.logger.error(
|
||||
'FixRolesOnReady: Could not find the channel for bot logs.',
|
||||
);
|
||||
} else if (sendLogs && !logChannel.isSendable()) {
|
||||
this.container.logger.info(
|
||||
'FixRolesOnReady: No permission to send in bots logs channel.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get all the current users
|
||||
this.container.logger.info('FixRolesOnReady: Fetching all the members...');
|
||||
if (sendLogs) {
|
||||
logChannel.send('Fetching all the users in ARA!');
|
||||
}
|
||||
|
||||
const members = await guild.members.fetch().catch(() => undefined);
|
||||
|
||||
if (members === undefined) {
|
||||
this.container.logger.error(
|
||||
'FixRolesOnReady: Could not fetch all the members, this function is stopping now.',
|
||||
);
|
||||
if (sendLogs) {
|
||||
logChannel.send("Never mind, something went wrong :'(");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const totalMembers = members.size;
|
||||
|
||||
this.container.logger.info(
|
||||
`FixRolesOnReady: Done fetching ${totalMembers} members!`,
|
||||
);
|
||||
|
||||
// Giving the roles to each user
|
||||
let count = 0;
|
||||
const startTime = new Date().getTime();
|
||||
|
||||
this.container.logger.info(
|
||||
'FixRolesOnReady: Starting the process of fixing the roles for every member...',
|
||||
);
|
||||
|
||||
for (const [userId, member] of members) {
|
||||
// Send a message with an update for every 50 completions
|
||||
// Checks if `channelLog` has been set to null
|
||||
// The RHS of the modulo should be around 100
|
||||
if (sendLogs && count % 50 === 0) {
|
||||
const currentTime = new Date().getTime();
|
||||
const runningTime = currentTime - startTime;
|
||||
|
||||
const remaining = totalMembers - count;
|
||||
// Basing this on the fact that
|
||||
const eta = remaining * (runningTime / count);
|
||||
const estimate = new DurationFormatter().format(eta);
|
||||
|
||||
logChannel.send(
|
||||
`Given roles to ${count} out of ${totalMembers} members. Estimated time until completion: ${estimate}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Checks if the user is vegan
|
||||
if (member.roles.cache.has(IDs.roles.vegan.vegan)) {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Checks if the user is restricted, and skips over them if they are
|
||||
const restricted = await checkActive(userId);
|
||||
|
||||
if (
|
||||
restricted ||
|
||||
member.roles.cache.has(IDs.roles.restrictions.restricted1) ||
|
||||
member.roles.cache.has(IDs.roles.restrictions.restricted2) ||
|
||||
member.roles.cache.has(IDs.roles.restrictions.restrictedVegan)
|
||||
) {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Fetch the roles for the member in the database
|
||||
const dbRoles = await fetchRoles(userId);
|
||||
|
||||
// Filters out the roles that the member does not have
|
||||
const roles = dbRoles.filter((role) => !member.roles.cache.has(role));
|
||||
|
||||
if (!roles.includes(IDs.roles.nonvegan.nonvegan)) {
|
||||
const xp = await getUser(userId);
|
||||
|
||||
if (xp !== null && xp.xp > 0) {
|
||||
roles.push(IDs.roles.nonvegan.nonvegan);
|
||||
} else {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Give the roles to the member
|
||||
if (roles.length > 0) {
|
||||
await member.roles.add(roles);
|
||||
}
|
||||
|
||||
// Log the completion
|
||||
count += 1;
|
||||
this.container.logger.info(
|
||||
`FixRolesOnReady: Given roles to ${count}/${totalMembers}.`,
|
||||
);
|
||||
|
||||
// Add a delay so that there's around 4 users processed a second
|
||||
await this.delay(500);
|
||||
}
|
||||
|
||||
// Send the logs that the fix has finished.
|
||||
const endTime = new Date().getTime();
|
||||
const totalTime = endTime - startTime;
|
||||
const totalTimeWritten = new DurationFormatter().format(totalTime);
|
||||
const finishMessage = `Finished fixing roles for all ${totalMembers} members! It took ${totalTimeWritten} to complete.`;
|
||||
|
||||
this.container.logger.info(`FixRolesOnReady: ${finishMessage}`);
|
||||
if (sendLogs) {
|
||||
logChannel.send(finishMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private delay(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
import { Listener } from '@sapphire/framework';
|
||||
import type { Client } from 'discord.js';
|
||||
import IDs from '#utils/ids';
|
||||
|
||||
export class ReadyListener extends Listener {
|
||||
public constructor(
|
||||
@@ -35,8 +36,24 @@ export class ReadyListener extends Listener {
|
||||
});
|
||||
}
|
||||
|
||||
public run(client: Client) {
|
||||
public async run(client: Client) {
|
||||
const { username, id } = client.user!;
|
||||
this.container.logger.info(`Successfully logged in as ${username} (${id})`);
|
||||
|
||||
const botLogChannel = await client.channels.fetch(IDs.channels.logs.bot);
|
||||
|
||||
if (botLogChannel === null) {
|
||||
this.container.logger.error(
|
||||
'ReadyListener: Could not find the channel for bot logs.',
|
||||
);
|
||||
return;
|
||||
} else if (!botLogChannel.isSendable()) {
|
||||
this.container.logger.info(
|
||||
'ReadyListener: No permission to send in bots logs channel.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
botLogChannel.send('The bot has started up!');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,11 @@ export class Suggestions extends Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mailbox.isSendable()) {
|
||||
// TODO manage logging/errors properly
|
||||
return;
|
||||
}
|
||||
|
||||
const sent = await mailbox.send({
|
||||
embeds: [suggestion],
|
||||
content: message.author.toString(),
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
const devIDs = {
|
||||
guild: '999431674972618792',
|
||||
roles: {
|
||||
trusted: '999431675081666599',
|
||||
booster: '',
|
||||
@@ -41,6 +42,7 @@ const devIDs = {
|
||||
restricted2: '999431674997788676',
|
||||
restricted3: '999431674997788675',
|
||||
restricted4: '999431674997788674',
|
||||
restrictedVegan: '1075952207091994726',
|
||||
restricted: [
|
||||
'999431674997788677', // Restricted 1
|
||||
'999431674997788676', // Restricted 2
|
||||
@@ -126,6 +128,7 @@ const devIDs = {
|
||||
},
|
||||
logs: {
|
||||
restricted: '999431681217937513',
|
||||
bot: '999431681217937516',
|
||||
economy: '999431681599623198',
|
||||
sus: '999431681599623199',
|
||||
},
|
||||
@@ -139,6 +142,7 @@ const devIDs = {
|
||||
private: '999431679527628818',
|
||||
restricted: '999431679812845654',
|
||||
},
|
||||
modMail: '575252669443211264',
|
||||
};
|
||||
|
||||
export default devIDs;
|
||||
|
||||
@@ -20,34 +20,36 @@
|
||||
import devIDs from '#utils/devIDs';
|
||||
|
||||
let IDs = {
|
||||
guild: '730907954345279591',
|
||||
roles: {
|
||||
trusted: '731563158011117590',
|
||||
trusted: '1329089675977035879',
|
||||
booster: '731213264540795012',
|
||||
nonvegan: {
|
||||
nonvegan: '774763753308815400',
|
||||
vegCurious: '832656046572961803',
|
||||
nonvegan: '1329093962153332848',
|
||||
vegCurious: '1329107984227369020',
|
||||
convinced: '797132019166871612',
|
||||
},
|
||||
vegan: {
|
||||
vegan: '788114978020392982',
|
||||
activist: '730915638746546257',
|
||||
activist: '1329112833115295815',
|
||||
nvAccess: '1076857105648209971',
|
||||
plus: '798682625619132428',
|
||||
araVegan: '995394977658044506',
|
||||
},
|
||||
restrictions: {
|
||||
sus: '859145930640457729',
|
||||
sus: '1329125130949103626',
|
||||
muted: '730924813681688596',
|
||||
softMute: '775934741139554335',
|
||||
restricted1: '809769217477050369',
|
||||
restricted2: '872482843304001566',
|
||||
restricted3: '856582673258774538',
|
||||
restricted4: '872472182888992858',
|
||||
restricted3: '1329126085207789658',
|
||||
restricted4: '1329126181164945499',
|
||||
restrictedVegan: '1075951477379567646',
|
||||
restricted: [
|
||||
'809769217477050369', // Restricted 1
|
||||
'872482843304001566', // Restricted 2
|
||||
'856582673258774538', // Restricted 3
|
||||
'872472182888992858', // Restricted 4
|
||||
'1329126085207789658', // Restricted 3
|
||||
'1329126181164945499', // Restricted 4
|
||||
'1075951477379567646', // Restricted Vegan
|
||||
],
|
||||
},
|
||||
@@ -75,7 +77,7 @@ let IDs = {
|
||||
stageHost: '854893757593419786',
|
||||
patron: '765370219207852055',
|
||||
patreon: '993848684640997406',
|
||||
verifyBlock: '1032765019269640203',
|
||||
verifyBlock: '1329107805130461247',
|
||||
bookClub: '955516408249352212',
|
||||
debateHost: '935508325615931443',
|
||||
gameNightHost: '952779915701415966',
|
||||
@@ -128,6 +130,7 @@ let IDs = {
|
||||
},
|
||||
logs: {
|
||||
restricted: '920993034462715925',
|
||||
bot: '872126272015314966',
|
||||
economy: '932050015034159174',
|
||||
sus: '872884989950324826',
|
||||
},
|
||||
@@ -141,6 +144,7 @@ let IDs = {
|
||||
private: '992581296901599302',
|
||||
restricted: '809765577236283472',
|
||||
},
|
||||
modMail: '575252669443211264',
|
||||
};
|
||||
|
||||
// Check if the bot is in development mode
|
||||
|
||||
Reference in New Issue
Block a user