Compare commits
18 commits
Author | SHA1 | Date | |
---|---|---|---|
7c85aec971 | |||
8e9db75a30 | |||
5676efd969 | |||
16ac225a44 | |||
|
e302f2ee4d | ||
|
f6d57a1fda | ||
c88a15187e | |||
1a8baecfa1 | |||
d3f9fc4fa0 | |||
5ce0960606 | |||
799b04e936 | |||
3a9f1965ae | |||
00a057792b | |||
1b1933a9ce | |||
b10ac37007 | |||
3392e6f031 | |||
a3230cad20 | |||
4e1c418246 |
13 changed files with 216 additions and 65 deletions
|
@ -10,4 +10,7 @@ BOT_TOKEN=
|
|||
BOT_PREFIX=v!
|
||||
|
||||
FOLDERS_COMMANDS=commands
|
||||
FOLDERS_EVENTS=events
|
||||
FOLDERS_EVENTS=events
|
||||
|
||||
COMMANDS_DISABLED=
|
||||
COMMANDS_DISABLED_MESSAGE=This command is disabled.
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -113,3 +113,6 @@ events/
|
|||
|
||||
# Linux Environment Files
|
||||
*.swp
|
||||
|
||||
# macOS Environment Files
|
||||
.DS_Store
|
|
@ -61,7 +61,7 @@ representative at an online or offline event.
|
|||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
getgravitysoftware@gmail.com.
|
||||
ethan@vylpes.com.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
|
|
|
@ -12,7 +12,7 @@ This project and everyone participating in it is governed by the VylBot Core Cod
|
|||
|
||||
> **Note:** Please don't file an issue to ask a question. You'll get faster results by using the resources below.
|
||||
|
||||
You can ask a question about the project by emailing us at `getgravitysoftware@gmail.com`.
|
||||
You can ask a question about the project by emailing us at `ethan@vylpes.com`.
|
||||
|
||||
You can ask a question about the project in the `#development` channel in the [Discord Server](https://discord.gg/UyAhAVp).
|
||||
|
||||
|
@ -32,7 +32,7 @@ There are a few conventions that have developed over time for this project. When
|
|||
|
||||
We won't accept pull requests unless these checks pass. If yours fail, simply fix what the bot says until it passes and then get a repo member to review your code.
|
||||
|
||||
The rules for the code is based upon [Gravity Software's Config Repo](https://github.com/GetGravitySoft/Config)
|
||||
The rules for the code is based upon [Vylpes' Config Repo](https://github.com/vylpes/Config)
|
||||
|
||||
* Variable names should use **Camel Case**
|
||||
* Functions should put **braces on the same line**
|
||||
|
@ -119,26 +119,26 @@ Enhancement suggestions are tracked as GitHub issues. After you've determined th
|
|||
|
||||
Unsure where to begin contributing to VylBot Core? You can start by looking through these `good first` and `help wanted` issues:
|
||||
|
||||
* [Good first issue](https://github.com/getgravitysoft/vylbot-core/labels/good%20first%20issue) - issues which should only require a few lines of code, and a test or two.
|
||||
* [Help wanted](https://github.com/getgravitysoft/vylbot-core/labels/help%20wanted) - issues which should be a bit more involved than `good first` issues.
|
||||
* [Good first issue](https://github.com/vylpes/vylbot-core/labels/good%20first%20issue) - issues which should only require a few lines of code, and a test or two.
|
||||
* [Help wanted](https://github.com/vylpes/vylbot-core/labels/help%20wanted) - issues which should be a bit more involved than `good first` issues.
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
In order to download necessary tools, clone the repository, and install dependencies via `npm` you need network access.
|
||||
In order to download necessary tools, clone the repository, and install dependencies via `yarn` you need network access.
|
||||
|
||||
You'll need the following tools:
|
||||
|
||||
* Git
|
||||
* NodeJS
|
||||
|
||||
Install and build all of the dependencies using `npm`
|
||||
Install and build all of the dependencies using `yarn`
|
||||
|
||||
```bash
|
||||
cd VylBot Core
|
||||
npm install
|
||||
cp config.json.template config.json
|
||||
cd vylbot-core
|
||||
yarn install
|
||||
cp .env.template .env
|
||||
```
|
||||
And then use your text editor of choice to fill in the `config.json` file.
|
||||
And then use your text editor of choice to fill in the `.env` file.
|
||||
|
||||
#### Build and Run
|
||||
|
||||
|
@ -147,15 +147,15 @@ If you want to understand how VylBot Core works or want to debug an issue, you'l
|
|||
First, fork the VylBot Core repository so that you can make a pull request. Then, clone your fork locally:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/<your-github-account>/VylBot Core.git
|
||||
git clone https://github.com/<your-github-account>/vylbot-core.git
|
||||
```
|
||||
|
||||
Occasionally, you will want to merge changes in the upstream repository (the official code repo) with your fork.
|
||||
|
||||
```bash
|
||||
cd VylBot Core
|
||||
cd vylbot-core
|
||||
git checkout master
|
||||
git pull https://github.com/getgravitysoft/VylBot Core.git master
|
||||
git pull https://github.com/vylpes/vylbot-core.git master
|
||||
```
|
||||
|
||||
Manage any merge conflicts, commit them, and then push them to your fork.
|
||||
|
@ -202,20 +202,18 @@ As well as eslint's recommended defaults.
|
|||
|
||||
Example
|
||||
|
||||
```js
|
||||
function ban (member) {
|
||||
let reason = "Example reason";
|
||||
```ts
|
||||
// hello.ts
|
||||
import { Command, ICommandContext } from "vylbot-core";
|
||||
|
||||
let args = [
|
||||
"one",
|
||||
"two"
|
||||
];
|
||||
export class hello extends Command {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
member.ban(reason).then(() => {
|
||||
// handle then here
|
||||
}).catch(err => {
|
||||
// handle error here
|
||||
});
|
||||
public override execute(context: ICommandContext) {
|
||||
context.message.reply("Hello");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -251,7 +249,7 @@ There are a few conventions that have developed over time for this project. When
|
|||
|
||||
We won't accept pull requests unless these checks pass. If yours fail, simply fix what the bot says until it passes and then get a repo member to review your code.
|
||||
|
||||
The rules for the code is based upon [Gravity Software's Config Repo](https://github.com/getgravitysoft/config)
|
||||
The rules for the code is based upon [Vylpes' Config Repo](https://github.com/vylpes/config)
|
||||
|
||||
* Variable names should use **Camel Case**
|
||||
* Functions should put **braces on the same line**
|
||||
|
|
15
README.md
15
README.md
|
@ -14,12 +14,17 @@ BOT_PREFIX=v!
|
|||
|
||||
FOLDERS_COMMANDS=commands
|
||||
FOLDERS_EVENTS=events
|
||||
|
||||
COMMANDS_DISABLED=
|
||||
COMMANDS_DISABLED_MESSAGE=This command is disabled.
|
||||
```
|
||||
|
||||
* **BOT_TOKEN:** Your bot's token, replace {TOKEN} with your bot token
|
||||
* **BOT_PREFIX** The command prefix
|
||||
* **FOLDERS_COMMANDS:** The folder which contains your commands
|
||||
* **FOLDERS_EVENTS** The folder which contains your events
|
||||
* **BOT_TOKEN:** Your bot's token, replace {TOKEN} with your bot token.
|
||||
* **BOT_PREFIX:** The command prefix.
|
||||
* **FOLDERS_COMMANDS:** The folder which contains your commands.
|
||||
* **FOLDERS_EVENTS:** The folder which contains your events.
|
||||
* **COMMANDS_DISABLED:** List of command file names that won't run, separated by commas.
|
||||
* **COMMANDS_DISABLED_MESSAGE:** The message which is replied to the user who tries to run a disabled command.
|
||||
|
||||
Make sure that you **DO NOT** put your .env file into VCS!
|
||||
|
||||
|
@ -45,7 +50,7 @@ The code below will reply to the user with 'PONG' when they type {PREFIX}ping
|
|||
|
||||
import { Command, ICommandContext } from "vylbot-core";
|
||||
|
||||
export class Ping extends Command {
|
||||
export default class Ping extends Command {
|
||||
constructor() {
|
||||
super();
|
||||
this._roles = [ "Moderator" ];
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
{
|
||||
"name": "vylbot-core",
|
||||
"version": "1.0.5",
|
||||
"version": "2.0.1",
|
||||
"description": "A discord client based upon discord.js",
|
||||
"main": "./src/index",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "jest --coverage",
|
||||
"test": "jest",
|
||||
"test:coverage": "jest --coverage",
|
||||
"lint": "eslint ."
|
||||
},
|
||||
"author": "Vylpes",
|
||||
"license": "MIT",
|
||||
"funding": "https://ko-fi.com/gravitysoftware",
|
||||
"funding": "https://ko-fi.com/vylpes",
|
||||
"dependencies": {
|
||||
"discord.js": "^12.3.1",
|
||||
"dotenv": "^10.0.0"
|
||||
|
|
|
@ -22,13 +22,24 @@ export class Util {
|
|||
message: "Member is not part of message",
|
||||
};
|
||||
|
||||
const disabledCommands = process.env.COMMANDS_DISABLED?.split(',');
|
||||
|
||||
if (disabledCommands?.find(x => x == name)) {
|
||||
message.reply(process.env.COMMANDS_DISABLED_MESSAGE || "This command is disabled.");
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: "Command is disabled",
|
||||
};
|
||||
}
|
||||
|
||||
const folder = process.env.FOLDERS_COMMANDS;
|
||||
|
||||
if (existsSync(`${process.cwd()}/${folder}/`)) {
|
||||
if (existsSync(`${process.cwd()}/${folder}/${name}.ts`)) {
|
||||
const commandFile = require(`${process.cwd()}/${folder}/${name}.ts`);
|
||||
const command = new commandFile[name]() as Command;
|
||||
|
||||
const commandFile = require(`${process.cwd()}/${folder}/${name}.ts`).default;
|
||||
const command = new commandFile() as Command;
|
||||
|
||||
const requiredRoles = command._roles;
|
||||
|
||||
if (!command._category) command._category = "none";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Command } from "../../../src/type/command";
|
||||
|
||||
export class noCategory extends Command {
|
||||
export default class noCategory extends Command {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Command } from "../../../src/type/command";
|
||||
|
||||
export class normal extends Command {
|
||||
export default class normal extends Command {
|
||||
constructor() {
|
||||
super();
|
||||
this._category = "General";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Command } from "../../../src/type/command";
|
||||
|
||||
export class roles extends Command {
|
||||
export default class roles extends Command {
|
||||
constructor() {
|
||||
super();
|
||||
this._roles = [ "Moderator" ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ beforeEach(() => {
|
|||
});
|
||||
|
||||
describe('OnMessage', () => {
|
||||
test('Given Message Is Valid Expect Message Sent', () => {
|
||||
test('Given Message Is Valid Expect Message Sent', async () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
|
@ -30,7 +30,7 @@ describe('OnMessage', () => {
|
|||
|
||||
const events = new Events();
|
||||
|
||||
const result = events.onMessage(message);
|
||||
const result = await events.onMessage(message);
|
||||
|
||||
expect(result.valid).toBeTruthy();
|
||||
|
||||
|
@ -41,7 +41,7 @@ describe('OnMessage', () => {
|
|||
expect(result.context?.message).toBe(message);
|
||||
});
|
||||
|
||||
test('Given Guild Is Null, Expect Failed Result', () => {
|
||||
test('Given Guild Is Null, Expect Failed Result', async () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
|
@ -61,13 +61,13 @@ describe('OnMessage', () => {
|
|||
|
||||
const events = new Events();
|
||||
|
||||
const result = events.onMessage(message);
|
||||
const result = await events.onMessage(message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Message was not sent in a guild, ignoring.");
|
||||
});
|
||||
|
||||
test('Given Author Is A Bot, Expect Failed Result', () => {
|
||||
test('Given Author Is A Bot, Expect Failed Result', async () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
|
@ -87,13 +87,13 @@ describe('OnMessage', () => {
|
|||
|
||||
const events = new Events();
|
||||
|
||||
const result = events.onMessage(message);
|
||||
const result = await events.onMessage(message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Message was sent by a bot, ignoring.");
|
||||
});
|
||||
|
||||
test('Given Message Content Was Not A Command, Expect Failed Result', () => {
|
||||
test('Given Message Content Was Not A Command, Expect Failed Result', async () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
|
@ -113,13 +113,13 @@ describe('OnMessage', () => {
|
|||
|
||||
const events = new Events();
|
||||
|
||||
const result = events.onMessage(message);
|
||||
const result = await events.onMessage(message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Message was not a command, ignoring.");
|
||||
});
|
||||
|
||||
test('Given Message Had No Command Name, Expect Failed Result', () => {
|
||||
test('Given Message Had No Command Name, Expect Failed Result', async () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
|
@ -139,13 +139,13 @@ describe('OnMessage', () => {
|
|||
|
||||
const events = new Events();
|
||||
|
||||
const result = events.onMessage(message);
|
||||
const result = await events.onMessage(message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Command name was not found");
|
||||
});
|
||||
|
||||
test('Given Command Failed To Execute, Expect Failed Result', () => {
|
||||
test('Given Command Failed To Execute, Expect Failed Result', async () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
|
@ -165,7 +165,7 @@ describe('OnMessage', () => {
|
|||
|
||||
const events = new Events();
|
||||
|
||||
const result = events.onMessage(message);
|
||||
const result = await events.onMessage(message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Command failed");
|
||||
|
@ -182,4 +182,4 @@ describe('OnReady', () => {
|
|||
|
||||
expect(console.log).toBeCalledWith("Ready");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -210,6 +210,136 @@ describe('LoadCommand', () => {
|
|||
|
||||
expect(result.valid).toBeTruthy();
|
||||
});
|
||||
|
||||
test('Given command is set to disabled, Expect command to not fire', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
COMMANDS_DISABLED: 'normal',
|
||||
COMMANDS_DISABLED_MESSAGE: 'disabled',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(true);
|
||||
|
||||
const message = {
|
||||
member: {
|
||||
roles: {
|
||||
cache: {
|
||||
find: jest.fn().mockReturnValue(true),
|
||||
}
|
||||
},
|
||||
},
|
||||
reply: jest.fn(),
|
||||
} as unknown as Message;
|
||||
|
||||
const messageReply = jest.spyOn(message, 'reply');
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadCommand("normal", [ "first" ], message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Command is disabled");
|
||||
expect(messageReply).toBeCalledWith("disabled");
|
||||
});
|
||||
|
||||
test('Given command COMMANDS_DISABLED_MESSAGE is empty, Expect default message sent', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
COMMANDS_DISABLED: 'normal',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(true);
|
||||
|
||||
const message = {
|
||||
member: {
|
||||
roles: {
|
||||
cache: {
|
||||
find: jest.fn().mockReturnValue(true),
|
||||
}
|
||||
},
|
||||
},
|
||||
reply: jest.fn(),
|
||||
} as unknown as Message;
|
||||
|
||||
const messageReply = jest.spyOn(message, 'reply');
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadCommand("normal", [ "first" ], message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Command is disabled");
|
||||
expect(messageReply).toBeCalledWith("This command is disabled.");
|
||||
});
|
||||
|
||||
test('Given a different command is disabled, Expect command to still fire', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
COMMANDS_DISABLED: 'anything',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(true);
|
||||
|
||||
const message = {
|
||||
member: {
|
||||
roles: {
|
||||
cache: {
|
||||
find: jest.fn().mockReturnValue(true),
|
||||
}
|
||||
},
|
||||
},
|
||||
reply: jest.fn(),
|
||||
} as unknown as Message;
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadCommand("normal", [ "first" ], message);
|
||||
|
||||
expect(result.valid).toBeTruthy();
|
||||
});
|
||||
|
||||
test('Given a different command is disabled with this one, Expect command to not fire', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
COMMANDS_DISABLED: 'normal,anything,',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(true);
|
||||
|
||||
const message = {
|
||||
member: {
|
||||
roles: {
|
||||
cache: {
|
||||
find: jest.fn().mockReturnValue(true),
|
||||
}
|
||||
},
|
||||
},
|
||||
reply: jest.fn(),
|
||||
} as unknown as Message;
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadCommand("normal", [ "first" ], message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Command is disabled");
|
||||
});
|
||||
});
|
||||
|
||||
describe('LoadEvents', () => {
|
||||
|
@ -288,4 +418,4 @@ describe('LoadEvents', () => {
|
|||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Event folder does not exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
12
yarn.lock
12
yarn.lock
|
@ -848,9 +848,9 @@ ansi-escapes@^4.2.1:
|
|||
type-fest "^0.21.3"
|
||||
|
||||
ansi-regex@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
|
||||
integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
|
||||
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
|
||||
|
||||
ansi-styles@^3.2.1:
|
||||
version "3.2.1"
|
||||
|
@ -2984,9 +2984,9 @@ throat@^6.0.1:
|
|||
integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==
|
||||
|
||||
tmpl@1.0.x:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
|
||||
integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc"
|
||||
integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==
|
||||
|
||||
to-fast-properties@^2.0.0:
|
||||
version "2.0.0"
|
||||
|
|
Reference in a new issue