More debug logging, added dev command to enable debug logging in specific guild #9
1
@types/Guild.d.ts
vendored
1
@types/Guild.d.ts
vendored
@ -120,6 +120,7 @@ export type GuildData = {
|
||||
caseId?: number,
|
||||
settings?: GuildSettings,
|
||||
premium?: number,
|
||||
debug?: boolean,
|
||||
_version?: string,
|
||||
_imported?: {
|
||||
[key: string]: boolean | undefined,
|
||||
|
@ -69,6 +69,7 @@
|
||||
"tables": [
|
||||
"guilds",
|
||||
"attachments",
|
||||
"messages",
|
||||
"permissions",
|
||||
"webhooks",
|
||||
"wordwatcher",
|
||||
|
59
src/client/components/commands/developer/Debug.ts
Normal file
59
src/client/components/commands/developer/Debug.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { CommandOptionType, CommandParams } from '../../../../../@types/Client.js';
|
||||
import DiscordClient from '../../../DiscordClient.js';
|
||||
import { Command } from '../../../interfaces/index.js';
|
||||
import InvokerWrapper from '../../wrappers/InvokerWrapper.js';
|
||||
|
||||
class DebugCommand extends Command
|
||||
{
|
||||
constructor (client: DiscordClient)
|
||||
{
|
||||
super(client, {
|
||||
name: 'debug',
|
||||
restricted: true,
|
||||
moduleName: 'developer',
|
||||
options: [
|
||||
{ name: 'guild', required: true },
|
||||
{ name: 'enabled', required: true, type: CommandOptionType.BOOLEAN }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async execute (_invoker: InvokerWrapper, options: CommandParams)
|
||||
{
|
||||
const guildId = options.guild!.asString;
|
||||
return this.enableDebug(guildId, options.enabled?.asBool);
|
||||
}
|
||||
|
||||
async enableDebug (guildId: string, enabled = false)
|
||||
{
|
||||
let output = '';
|
||||
if (this.client.shard)
|
||||
{
|
||||
const result = await this.client.shard.broadcastEval(async (client, context) =>
|
||||
{
|
||||
const bot = client as DiscordClient;
|
||||
const wrapper = await bot.getGuildWrapper(context.guildId);
|
||||
if (!wrapper)
|
||||
return false;
|
||||
await wrapper.setDebug(context.enabled);
|
||||
return `${wrapper.name} (${wrapper.id})`;
|
||||
}, { context: { guildId, enabled } });
|
||||
|
||||
if (!result.some(val => val))
|
||||
return 'No such guild';
|
||||
output = result.find(entry => entry) as string;
|
||||
}
|
||||
else
|
||||
{
|
||||
const wrapper = await this.client.getGuildWrapper(guildId).catch(() => null);
|
||||
if (!wrapper)
|
||||
return 'No such guild';
|
||||
await wrapper.setDebug(enabled);
|
||||
output = `${wrapper.name} (${wrapper.id})`;
|
||||
}
|
||||
return `${enabled ? 'Enabled' : 'Disabled'} debug on **${output}**`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DebugCommand;
|
@ -8,7 +8,6 @@ import MemberWrapper from '../../wrappers/MemberWrapper.js';
|
||||
|
||||
class AddroleCommand extends ModerationCommand
|
||||
{
|
||||
|
||||
constructor (client: DiscordClient)
|
||||
{
|
||||
super(client, {
|
||||
@ -43,12 +42,10 @@ class AddroleCommand extends ModerationCommand
|
||||
clientPermissions: [ 'ManageRoles' ],
|
||||
skipOptions: [ 'points', 'expiration', 'force', 'prune' ]
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
async execute (invoker: InvokerWrapper<true>, { users, roles, ...args }: CommandParams)
|
||||
{
|
||||
|
||||
if (!users)
|
||||
throw new CommandError(invoker, { index: 'MODERATION_MISSING_USERS' });
|
||||
if (!roles)
|
||||
@ -66,7 +63,6 @@ class AddroleCommand extends ModerationCommand
|
||||
roles: roles.asString
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -59,89 +59,9 @@ class GuildWrapper
|
||||
this.#guild = guild;
|
||||
this.#webhooks = new Collection();
|
||||
this.#memberWrappers = new Collection();
|
||||
this.#debugLog('Created wrapper');
|
||||
this.debug('Created wrapper');
|
||||
}
|
||||
|
||||
// async createPoll ({ user, duration, ...opts }: PollData)
|
||||
// {
|
||||
// // Idk polls that don't have a duration should still be stored somewhere so they can be ended at an arbitrary point
|
||||
// const type = 'poll';
|
||||
// const now = Date.now();
|
||||
// const id = `${type}:${user}:${now}`;
|
||||
// const data = { ...opts, user, id, guild: this.id, type, time: duration * 1000, created: now };
|
||||
// if (duration)
|
||||
// await this.createCallback(data satisfies CallbackData);
|
||||
// }
|
||||
|
||||
// async loadCallbacks ()
|
||||
// {
|
||||
// const data = await this.#client.mongodb.callbacks.find<CallbackData>({ guild: this.id });
|
||||
// for (const cb of data)
|
||||
// await this.createCallback(cb, false);
|
||||
// }
|
||||
|
||||
// async createCallback (data: CallbackData, update = true)
|
||||
// {
|
||||
// const handler = this[`_${data.type}`] as CallbackFn;// .bind(this);
|
||||
// if (!handler)
|
||||
// throw new Error('Invalid callback type');
|
||||
|
||||
// const now = Date.now();
|
||||
// const time = data.created + data.time;
|
||||
// const diff = time - now;
|
||||
// if (diff < 5000)
|
||||
// return handler.bind(this)(data);
|
||||
|
||||
// const cb = { timeout: setTimeout(handler.bind(this), diff, data), data };
|
||||
// this.#callbacks.set(data.id, cb);
|
||||
// if (update)
|
||||
// await this.#client.mongodb.callbacks.updateOne({ id: data.id, guild: this.id }, { $set: data });
|
||||
// }
|
||||
|
||||
// async removeCallback (id: string)
|
||||
// {
|
||||
// const cb = this.#callbacks.get(id);
|
||||
// if (cb)
|
||||
// clearTimeout(cb.timeout);
|
||||
// this.#callbacks.delete(id);
|
||||
// await this.#client.mongodb.callbacks.deleteOne({ guild: this.id, id });
|
||||
// }
|
||||
|
||||
// async _poll ({ user, message, channel, id, questions, startedIn }: PollData & CallbackData)
|
||||
// { // multichoice,
|
||||
// const startedInChannel = await this.resolveChannel<TextChannel>(startedIn);
|
||||
// const pollChannel = await this.resolveChannel<TextChannel>(channel);
|
||||
// if (pollChannel)
|
||||
// {
|
||||
// const msg = await pollChannel.messages.fetch(message).catch(() => null);
|
||||
// if (msg)
|
||||
// {
|
||||
// const { reactions } = msg;
|
||||
// const reactionEmojis = questions.length ? PollReactions.Multi : PollReactions.Single;
|
||||
// const result: {[key: string]: number} = {};
|
||||
// for (const emoji of reactionEmojis)
|
||||
// {
|
||||
// let reaction = reactions.resolve(emoji);
|
||||
// // eslint-disable-next-line max-depth
|
||||
// if (!reaction)
|
||||
// continue;
|
||||
// // eslint-disable-next-line max-depth
|
||||
// if (reaction.partial)
|
||||
// reaction = await reaction.fetch();
|
||||
// result[emoji] = reaction.count - 1;
|
||||
// }
|
||||
|
||||
// const embed = msg.embeds[0].toJSON();
|
||||
// const results = Object.entries(result).map(([ emoji, count ]) => `${emoji} - ${count}`).join('\n');
|
||||
// embed.description = this.format('COMMAND_POLL_END', { results });
|
||||
// await msg.edit({ embeds: [ embed ] });
|
||||
// }
|
||||
// }
|
||||
// await this.removeCallback(id);
|
||||
// if (startedInChannel)
|
||||
// await startedInChannel.send(this.format('COMMAND_POLL_NOTIFY_STARTER', { user, channel }));
|
||||
// }
|
||||
|
||||
async filterText (member: GuildMember, text: string)
|
||||
{
|
||||
const settings = await this.settings();
|
||||
@ -289,72 +209,6 @@ class GuildWrapper
|
||||
return true;
|
||||
}
|
||||
|
||||
// async _attemptDataImport ()
|
||||
// {
|
||||
// const migratorOptions = {
|
||||
// // host: MONGODB_V2_HOST,
|
||||
// database: 'galacticbot',
|
||||
// version: '2'
|
||||
// };
|
||||
|
||||
// const settingsMigrator = new SettingsMigrator(this.client, this, migratorOptions);
|
||||
// const modlogsMigrator = new InfractionMigrator(this.client, this, migratorOptions);
|
||||
|
||||
// await settingsMigrator.connect();
|
||||
// await modlogsMigrator.connect();
|
||||
|
||||
// let importedSettings = null;
|
||||
// let importedModlogs = null;
|
||||
|
||||
// try
|
||||
// {
|
||||
// importedSettings = await settingsMigrator.import();
|
||||
// importedModlogs = await modlogsMigrator.import();
|
||||
// importedModlogs.sort((a, b) => a.case - b.case);
|
||||
// }
|
||||
// catch (err)
|
||||
// {
|
||||
// await settingsMigrator.end();
|
||||
// await modlogsMigrator.end();
|
||||
// // Did not find old settings, marking as imported anyway
|
||||
// if (err.message.includes('No old'))
|
||||
// {
|
||||
// await this.updateData({ _imported: { settings: true, modlogs: true } });
|
||||
// }
|
||||
// else
|
||||
// this.client.logger.error(err.stack);
|
||||
// return null;
|
||||
// }
|
||||
// await settingsMigrator.end();
|
||||
// await modlogsMigrator.end();
|
||||
|
||||
// await this.client.mongodb.infractions.deleteMany({ guild: this.id });
|
||||
// await this.client.mongodb.infractions.insertMany(importedModlogs);
|
||||
// this._data.caseId = importedModlogs[importedModlogs.length - 1].case;
|
||||
// await this.updateData({
|
||||
// caseId: this._data.caseId,
|
||||
// premium: importedSettings.premium,
|
||||
// _imported: { settings: true, modlogs: true }
|
||||
// });
|
||||
|
||||
// const { webhook, permissions, settings } = importedSettings;
|
||||
// await this.updateSettings(settings);
|
||||
// if (webhook)
|
||||
// {
|
||||
// const hooks = await this.fetchWebhooks().catch(() => null);
|
||||
// const hook = hooks?.get(webhook);
|
||||
// if (hook)
|
||||
// await this.updateWebhook('messages', hook);
|
||||
// }
|
||||
|
||||
// if (permissions)
|
||||
// await this.#client.mongodb.permissions.updateOne({ guildId: this.id }, permissions);
|
||||
|
||||
|
||||
// return settings;
|
||||
|
||||
// }
|
||||
|
||||
/**
|
||||
* Update a webhook entry in the database
|
||||
*
|
||||
@ -528,11 +382,18 @@ class GuildWrapper
|
||||
this.#logger.error(`Database error (guild:${this.id}) :\n${error.stack || error}`);
|
||||
}
|
||||
|
||||
#debugLog (log: string)
|
||||
debug (log: string)
|
||||
{
|
||||
if (!this.#data || this.#data.debug)
|
||||
this.#logger.debug(`[${this.name}]: ${log}`);
|
||||
}
|
||||
|
||||
async setDebug (enabled: boolean)
|
||||
{
|
||||
await this.#client.mongodb.guilds.updateOne({ guildId: this.id }, { $set: { debug: enabled } });
|
||||
this.#data.debug = enabled;
|
||||
}
|
||||
|
||||
/* Wrapper Functions */
|
||||
|
||||
fetchAuditLogs<T extends GuildAuditLogsResolvable> (opts: GuildAuditLogsFetchOptions<T>)
|
||||
|
@ -62,10 +62,12 @@ class AddroleInfraction extends Infraction
|
||||
}
|
||||
try
|
||||
{
|
||||
this.guild.debug(`Adding roles ${this.data.roleIds.join(', ')} to ${this.member.tag} (${this.member.id})`);
|
||||
await this.member.roles.add(this.data.roleIds, this._reason);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
this.logger.error(`Failed to add roles (${this.data.roleIds.join(', ')}) to ${this.member.tag} (${this.member.id})\n${error}`);
|
||||
return this._fail('INFRACTION_ERROR');
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,7 @@ class BanInfraction extends Infraction
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
this.logger.error(`Failed to ban ${(this.target as UserWrapper).tag} (${this.target!.id}) from ${this.guild.name} (${this.guild.id})\n${error}`);
|
||||
return this._fail('INFRACTION_ERROR');
|
||||
}
|
||||
await this.handle();
|
||||
|
@ -4,6 +4,7 @@ import DiscordClient from '../DiscordClient.js';
|
||||
import MemberWrapper from '../components/wrappers/MemberWrapper.js';
|
||||
import Infraction from '../interfaces/Infraction.js';
|
||||
import { KickData } from '../../../@types/Infractions.js';
|
||||
import UserWrapper from '../components/wrappers/UserWrapper.js';
|
||||
|
||||
class KickInfraction extends Infraction
|
||||
{
|
||||
@ -56,6 +57,7 @@ class KickInfraction extends Infraction
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
this.logger.error(`Failed to kick ${(this.target as UserWrapper).tag} (${this.target!.id}) from ${this.guild.name} (${this.guild.id})\n${error}`);
|
||||
return this._fail('INFRACTION_ERROR');
|
||||
}
|
||||
await this.handle();
|
||||
|
@ -59,6 +59,7 @@ class RemoveroleInfraction extends Infraction
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
this.logger.error(`Failed to remove roles (${this.data.roleIds!.join(', ')}) to ${this.member!.tag} (${this.member!.id})\n${error}`);
|
||||
return this._fail('INFRACTION_ERROR');
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,7 @@ class UnbanInfraction extends Infraction
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
this.logger.error(`Failed to unban ${this.targetId} in ${this.guild.name} (${this.guild.id})\n${error}`);
|
||||
return this._fail('INFRACTION_ERROR');
|
||||
}
|
||||
|
||||
|
@ -107,8 +107,9 @@ class UnmuteInfraction extends Infraction
|
||||
{
|
||||
this.member!.roles.remove(role, this._reason);
|
||||
}
|
||||
catch (e)
|
||||
catch (error)
|
||||
{
|
||||
this.logger.error(`Failed to unmute ${this.member.tag} (${this.member.id})\n${error}`);
|
||||
return this._fail('C_UNMUTE_1FAIL');
|
||||
}
|
||||
}
|
||||
@ -131,8 +132,9 @@ class UnmuteInfraction extends Infraction
|
||||
{
|
||||
this.member.roles.remove(role, this._reason);
|
||||
}
|
||||
catch (e)
|
||||
catch (error)
|
||||
{
|
||||
this.logger.error(`Failed to unmute ${this.member.tag} (${this.member.id})\n${error}`);
|
||||
return this._fail('C_UNMUTE_1FAIL');
|
||||
}
|
||||
break;
|
||||
|
@ -234,6 +234,10 @@ class Infraction
|
||||
}).catch(() => null);
|
||||
this.#dmLogMessageId = logMessage?.id ?? null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.logger.debug(`Target not sendable? ${inspect(this.#target)}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.#duration)
|
||||
|
@ -111,7 +111,7 @@
|
||||
},
|
||||
"compileOnSave": true,
|
||||
"exclude": ["archive", "api"],
|
||||
"include": ["src", "index.ts", "@types"],
|
||||
"include": ["src/**/*", "index.ts", "@types/*"],
|
||||
"watchOptions": {
|
||||
"watchFile": "useFsEvents",
|
||||
"watchDirectory": "useFsEvents",
|
||||
|
Loading…
Reference in New Issue
Block a user