aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package.json1
-rw-r--r--src/commands/admin/prefix.ts8
-rw-r--r--src/commands/moderation/ban.ts26
-rw-r--r--src/commands/moderation/kick.ts18
-rw-r--r--src/commands/moderation/modlog.ts7
-rw-r--r--src/commands/moderation/warn.ts18
-rw-r--r--src/config/example-options.ts1
-rw-r--r--src/lib/extensions/BotClient.ts40
-rw-r--r--src/lib/extensions/BotCommand.ts5
-rw-r--r--src/lib/extensions/Util.ts49
-rw-r--r--src/lib/utils/Logger.ts44
-rw-r--r--src/listeners/client/CreateSlashCommands.ts17
-rw-r--r--src/listeners/client/ready.ts6
-rw-r--r--src/listeners/commands/commandstarted.ts24
-rw-r--r--src/listeners/message/levels.ts8
-rw-r--r--src/tasks.ts7
-rw-r--r--yarn.lock2
17 files changed, 188 insertions, 93 deletions
diff --git a/package.json b/package.json
index 67b772f..ad755a0 100644
--- a/package.json
+++ b/package.json
@@ -30,6 +30,7 @@
"dependencies": {
"@top-gg/sdk": "^3.0.9",
"body-parser": "^1.19.0",
+ "chalk": "^4.1.1",
"common-tags": "^1.8.0",
"discord-akairo": "SkyBlockDev/discord-akairo",
"discord-api-types": "^0.18.1",
diff --git a/src/commands/admin/prefix.ts b/src/commands/admin/prefix.ts
index 8fb50f8..3948a7e 100644
--- a/src/commands/admin/prefix.ts
+++ b/src/commands/admin/prefix.ts
@@ -10,7 +10,13 @@ export default class PrefixCommand extends BotCommand {
id: 'prefix'
}
],
- userPermissions: ['MANAGE_GUILD']
+ userPermissions: ['MANAGE_GUILD'],
+ description: {
+ content:
+ 'Set the prefix of the current server (resets to default if prefix is not given)',
+ usage: 'prefix [prefix]',
+ examples: ['prefix', 'prefix +']
+ }
});
}
async exec(
diff --git a/src/commands/moderation/ban.ts b/src/commands/moderation/ban.ts
index fc861dc..7ce36d3 100644
--- a/src/commands/moderation/ban.ts
+++ b/src/commands/moderation/ban.ts
@@ -1,4 +1,5 @@
import { User } from 'discord.js';
+import { Guild } from '../../lib/models';
import { BotCommand } from '../../lib/extensions/BotCommand';
import { BotMessage } from '../../lib/extensions/BotMessage';
import { Ban, Modlog, ModlogType } from '../../lib/models';
@@ -27,7 +28,8 @@ export default class PrefixCommand extends BotCommand {
}
},
{
- id: 'reason'
+ id: 'reason',
+ match: 'rest'
},
{
id: 'time',
@@ -36,7 +38,16 @@ export default class PrefixCommand extends BotCommand {
}
],
clientPermissions: ['BAN_MEMBERS'],
- userPermissions: ['BAN_MEMBERS']
+ userPermissions: ['BAN_MEMBERS'],
+ description: {
+ content:
+ 'Ban a member and log it in modlogs (with optional time to unban)',
+ usage: 'ban <member> <reason> [--time]',
+ examples: [
+ 'ban @Tyman being cool',
+ 'ban @Tyman being cool --time 7days'
+ ]
+ }
});
}
async exec(
@@ -47,6 +58,15 @@ export default class PrefixCommand extends BotCommand {
let modlogEnry: Modlog;
let banEntry: Ban;
const translatedTime: string[] = [];
+ // Create guild entry so postgres doesn't get mad when I try and add a modlog entry
+ await Guild.findOrCreate({
+ where: {
+ id: message.guild.id
+ },
+ defaults: {
+ id: message.guild.id
+ }
+ });
try {
try {
if (time) {
@@ -129,8 +149,8 @@ export default class PrefixCommand extends BotCommand {
);
} catch {
await message.util.send('Error banning :/');
- await modlogEnry.destroy();
await banEntry.destroy();
+ await modlogEnry.destroy();
return;
}
}
diff --git a/src/commands/moderation/kick.ts b/src/commands/moderation/kick.ts
index dcd19de..23fc092 100644
--- a/src/commands/moderation/kick.ts
+++ b/src/commands/moderation/kick.ts
@@ -1,6 +1,6 @@
import { BotCommand } from '../../lib/extensions/BotCommand';
import { BotMessage } from '../../lib/extensions/BotMessage';
-import { Modlog, ModlogType } from '../../lib/models';
+import { Guild, Modlog, ModlogType } from '../../lib/models';
import { GuildMember } from 'discord.js';
export default class PrefixCommand extends BotCommand {
@@ -21,7 +21,12 @@ export default class PrefixCommand extends BotCommand {
}
],
clientPermissions: ['KICK_MEMBERS'],
- userPermissions: ['KICK_MEMBERS']
+ userPermissions: ['KICK_MEMBERS'],
+ description: {
+ content: 'Kick a member and log it in modlogs',
+ usage: 'kick <member> <reason>',
+ examples: ['kick @Tyman being cool']
+ }
});
}
async exec(
@@ -29,6 +34,15 @@ export default class PrefixCommand extends BotCommand {
{ user, reason }: { user: GuildMember; reason?: string }
): Promise<void> {
let modlogEnry: Modlog;
+ // Create guild entry so postgres doesn't get mad when I try and add a modlog entry
+ await Guild.findOrCreate({
+ where: {
+ id: message.guild.id
+ },
+ defaults: {
+ id: message.guild.id
+ }
+ });
try {
modlogEnry = Modlog.build({
user: user.id,
diff --git a/src/commands/moderation/modlog.ts b/src/commands/moderation/modlog.ts
index dbb101c..320c6b4 100644
--- a/src/commands/moderation/modlog.ts
+++ b/src/commands/moderation/modlog.ts
@@ -22,7 +22,12 @@ export default class ModlogCommand extends BotCommand {
type: 'number'
}
],
- userPermissions: ['MANAGE_MESSAGES']
+ userPermissions: ['MANAGE_MESSAGES'],
+ description: {
+ content: "View a user's modlogs, or view a specific modlog entry",
+ usage: 'warn <search> [page]',
+ examples: ['modlogs @Tyman', 'modlogs @Tyman 3']
+ }
});
}
*args(): unknown {
diff --git a/src/commands/moderation/warn.ts b/src/commands/moderation/warn.ts
index 755a036..98ba4bd 100644
--- a/src/commands/moderation/warn.ts
+++ b/src/commands/moderation/warn.ts
@@ -1,7 +1,7 @@
import { GuildMember } from 'discord.js';
import { BotCommand } from '../../lib/extensions/BotCommand';
import { BotMessage } from '../../lib/extensions/BotMessage';
-import { Modlog, ModlogType } from '../../lib/models';
+import { Guild, Modlog, ModlogType } from '../../lib/models';
export default class WarnCommand extends BotCommand {
public constructor() {
@@ -17,13 +17,27 @@ export default class WarnCommand extends BotCommand {
id: 'reason',
match: 'rest'
}
- ]
+ ],
+ description: {
+ content: 'Warn a member and log it in modlogs',
+ usage: 'warn <member> <reason>',
+ examples: ['warn @Tyman being cool']
+ }
});
}
public async exec(
message: BotMessage,
{ member, reason }: { member: GuildMember; reason: string }
): Promise<void> {
+ // Create guild entry so postgres doesn't get mad when I try and add a modlog entry
+ await Guild.findOrCreate({
+ where: {
+ id: message.guild.id
+ },
+ defaults: {
+ id: message.guild.id
+ }
+ });
try {
const entry = Modlog.build({
user: member.id,
diff --git a/src/config/example-options.ts b/src/config/example-options.ts
index 2da1374..5bfb92f 100644
--- a/src/config/example-options.ts
+++ b/src/config/example-options.ts
@@ -17,6 +17,7 @@ export const channels = {
dm: 'id here',
command: 'id here'
};
+export const verbose = false;
// Database specific
export const db = {
diff --git a/src/lib/extensions/BotClient.ts b/src/lib/extensions/BotClient.ts
index e2de812..99b40ef 100644
--- a/src/lib/extensions/BotClient.ts
+++ b/src/lib/extensions/BotClient.ts
@@ -15,27 +15,11 @@ import * as Tasks from '../../tasks';
import { v4 as uuidv4 } from 'uuid';
import { exit } from 'process';
import { Intents } from 'discord.js';
+import * as config from '../../config/options';
+import { Logger } from '../utils/Logger';
+import chalk from 'chalk';
-export interface BotConfig {
- credentials: {
- botToken: string;
- };
- owners: string[];
- prefix: string;
- dev: boolean;
- db: {
- username: string;
- password: string;
- host: string;
- port: number;
- };
- channels: {
- log: string;
- error: string;
- dm: string;
- command: string;
- };
-}
+export type BotConfig = typeof config;
export class BotClient extends AkairoClient {
public config: BotConfig;
@@ -45,6 +29,7 @@ export class BotClient extends AkairoClient {
public util: Util;
public ownerID: string[];
public db: Sequelize;
+ public logger: Logger;
constructor(config: BotConfig) {
super(
{
@@ -114,6 +99,7 @@ export class BotClient extends AkairoClient {
);
BotGuild.install();
BotMessage.install();
+ this.logger = new Logger(this);
}
// Initialize everything
@@ -134,14 +120,20 @@ export class BotClient extends AkairoClient {
for (const loader of Object.keys(loaders)) {
try {
loaders[loader].loadAll();
- console.log('Successfully loaded ' + loader + '.');
+ this.logger.log(
+ chalk.green('Successfully loaded ' + chalk.cyan(loader) + '.')
+ );
} catch (e) {
- console.error('Unable to load loader ' + loader + ' with error ' + e);
+ console.error(
+ chalk.red(
+ 'Unable to load loader ' + chalk.cyan(loader) + ' with error ' + e
+ )
+ );
}
}
await this.dbPreInit();
Object.keys(Tasks).forEach((t) => {
- setInterval(() => Tasks[t](this), 60000);
+ setInterval(() => Tasks[t](this), 30000);
});
}
@@ -270,7 +262,7 @@ export class BotClient extends AkairoClient {
await this._init();
await this.login(this.token);
} catch (e) {
- console.error(e.stack);
+ console.error(chalk.red(e.stack));
exit(2);
}
}
diff --git a/src/lib/extensions/BotCommand.ts b/src/lib/extensions/BotCommand.ts
index 2db93b0..c5d31e9 100644
--- a/src/lib/extensions/BotCommand.ts
+++ b/src/lib/extensions/BotCommand.ts
@@ -4,6 +4,11 @@ import { BotClient } from './BotClient';
export interface BotCommandOptions extends CommandOptions {
slashCommandOptions?: APIApplicationCommandOption[];
+ description: {
+ content: string;
+ usage: string;
+ examples: string[];
+ };
}
export class BotCommand extends Command {
diff --git a/src/lib/extensions/Util.ts b/src/lib/extensions/Util.ts
index 4243ebf..661392f 100644
--- a/src/lib/extensions/Util.ts
+++ b/src/lib/extensions/Util.ts
@@ -1,12 +1,9 @@
import { ClientUtil } from 'discord-akairo';
import { BotClient } from './BotClient';
-import { User } from 'discord.js';
import { promisify } from 'util';
import { exec } from 'child_process';
import got from 'got';
-import { TextChannel } from 'discord.js';
-import { MessageEmbed } from 'discord.js';
-import { GuildMember } from 'discord.js';
+import { MessageEmbed, GuildMember, User } from 'discord.js';
interface hastebinRes {
key: string;
@@ -120,14 +117,6 @@ export class Util extends ClientUtil {
}
/**
- * Logs something but only in dev mode
- * @param content The thing to log
- */
- public devLog(content: unknown): void {
- if (this.client.config.dev) console.log(content);
- }
-
- /**
* Resolves a user-provided string into a user object, if possible
* @param text The text to try and resolve
* @returns The user resolved or null
@@ -184,42 +173,6 @@ export class Util extends ClientUtil {
}
/**
- * Logs a message to console and log channel as info
- * @param message The message to send
- */
- public async info(message: string): Promise<void> {
- console.log(`INFO: ${message}`);
- const channel = (await this.client.channels.fetch(
- this.client.config.channels.log
- )) as TextChannel;
- await channel.send(`INFO: ${message}`);
- }
-
- /**
- * Logs a message to console and log channel as a warning
- * @param message The message to send
- */
- public async warn(message: string): Promise<void> {
- console.warn(`WARN: ${message}`);
- const channel = (await this.client.channels.fetch(
- this.client.config.channels.log
- )) as TextChannel;
- await channel.send(`WARN: ${message}`);
- }
-
- /**
- * Logs a message to console and log channel as an error
- * @param message The message to send
- */
- public async error(message: string): Promise<void> {
- console.error(`ERROR: ${message}`);
- const channel = (await this.client.channels.fetch(
- this.client.config.channels.error
- )) as TextChannel;
- await channel.send(`ERROR: ${message}`);
- }
-
- /**
* The colors used throught the bot
*/
public colors = {
diff --git a/src/lib/utils/Logger.ts b/src/lib/utils/Logger.ts
new file mode 100644
index 0000000..455ba36
--- /dev/null
+++ b/src/lib/utils/Logger.ts
@@ -0,0 +1,44 @@
+import { TextChannel } from 'discord.js';
+import { BotClient } from '../extensions/BotClient';
+import chalk from 'chalk';
+
+export class Logger {
+ private client: BotClient;
+ public constructor(client: BotClient) {
+ this.client = client;
+ }
+ private stripColor(text: string): string {
+ return text.replace(
+ // eslint-disable-next-line no-control-regex
+ /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
+ ''
+ );
+ }
+ public getChannel(channel: 'log' | 'error' | 'dm'): Promise<TextChannel> {
+ return this.client.channels.fetch(
+ this.client.config.channels[channel]
+ ) as Promise<TextChannel>;
+ }
+ public async log(message: string, sendChannel = false): Promise<void> {
+ console.log(chalk`{bgCyan LOG} ` + message);
+ if (sendChannel) {
+ const channel = await this.getChannel('log');
+ await channel.send('[LOG] ' + this.stripColor(message));
+ }
+ }
+ public async verbose(message: string, sendChannel = false): Promise<void> {
+ if (!this.client.config.verbose) return;
+ console.log(chalk`{bgMagenta VERBOSE} ` + message);
+ if (sendChannel) {
+ const channel = await this.getChannel('log');
+ await channel.send('[VERBOSE] ' + this.stripColor(message));
+ }
+ }
+ public async error(message: string, sendChannel = false): Promise<void> {
+ console.log(chalk`{bgRed ERROR} ` + message);
+ if (sendChannel) {
+ const channel = await this.getChannel('error');
+ await channel.send('[ERROR] ' + this.stripColor(message));
+ }
+ }
+}
diff --git a/src/listeners/client/CreateSlashCommands.ts b/src/listeners/client/CreateSlashCommands.ts
index b860bec..c395b3a 100644
--- a/src/listeners/client/CreateSlashCommands.ts
+++ b/src/listeners/client/CreateSlashCommands.ts
@@ -1,3 +1,4 @@
+import chalk from 'chalk';
import { BotListener } from '../../lib/extensions/BotListener';
export default class CreateSlashCommands extends BotListener {
@@ -17,7 +18,9 @@ export default class CreateSlashCommands extends BotListener {
)
) {
await this.client.application.commands.delete(command[1].id);
- console.log('deleted', command[1].name);
+ this.client.logger.verbose(
+ `{red Deleted slash command ${command[1].name}}`
+ );
}
}
@@ -36,16 +39,20 @@ export default class CreateSlashCommands extends BotListener {
await this.client.application.commands.edit(found.id, slashdata);
}
} else {
- console.log('enabled', cmd[1].id);
+ this.client.logger.verbose(
+ `{red Deleted slash command ${cmd[1].id}}`
+ );
await this.client.application.commands.create(slashdata);
}
}
}
- return console.log('Slash commands registered');
+ return this.client.logger.log(chalk.green('Slash commands registered'));
} catch (e) {
- console.log(e);
- return console.log('Slash commands not registered, see above error.');
+ console.log(chalk.red(e));
+ return this.client.logger.error(
+ '{red Slash commands not registered, see above error.}'
+ );
}
}
}
diff --git a/src/listeners/client/ready.ts b/src/listeners/client/ready.ts
index ae510f6..fc43f3c 100644
--- a/src/listeners/client/ready.ts
+++ b/src/listeners/client/ready.ts
@@ -1,3 +1,4 @@
+import chalk from 'chalk';
import { BotListener } from '../../lib/extensions/BotListener';
export default class CommandBlockedListener extends BotListener {
@@ -9,8 +10,9 @@ export default class CommandBlockedListener extends BotListener {
}
public async exec(): Promise<void> {
- await this.client.util.info(
- `Sucessfully logged in as ${this.client.user.tag}`
+ await this.client.logger.log(
+ chalk`{green Sucessfully logged in as {cyan ${this.client.user.tag}}.}`,
+ true
);
}
}
diff --git a/src/listeners/commands/commandstarted.ts b/src/listeners/commands/commandstarted.ts
new file mode 100644
index 0000000..15eea9d
--- /dev/null
+++ b/src/listeners/commands/commandstarted.ts
@@ -0,0 +1,24 @@
+import chalk from 'chalk';
+import { Message, DMChannel } from 'discord.js';
+import { BotCommand } from '../../lib/extensions/BotCommand';
+import { BotListener } from '../../lib/extensions/BotListener';
+
+export default class CommandStartedListener extends BotListener {
+ constructor() {
+ super('logCommands', {
+ emitter: 'commandHandler',
+ event: 'commandStarted'
+ });
+ }
+ exec(message: Message, command: BotCommand): void {
+ this.client.logger.verbose(
+ chalk`{cyan {green ${message.author.tag}} is running {green ${
+ command.aliases[0]
+ }} in {green ${
+ message.channel instanceof DMChannel
+ ? 'DMs'
+ : `#${message.channel.name} (Server: ${message.guild.name})`
+ }}.}`
+ );
+ }
+}
diff --git a/src/listeners/message/levels.ts b/src/listeners/message/levels.ts
index 0767286..9a5fbe8 100644
--- a/src/listeners/message/levels.ts
+++ b/src/listeners/message/levels.ts
@@ -1,3 +1,4 @@
+import chalk from 'chalk';
import { Message } from 'discord.js';
import { BotListener } from '../../lib/extensions/BotListener';
import { Level } from '../../lib/models';
@@ -15,7 +16,8 @@ export default class LevelListener extends BotListener {
if (message.author.bot) return;
if (message.util?.parsed?.command) return;
if (this.levelCooldowns.has(message.author.id)) return;
- if (message.guild.id != '516977525906341928') return;
+ if (!this.client.config.dev && message.guild.id != '516977525906341928')
+ return;
if (this.blacklistedChannels.includes(message.channel.id)) return;
const [user] = await Level.findOrBuild({
where: {
@@ -28,7 +30,9 @@ export default class LevelListener extends BotListener {
const xpToGive = Level.genRandomizedXp();
user.xp += xpToGive;
await user.save();
- console.log(`Gave XP to ${message.author.tag}: ${xpToGive}xp`);
+ await this.client.logger.verbose(
+ chalk`{cyan Gave XP to {green ${message.author.tag}}: {green ${xpToGive}xp}.}`
+ );
this.levelCooldowns.add(message.author.id);
setTimeout(() => this.levelCooldowns.delete(message.author.id), 60_000);
}
diff --git a/src/tasks.ts b/src/tasks.ts
index 69fe97a..d728636 100644
--- a/src/tasks.ts
+++ b/src/tasks.ts
@@ -1,3 +1,4 @@
+import chalk from 'chalk';
import { DiscordAPIError } from 'discord.js';
import { Op } from 'sequelize';
import { BotClient } from './lib/extensions/BotClient';
@@ -15,7 +16,9 @@ export const BanTask = async (client: BotClient): Promise<void> => {
]
}
});
- client.util.devLog(`Queried bans, found ${rows.length} expired bans.`);
+ client.logger.verbose(
+ chalk.cyan(`Queried bans, found ${rows.length} expired bans.`)
+ );
for (const row of rows) {
const guild = client.guilds.cache.get(row.guild);
if (!guild) {
@@ -33,6 +36,6 @@ export const BanTask = async (client: BotClient): Promise<void> => {
} else throw e;
}
await row.destroy();
- client.util.devLog('Unbanned user');
+ client.logger.verbose(chalk.cyan('Unbanned user'));
}
};
diff --git a/yarn.lock b/yarn.lock
index c34cc7e..349f178 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -458,7 +458,7 @@ chalk@^2.0.0:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
-chalk@^4.0.0:
+chalk@^4.0.0, chalk@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad"
integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==