forked from PluralFlux/PluralFlux
separated out commands to be more easily testable and added functionality for aliases
This commit is contained in:
10
src/bot.js
10
src/bot.js
@@ -44,14 +44,20 @@ export const handleMessageCreate = async function(message) {
|
||||
}
|
||||
|
||||
const commandName = content.slice(messageHelper.prefix.length).split(" ")[0];
|
||||
|
||||
// If there's no command name (ie just the prefix)
|
||||
if (!commandName) return await message.reply(enums.help.SHORT_DESC_PLURALFLUX);
|
||||
|
||||
const args = messageHelper.parseCommandArgs(content, commandName);
|
||||
|
||||
const command = commands.get(commandName);
|
||||
let command = commands.commandsMap.get(commandName)
|
||||
if (!command) {
|
||||
const commandFromAlias = commands.aliasesMap.get(commandName);
|
||||
command = commandFromAlias ? commands.commandsMap.get(commandFromAlias.command) : null;
|
||||
}
|
||||
|
||||
if (command) {
|
||||
await command.execute(message, client, args).catch(e => {
|
||||
await command.execute(message, args).catch(e => {
|
||||
throw e
|
||||
});
|
||||
}
|
||||
|
||||
118
src/commands.js
118
src/commands.js
@@ -4,30 +4,50 @@ import {memberHelper} from "./helpers/memberHelper.js";
|
||||
import {EmbedBuilder} from "@fluxerjs/core";
|
||||
import {importHelper} from "./helpers/importHelper.js";
|
||||
|
||||
const cmds = new Map();
|
||||
const cmds = {
|
||||
commandsMap: new Map(),
|
||||
aliasesMap: new Map()
|
||||
};
|
||||
|
||||
cmds.set('member', {
|
||||
cmds.aliasesMap.set('m', {command: 'member'})
|
||||
|
||||
cmds.commandsMap.set('member', {
|
||||
description: enums.help.SHORT_DESC_MEMBER,
|
||||
async execute(message, client, args) {
|
||||
const authorFull = `${message.author.username}#${message.author.discriminator}`
|
||||
const attachmentUrl = message.attachments.size > 0 ? message.attachments.first().url : null;
|
||||
const attachmentExpires = message.attachments.size > 0 ? message.attachments.first().expires_at : null;
|
||||
const reply = await memberHelper.parseMemberCommand(message.author.id, authorFull, args, attachmentUrl, attachmentExpires).catch(async (e) =>{await message.reply(e.message);});
|
||||
if (typeof reply === 'string') {
|
||||
return await message.reply(reply);
|
||||
}
|
||||
else if (reply instanceof EmbedBuilder) {
|
||||
await message.reply({embeds: [reply.toJSON()]})
|
||||
}
|
||||
else if (typeof reply === 'object') {
|
||||
const errorsText = reply.errors.length > 0 ? reply.errors.join('\n- ') : null;
|
||||
return await message.reply({content: `${reply.success} ${errorsText ? "\nThese errors occurred:\n" + errorsText : ""}`, embeds: [reply.embed.toJSON()]})
|
||||
}
|
||||
|
||||
async execute(message, args) {
|
||||
await cmds.memberCommand(message, args)
|
||||
}
|
||||
})
|
||||
|
||||
cmds.set('help', {
|
||||
/**
|
||||
* Calls the member-related functions.
|
||||
*
|
||||
* @async
|
||||
* @param {Message} message - The message object
|
||||
* @param {string[]} args - The parsed arguments
|
||||
*
|
||||
**/
|
||||
cmds.memberCommand = async function(message, args) {
|
||||
const authorFull = `${message.author.username}#${message.author.discriminator}`
|
||||
const attachmentUrl = message.attachments.size > 0 ? message.attachments.first().url : null;
|
||||
const attachmentExpires = message.attachments.size > 0 ? message.attachments.first().expires_at : null;
|
||||
|
||||
const reply = await memberHelper.parseMemberCommand(message.author.id, authorFull, args, attachmentUrl, attachmentExpires).catch(async (e) =>{console.error(e); await message.reply(e.message);});
|
||||
|
||||
if (typeof reply === 'string') {
|
||||
return await message.reply(reply);
|
||||
}
|
||||
else if (reply instanceof EmbedBuilder) {
|
||||
await message.reply({embeds: [reply]})
|
||||
}
|
||||
else if (typeof reply === 'object') {
|
||||
const errorsText = reply.errors.length > 0 ? reply.errors.join('\n- ') : null;
|
||||
return await message.reply({content: `${reply.success} ${errorsText ? "\nThese errors occurred:\n" + errorsText : ""}`, embeds: [reply.embed]})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
cmds.commandsMap.set('help', {
|
||||
description: enums.help.SHORT_DESC_HELP,
|
||||
async execute(message) {
|
||||
const fields = [...cmds.entries()].map(([name, cmd]) => ({
|
||||
@@ -47,32 +67,44 @@ cmds.set('help', {
|
||||
},
|
||||
})
|
||||
|
||||
cmds.set('import', {
|
||||
cmds.commandsMap.set('import', {
|
||||
description: enums.help.SHORT_DESC_IMPORT,
|
||||
async execute(message, client, args) {
|
||||
const attachmentUrl = message.attachments.size > 0 ? message.attachments.first().url : null;
|
||||
if ((message.content.includes('--help') || (args[0] === '' && args.length === 1)) && !attachmentUrl ) {
|
||||
return await message.reply(enums.help.IMPORT);
|
||||
}
|
||||
return await importHelper.pluralKitImport(message.author.id, attachmentUrl).then(async (successfullyAdded) => {
|
||||
await message.reply(successfullyAdded);
|
||||
}).catch(async (error) => {
|
||||
if (error instanceof AggregateError) {
|
||||
// errors.message can be a list of successfully added members, or say that none were successful.
|
||||
let errorsText = `${error.message}.\nThese errors occurred:\n${error.errors.join('\n')}`;
|
||||
|
||||
await message.reply(errorsText).catch(async () => {
|
||||
const returnedBuffer = messageHelper.returnBufferFromText(errorsText);
|
||||
await message.reply({content: returnedBuffer.text, files: [{ name: 'text.pdf', data: returnedBuffer.file }]
|
||||
})
|
||||
});
|
||||
}
|
||||
// If just one error was returned.
|
||||
else {
|
||||
return await message.reply(error.message);
|
||||
}
|
||||
})
|
||||
async execute(message, args) {
|
||||
await cmds.importCommand(message, args);
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Calls the import-related functions.
|
||||
*
|
||||
* @async
|
||||
* @param {Message} message - The message object
|
||||
* @param {string[]} args - The parsed arguments
|
||||
*
|
||||
**/
|
||||
cmds.importCommand = async function(message, args) {
|
||||
const attachmentUrl = message.attachments.size > 0 ? message.attachments.first().url : null;
|
||||
if ((message.content.includes('--help') || (args[0] === '' && args.length === 1)) && !attachmentUrl ) {
|
||||
return await message.reply(enums.help.IMPORT);
|
||||
}
|
||||
return await importHelper.pluralKitImport(message.author.id, attachmentUrl).then(async (successfullyAdded) => {
|
||||
await message.reply(successfullyAdded);
|
||||
}).catch(async (error) => {
|
||||
if (error instanceof AggregateError) {
|
||||
// errors.message can be a list of successfully added members, or say that none were successful.
|
||||
let errorsText = `${error.message}.\n\nThese errors occurred:\n${error.errors.join('\n')}`;
|
||||
|
||||
await message.reply(errorsText).catch(async () => {
|
||||
const returnedBuffer = messageHelper.returnBufferFromText(errorsText);
|
||||
await message.reply({content: returnedBuffer.text, files: [{ name: 'text.pdf', data: returnedBuffer.file }]
|
||||
})
|
||||
});
|
||||
}
|
||||
// If just one error was returned.
|
||||
else {
|
||||
return await message.reply(error.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const commands = cmds;
|
||||
@@ -46,7 +46,12 @@ jest.mock("../src/helpers/utils.js", () => {
|
||||
jest.mock("../src/commands.js", () => {
|
||||
return {
|
||||
commands: {
|
||||
get: jest.fn()
|
||||
commandsMap: {
|
||||
get: jest.fn(),
|
||||
},
|
||||
aliasesMap: {
|
||||
get: jest.fn()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -71,7 +76,6 @@ describe('bot', () => {
|
||||
|
||||
test('on message creation, if message is from bot, return', () => {
|
||||
// Arrange
|
||||
console.log(env)
|
||||
const message = {
|
||||
author: {
|
||||
bot: true
|
||||
@@ -157,7 +161,7 @@ describe('bot', () => {
|
||||
});
|
||||
})
|
||||
|
||||
test("if command after prefix, call parseCommandArgs and commands.get", () => {
|
||||
test("if command after prefix, call parseCommandArgs and commandsMap.get", () => {
|
||||
// Arrange
|
||||
const message = {
|
||||
content: "pf;help",
|
||||
@@ -166,17 +170,71 @@ describe('bot', () => {
|
||||
},
|
||||
reply: jest.fn()
|
||||
}
|
||||
const command = {
|
||||
execute: jest.fn().mockResolvedValue(),
|
||||
}
|
||||
commands.commandsMap.get = jest.fn().mockReturnValue(command);
|
||||
// Act
|
||||
return handleMessageCreate(message).then(() => {
|
||||
// Assert
|
||||
expect(messageHelper.parseCommandArgs).toHaveBeenCalledTimes(1);
|
||||
expect(messageHelper.parseCommandArgs).toHaveBeenCalledWith('pf;help', 'help');
|
||||
expect(commands.get).toHaveBeenCalledTimes(1);
|
||||
expect(commands.get).toHaveBeenCalledWith('help');
|
||||
expect(commands.commandsMap.get).toHaveBeenCalledTimes(1);
|
||||
expect(commands.commandsMap.get).toHaveBeenCalledWith('help');
|
||||
expect(webhookHelper.sendMessageAsMember).not.toHaveBeenCalled();
|
||||
});
|
||||
})
|
||||
|
||||
test('if commands.commandsMap.get returns undefined, call aliasesMap.get and commandsMap.get again with that value', () => {
|
||||
// Arrange
|
||||
const message = {
|
||||
content: "pf;m",
|
||||
author: {
|
||||
bot: false
|
||||
},
|
||||
reply: jest.fn()
|
||||
}
|
||||
const mockAlias = {
|
||||
command: 'member'
|
||||
}
|
||||
commands.commandsMap.get = jest.fn().mockReturnValueOnce();
|
||||
commands.aliasesMap.get = jest.fn().mockReturnValueOnce(mockAlias);
|
||||
// Act
|
||||
return handleMessageCreate(message).then(() => {
|
||||
// Assert
|
||||
expect(commands.commandsMap.get).toHaveBeenCalledTimes(2);
|
||||
expect(commands.commandsMap.get).toHaveBeenNthCalledWith(1, 'm');
|
||||
expect(commands.commandsMap.get).toHaveBeenNthCalledWith(2, 'member');
|
||||
expect(commands.aliasesMap.get).toHaveBeenCalledTimes(1);
|
||||
expect(commands.aliasesMap.get).toHaveBeenCalledWith('m');
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
test('if aliasesMap.get returns undefined, do not call commandsMap again', () => {
|
||||
// Arrange
|
||||
const message = {
|
||||
content: "pf;m",
|
||||
author: {
|
||||
bot: false
|
||||
},
|
||||
reply: jest.fn()
|
||||
}
|
||||
const mockAlias = {
|
||||
command: 'member'
|
||||
}
|
||||
commands.commandsMap.get = jest.fn().mockReturnValueOnce();
|
||||
commands.aliasesMap.get = jest.fn().mockReturnValueOnce();
|
||||
// Act
|
||||
return handleMessageCreate(message).then(() => {
|
||||
// Assert
|
||||
expect(commands.commandsMap.get).toHaveBeenCalledTimes(1);
|
||||
expect(commands.commandsMap.get).toHaveBeenNthCalledWith(1, 'm');
|
||||
expect(commands.aliasesMap.get).toHaveBeenCalledTimes(1);
|
||||
expect(commands.aliasesMap.get).toHaveBeenCalledWith('m');
|
||||
});
|
||||
})
|
||||
|
||||
test("if command exists, call command.execute", () => {
|
||||
// Arrange
|
||||
const message = {
|
||||
@@ -190,14 +248,14 @@ describe('bot', () => {
|
||||
execute: jest.fn()
|
||||
}
|
||||
messageHelper.parseCommandArgs = jest.fn().mockReturnValue(['test']);
|
||||
commands.get = jest.fn().mockReturnValue(command);
|
||||
commands.commandsMap.get = jest.fn().mockReturnValue(command);
|
||||
command.execute = jest.fn().mockResolvedValue();
|
||||
|
||||
// Act
|
||||
return handleMessageCreate(message).then(() => {
|
||||
// Assert
|
||||
expect(command.execute).toHaveBeenCalledTimes(1);
|
||||
expect(command.execute).toHaveBeenCalledWith(message, client, ['test']);
|
||||
expect(command.execute).toHaveBeenCalledWith(message, ['test']);
|
||||
expect(webhookHelper.sendMessageAsMember).not.toHaveBeenCalled();
|
||||
});
|
||||
})
|
||||
@@ -211,7 +269,6 @@ describe('bot', () => {
|
||||
command.execute.mockImplementation(() => {
|
||||
throw Error("error")
|
||||
});
|
||||
// Arrange
|
||||
const message = {
|
||||
content: "pf;member test",
|
||||
author: {
|
||||
@@ -232,7 +289,8 @@ describe('bot', () => {
|
||||
|
||||
test("if command does not exist, return correct enum", () => {
|
||||
// Arrange
|
||||
commands.get = jest.fn().mockReturnValue();
|
||||
commands.commandsMap.get = jest.fn().mockReturnValue();
|
||||
commands.aliasesMap.get = jest.fn().mockReturnValue();
|
||||
const message = {
|
||||
content: "pf;asdfjlas",
|
||||
author: {
|
||||
|
||||
Reference in New Issue
Block a user