diff --git a/.env.template b/.env.template index 22c5724..4c776c2 100644 --- a/.env.template +++ b/.env.template @@ -14,21 +14,4 @@ BOT_DATE=28 Nov 2021 BOT_OWNERID=147392775707426816 FOLDERS_COMMANDS=src/commands -FOLDERS_EVENTS=src/events - -COMMANDS_DISABLED= -COMMANDS_DISABLED_MESSAGE=This command is disabled. - -COMMANDS_ROLE_ROLES=Notify,VotePings,ProjectUpdates - -COMMANDS_RULES_FILE=data/rules/rules.json - -EMBED_COLOUR=0x3050ba -EMBED_COLOUR_ERROR=0xD52803 - -ROLES_MODERATOR=Moderator -ROLES_MUTED=Muted - -CHANNELS_LOGS_MESSAGE=message-logs -CHANNELS_LOGS_MEMBER=member-logs -CHANNELS_LOGS_MOD=mod-logs \ No newline at end of file +FOLDERS_EVENTS=src/events \ No newline at end of file diff --git a/data/config.txt b/data/config.txt new file mode 100644 index 0000000..efa13ed --- /dev/null +++ b/data/config.txt @@ -0,0 +1,18 @@ +USAGE: [value] + +===[ KEYS ]=== +commands.disabled: Disabled commands (Default: "") +commands.disabled.message: The message to show when a disabled command is ran (Default: "This command is disabled.") + +role.assignable: List of roles assignable to user (Default: []) +role.moderator: The moderator role name (Default: "Moderator") +role.muted: The muted role name (Default: "Muted") + +rules.file: The location of the rules file (Default: "data/rules/rules") + +embed.colour.info: The HEX value of the info embeds (Default: "0x3050ba") +embed.colour.error: The HEX value of the error embeds (Default: "0xd52803") + +channels.logs.message: The channel message events will be logged to (Default: "message-logs") +channels.logs.member: The channel member events will be logged to (Default: "member-logs") +channels.logs.mod: The channel mod events will be logged to (Default: "mod-logs") \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 62c761e..a10aebd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: "3.9" services: - discord: - build: . + # discord: + # build: . database: image: mysql/mysql-server diff --git a/package.json b/package.json index c9f1ecd..e455a26 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "emoji-regex": "^9.2.0", "jest": "^27.4.5", "jest-mock-extended": "^2.0.4", + "mysql": "^2.18.1", "random-bunny": "^2.0.0", "ts-jest": "^27.1.2", "typeorm": "^0.2.44", diff --git a/src/Register.ts b/src/Register.ts index d8390bf..452c6c4 100644 --- a/src/Register.ts +++ b/src/Register.ts @@ -2,6 +2,7 @@ import { CoreClient } from "./client/client"; import About from "./commands/about"; import Ban from "./commands/ban"; import Clear from "./commands/clear"; +import Config from "./commands/config"; import Evaluate from "./commands/eval"; import Help from "./commands/help"; import Kick from "./commands/kick"; @@ -9,6 +10,7 @@ import Mute from "./commands/mute"; import Poll from "./commands/poll"; import Role from "./commands/role"; import Rules from "./commands/rules"; +import Setup from "./commands/setup"; import Unmute from "./commands/unmute"; import Warn from "./commands/warn"; import MemberEvents from "./events/MemberEvents"; @@ -28,6 +30,8 @@ export default class Register { client.RegisterCommand("rules", new Rules()); client.RegisterCommand("unmute", new Unmute()); client.RegisterCommand("warn", new Warn()); + client.RegisterCommand("setup", new Setup()); + client.RegisterCommand("config", new Config()); } public static RegisterEvents(client: CoreClient) { diff --git a/src/client/client.ts b/src/client/client.ts index c52734c..f5a8a6e 100644 --- a/src/client/client.ts +++ b/src/client/client.ts @@ -1,5 +1,6 @@ import { Client } from "discord.js"; import * as dotenv from "dotenv"; +import { createConnection } from "typeorm"; import ICommandItem from "../contracts/ICommandItem"; import IEventItem from "../contracts/IEventItem"; import { Command } from "../type/command"; @@ -34,12 +35,16 @@ export class CoreClient extends Client { this._util = new Util(); } - public start() { + public async start() { if (!process.env.BOT_TOKEN) throw "BOT_TOKEN is not defined in .env"; if (!process.env.BOT_PREFIX) throw "BOT_PREFIX is not defined in .env"; if (!process.env.FOLDERS_COMMANDS) throw "FOLDERS_COMMANDS is not defined in .env"; if (!process.env.FOLDERS_EVENTS) throw "FOLDERS_EVENTS is not defined in .env"; + await createConnection().catch(e => { + throw e; + }); + super.on("message", (message) => this._events.onMessage(message, this._commandItems)); super.on("ready", this._events.onReady); diff --git a/src/commands/config.ts b/src/commands/config.ts new file mode 100644 index 0000000..7e719da --- /dev/null +++ b/src/commands/config.ts @@ -0,0 +1,118 @@ +import { Guild } from "discord.js"; +import { readFileSync } from "fs"; +import DefaultValues from "../constants/DefaultValues"; +import { ICommandContext } from "../contracts/ICommandContext"; +import ICommandReturnContext from "../contracts/ICommandReturnContext"; +import Server from "../entity/Server"; +import Setting from "../entity/Setting"; +import ErrorEmbed from "../helpers/embeds/ErrorEmbed"; +import PublicEmbed from "../helpers/embeds/PublicEmbed"; +import { Command } from "../type/command"; + +export default class Config extends Command { + constructor() { + super(); + super._category = "Administration"; + } + + public override async execute(context: ICommandContext) { + if (!context.message.guild) { + return; + } + + const server = await Server.FetchOneById(Server, context.message.guild?.id, [ + "Settings", + ]); + + if (!server) { + const embed = new ErrorEmbed(context, "This server hasn't been setup yet, please run the setup command"); + embed.SendToCurrentChannel(); + return; + } + + const key = context.args[0]; + const action = context.args[1]; + const value = context.args.splice(2).join(" "); + + if (!key) { + this.SendHelpText(context); + } else if (!action) { + this.GetValue(context, server, key); + } else { + switch(action) { + case 'reset': + this.ResetValue(context, server, key); + break; + case 'set': + if (!value) { + const errorEmbed = new ErrorEmbed(context, "Value is required when setting"); + errorEmbed.SendToCurrentChannel(); + return; + } + + this.SetValue(context, server, key, value); + break; + default: + const errorEmbed = new ErrorEmbed(context, "Action must be either set or reset"); + errorEmbed.SendToCurrentChannel(); + return; + } + } + } + + private async SendHelpText(context: ICommandContext) { + const description = readFileSync(`${process.cwd()}/data/config.txt`).toString(); + + const embed = new PublicEmbed(context, "Config", description); + + embed.SendToCurrentChannel(); + } + + private async GetValue(context: ICommandContext, server: Server, key: string) { + const setting = server.Settings.filter(x => x.Key == key)[0]; + + if (setting) { + const embed = new PublicEmbed(context, "", `${key}: ${setting.Value}`); + embed.SendToCurrentChannel(); + } else { + const embed = new PublicEmbed(context, "", `${key}: ${DefaultValues.GetValue(key)} `); + embed.SendToCurrentChannel(); + } + } + + private async ResetValue(context: ICommandContext, server: Server, key: string) { + const setting = server.Settings.filter(x => x.Key == key)[0]; + + if (!setting) { + const embed = new PublicEmbed(context, "", "Setting has been reset"); + embed.SendToCurrentChannel(); + return; + } + + await Setting.Remove(Setting, setting); + + const embed = new PublicEmbed(context, "", "Setting has been reset"); + embed.SendToCurrentChannel(); + } + + private async SetValue(context: ICommandContext, server: Server, key: string, value: string) { + const setting = server.Settings.filter(x => x.Key == key)[0]; + + if (setting) { + setting.UpdateBasicDetails(key, value); + + await setting.Save(Setting, setting); + } else { + const newSetting = new Setting(key, value); + + await newSetting.Save(Setting, newSetting); + + server.AddSettingToServer(newSetting); + + await server.Save(Server, server); + } + + const embed = new PublicEmbed(context, "", "Setting has been set"); + embed.SendToCurrentChannel(); + } +} \ No newline at end of file diff --git a/src/commands/setup.ts b/src/commands/setup.ts new file mode 100644 index 0000000..73ae1ab --- /dev/null +++ b/src/commands/setup.ts @@ -0,0 +1,34 @@ +import { ICommandContext } from "../contracts/ICommandContext"; +import ICommandReturnContext from "../contracts/ICommandReturnContext"; +import Server from "../entity/Server"; +import ErrorEmbed from "../helpers/embeds/ErrorEmbed"; +import PublicEmbed from "../helpers/embeds/PublicEmbed"; +import { Command } from "../type/command"; + +export default class Setup extends Command { + constructor() { + super(); + super._category = "Administration"; + } + + public override async execute(context: ICommandContext) { + if (!context.message.guild) { + return; + } + + const server = await Server.FetchOneById(Server, context.message.guild?.id); + + if (server) { + const embed = new ErrorEmbed(context, "This server has already been setup, please configure using the config command"); + embed.SendToCurrentChannel(); + return; + } + + const newServer = new Server(context.message.guild?.id); + + await newServer.Save(Server, newServer); + + const embed = new PublicEmbed(context, "Success", "Please configure using the config command"); + embed.SendToCurrentChannel(); + } +} \ No newline at end of file diff --git a/src/constants/DefaultValues.ts b/src/constants/DefaultValues.ts index e099a5a..12f8142 100644 --- a/src/constants/DefaultValues.ts +++ b/src/constants/DefaultValues.ts @@ -1,5 +1,5 @@ export default class DefaultValues { - public static readonly values: ISettingValue[]; + public static readonly values: ISettingValue[] = []; public static GetValue(key: string): string | undefined { this.SetValues(); diff --git a/src/vylbot.ts b/src/vylbot.ts index 56cbdc4..3437d89 100644 --- a/src/vylbot.ts +++ b/src/vylbot.ts @@ -4,16 +4,7 @@ import Register from "./Register"; dotenv.config(); -const requiredConfigs = [ - "EMBED_COLOUR", - "EMBED_COLOUR_ERROR", - "ROLES_MODERATOR", - "ROLES_MUTED", - "CHANNELS_LOGS_MESSAGE", - "CHANNELS_LOGS_MEMBER", - "CHANNELS_LOGS_MOD", - "COMMANDS_ROLE_ROLES", - "COMMANDS_RULES_FILE" +const requiredConfigs: string[] = [ ]; requiredConfigs.forEach(config => { diff --git a/tsconfig.json b/tsconfig.json index 4cd216c..e11fe0b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -63,7 +63,7 @@ /* Experimental Options */ "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ /* Advanced Options */ "skipLibCheck": true, /* Skip type checking of declaration files. */ diff --git a/yarn.lock b/yarn.lock index 92ce5f0..71fe276 100644 --- a/yarn.lock +++ b/yarn.lock @@ -838,6 +838,11 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +bignumber.js@9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075" + integrity sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -1047,6 +1052,11 @@ convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: dependencies: safe-buffer "~5.1.1" +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -1511,7 +1521,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1: +inherits@2, inherits@^2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -1565,6 +1575,11 @@ is-typedarray@^1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -2245,6 +2260,16 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +mysql@^2.18.1: + version "2.18.1" + resolved "https://registry.yarnpkg.com/mysql/-/mysql-2.18.1.tgz#2254143855c5a8c73825e4522baf2ea021766717" + integrity sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig== + dependencies: + bignumber.js "9.0.0" + readable-stream "2.3.7" + safe-buffer "5.1.2" + sqlstring "2.3.1" + mz@^2.4.0: version "2.7.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" @@ -2432,6 +2457,11 @@ prism-media@^1.2.9: resolved "https://registry.yarnpkg.com/prism-media/-/prism-media-1.3.2.tgz#a1f04423ec15d22f3d62b1987b6a25dc49aad13b" integrity sha512-L6UsGHcT6i4wrQhFF1aPK+MNYgjRqR2tUoIqEY+CG1NqVkMjPRKzS37j9f8GiYPlD6wG9ruBj+q5Ax+bH8Ik1g== +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + prompts@^2.0.1: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" @@ -2476,6 +2506,19 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +readable-stream@2.3.7: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + reflect-metadata@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" @@ -2530,16 +2573,16 @@ rimraf@^3.0.0: dependencies: glob "^7.1.3" +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + safe-buffer@^5.0.1: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - "safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -2637,6 +2680,11 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= +sqlstring@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.1.tgz#475393ff9e91479aea62dcaf0ca3d14983a7fb40" + integrity sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A= + stack-utils@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" @@ -2661,6 +2709,13 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -2872,6 +2927,11 @@ universalify@^0.1.2: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"