From 3296bc3d4e109c4b03a81a74361c22de11e86653 Mon Sep 17 00:00:00 2001 From: "Toe, Knee" Date: Fri, 27 Jul 2018 19:11:41 +1000 Subject: [PATCH 01/15] Minor fixes await functions --- src/command/DefaultCommands.ts | 16 ++++++++-------- src/command/ShopCommand.ts | 6 +++--- src/core/FortniteBotCore.ts | 2 +- src/database/GlobalCollection.ts | 9 ++++++++- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/command/DefaultCommands.ts b/src/command/DefaultCommands.ts index 83207c8..c09f306 100644 --- a/src/command/DefaultCommands.ts +++ b/src/command/DefaultCommands.ts @@ -163,8 +163,8 @@ const auto = { max: 1, time: 300000, errors: ["time"] - }).then(() => { - if (m.content.toLowerCase() === "yes") { + }).then((response) => { + if (response.first().content === "yes") { db.collections.user.incrementCoin(id, "DotmaCoin", -price, (c: boolean) => { if (!c) { @@ -179,8 +179,7 @@ const auto = { self.loop.startLoop(); self.looping = true; }); - - } else if (m.content.toLowerCase() === "no") { + } else if (response.first().content === "no") { m.channel.send("Okey."); } @@ -224,11 +223,11 @@ const addTarget = new FortniteBotAction(1, m.channel.awaitMessages(() => { return state.updateHandle().author.id === id; }, { - max: 5, + max: 1, time: 300000, errors: ["time"] - }).then(() => { - if (m.content.toLowerCase() === "yes") { + }).then((response) => { + if (response.first().content === "yes") { m.channel.send("Okey, adding you as a target."); activeCore.getDbCore().collections.global.add(id, (c: boolean) => { @@ -238,7 +237,7 @@ const addTarget = new FortniteBotAction(1, m.channel.send("Failed to add as target."); } }); - } else if (m.content.toLowerCase() === "no") { + } else if (response.first().content === "no") { m.channel.send("Okey."); } }).catch(() => { @@ -250,6 +249,7 @@ const addTarget = new FortniteBotAction(1, const getTargetList = new FortniteBotAction(0, (state: FortniteBotState) => { activeCore.getDbCore().collections.global.get((res) => { + console.log(res); const m: Discord.Message = state.getHandle(); let userlist = "```Current Targets: (" + res[0].targets.length + ")\n"; for (const id of res[0].targets) { diff --git a/src/command/ShopCommand.ts b/src/command/ShopCommand.ts index a98059a..ac8e495 100644 --- a/src/command/ShopCommand.ts +++ b/src/command/ShopCommand.ts @@ -145,9 +145,9 @@ const buy = new FortniteBotAction(0, max: 1, time: 300000, errors: ["time"] - }).then(() => { + }).then((response) => { m = state.updateHandle(); - if (m.content.toLowerCase() === "yes") { + if (response.first().content === "yes") { m.channel.send("Buying..."); db.collections.user.getUser(m.author.id, (u: User) => { if (!u) { @@ -165,7 +165,7 @@ const buy = new FortniteBotAction(0, m.channel.send("Purchase Complete!"); }); }); - } else if (m.content.toLowerCase() === "no") { + } else if (response.first().content === "no") { m.channel.send("Okey."); } }).catch(() => { diff --git a/src/core/FortniteBotCore.ts b/src/core/FortniteBotCore.ts index 5d54c17..1a2426d 100644 --- a/src/core/FortniteBotCore.ts +++ b/src/core/FortniteBotCore.ts @@ -27,7 +27,7 @@ export class FortniteBotCore { this.bot.login(this.initConfig.botToken); this.bot.on("ready", () => { this.eventCore.listenMessages(); - this.bot.user.setGame("Brad's Weight: 214.23kg"); + this.bot.user.setActivity("Brad's Weight: 214.23kg"); }); const db = this.DbCore.getDb(); }); diff --git a/src/database/GlobalCollection.ts b/src/database/GlobalCollection.ts index 76e566c..b238684 100644 --- a/src/database/GlobalCollection.ts +++ b/src/database/GlobalCollection.ts @@ -10,7 +10,14 @@ export class GlobalCollection extends FrotniteBotCollection implements ICollecti constructor(localDb: any) { super(); this.localDb = localDb; - this.dbId = new MongoDb.ObjectId("5b253b8cb43a095ddc7ff9a7"); + this.dbId = new MongoDb.ObjectId("5b5adfbcfe69061b34ba342c"); + } + public createSchema(): void { + this.db.collection("global").insertOne({targets: []}, (err) => { + if (err) { + throw new DatabaseException(err); + } + }); } public add(id: string, callback: (res: boolean) => void): void { this.db.collection("global").updateOne({_id: this.dbId}, From 7aa4d53685eef48bce448089e95b8f51d11a1747 Mon Sep 17 00:00:00 2001 From: "Toe, Knee" Date: Fri, 27 Jul 2018 19:11:49 +1000 Subject: [PATCH 02/15] Added optional welcome message --- src/shop/Shop.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/shop/Shop.ts b/src/shop/Shop.ts index c32a55a..88edd6f 100644 --- a/src/shop/Shop.ts +++ b/src/shop/Shop.ts @@ -5,10 +5,11 @@ export class Shop { public inventory: Item[]; public name: string; public description?: string; - public allowDiscounts: boolean; + public welcomeMessage?: string; + public allowDiscounts?: boolean; private coinType: string; constructor(name: string, coinType: string, allowDiscounts?: boolean, - description?: string) { + description?: string, welcomeMessage?: string) { this.name = name; this.coinType = coinType; this.description = description; From 8798ceb15f51ad17a70e1743ec1e850364f4366f Mon Sep 17 00:00:00 2001 From: "Toe, Knee" Date: Fri, 27 Jul 2018 19:17:12 +1000 Subject: [PATCH 03/15] Fixed empty target list --- src/command/DefaultCommands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/command/DefaultCommands.ts b/src/command/DefaultCommands.ts index c09f306..c243be4 100644 --- a/src/command/DefaultCommands.ts +++ b/src/command/DefaultCommands.ts @@ -45,7 +45,7 @@ const sendDefaultText = (state: FortniteBotState): void => { } }); } - targetString += " fortnite?"; + targetString += res[0].targets.length === 0 ? "<@!458602122540220416> fortnite?" : "fortnite?"; m.channel.send(targetString); }); }; From f15fc31882f5963118c071c5ee20ace30e2c3b87 Mon Sep 17 00:00:00 2001 From: "Toe, Knee" Date: Fri, 27 Jul 2018 21:49:00 +1000 Subject: [PATCH 04/15] Added docstrings --- src/action/FortniteBotAction.ts | 20 ++++++ src/action/FortniteBotTrigger.ts | 10 +++ src/action/RequestResponseAction.ts | 5 ++ src/command/AutoTriggerCommand.ts | 19 ++++-- src/command/Command.ts | 33 +++++++++- src/command/CommandManager.ts | 56 +++++++++++++++- src/command/DebugCommand.ts | 6 ++ src/command/DefaultCommands.ts | 5 ++ src/command/ExecutableCommand.ts | 10 +-- src/command/ICommand.ts | 14 ++++ src/command/RequireResponseCommand.ts | 11 ++++ src/command/ShopCommand.ts | 4 ++ src/command/UserCommands.ts | 4 ++ src/config/FortniteBotCommandConfig.ts | 24 +++++++ src/config/FortniteBotDbConfig.ts | 8 +++ src/config/FortniteBotInitConfig.ts | 18 +++++ src/core/FortniteBotCore.ts | 63 ++++++++++++++++++ src/core/FortniteBotDbCore.ts | 32 ++++++++- src/core/FortniteBotEventCore.ts | 33 ++++++++++ src/database/FortniteBotCollection.ts | 9 ++- src/database/GlobalCollection.ts | 49 +++++++++++++- src/database/ICollection.ts | 5 +- src/database/UserCollection.ts | 65 ++++++++++++++++++- src/exceptions/DatabaseException.ts | 4 ++ src/exceptions/FortniteBotException.ts | 6 ++ .../UnauthorizedCommandException.ts | 5 ++ src/shop/IItem.ts | 3 + src/shop/Item.ts | 26 ++++++++ src/shop/Shop.ts | 51 +++++++++++++++ src/shop/Shops.ts | 4 ++ src/shop/Title.ts | 6 ++ src/state/CommandExecutionState.ts | 4 ++ src/state/FortniteBotState.ts | 22 +++++++ src/state/PendingResponseState.ts | 4 ++ src/user/IUser.ts | 14 ++++ src/user/User.ts | 33 ++++++++++ src/utils/CommandUtil.ts | 5 ++ src/utils/Loop.ts | 20 ++++++ 38 files changed, 689 insertions(+), 21 deletions(-) diff --git a/src/action/FortniteBotAction.ts b/src/action/FortniteBotAction.ts index d74e36e..1de3269 100644 --- a/src/action/FortniteBotAction.ts +++ b/src/action/FortniteBotAction.ts @@ -1,14 +1,34 @@ import { FortniteBotState } from "../state/FortniteBotState"; export class FortniteBotAction { + /** + * Number of arguments this action requires. + */ public argLength: number; + + /** + * An action to invoke. + */ public action: (stateHandle: FortniteBotState, args: string[]) => boolean; + + /** + * @classdesc Base class for a standard action executed by the bot. + * @param argLength - Number of arguments the action requires. + * @param action - An action to invoke. + */ public constructor(argLength: number, action: (stateHandle: FortniteBotState, args: string[]) => boolean) { this.argLength = argLength; this.action = action; } + + /** + * Executes the action with a set of arguments. + * @param state - A Handle for the action to bind to. + * @param args - Arguments to execute the action with. + * @returns true if the command was successfully executed. + */ public execute(state: FortniteBotState, args: string[]): boolean { return this.action(state, args); } diff --git a/src/action/FortniteBotTrigger.ts b/src/action/FortniteBotTrigger.ts index 88e40f4..efaa7fd 100644 --- a/src/action/FortniteBotTrigger.ts +++ b/src/action/FortniteBotTrigger.ts @@ -2,9 +2,19 @@ import { FortniteBotAction } from "./FortniteBotAction"; import { FortniteBotState } from "../state/FortniteBotState"; export class FortniteBotTrigger extends FortniteBotAction { + /** + * @classdesc Base trigger class, invokes an FortniteBotAction if conditions are met. + * @param trigger - A trigger to invoke, returns true if conditions are met. + */ public constructor(trigger: (state: FortniteBotState) => boolean) { super(0, trigger); } + + /** + * Attempt to execute the trigger. + * @param state A Handle for the trigger to bind to. + * @returns true if the command was successfully executed. + */ public execute(state: FortniteBotState): boolean { return super.execute(state, null); } diff --git a/src/action/RequestResponseAction.ts b/src/action/RequestResponseAction.ts index 32f142a..612523c 100644 --- a/src/action/RequestResponseAction.ts +++ b/src/action/RequestResponseAction.ts @@ -2,6 +2,11 @@ import { FortniteBotState } from "../state/FortniteBotState"; import { FortniteBotAction } from "./FortniteBotAction"; export class RequestResponseAction extends FortniteBotAction { + /** + * @classdesc An action which requires a user response. + * @param argLength - Number of arguments the action requires. + * @param action - An action to invoke. + */ public constructor(argLength: number, action: (stateHandle: FortniteBotState, args: string[]) => boolean) { diff --git a/src/command/AutoTriggerCommand.ts b/src/command/AutoTriggerCommand.ts index 1097edf..9a098ff 100644 --- a/src/command/AutoTriggerCommand.ts +++ b/src/command/AutoTriggerCommand.ts @@ -4,17 +4,28 @@ import { FortniteBotAction } from "action/FortniteBotAction"; import { FortniteBotTrigger } from "action/FortniteBotTrigger"; import { fortniteBotCore as activeCore } from "../../fortniteBot"; -/** - * Commands which are auto triggered. - */ - export class AutoTriggerCommand extends Command implements ICommand { + /** + * The condition required to execute the action. + */ public trigger: FortniteBotTrigger; + + /** + * @classdesc Commands which are triggered without user directly calling it. + * @param accessLevel - The required access level to execute this command. + * @param action - The action to execute. + * @param trigger - The condition required to execute the action. + */ public constructor(accessLevel: number, action: FortniteBotAction, trigger: FortniteBotTrigger) { super(null, accessLevel, action); this.trigger = trigger; } + + /** + * Attempt to execute the trigger. + * @returns true if conditions of the trigger has been met. + */ public tryTrigger(): boolean { return this.trigger.execute(activeCore.getCoreState()); } diff --git a/src/command/Command.ts b/src/command/Command.ts index 9767ad2..8ccd743 100644 --- a/src/command/Command.ts +++ b/src/command/Command.ts @@ -8,21 +8,52 @@ import { fortniteBotCore } from "../../fortniteBot"; import { fortniteBotCore as activeCore } from "../../fortniteBot"; export class Command implements ICommand { + /** + * The string required to execute this command. + */ public commandString?: string; + + /** + * The required access level to execute this command. + */ public readonly accessLevel: number; + + /** + * An action to execute. + */ public action: FortniteBotAction; + + /** + * Arguments to execute the action with. + */ public args: string[]; + + /** + * @classdesc Base command class for the bot. + * @param commandString - The string required to execute this command. + * @param accessLevel - The required access level to execute this command. + * @param action - The action to execute. + */ public constructor(commandString: string, accessLevel: number, action: FortniteBotAction) { this.action = action; this.accessLevel = accessLevel; this.commandString = commandString; } + + /** + * Changes the arguments of the command. + * @param args - New arguments for the command. + */ public setArgs(args: string[]): void { this.args = args; } - public executeAction(user: User): void { + /** + * Execute the action provided by this command. + * @param user - The user attempting to execute this command. + */ + public executeAction(user: User): void { if (user.accessLevel < this.accessLevel) { const m = activeCore.getCoreState().getHandle() as Discord.Message; m.reply( diff --git a/src/command/CommandManager.ts b/src/command/CommandManager.ts index 7c55a12..3d01a48 100644 --- a/src/command/CommandManager.ts +++ b/src/command/CommandManager.ts @@ -6,8 +6,20 @@ import { FortniteBotException } from "../exceptions/FortniteBotException"; import { fortniteBotCore as activeCore } from "../../fortniteBot"; export class CommandManager { + /** + * Set of all commands. + */ public commands: Command[]; + + /** + * The prefix required to begin calling a command. + */ private prefix: FortniteBotCommandConfig; + + /** + * @classdesc Class to handle import and execution of commands. + * @param commands - Set of initial commands to be loaded in to memory. + */ public constructor(commands?: Command[]) { this.commands = commands; this.prefix = new FortniteBotCommandConfig( @@ -16,16 +28,32 @@ export class CommandManager { ] ); } - public addCommand(command: Command) { + + /** + * Loads a single command. + * @param command - The command to load. + */ + public addCommand(command: Command): void { if (!this.commandExists(command.commandString)) { this.commands.push(command); } } - public addBulkCommand(commands: Command[]) { + + /** + * Loads a array of commands. + * @param commands - The set of commands to load. + */ + public addBulkCommand(commands: Command[]): void { for (const command of commands) { this.addCommand(command); } } + + /** + * Listens for channel messages and attempts to run a command by invoking its action or trigger. + * @param line - The channel message to evaluate. + * @param id - The discord id of the user invoking the command. + */ public attemptExecution(line: string, id: string): void { this.triggerAction(id); const commandString = this.extractCommand(line); @@ -70,14 +98,32 @@ export class CommandManager { } } } + + /** + * Extracts the command name from a message. + * @param line - The channel message to evaluate. + * @returns The command string for a command. + */ public extractCommand(line: string): string { return line.split(" ")[1] ? line.split(" ")[1] : " "; } + + /** + * Extracts the arguments provided for a command. + * @param line - line - The channel message to evaluate. + * @param amount - The amount of arguments to extract. + * @returns A array of arguments for the command. + */ public extractArguments(line: string, amount: number): string[] { return amount === 0 ? line.split(" ").splice(2, line.split(" ").length) : line.split(" ").splice(2, amount); } + + /** + * Attempt to invoke the action by testing if the trigger conditions are met. + * @param id - The discord id of the user invoking the command. + */ public triggerAction(id: string): void { for (const command of this.commands) { if (command instanceof AutoTriggerCommand) { @@ -94,6 +140,12 @@ export class CommandManager { } } } + + /** + * Checks if a command has already been loaded. + * @param name - The name of the command. + * @returns true if commands exists, false otherwise. + */ private commandExists(name: string): boolean { if (Object.keys(this.commands).length > 1) { for (const command of this.commands) { diff --git a/src/command/DebugCommand.ts b/src/command/DebugCommand.ts index 24799cb..3f10e08 100644 --- a/src/command/DebugCommand.ts +++ b/src/command/DebugCommand.ts @@ -3,6 +3,12 @@ import { ExecutableCommand } from "./ExecutableCommand"; import { FortniteBotAction } from "action/FortniteBotAction"; export class DebugCommand extends ExecutableCommand implements ICommand { + + /** + * @classdesc Debug commands for testing purposes. + * @param commandString - The string required to execute this command. + * @param action - The action to execute. + */ public constructor(commandString: string, action: FortniteBotAction) { super(commandString, 3, action); } diff --git a/src/command/DefaultCommands.ts b/src/command/DefaultCommands.ts index c243be4..25faeb3 100644 --- a/src/command/DefaultCommands.ts +++ b/src/command/DefaultCommands.ts @@ -14,6 +14,11 @@ import { Loop } from "../utils/Loop"; import { User } from "../user/User"; import { getId } from "../utils/CommandUtil"; import { config as dotenvConfig } from "dotenv"; + +/** + * Default commands ported over from v1. + */ + dotenvConfig(); const chatBot = new Chatbot(process.env.chatBotUserId, process.env.chatBotApiKey); diff --git a/src/command/ExecutableCommand.ts b/src/command/ExecutableCommand.ts index 7c9ffda..54eb444 100644 --- a/src/command/ExecutableCommand.ts +++ b/src/command/ExecutableCommand.ts @@ -2,11 +2,13 @@ import { ICommand } from "../command/ICommand"; import { Command } from "../command/Command"; import { FortniteBotAction } from "../action/FortniteBotAction"; -/** - * Commands which must be executed by a user to run. - */ - export class ExecutableCommand extends Command implements ICommand { + /** + * @classdesc Commands which must be executed by a user to run. + * @param commandString - The string required to execute this command. + * @param accessLevel - The required access level to execute this command. + * @param action - The action to execute. + */ public constructor(commandString: string, accessLevel: number, action: FortniteBotAction) { super(commandString, accessLevel, action); diff --git a/src/command/ICommand.ts b/src/command/ICommand.ts index 3bb90cb..0fd25ef 100644 --- a/src/command/ICommand.ts +++ b/src/command/ICommand.ts @@ -1,7 +1,21 @@ import { FortniteBotAction } from "../action/FortniteBotAction"; +/** + * Interface for all fortniteBot commands. + */ export interface ICommand { + /** + * The name of the command. + */ command?: string; + + /** + * The access level required to execute the command. + */ accessLevel: number; + + /** + * An action to invoke when the command is called. + */ action: FortniteBotAction; } diff --git a/src/command/RequireResponseCommand.ts b/src/command/RequireResponseCommand.ts index 1e85bd7..c9576bc 100644 --- a/src/command/RequireResponseCommand.ts +++ b/src/command/RequireResponseCommand.ts @@ -7,10 +7,21 @@ import { fortniteBotCore as activeCore } from "../../fortniteBot"; export class RequireResponseCommand extends ExecutableCommand implements ICommand { + /** + * @classdesc Commands which require a user response. + * @param commandString - The string required to execute this command. + * @param accessLevel - The required access level to execute this command. + * @param action - The action to execute. + */ public constructor(commandString: string, accessLevel: number, action: FortniteBotAction) { super(commandString, accessLevel, action); } + + /** + * Execute the action provided by this command. Changes the core state. + * @param user - The user attempting to execute this command. + */ public executeAction(user: User): void { activeCore.changeCoreState(new PendingResponseState(null)); super.executeAction(user); diff --git a/src/command/ShopCommand.ts b/src/command/ShopCommand.ts index ac8e495..67d1b32 100644 --- a/src/command/ShopCommand.ts +++ b/src/command/ShopCommand.ts @@ -16,6 +16,10 @@ import { Shops } from "../shop/Shops"; import { Item } from "../shop/Item"; import { getId } from "../utils/CommandUtil"; +/** + * Commands which deal with shop interfaces. + */ + const shopList = new FortniteBotAction(0, (state: FortniteBotState, args: string[]) => { const m = (state.getHandle() as Discord.Message); diff --git a/src/command/UserCommands.ts b/src/command/UserCommands.ts index 4637e60..59cebf0 100644 --- a/src/command/UserCommands.ts +++ b/src/command/UserCommands.ts @@ -13,6 +13,10 @@ import { Loop } from "../utils/Loop"; import { User } from "../user/User"; import { getId } from "../utils/CommandUtil"; +/** + * Commands which deal with the user. + */ + const register = new FortniteBotAction(0, (state: FortniteBotState) => { const m: Discord.Message = state.getHandle(); const id = m.author.id; diff --git a/src/config/FortniteBotCommandConfig.ts b/src/config/FortniteBotCommandConfig.ts index 4db6dcc..564ea4c 100644 --- a/src/config/FortniteBotCommandConfig.ts +++ b/src/config/FortniteBotCommandConfig.ts @@ -1,8 +1,22 @@ export class FortniteBotCommandConfig { + /** + * An array of prefixes accepted by the bot. + */ private prefix: string[]; + + /** + * @classdesc Initial configuration for commands. + * @param prefix - The array of prefixes used to call commands. + */ public constructor(prefix: string[]) { this.prefix = prefix; } + + /** + * Adds a prefix. + * @param prefix - The prefix to add. + * @returns true if successfully added. + */ public addPrefix(prefix: string): boolean { if (prefix as any instanceof String) { this.prefix.push(prefix); @@ -10,6 +24,12 @@ export class FortniteBotCommandConfig { } return false; } + + /** + * Removes a prefix. + * @param prefix - The prefix to remove. + * @returns true if successfully removed. + */ public removePrefix(prefix: string): boolean { const index = this.prefix.indexOf(prefix); if (index > -1) { @@ -18,6 +38,10 @@ export class FortniteBotCommandConfig { } return false; } + + /** + * @return The array of prefixes. + */ public getPrefix(): string[] { return this.prefix; } diff --git a/src/config/FortniteBotDbConfig.ts b/src/config/FortniteBotDbConfig.ts index 246eb43..7710dfa 100644 --- a/src/config/FortniteBotDbConfig.ts +++ b/src/config/FortniteBotDbConfig.ts @@ -1,5 +1,13 @@ export class FortniteBotDbConfig { + /** + * The url to the database + */ public readonly url: string; + + /** + * @classdesc Initial configuration for databases. + * @param host - The host string of the database. + */ constructor(host: string) { this.url = host + "fortniteBotDb"; } diff --git a/src/config/FortniteBotInitConfig.ts b/src/config/FortniteBotInitConfig.ts index 81d951c..04df841 100644 --- a/src/config/FortniteBotInitConfig.ts +++ b/src/config/FortniteBotInitConfig.ts @@ -1,7 +1,25 @@ export class FortniteBotInitConfig { + /** + * Discord Token for the bot user. + */ public readonly botToken: string; + + /** + * Chatbot user ID. + */ public readonly chatBotUserId: string; + + /** + * Chatbot API key. + */ public readonly chatBotAPIKey: string; + + /** + * Initial configurations for the bot. + * @param botToken - Discord Token for the bot user. + * @param charBotUserId - Chatbot user ID. + * @param chatBotAPIKey - Chatbot API key. + */ public constructor(botToken: string, charBotUserId: string, chatBotAPIKey: string) { this.botToken = botToken; diff --git a/src/core/FortniteBotCore.ts b/src/core/FortniteBotCore.ts index 1a2426d..3460911 100644 --- a/src/core/FortniteBotCore.ts +++ b/src/core/FortniteBotCore.ts @@ -8,11 +8,35 @@ import { FortniteBotDbCore } from "./FortniteBotDbCore"; import { FortniteBotDbConfig } from "../config/FortniteBotDbConfig"; export class FortniteBotCore { + /** + * Main interface with Discord.js + */ public bot: Discord.Client; + + /** + * Current state of the bot. + */ private coreState: FortniteBotState; + + /** + * Initial configurations loaded in to the bot. + */ private initConfig: FortniteBotInitConfig; + + /** + * Main event handlers for the bot. + */ private eventCore: FortniteBotEventCore; + + /** + * Main database methods for the bot. + */ private DbCore: FortniteBotDbCore; + + /** + * @classdesc The main class of the bot. Initializes most of the main methods. + * @param initConfig - Initial configurations to load in to the bot. + */ public constructor(initConfig: FortniteBotInitConfig) { dotenvConfig(); this.initConfig = initConfig; @@ -21,6 +45,11 @@ export class FortniteBotCore { const dbConfig = new FortniteBotDbConfig(process.env.dbIp); this.DbCore = new FortniteBotDbCore(dbConfig); } + + /** + * Start the main processes of the bot. + * @returns The current instance of the core. + */ public start(): FortniteBotCore { try { this.DbCore.connectDb(() => { @@ -38,29 +67,63 @@ export class FortniteBotCore { } return this; } + + /** + * @returns The event core of the bot. + */ public getEventCore(): FortniteBotEventCore { return this.eventCore; } + + /** + * @returns The db core of the bot. + */ public getDbCore(): FortniteBotDbCore { return this.DbCore; } + + /** + * Changes the current state the bot is in. Handle is preserved. + * @param coreState - New state for the bot. + */ public changeCoreState(coreState: FortniteBotState): void { const newState = coreState; newState.setHandle(this.getCoreState().getHandle()); this.setCoreState(newState); } + + /** + * Changes the current state the bot is in. + * @param coreState - New state for the bot. + */ public setCoreState(coreState: FortniteBotState): void { this.coreState = coreState; } + + /** + * @returns The current state of the bot. + */ public getCoreState(): FortniteBotState { return this.coreState; } + + /** + * Clears the state of the bot. + */ public clearState(): void { this.coreState = null; } + + /** + * Clears initial configurations loaded in the bot. + */ public clearInitConfig(): void { this.initConfig = null; } + + /** + * Clears the discordAPI. + */ public clearDiscordAPI(): void { this.bot = null; if (this.eventCore) { diff --git a/src/core/FortniteBotDbCore.ts b/src/core/FortniteBotDbCore.ts index 56b0f75..0232b74 100644 --- a/src/core/FortniteBotDbCore.ts +++ b/src/core/FortniteBotDbCore.ts @@ -6,14 +6,29 @@ import { GlobalCollection } from "../database/GlobalCollection"; import { UserCollection } from "../database/UserCollection"; export class FortniteBotDbCore { + /** + * Collections which store other forms of data. + */ public collections: { global: GlobalCollection; user: UserCollection; }; - public GlobalCollection: GlobalCollection; + + /** + * Database configurations. + */ private readonly config: FortniteBotDbConfig; + + /** + * Database object to interact with. + */ private database: MongoDb.MongoClient; private db: MongoDb.Db; + + /** + * @classdesc Class for handling important database methods. + * @param config - Initial database configurations. + */ constructor(config: FortniteBotDbConfig) { this.config = config; this.collections = { @@ -21,6 +36,11 @@ export class FortniteBotDbCore { user: null }; } + + /** + * Attempts to connect to the host. + * @param callback - callback when database has been connected. + */ public connectDb(callback: () => void): void { MongoClient.connect(this.config.url, (err, database) => { if (err) { @@ -34,12 +54,20 @@ export class FortniteBotDbCore { this.db.collection("user").find().toArray().then((res) => { this.collections.user = new UserCollection(res); }); - callback(); + callback(); // Todo async.parallel }); } + + /** + * Gets the current database. + */ public getDb(): MongoDb.Db { return this.db; } + + /** + * Closes connection to the host of the db. + */ public closeDb(): void { this.database.close(); } diff --git a/src/core/FortniteBotEventCore.ts b/src/core/FortniteBotEventCore.ts index 550f2a5..d4dcfeb 100644 --- a/src/core/FortniteBotEventCore.ts +++ b/src/core/FortniteBotEventCore.ts @@ -8,10 +8,30 @@ import { User } from "../user/User"; import { shopCommands } from "../command/ShopCommand"; export class FortniteBotEventCore { + /** + * Main core of the bot. + */ private core: FortniteBotCore; + + /** + * Main interface with Discord.js + */ private client: Discord.Client; + + /** + * Current state handler for events. + */ private currentHandles: any; + + /** + * The command manager to handle commands execution. + */ private commandManager: CommandManager; + + /** + * @classdesc Class for handling events. + * @param core - The main bot core. + */ public constructor(core: FortniteBotCore) { this.core = core; this.client = core.bot; @@ -20,6 +40,10 @@ export class FortniteBotEventCore { this.commandManager.addBulkCommand(shopCommands); this.currentHandles = {}; } + + /** + * Begin listening for channel messages. + */ public listenMessages(): void { this.client.on("message", (message) => { this.currentHandles.message = message; @@ -30,9 +54,18 @@ export class FortniteBotEventCore { } }); } + + /** + * Gets the current event handles. + * @returns The current event handles. + */ public getHandles(): any { return this.currentHandles; } + + /** + * Clears the discordAPI. + */ public clearClient(): void { this.client = null; } diff --git a/src/database/FortniteBotCollection.ts b/src/database/FortniteBotCollection.ts index 5bf7caf..a074814 100644 --- a/src/database/FortniteBotCollection.ts +++ b/src/database/FortniteBotCollection.ts @@ -1,8 +1,15 @@ import * as MongoDb from "mongodb"; import { fortniteBotCore as activeCore } from "../../fortniteBot"; -export class FrotniteBotCollection { +export class FortniteBotCollection { + /** + * Main database object. + */ protected db: MongoDb.Db; + + /** + * @classdesc Main data collection for the bot. + */ constructor() { this.db = activeCore.getDbCore().getDb(); } diff --git a/src/database/GlobalCollection.ts b/src/database/GlobalCollection.ts index b238684..c820a2a 100644 --- a/src/database/GlobalCollection.ts +++ b/src/database/GlobalCollection.ts @@ -1,24 +1,51 @@ import * as MongoDb from "mongodb"; import { fortniteBotCore as activeCore } from "../../fortniteBot"; import { DatabaseException } from "../exceptions/DatabaseException"; -import { FrotniteBotCollection } from "./FortniteBotCollection"; +import { FortniteBotCollection } from "./FortniteBotCollection"; import { ICollection } from "./ICollection"; -export class GlobalCollection extends FrotniteBotCollection implements ICollection { +export class GlobalCollection extends FortniteBotCollection implements ICollection { + /** + * The local database for this collection. + */ private localDb: any; + + /** + * The id of the collection. + */ private dbId: MongoDb.ObjectId; + + /** + * @classdesc Collection of global values and objects. + * @param localDb - The local database for this collection. + */ constructor(localDb: any) { super(); this.localDb = localDb; this.dbId = new MongoDb.ObjectId("5b5adfbcfe69061b34ba342c"); } + + /** + * Sets up the required fields for operation. + */ public createSchema(): void { this.db.collection("global").insertOne({targets: []}, (err) => { if (err) { throw new DatabaseException(err); } }); + this.db.collection("global").insertOne({lastUpdate: new Date()}, (err) => { + if (err) { + throw new DatabaseException(err); + } + }); } + + /** + * Adds a object to an array currently in the DB. + * @param id - The id to add. + * @param callback - Callback true if update success. + */ public add(id: string, callback: (res: boolean) => void): void { this.db.collection("global").updateOne({_id: this.dbId}, {$push: { targets: id }}, (err) => { @@ -29,11 +56,23 @@ export class GlobalCollection extends FrotniteBotCollection implements ICollecti callback(true); }); } + + /** + * Gets the collection. + * @param callback - Callback the results of the collection. + */ public get(callback: (res: any[]) => void): void { this.db.collection("global").find({}).toArray().then((res: any) => { callback(res); }); } + + /** + * Updates a specific field with an value + * @param field - The field to update. + * @param value - The new value. + * @param callback - Callback true if updated successfully. + */ public update(field: string, value: any, callback: (res: boolean) => void): void { const set = {}; @@ -47,6 +86,12 @@ export class GlobalCollection extends FrotniteBotCollection implements ICollecti callback(true); }); } + + /** + * Removes a user from the target array. + * @param id - The id of the user to remove. + * @param callback - Callback true if removed successfully. + */ public removeTarget(id: string, callback: (res: boolean) => void): void { this.db.collection("global").updateOne({_id: this.dbId}, {$pull: { targets: id }}, (err) => { diff --git a/src/database/ICollection.ts b/src/database/ICollection.ts index 6d2926f..6d6b453 100644 --- a/src/database/ICollection.ts +++ b/src/database/ICollection.ts @@ -1,5 +1,6 @@ -import * as MongoDb from "mongodb"; - +/** + * Collection interface. + */ export interface ICollection { add(obj: any, callback: (res: boolean) => void): void; get(callback: (res: any[]) => void): void; diff --git a/src/database/UserCollection.ts b/src/database/UserCollection.ts index e856526..5b06c4e 100644 --- a/src/database/UserCollection.ts +++ b/src/database/UserCollection.ts @@ -1,15 +1,28 @@ import * as MongoDb from "mongodb"; import { DatabaseException } from "../exceptions/DatabaseException"; -import { FrotniteBotCollection } from "./FortniteBotCollection"; +import { FortniteBotCollection } from "./FortniteBotCollection"; import { ICollection } from "./ICollection"; import { User } from "../user/User"; -export class UserCollection extends FrotniteBotCollection implements ICollection { +export class UserCollection extends FortniteBotCollection implements ICollection { + /** + * The local database for this collection. + */ private localDb: any; + /** + * @classdesc Collection of user objects. + * @param localDb - The local database for this collection. + */ constructor(localDb: any) { super(); this.localDb = localDb; } + + /** + * Adds a user to the collection. + * @param user - The user to add to the collection. + * @param callback - Callback true if successfully added. + */ public add(user: User, callback: (res: boolean) => void): void { this.db.collection("user").insert(user, (err) => { if (err) { @@ -19,11 +32,22 @@ export class UserCollection extends FrotniteBotCollection implements ICollection callback(true); }); } + + /** + * Gets the collection. + * @param callback - Callback the results of the collection. + */ public get(callback: (res: any[]) => void): void { this.db.collection("user").find({}).toArray().then((res: any) => { callback(res); }); } + + /** + * Retrieves the data of a user by their id. + * @param id - The id of the user. + * @param callback - Callback data of the user. + */ public getUser(id: string, callback: (user: User) => void): void { this.get((res: User[]) => { const index = res.findIndex((user: User) => user.id === id); @@ -34,11 +58,26 @@ export class UserCollection extends FrotniteBotCollection implements ICollection callback(res[index]); }); } + + /** + * Updates a user by their id. + * @param id - The id of the user to update. + * @param user - The new entries for the user. + * @param callback - true if successfully updated. + */ public updateUser(id: string, user: User, callback: (res: boolean) => void) { - + // Todo return; } + + /** + * Updates a specific field of a user. + * @param userId - The id of the user to update. + * @param field - The field to update. + * @param value - The new value for the field. + * @param callback - Callback true if successfully updated. + */ public update(userId: string, field: string, value: any, callback: (res: boolean) => void): void { const set = {}; @@ -52,6 +91,14 @@ export class UserCollection extends FrotniteBotCollection implements ICollection callback(true); }); } + + /** + * Increments a number value associated with the user. + * @param userId - The id of the user to update. + * @param field - The field to update. + * @param value - The new value for the field. + * @param callback - Callback true if successfully updated. + */ public incrementCoin(userId: string, field: string, value: number, callback: (res: boolean) => void): void { this.get((res: User[]) => { @@ -65,6 +112,12 @@ export class UserCollection extends FrotniteBotCollection implements ICollection }); }); } + + /** + * Removes a user from the collection. + * @param userId - The user to remove. + * @param callback - Callback true if successfully removed. + */ public removeUser(userId: string, callback: (res: boolean) => void): void { this.db.collection("user").deleteOne({id: userId}, (err) => { if (err) { @@ -74,6 +127,12 @@ export class UserCollection extends FrotniteBotCollection implements ICollection callback(true); }); } + + /** + * Replaces a user. + * @param user - The user to replace + * @param callback - true if successfully replaced. + */ public replace(user: User, callback: (res: boolean) => void) { this.db.collection("user").update({id: user.id}, user, (err) => { if (err) { diff --git a/src/exceptions/DatabaseException.ts b/src/exceptions/DatabaseException.ts index 9c7056a..783c719 100644 --- a/src/exceptions/DatabaseException.ts +++ b/src/exceptions/DatabaseException.ts @@ -1,6 +1,10 @@ import { FortniteBotException } from "./FortniteBotException"; export class DatabaseException extends FortniteBotException { + /** + * @classdesc Exception thrown for database related errors. + * @param message - Message associated with the error. + */ constructor(message: any) { super(message); } diff --git a/src/exceptions/FortniteBotException.ts b/src/exceptions/FortniteBotException.ts index 0da66a1..4cdc464 100644 --- a/src/exceptions/FortniteBotException.ts +++ b/src/exceptions/FortniteBotException.ts @@ -1,5 +1,11 @@ export class FortniteBotException extends Error { public message: string; + + /** + * @classdesc Base custom exception class. + * @param message - Message associated with the error. + * @param stack - Stack associated with the error. + */ constructor(message: string, stack?: string) { super(stack); this.message = message; diff --git a/src/exceptions/UnauthorizedCommandException.ts b/src/exceptions/UnauthorizedCommandException.ts index cbbfb76..014ea6e 100644 --- a/src/exceptions/UnauthorizedCommandException.ts +++ b/src/exceptions/UnauthorizedCommandException.ts @@ -1,6 +1,11 @@ import { FortniteBotException } from "./FortniteBotException"; export class UnauthorizedCommandException extends FortniteBotException { + + /** + * @classdesc Exception thrown when a command is executed without the appropriate access level. + * @param message - Message associated with the error. + */ constructor(message: string) { super(message); } diff --git a/src/shop/IItem.ts b/src/shop/IItem.ts index 9b506be..ab4862e 100644 --- a/src/shop/IItem.ts +++ b/src/shop/IItem.ts @@ -1,3 +1,6 @@ +/** + * Base interface for purchaseable item. + */ export interface IItem { name: string; cost: { diff --git a/src/shop/Item.ts b/src/shop/Item.ts index e785113..98b015d 100644 --- a/src/shop/Item.ts +++ b/src/shop/Item.ts @@ -1,13 +1,35 @@ import { IItem } from "./IItem"; export class Item implements IItem { + /** + * The name of the item. + */ public name: string; + + /** + * The price property of the item. + */ public cost: { coinType: string, value: number }; + + /** + * Discounts applied to the value of the item. + */ public discountPercent: number; + + /** + * The type associated with the item. + */ public type: string; + + /** + * @classdesc Base class for a purchaseable item. + * @param name - The name of the item. + * @param value - The value of the item. + * @param coinType - The type of currency for this item. Overrides the shop currency. + */ constructor(name: string, value: number, coinType?: string) { this.name = name; this.cost = { @@ -19,6 +41,10 @@ export class Item implements IItem { this.cost.coinType = null; } } + + /** + * Gets the acutal price of the item. + */ public getPrice(): number { return Math.round(this.cost.value - (this.cost.value * (this.discountPercent / 100)) diff --git a/src/shop/Shop.ts b/src/shop/Shop.ts index 88edd6f..d4cd688 100644 --- a/src/shop/Shop.ts +++ b/src/shop/Shop.ts @@ -2,12 +2,44 @@ import { Item } from "./Item"; import { randInt } from "../utils/Random"; export class Shop { + /** + * A array of items offered by the shop. + */ public inventory: Item[]; + + /** + * The name of the shop. + */ public name: string; + + /** + * The description of the store. + */ public description?: string; + + /** + * Welcome message to greet a user with. + */ public welcomeMessage?: string; + + /** + * Whether if discounts are allowed for the items. + */ public allowDiscounts?: boolean; + + /** + * The currency the shop accepts. + */ private coinType: string; + + /** + * @classdesc Base class for a shop. + * @param name - The name of the shop. + * @param coinType - The currency the shop accepts. + * @param allowDiscounts - Whether if discounts are allowed for the items. + * @param description - The description of the store. + * @param welcomeMessage - Welcome message to greet a user with. + */ constructor(name: string, coinType: string, allowDiscounts?: boolean, description?: string, welcomeMessage?: string) { this.name = name; @@ -16,6 +48,11 @@ export class Shop { this.allowDiscounts = allowDiscounts ? allowDiscounts : false; this.inventory = []; } + + /** + * Adds items to the store. + * @param items - Items to add to the store. + */ public addItems(items: Item[]): void { for (const item of items) { if (this.inventory.indexOf(item) === -1) { @@ -26,6 +63,11 @@ export class Shop { } } } + + /** + * Applies discounts to a random set of items. + * @param amount - The amount of items to apply discounts to. + */ public setRandomDiscount(amount: number): void { this.resetDiscount(); const itemIndex = []; @@ -42,11 +84,20 @@ export class Shop { i++; } } + + /** + * Resets all discounts for items. + */ public resetDiscount(): void { for (const item of this.inventory) { item.discountPercent = 0; } } + + /** + * Gets the inventory of the store. + * @returns A string representation of all the items in the store. + */ public getInventory(): string { let text = this.name + "\n"; let i = 0; diff --git a/src/shop/Shops.ts b/src/shop/Shops.ts index f0f3e0f..8dbd154 100644 --- a/src/shop/Shops.ts +++ b/src/shop/Shops.ts @@ -1,6 +1,10 @@ import { Shop } from "./Shop"; import { Title } from "./Title"; +/** + * Shop items and shop data. + */ + export const Shops = [ new Shop("Title Shop", "DotmaCoin", true, "Buy titles for your profile."), new Shop("Brad Shop", "BradCoin", false, "Some fat kid sells stuff here.") diff --git a/src/shop/Title.ts b/src/shop/Title.ts index 666f220..17aac35 100644 --- a/src/shop/Title.ts +++ b/src/shop/Title.ts @@ -2,6 +2,12 @@ import { Item } from "./Item"; import { IItem } from "./IItem"; export class Title extends Item implements IItem { + /** + * @classdesc A title which can be applied to users. + * @param name - The name of the title. + * @param value - The price of the title. + * @param coinType - The currency required for the title. + */ constructor(name: string, value: number, coinType?: string) { super(name, value, coinType); this.type = "Title"; diff --git a/src/state/CommandExecutionState.ts b/src/state/CommandExecutionState.ts index 50a0625..dd52f6d 100644 --- a/src/state/CommandExecutionState.ts +++ b/src/state/CommandExecutionState.ts @@ -3,6 +3,10 @@ import { Message } from "discord.js"; import { FortniteBotState } from "./FortniteBotState"; export class CommandExecutionState extends FortniteBotState { + /** + * @classdesc State for when a command is being executed. + * @param message - Discord message handler. + */ public constructor(message: Message) { super(message); } diff --git a/src/state/FortniteBotState.ts b/src/state/FortniteBotState.ts index fb574ed..b3ddab8 100644 --- a/src/state/FortniteBotState.ts +++ b/src/state/FortniteBotState.ts @@ -2,17 +2,39 @@ import * as Discord from "discord.js"; import { fortniteBotCore as activeCore } from "../../fortniteBot"; export class FortniteBotState { + /** + * Hander for the state. + */ public handle: any; + + /** + * @classdesc Base state for the bot. + * @param handle - Handler for the state. + */ constructor(handle: object) { this.handle = handle; } + + /** + * Sets the handle of the state. + * @param handle - New handle to set. + */ public setHandle(handle: object): void { this.handle = handle; } + + /** + * Gets the current handle. + */ public getHandle(): any { return this.handle; } + + /** + * Updates the current handle. + */ public updateHandle(): any { + // Todo. return activeCore.getCoreState().getHandle(); } } diff --git a/src/state/PendingResponseState.ts b/src/state/PendingResponseState.ts index 004a8e2..e4d092d 100644 --- a/src/state/PendingResponseState.ts +++ b/src/state/PendingResponseState.ts @@ -2,6 +2,10 @@ import { Message } from "discord.js"; import { CommandExecutionState } from "./CommandExecutionState"; export class PendingResponseState extends CommandExecutionState { + /** + * @classdesc State for when a response is required. + * @param message - Discord message handler. + */ public constructor(message: Message) { super(message); } diff --git a/src/user/IUser.ts b/src/user/IUser.ts index 93a5127..039f528 100644 --- a/src/user/IUser.ts +++ b/src/user/IUser.ts @@ -1,5 +1,19 @@ +/** + * Base interface for a user. + */ export interface IUser { + /** + * Id of the user. + */ readonly id: string; + + /** + * Access level of the user. + */ accessLevel: number; + + /** + * The name of the user. + */ name?: string; } diff --git a/src/user/User.ts b/src/user/User.ts index ce77603..f37633f 100644 --- a/src/user/User.ts +++ b/src/user/User.ts @@ -1,23 +1,56 @@ import { IUser } from "../user/IUser"; export class User implements IUser { + /** + * The id of the user. + */ public readonly id: string; + + /** + * The access level of the user. + */ public accessLevel: number; + + /** + * The user's wallet. + */ public currency: { DotmaCoin: number; BradCoin: number; }; + + /** + * The user's daily actions. + */ public daily: { lastUpdate: { DotmaCoin: Date; } }; + + /** + * The user's current title and titles which they have purchased. + */ public title: { active: string list: string[] }; + + /** + * Equipment of the user. + */ public equipment; + + /** + * Skills of the user. + */ public skills; + + /** + * @classdesc Base user class. + * @param id - The id of the user. + * @param accessLevel - The access level of the user. + */ constructor(id: string, accessLevel: number) { this.id = id; this.accessLevel = accessLevel; diff --git a/src/utils/CommandUtil.ts b/src/utils/CommandUtil.ts index 11f96a5..9b23c5e 100644 --- a/src/utils/CommandUtil.ts +++ b/src/utils/CommandUtil.ts @@ -1,3 +1,8 @@ + +/** + * Extracts the user id from a string. + * @param text - The text to extract id from. + */ export const getId = (text: string): string => { return text.charAt(2) !== "!" ? text.slice(2, text.length - 1) : text.slice(3, text.length - 1); diff --git a/src/utils/Loop.ts b/src/utils/Loop.ts index 31fa6c6..35432a8 100644 --- a/src/utils/Loop.ts +++ b/src/utils/Loop.ts @@ -3,6 +3,13 @@ export class Loop { private delay: number; private callback: (amount: number) => void; private interval: any; + + /** + * @classdesc A base recursive loop class. + * @param amount - Amount of times to loop. + * @param delay - The delay between each loop. + * @param callback - Recursive callback to iterate the loop. + */ constructor(amount: number, delay: number, callback: (amount: number) => void) { this.amount = amount; @@ -10,6 +17,11 @@ export class Loop { this.callback = callback; this.interval = null; } + + /** + * Execute one cycle of the loop. + * @param self - The previous iteration of the loop. + */ public loop(self: Loop): void { self.callback(self.amount); self.amount--; @@ -18,9 +30,17 @@ export class Loop { self.stopLoop(); } } + + /** + * Starts the loop. + */ public startLoop(): void { this.interval = setTimeout(this.loop, this.delay, this); } + + /** + * Terminates the loop. + */ public stopLoop(): void { clearTimeout(this.interval); } From 030e8649ab0594a5444cf6c2898c387d3fee96f6 Mon Sep 17 00:00:00 2001 From: "Toe, Knee" Date: Fri, 27 Jul 2018 22:03:40 +1000 Subject: [PATCH 05/15] Merge insert methods --- src/database/GlobalCollection.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/database/GlobalCollection.ts b/src/database/GlobalCollection.ts index c820a2a..faa424a 100644 --- a/src/database/GlobalCollection.ts +++ b/src/database/GlobalCollection.ts @@ -29,12 +29,7 @@ export class GlobalCollection extends FortniteBotCollection implements ICollecti * Sets up the required fields for operation. */ public createSchema(): void { - this.db.collection("global").insertOne({targets: []}, (err) => { - if (err) { - throw new DatabaseException(err); - } - }); - this.db.collection("global").insertOne({lastUpdate: new Date()}, (err) => { + this.db.collection("global").insertOne({targets: [], shops: { lastUpdate: new Date() }}, (err) => { if (err) { throw new DatabaseException(err); } From 2ffeb54460efa4df6f2d48f47475ff912d2c7ca7 Mon Sep 17 00:00:00 2001 From: "Toe, Knee" Date: Fri, 27 Jul 2018 23:19:42 +1000 Subject: [PATCH 06/15] Fix typo --- fortniteBot.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fortniteBot.ts b/fortniteBot.ts index ff4330a..414b938 100644 --- a/fortniteBot.ts +++ b/fortniteBot.ts @@ -8,11 +8,11 @@ dotenvConfig(); const keys = { discordToken: process.env.discordToken, chatBotUserId: process.env.chatBotUserId, - chatBotAPIKey: process.env.chatBotAPIKey + chatBotApiKey: process.env.chatBotApiKey }; const initConfig = new FortniteBotInitConfig(keys.discordToken, - keys.chatBotUserId, keys.chatBotAPIKey); + keys.chatBotUserId, keys.chatBotApiKey); export const fortniteBotCore = new FortniteBotCore(initConfig); From b1cd1c59a08464786ee784f7b73d50bc5bd7a270 Mon Sep 17 00:00:00 2001 From: Xinyi Li Date: Fri, 27 Jul 2018 23:41:50 +1000 Subject: [PATCH 07/15] Update README.md --- README.md | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bb3e4d9..e98fb62 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,29 @@ # Fortnite Bot -A bot which pings selected targets whenever fortnite is mentioned. Use at your own risk. +A bot which pings selected targets whenever fortnite is mentioned. Use at your own risk. Despite its name, the main focus of the bot is to provide a flexible command system so that fun commands can be easily added to provide entertaining interactions between users and the bot. ## Commands ``` -!fortnite - Asks your targets to play fortnite. -!fortnite tts - Asks your targets to play fortnite but more nicely. -!fortnite target {@target1} {@target2} ... {@targetn} - Set new targets/friends. -!fortnite auto {amount} {delay(ms)} - Ask your friends many times -!fortnite delete - Deletes all messages sent by the bot. +Standard Commands +!f - Asks your targets to play fortnite. +!f ping - Check for response. +!f help - Displays help message. +!f target @target - Adds target to the targetlist. +!f targetlist - Shows the current targets. +!f removeself - Removes yourself from the targetlist. +!f auto amount delay(ms) - Ask your friends many times +!f stop - Deletes all messages sent by the bot. + +User Commands +!f register - Registers yourself. +!f profile - Check your profile. +!f daily - Grab daily rewards. + +Shop Commands +!f shoplist - Displays all avaliable shops. +!f viewshop shopname - View a shop. +!f buy index/itemname from shopname - Buy an item from a shop. + +...More coming soon. ``` ## Contributing ~~Don't.~~ From 767708cf66d733877b6d50003f5126f90a791360 Mon Sep 17 00:00:00 2001 From: Xinyi Li Date: Fri, 27 Jul 2018 23:47:38 +1000 Subject: [PATCH 08/15] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e98fb62..c1424cf 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,7 @@ Standard Commands !f target @target - Adds target to the targetlist. !f targetlist - Shows the current targets. !f removeself - Removes yourself from the targetlist. -!f auto amount delay(ms) - Ask your friends many times -!f stop - Deletes all messages sent by the bot. +!f auto amount delay(s) - Automatically ping the targets a set amount of times with an delay. User Commands !f register - Registers yourself. @@ -19,7 +18,7 @@ User Commands !f daily - Grab daily rewards. Shop Commands -!f shoplist - Displays all avaliable shops. +!f shoplist - Displays all available shops. !f viewshop shopname - View a shop. !f buy index/itemname from shopname - Buy an item from a shop. From 3f72edea0255ec766a8b60175ae79d115250c472 Mon Sep 17 00:00:00 2001 From: "Toe, Knee" Date: Fri, 27 Jul 2018 23:47:54 +1000 Subject: [PATCH 09/15] Added help response text --- src/command/DefaultCommands.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/command/DefaultCommands.ts b/src/command/DefaultCommands.ts index 25faeb3..7a27c3f 100644 --- a/src/command/DefaultCommands.ts +++ b/src/command/DefaultCommands.ts @@ -121,7 +121,26 @@ const doNothing = new FortniteBotAction(0, (state: FortniteBotState) => { const showHelp = new FortniteBotAction(0, (state: FortniteBotState) => { (state.getHandle() as Discord.Message).channel.send( - "``` help response ```" + "``` Standard Commands\n" + + "!f - Asks your targets to play fortnite.\n" + + "!f ping - Check for response.\n" + + "!f help - Displays help message.\n" + + "!f target @target - Adds target to the targetlist.\n" + + "!f targetlist - Shows the current targets.\n" + + "!f removeself - Removes yourself from the targetlist.\n" + + "!f auto amount delay(s) - Automatically ping the targets a set amount of times with an delay.\n" + + "\n" + + "User Commands\n" + + "!f register - Registers yourself.\n" + + "!f profile - Check your profile.\n" + + "!f daily - Grab daily rewards.\n" + + "\n" + + "Shop Commands\n" + + "!f shoplist - Displays all available shops.\n" + + "!f viewshop shopname - View a shop.\n" + + "!f buy index/itemname from shopname - Buy an item from a shop.\n" + + "\n" + + "...More coming soon. Contribute here! at https://github.com/aXises/fortniteBot```" ); return true; }); From acc3bf7400373df58c414de0ca1942ed469baa1c Mon Sep 17 00:00:00 2001 From: "Toe, Knee" Date: Fri, 27 Jul 2018 23:52:17 +1000 Subject: [PATCH 10/15] Formatting --- src/command/DefaultCommands.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/command/DefaultCommands.ts b/src/command/DefaultCommands.ts index 7a27c3f..b8d9194 100644 --- a/src/command/DefaultCommands.ts +++ b/src/command/DefaultCommands.ts @@ -121,7 +121,9 @@ const doNothing = new FortniteBotAction(0, (state: FortniteBotState) => { const showHelp = new FortniteBotAction(0, (state: FortniteBotState) => { (state.getHandle() as Discord.Message).channel.send( - "``` Standard Commands\n" + + "```OwO you wan halp? >///<\n" + + "\n" + + "Standard Commands\n" + "!f - Asks your targets to play fortnite.\n" + "!f ping - Check for response.\n" + "!f help - Displays help message.\n" + From 8a230cac2959d1a16c1bd42c19fd935bc14e7fca Mon Sep 17 00:00:00 2001 From: "Toe, Knee" Date: Sat, 28 Jul 2018 14:56:35 +1000 Subject: [PATCH 11/15] Minor id fixes --- src/command/DefaultCommands.ts | 3 +-- src/database/GlobalCollection.ts | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/command/DefaultCommands.ts b/src/command/DefaultCommands.ts index b8d9194..2c491a9 100644 --- a/src/command/DefaultCommands.ts +++ b/src/command/DefaultCommands.ts @@ -50,7 +50,7 @@ const sendDefaultText = (state: FortniteBotState): void => { } }); } - targetString += res[0].targets.length === 0 ? "<@!458602122540220416> fortnite?" : "fortnite?"; + targetString += res[0].targets.length === 0 ? "<@!455679698610159616> fortnite?" : "fortnite?"; m.channel.send(targetString); }); }; @@ -275,7 +275,6 @@ const addTarget = new FortniteBotAction(1, const getTargetList = new FortniteBotAction(0, (state: FortniteBotState) => { activeCore.getDbCore().collections.global.get((res) => { - console.log(res); const m: Discord.Message = state.getHandle(); let userlist = "```Current Targets: (" + res[0].targets.length + ")\n"; for (const id of res[0].targets) { diff --git a/src/database/GlobalCollection.ts b/src/database/GlobalCollection.ts index faa424a..2b62608 100644 --- a/src/database/GlobalCollection.ts +++ b/src/database/GlobalCollection.ts @@ -22,7 +22,8 @@ export class GlobalCollection extends FortniteBotCollection implements ICollecti constructor(localDb: any) { super(); this.localDb = localDb; - this.dbId = new MongoDb.ObjectId("5b5adfbcfe69061b34ba342c"); + // Separate in to multiple collection later. + this.dbId = new MongoDb.ObjectId("5b5b09dbf0c94f161827b2cb"); } /** From 39722c732570290b74864b19d6d6c06c7c25352e Mon Sep 17 00:00:00 2001 From: "Toe, Knee" Date: Sat, 28 Jul 2018 14:57:57 +1000 Subject: [PATCH 12/15] Allow tts for chatbot responses --- src/command/DefaultCommands.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/command/DefaultCommands.ts b/src/command/DefaultCommands.ts index 2c491a9..8846eff 100644 --- a/src/command/DefaultCommands.ts +++ b/src/command/DefaultCommands.ts @@ -31,7 +31,10 @@ const askChatBot = (state: FortniteBotState) => { if (err1 || err2) { return; } - m.channel.send(res); + // Todo: Allow tts toggle. + m.channel.send(res, { + tts: true + }); }); }); }; From c64fd82deaba939f8146c43f635648906891b975 Mon Sep 17 00:00:00 2001 From: Xinyi Li Date: Sat, 28 Jul 2018 23:35:10 +1000 Subject: [PATCH 13/15] Update README.md --- README.md | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c1424cf..2c1388e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,88 @@ # Fortnite Bot + +![CodeFactor](https://www.codefactor.io/repository/github/axises/fortnitebot/badge) [![codecov](https://codecov.io/gh/aXises/fortniteBot/branch/master/graph/badge.svg)](https://codecov.io/gh/aXises/fortniteBot) +[![Maintainability](https://api.codeclimate.com/v1/badges/51cbd263ff1f0afff332/maintainability)](https://codeclimate.com/github/aXises/fortniteBot/maintainability) +[![Test Coverage](https://api.codeclimate.com/v1/badges/51cbd263ff1f0afff332/test_coverage)](https://codeclimate.com/github/aXises/fortniteBot/test_coverage) + A bot which pings selected targets whenever fortnite is mentioned. Use at your own risk. Despite its name, the main focus of the bot is to provide a flexible command system so that fun commands can be easily added to provide entertaining interactions between users and the bot. +## Requirements +- Node 6 or higher +- TypeScript 2 +- tslint is recommended for style consistency + +## Build +Clone the repository `git clone https://github.com/aXises/fortniteBot` + +Install required packages `npm install` + +Install TypeScript `npm install -g typescript` + +Nodemon is recommended `npm install -g nodemon` + +Compile TypeScript `tsc` + +Configure API keys in fortniteBot.ts or with .env file + +Running the application `node fortniteBot.js` or `nodemon fortniteBot.js` + +## Creating commands +It is recommended to place these in a seperate file. +``` +// MyCustomCommands.ts +// Examples to demonstrate adding different types of commands. +import * as Discord from "discord.js"; +import { FortniteBotAction } from "../action/FortniteBotAction"; +import { ExecutableCommand } from "../command/ExecutableCommand"; +import { AutoTriggerCommand } from "../command/AutoTriggerCommand"; +import { FortniteBotTrigger } from "../action/FortniteBotTrigger"; + +// Example Executable Command. + +// Example action. Takes 1 argument and sends it back to the channel. +const testCommandAction = new FortniteBotAction(1, (state, args) => { + const m: Discord.Message = state.getHandle(); + if (args.length !== 1) { + return false; // Command failed. + } + m.channel.send(args[0]); + return true; // Command was successfully executed. +}); + +// To execute the command, call '!f testcommand'. Anyone with access level 0 can execute this command. +const testCommand = new ExecutableCommand("testcommand", 0, testCommandAction); + +// Example Auto Trigger Command + +// Example Triggers. +const trigger1 = new FortniteBotTrigger((state) => { + return Math.random() > 0.5; // Action will be executed if true. (50%) +}); + +const trigger2 = new FortniteBotTrigger((state) => { + const m: Discord.Message = state.getHandle(); + return m.content === "egg"; // Action will be executed whenever the message is "egg". +}); + +// Example Action for auto trigger. +const testAutoAction = new FortniteBotAction(1, (state) => { + const m: Discord.Message = state.getHandle(); + m.channel.send("This action was triggered"); + return true; +}); + +// Set up the command with different triggers. +const autoCommand1 = new AutoTriggerCommand(0, testAutoAction, trigger1); +const autoCommand2 = new AutoTriggerCommand(0, testAutoAction, trigger2); + +// Export all the commands. +export const myCustomCommands = [testCommand, autoCommand1, autoCommand2]; + +// Import in to the command manager with CommandManager.addBulkCommand() or CommandManager.addCommand(). +// See FortniteBotEventCore.ts for example. +``` + + ## Commands ``` Standard Commands @@ -24,8 +106,9 @@ Shop Commands ...More coming soon. ``` + ## Contributing -~~Don't.~~ +All contribtions are welcome. Adhering to tslint style is recommeded. ## Disclaimer I do not play nor have any affiliation with Fortnite. This application is a simple tool to ~~spam~~ ask your friends/server members. From e6a74fadc5d79b9e0ad73437771f54349806054c Mon Sep 17 00:00:00 2001 From: "Toe, Knee" Date: Sat, 28 Jul 2018 23:32:38 +1000 Subject: [PATCH 14/15] Fix commandExists detecting null type Make add command more consistent --- src/command/CommandManager.ts | 10 ++++++---- src/core/FortniteBotEventCore.ts | 11 ++++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/command/CommandManager.ts b/src/command/CommandManager.ts index 3d01a48..26519da 100644 --- a/src/command/CommandManager.ts +++ b/src/command/CommandManager.ts @@ -1,6 +1,6 @@ import { FortniteBotCommandConfig } from "../config/FortniteBotCommandConfig"; import { Command } from "../command/Command"; -import { AutoTriggerCommand } from "./AutoTriggerCommand"; +import { AutoTriggerCommand } from "../command/AutoTriggerCommand"; import { User } from "../user/User"; import { FortniteBotException } from "../exceptions/FortniteBotException"; import { fortniteBotCore as activeCore } from "../../fortniteBot"; @@ -18,10 +18,9 @@ export class CommandManager { /** * @classdesc Class to handle import and execution of commands. - * @param commands - Set of initial commands to be loaded in to memory. */ - public constructor(commands?: Command[]) { - this.commands = commands; + public constructor() { + this.commands = []; this.prefix = new FortniteBotCommandConfig( [ "!f" @@ -147,6 +146,9 @@ export class CommandManager { * @returns true if commands exists, false otherwise. */ private commandExists(name: string): boolean { + if (!name) { + return false; + } if (Object.keys(this.commands).length > 1) { for (const command of this.commands) { if (command.commandString === name) { diff --git a/src/core/FortniteBotEventCore.ts b/src/core/FortniteBotEventCore.ts index d4dcfeb..c0f1515 100644 --- a/src/core/FortniteBotEventCore.ts +++ b/src/core/FortniteBotEventCore.ts @@ -35,7 +35,8 @@ export class FortniteBotEventCore { public constructor(core: FortniteBotCore) { this.core = core; this.client = core.bot; - this.commandManager = new CommandManager(defaultCommands); + this.commandManager = new CommandManager(); + this.commandManager.addBulkCommand(defaultCommands); this.commandManager.addBulkCommand(userCommands); this.commandManager.addBulkCommand(shopCommands); this.currentHandles = {}; @@ -69,4 +70,12 @@ export class FortniteBotEventCore { public clearClient(): void { this.client = null; } + + /** + * Gets the current CommandManager Object. + * @returns The current CommandManager Object. + */ + public getCommandManager(): CommandManager { + return this.commandManager; + } } From c2dd3e45bb2263445a399f53b54f8c8d1735090e Mon Sep 17 00:00:00 2001 From: "Toe, Knee" Date: Sat, 28 Jul 2018 23:33:46 +1000 Subject: [PATCH 15/15] Add example command file --- src/command/MyCustomCommands.ts | 51 +++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/command/MyCustomCommands.ts diff --git a/src/command/MyCustomCommands.ts b/src/command/MyCustomCommands.ts new file mode 100644 index 0000000..651c5be --- /dev/null +++ b/src/command/MyCustomCommands.ts @@ -0,0 +1,51 @@ +// MyCustomCommands.ts +// Examples to demonstrate adding different types of commands. +import * as Discord from "discord.js"; +import { FortniteBotAction } from "../action/FortniteBotAction"; +import { ExecutableCommand } from "../command/ExecutableCommand"; +import { AutoTriggerCommand } from "../command/AutoTriggerCommand"; +import { FortniteBotTrigger } from "../action/FortniteBotTrigger"; + +// Example Executable Command. + +// Example action. Takes 1 argument and sends it back to the channel. +const testCommandAction = new FortniteBotAction(1, (state, args) => { + const m: Discord.Message = state.getHandle(); + if (args.length !== 1) { + return false; // Command failed. + } + m.channel.send(args[0]); + return true; // Command was successfully executed. +}); + +// To execute the command, call '!f testcommand'. Anyone with access level 0 can execute this command. +const testCommand = new ExecutableCommand("testcommand", 0, testCommandAction); + +// Example Auto Trigger Command + +// Example Triggers. +const trigger1 = new FortniteBotTrigger((state) => { + return Math.random() > 0.5; // Action will be executed if true. (50%) +}); + +const trigger2 = new FortniteBotTrigger((state) => { + const m: Discord.Message = state.getHandle(); + return m.content === "egg"; // Action will be executed whenever the message is "egg". +}); + +// Example Action for auto trigger. +const testAutoAction = new FortniteBotAction(1, (state) => { + const m: Discord.Message = state.getHandle(); + m.channel.send("This action was triggered"); + return true; +}); + +// Set up the command with different triggers. +const autoCommand1 = new AutoTriggerCommand(0, testAutoAction, trigger1); +const autoCommand2 = new AutoTriggerCommand(0, testAutoAction, trigger2); + +// Export all the commands. +export const myCustomCommands = [testCommand, autoCommand1, autoCommand2]; + +// Import in to the command manager with CommandManager.addBulkCommand() or CommandManager.addCommand(). +// See FortniteBotEventCore.ts for example.