diff --git a/docs/README b/docs/README index f799806..edf2330 100644 --- a/docs/README +++ b/docs/README @@ -1 +1 @@ -This documentation is intended to be access through the website (https://eartharoid.github.io/discordtickets) \ No newline at end of file +This documentation is intended to be access through the website (https://discordtickets.eartharoid.me) \ No newline at end of file diff --git a/src/index.js b/src/index.js index 86dce1b..92533f4 100644 --- a/src/index.js +++ b/src/index.js @@ -28,29 +28,30 @@ if (node_version < 14) const fs = require('fs'); const { path } = require('./utils/fs'); -const ENV_PATH = path('./.env'); -const EXAMPLE_ENV_PATH = path('./example.env'); -if (!fs.existsSync(ENV_PATH )) { - if (!fs.existsSync(EXAMPLE_ENV_PATH)) { - console.log('Error: \'.env\' not found, and unable to create it due to \'example.env\' being missing'); +const checkFile = (file, example) => { + + file = path(file); + example = path(example); + + if (fs.existsSync(file)) return true; + if (!fs.existsSync(example)) { + console.log(`Error: '${file}' not found, and unable to create it due to '${example}' being missing`); return process.exit(); } - console.log('Copying \'example.env\' to \'.env\''); - fs.copyFileSync(EXAMPLE_ENV_PATH, ENV_PATH); - console.log('Please set your bot\'s token in your \'.env\' file'); + + console.log(`Copying '${example}' to '${file}'`); + fs.copyFileSync(example, file); + return false; + +}; + +if (!checkFile('./.env', './example.env')) { + console.log('Please set your bot\'s token in \'.env\''); process.exit(); } - -const CONFIG_PATH = path('./user/config.js'); -const EXAMPLE_CONFIG_PATH = path('./user/example.config.js'); -if (!fs.existsSync(CONFIG_PATH)) { - if (!fs.existsSync(EXAMPLE_CONFIG_PATH)) { - console.log('Error: \'user/config.js\' not found, and unable to create it due to \'user/example.config.js\' being missing'); - return process.exit(); - } - console.log('Copying \'user/example.config.js\' to \'user/config.js\''); - fs.copyFileSync(EXAMPLE_CONFIG_PATH, CONFIG_PATH); -} + +checkFile('./user/config.js', './user/example.config.js'); + require('dotenv').config({ @@ -105,33 +106,36 @@ class Bot extends Client { } }); - /** The global bot configuration */ - this.config= config; - /** A sequelize instance */ - this.db = require('./database')(log), // this.db.models.Ticket... - /** A leekslazylogger instance */ - this.log = log; - /** An @eartharoid/i18n instance */ - this.i18n = new I18n(path('./src/locales'), 'en-GB'); - - // set the max listeners for each event to the number in the config - this.setMaxListeners(this.config.max_listeners); + (async () => { + /** The global bot configuration */ + this.config = config; - // check for updates - require('./updater')(this); - // load internal listeners - require('./modules/listeners')(this); + /** A sequelize instance */ + this.db = await require('./database')(log), // this.db.models.Ticket... - /** The command manager, used by internal and plugin commands */ - this.commands = new CommandManager(this); - /** The plugin manager */ - this.plugins = new PluginManager(this); - // load plugins - this.plugins.load(); + /** A leekslazylogger instance */ + this.log = log; - this.log.info('Connecting to Discord API...'); + /** An @eartharoid/i18n instance */ + this.i18n = new I18n(path('./src/locales'), 'en-GB'); - this.login(); + this.setMaxListeners(this.config.max_listeners); // set the max listeners for each event + + require('./updater')(this); // check for updates + require('./modules/listeners')(this); // load internal listeners + + /** The command manager, used by internal and plugin commands */ + this.commands = new CommandManager(this); + this.commands.load(); // load internal commands + + /** The plugin manager */ + this.plugins = new PluginManager(this); + this.plugins.load(); // load plugins + + this.log.info('Connecting to Discord API...'); + + this.login(); + })(); } } diff --git a/src/modules/commands.js b/src/modules/commands.js deleted file mode 100644 index e38d279..0000000 --- a/src/modules/commands.js +++ /dev/null @@ -1,41 +0,0 @@ -const fs = require('fs'); -const { join } = require('path'); -const { path } = require('../utils/fs'); - -class CommandManager { - constructor(client) { - this.client = client; - this.commands = new Map(); - } - - load(command) { - - } - - unload(command) { - - } - - reload(command) { - - } - - get(command) { - - } - - get list() { - return this.commands; - } -} - -class Command { - constructor(client) { - - } -} - -module.exports = { - CommandManager, - Command -}; \ No newline at end of file diff --git a/src/modules/commands/command.js b/src/modules/commands/command.js new file mode 100644 index 0000000..024741f --- /dev/null +++ b/src/modules/commands/command.js @@ -0,0 +1,92 @@ +/* eslint-disable no-unused-vars */ +const { Client } = require('discord.js'); + +const fs = require('fs'); +const { join } = require('path'); +const { path } = require('../../utils/fs'); + +/** A plugin */ +module.exports = class Plugin { + /** + * Create a new Plugin + * @param {Client} client The Discord Client + * @param {String} id The plugin ID + * @param {Object} options Plugin options + * @param {String} options.name A human-friendly name (can be different to the name in package.json) + */ + constructor(client, id, options = {}) { + /** The human-friendly name of the plugin */ + this.name = options.name || id; + + /** The Discord Client */ + this.client = client; + + /** The PluginManager */ + this.manager = this.client.plugins; + + // Object.assign(this, this.manager.plugins.get(id)); + // make JSDoc happy + + let { + version, + author, + description + } = this.manager.plugins.get(id); + + /** The unique ID of the plugin (NPM package name) */ + this.id = id; + + /** The version of the plugin (NPM package version) */ + this.version = version; + + /** The plugin author's name (NPM package author) */ + this.author = author; + + /** The plugin description (NPM package description) */ + this.description = description; + + this.directory = {}; + + /** A cleaned version of the plugin's ID suitable for use in the directory name */ + this.directory.name = this.id.replace(/@[-_a-zA-Z0-9]+\//, ''); + + /** The absolute path of the plugin directory */ + this.directory.path = path(`./user/plugins/${this.directory.name}`); + } + + /** + * Create the plugin directory if it doesn't already exist + * @returns {Boolean} True if created, false if it already existed + */ + createDirectory() { + if (!fs.existsSync(this.directory.path)) { + this.client.log.plugins(`Creating plugin directory for "${this.name}"`); + fs.mkdirSync(this.directory.path); + return true; + } else { + return false; + } + } + + /** + * Create the plugin config file if it doesn't already exist + * @param {Object} template The default config template + * @returns {Boolean} True if created, false if it already existed + */ + createConfig(template) { + this.createDirectory(); + let file = join(this.directory.path, 'config.json'); + if (!fs.existsSync(file)) { + this.client.log.plugins(`Creating plugin config file for "${this.name}"`); + fs.writeFileSync(file, JSON.stringify(template, null, 2)); + return true; + } else { + return false; + } + } + + /** + * The main function where your code should go. Create functions and event listeners here + */ + load() {} +}; \ No newline at end of file diff --git a/src/modules/commands/index.js b/src/modules/commands/index.js new file mode 100644 index 0000000..c9cfb38 --- /dev/null +++ b/src/modules/commands/index.js @@ -0,0 +1,4 @@ +module.exports = { + CommandManager: require('./manager'), + Command: require('./command') +}; \ No newline at end of file diff --git a/src/modules/commands/manager.js b/src/modules/commands/manager.js new file mode 100644 index 0000000..3c7a3a8 --- /dev/null +++ b/src/modules/commands/manager.js @@ -0,0 +1,33 @@ +// eslint-disable-next-line no-unused-vars +const { Collection, Client } = require('discord.js'); +// eslint-disable-next-line no-unused-vars +const Command = require('./command'); + +const fs = require('fs'); +const { path } = require('../../utils/fs'); + +/** Manages the loading of commands */ +module.exports = class CommandManager { + /** + * Create a CommandManager instance + * @param {Client} client + */ + constructor(client) { + /** The Discord Client */ + this.client = client; + /** A discord.js Collection (Map) of loaded commands */ + this.commands = new Collection(); + } + + /** Automatically load all internal commands */ + load() { + const files = fs.readdirSync(path('./src/commands')) + .filter(file => file.endsWith('.js')); + + for (const file of files) { + const cmd = require(`../commands/${file}`); + this.commands.set(cmd, new cmd(this.client)); + } + } + +}; \ No newline at end of file diff --git a/src/modules/plugins/manager.js b/src/modules/plugins/manager.js index 4408b00..9397bb1 100644 --- a/src/modules/plugins/manager.js +++ b/src/modules/plugins/manager.js @@ -80,15 +80,13 @@ module.exports = class PluginManager { } } - /** - * Automatically register and load plugins - */ + /** Automatically register and load plugins */ load() { // normal plugins (NPM) this.client.config.plugins.forEach(plugin => { try { - let pkg = require(`${plugin}/package.json`); let main = require(plugin); + let pkg = require(`${plugin}/package.json`); this.registerPlugin(true, main, pkg); } catch (e) { this.client.log.warn(`An error occurred whilst loading ${plugin}; have you installed it?`); diff --git a/src/modules/plugins/plugin.js b/src/modules/plugins/plugin.js index dd77fca..024741f 100644 --- a/src/modules/plugins/plugin.js +++ b/src/modules/plugins/plugin.js @@ -14,14 +14,13 @@ module.exports = class Plugin { * @param {Object} options Plugin options * @param {String} options.name A human-friendly name (can be different to the name in package.json) */ - constructor(client, id, options) { - if (typeof options === 'object') { - /** The human-friendly name of the plugin */ - this.name = options.name || id; - } + constructor(client, id, options = {}) { + /** The human-friendly name of the plugin */ + this.name = options.name || id; /** The Discord Client */ this.client = client; + /** The PluginManager */ this.manager = this.client.plugins; @@ -36,16 +35,21 @@ module.exports = class Plugin { /** The unique ID of the plugin (NPM package name) */ this.id = id; + /** The version of the plugin (NPM package version) */ this.version = version; + /** The plugin author's name (NPM package author) */ this.author = author; + /** The plugin description (NPM package description) */ this.description = description; this.directory = {}; + /** A cleaned version of the plugin's ID suitable for use in the directory name */ this.directory.name = this.id.replace(/@[-_a-zA-Z0-9]+\//, ''); + /** The absolute path of the plugin directory */ this.directory.path = path(`./user/plugins/${this.directory.name}`); } diff --git a/user/example.config.js b/user/example.config.js index fd04b1e..d27972f 100644 --- a/user/example.config.js +++ b/user/example.config.js @@ -10,14 +10,14 @@ * Quick Start * --------------------- * - * > For detailed instructions, visit the documentation: https://eartharoid.github.io/discordtickets + * > For detailed instructions, visit the documentation: https://discordtickets.eartharoid.me * * --------------------- * Support * --------------------- * * > Discord support server: https://go.eartharoid.me/discord - * > Wiki: https://eartharoid.github.io/discordtickets + * > Documentation: https://discordtickets.eartharoid.me * * ############################################################################################### */ @@ -35,12 +35,8 @@ module.exports = { max_listeners: 10, plugins: [ // 'dsctickets.plugin-name' - 'discordtickets-portal' + // 'discordtickets-portal' ], - portal: { - enabled: false, - host: 'https://tickets.example.com' - }, presences: [ { activity: '/new | /help',