More debug logging, added dev command to enable debug logging in specific guild #9

Merged
Navy.gif merged 1 commits from development into alpha 2024-07-12 15:28:30 +02:00
13 changed files with 87 additions and 156 deletions

1
@types/Guild.d.ts vendored
View File

@ -120,6 +120,7 @@ export type GuildData = {
caseId?: number,
settings?: GuildSettings,
premium?: number,
debug?: boolean,
_version?: string,
_imported?: {
[key: string]: boolean | undefined,

View File

@ -69,6 +69,7 @@
"tables": [
"guilds",
"attachments",
"messages",
"permissions",
"webhooks",
"wordwatcher",

View 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;

View File

@ -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
}
});
}
}

View File

@ -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,9 +382,16 @@ class GuildWrapper
this.#logger.error(`Database error (guild:${this.id}) :\n${error.stack || error}`);
}
#debugLog (log: string)
debug (log: string)
{
this.#logger.debug(`[${this.name}]: ${log}`);
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 */

View File

@ -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');
}

View File

@ -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();

View File

@ -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();

View File

@ -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');
}

View File

@ -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');
}

View File

@ -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;

View File

@ -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)

View File

@ -111,7 +111,7 @@
},
"compileOnSave": true,
"exclude": ["archive", "api"],
"include": ["src", "index.ts", "@types"],
"include": ["src/**/*", "index.ts", "@types/*"],
"watchOptions": {
"watchFile": "useFsEvents",
"watchDirectory": "useFsEvents",