Compare commits

...

135 Commits

Author SHA1 Message Date
f88e14b34a Update template by merging fork 'DiscordJS-Example' 2024-03-25 01:54:13 +01:00
94b0797797 version upgrade: alpha release 2024-03-23 22:57:12 +01:00
1253c1acf4 remove permissionOverwrite bug in custom_vc from README 2024-03-23 22:55:57 +01:00
54dcfddd1a bugfix(linting): case block scope for variable usage 2024-03-23 22:49:57 +01:00
4653af6f90 bugfix: missing import for JSDoc 2024-03-23 22:49:42 +01:00
0d80761e2c refactor: auto format 2024-03-23 22:47:24 +01:00
bba1617926 bugfix: logging user id 2024-03-23 22:45:10 +01:00
b8adefd093 implement working version of custom channel permissions 2024-03-23 22:43:21 +01:00
c7aad7190e added new member role explaination to README 2024-03-23 22:13:38 +01:00
fe139004bf bufix: added missing import 2024-03-03 17:13:59 +01:00
3563e5be62 download & install instructions 2024-03-03 17:08:47 +01:00
8d2f647ffd find or create, then save guild on each interaction 2024-03-03 01:44:27 +01:00
146bdf363e verbose logging 2024-03-03 01:07:10 +01:00
647dc6211b bugfix: corrected path 2024-03-03 00:50:46 +01:00
aee298f791 bugfix: import Deferrable 2024-03-03 00:49:36 +01:00
2a695f24c6 bugfix: def / init order 2024-03-03 00:47:17 +01:00
cfc714611e implement guild member add event 2024-03-03 00:46:44 +01:00
580b54c549 implement role assignment slash command 2024-03-03 00:41:37 +01:00
aa3eac70ba boolean property to note role assignment 2024-03-03 00:41:04 +01:00
5b7862fe7b extend database by saving guilds 2024-03-02 23:51:18 +01:00
7983eb60f9 bugfix: JSDoc typing 2024-03-02 23:49:49 +01:00
4aee497fba prepare member_roles with template 2024-03-02 23:49:13 +01:00
e0c581dcfd get specific permissions from parent element 2024-02-28 21:19:20 +01:00
84f754dd5b clean up: consistant naming 2024-02-28 21:18:14 +01:00
3cea3694db clean up: code style 2024-02-28 21:12:38 +01:00
fa6a9fa2e3 extract member prop early 2024-02-28 20:51:59 +01:00
73562b3570 apply permission overwrites from parent channel 2024-02-28 20:50:34 +01:00
0c3c1b5582 reformat: auto format 2024-02-28 20:48:45 +01:00
7ea28db049 more verbose logging 2024-02-28 20:43:36 +01:00
e74bd83ee6 catch channel delete error 2024-02-24 18:46:46 +01:00
ab6ca9edeb forced reaction remove error handling 2024-02-16 18:26:25 +01:00
064abe7e24 save emoji identifier without name 2024-02-16 18:26:00 +01:00
5c4192eb4b reply and provide id 2024-02-16 17:37:53 +01:00
b99db199d7 fixed jsdoc type error 2024-02-13 20:29:02 +01:00
9f3bceeade clean up: auto format 2024-02-11 02:55:46 +01:00
bdb08c1810 correct typing on typedef methods 2024-02-11 02:53:28 +01:00
b76e772ee2 additional model methods 2024-02-11 02:40:26 +01:00
f919dde7fa clean up: consistant format 2024-02-11 02:40:10 +01:00
76526e08b9 remove old docs on jsdoc script execution 2024-02-11 02:39:52 +01:00
80d4693c3d document code with jsdoc comments 2024-02-11 02:04:12 +01:00
ffa4d43d8f ignore jsdoc output for prettier and eslint 2024-02-11 02:00:47 +01:00
2a33dea919 configure eslint to use jsdoc 2024-02-11 02:00:30 +01:00
04bbb7e376 update packages 2024-02-11 02:00:16 +01:00
14a63d43d1 clean up: auto format 2024-02-11 01:59:57 +01:00
d7bef27f52 better JSDoc config 2024-02-10 22:16:33 +01:00
fe211b7055 ignore JSDoc output 2024-02-10 22:10:51 +01:00
0edfd41c13 initialize JSDoc 2024-02-10 22:10:04 +01:00
a14298fa66 update packages 2024-02-10 22:00:17 +01:00
daef590b83 bugfix: attach to same parent 2024-02-09 22:59:35 +01:00
4e3cfacfa4 bugfix: default permissions for members to use commands 2024-02-09 22:41:58 +01:00
4ab74597b7 better note format 2024-02-09 21:39:19 +01:00
b5440ae98d unify formatting 2024-02-09 21:36:44 +01:00
78cdf79fc4 refactor: auto format 2024-02-09 21:32:56 +01:00
13497ebf43 place explaination in README 2024-02-09 21:23:40 +01:00
5e43e9ba18 version upgrade: first alpha version 2024-02-09 19:56:12 +01:00
1ebe30f981 set invite in README with perms for current state 2024-02-09 19:55:24 +01:00
746341d48a refactor: auto format 2024-02-09 19:42:27 +01:00
3a2073f61f edit owned messages to include pair explainations 2024-02-09 19:39:49 +01:00
73de6dbcec bugfix: simple logic patches 2024-02-09 19:34:20 +01:00
7a9c2441a3 reformat: auto format 2024-02-08 21:11:56 +01:00
5338b56e4c bugfix: moved property to correct parent 2024-02-08 20:37:31 +01:00
552b0b9c3d remove debug log 2024-02-08 20:33:10 +01:00
dc166dd286 set minimum required custom vc permissions 2024-02-08 20:30:50 +01:00
cb1662cefb bugfix: only delete registered custom channels 2024-02-08 20:13:12 +01:00
e69806c132 remove self roels contextcommand and shared function 2024-02-08 19:45:38 +01:00
dfe673bebc remove self roles slashcommand 2024-02-08 19:34:01 +01:00
81bb307896 group imports in shared 2024-02-08 19:09:17 +01:00
2c7dd26189 verbose console feedback 2024-02-08 19:09:02 +01:00
067702ecc6 remove vc from custom vc creation 2024-02-08 19:03:58 +01:00
03fb793b6c only use voice channels 2024-02-08 18:43:01 +01:00
83068ae085 reference channel directly 2024-02-08 18:24:47 +01:00
76641b31c7 delete empty custom vc 2024-02-08 18:12:10 +01:00
ea54565c6a bugfix: case sensitive 2024-02-08 17:50:32 +01:00
8e9ddb1e7b explicit permission overwrites 2024-02-08 00:21:53 +01:00
f5d8bcc449 bugfix: wrong feedback type 2024-02-07 23:20:10 +01:00
7f94c9ddd3 version upgrade: fully functioning prototype 2024-02-07 22:07:41 +01:00
b9407ed52c lowercase name for possessive apostroph 2024-02-07 22:02:02 +01:00
6ded01b046 handle message/channel deletion 2024-02-07 21:02:37 +01:00
3339d7a244 initialize deletion events 2024-02-07 20:27:16 +01:00
0ffb68fd96 prepare for better event grouping 2024-02-07 20:26:57 +01:00
f3e2715703 use existing private channels 2024-02-07 20:05:39 +01:00
a29e2074a5 ignore if channel is unregistered 2024-02-07 19:38:51 +01:00
d212ca398a acknowledge command with reply 2024-02-07 19:34:18 +01:00
d0ec7fbb6c basic custom vc slash command 2024-02-07 19:30:14 +01:00
b5079b6f40 basic error handling and comments 2024-02-07 17:40:29 +01:00
1a3e7ac96b basic chanel creation 2024-02-07 17:36:00 +01:00
a0eb75e4ee basic subcommand handling 2024-02-07 17:35:30 +01:00
c8e3fc2f2c initialize custom vc slash command 2024-02-06 21:26:29 +01:00
000acd20aa clean up: format 2024-02-06 21:25:47 +01:00
105932b5a3 refactor: better file structure 2024-02-06 19:12:34 +01:00
4fea72ad88 refactor: autoformat with prettier 2024-02-06 16:18:06 +01:00
32ceb7646b Merge branch 'sync' from 'https://git.baipyr.us/Baipyrus/DiscordJS-Template.git' 2024-02-06 16:09:02 +01:00
46e938946c clean up: fs.promises api and reformat 2024-02-06 14:09:04 +01:00
fdedb50bc5 better error handling 2024-02-05 23:32:59 +01:00
61b8a9a2ec shared add self role pair function 2024-02-05 23:26:49 +01:00
86091f5eee implement modal submit interaction logic 2024-02-05 23:07:19 +01:00
095ad012ff use modal to add self role pair 2024-02-05 22:57:08 +01:00
4bdd04a881 fix generic command name getter 2024-02-05 22:56:22 +01:00
cb56dded3b initialize context add pair command 2024-02-05 21:27:04 +01:00
7fa972b411 deny command access in DMs 2024-02-05 21:26:47 +01:00
70d183e1ef refactor: rename to prepare additional context commands 2024-02-05 21:26:17 +01:00
d272bdb15e remove example commands 2024-02-05 21:24:55 +01:00
c66cff1d21 reaction event error feedback 2024-02-05 21:19:47 +01:00
474a35a736 error handling on reaction roles 2024-02-05 21:11:59 +01:00
ddcec60be6 update bot invite in README 2024-02-05 03:19:30 +01:00
531b07e304 clean up: refactor by splitting into functions 2024-02-05 03:10:21 +01:00
42293efb68 refactor: more verbose output 2024-02-05 03:06:53 +01:00
3fa0bd9c1f refactor: await all asynchronous function calls 2024-02-05 03:01:48 +01:00
1e716d5f5e replace emoji name in identifier 2024-02-05 02:58:08 +01:00
afa958b557 implement reaction add/remove events 2024-02-05 02:56:18 +01:00
d7409ed0f7 implemented context menu command for registering self roles 2024-02-05 00:16:52 +01:00
124e5afe5a refactor: renamed to differentiate command types 2024-02-05 00:16:06 +01:00
7cd7d68d3b clean up: delete empty line 2024-02-04 23:52:36 +01:00
caa23d6cb2 generalise command execution for interaction create 2024-02-04 23:52:08 +01:00
3d89bd8e65 ignore own reactions 2024-02-04 23:41:04 +01:00
cd44a4717a clean up: refactor by splitting into functions 2024-02-04 23:40:07 +01:00
04b259cf56 implement database access for self roles 2024-01-29 15:00:30 +01:00
7026ed56a8 clean up: using unprotected sqlite database 2024-01-29 14:59:52 +01:00
ae8562c536 rename model code to fit convention 2024-01-29 14:59:36 +01:00
7468dca986 rename model files to fit convention 2024-01-29 14:58:51 +01:00
7126d34866 prepare role-emoji-pair adding 2024-01-29 02:35:29 +01:00
e41afe0ada implement self roles command 2024-01-29 02:10:16 +01:00
1f5f5621c3 added voice channels to database 2024-01-29 00:32:32 +01:00
56a2c697dc added role-emoji-pair to database 2024-01-29 00:32:13 +01:00
c19ef05c82 added message to database 2024-01-29 00:31:40 +01:00
8a619b53e4 initialize sequalize with sqlite setup 2024-01-29 00:30:33 +01:00
db551f7e5b use slashcommand examples 2024-01-28 18:34:35 +01:00
7fe865ad98 detect users joining/leaving voice channels 2024-01-28 18:33:22 +01:00
0edf46856a detect users adding/removing reactions 2024-01-28 18:33:03 +01:00
713135a021 initialize reaction events 2024-01-26 20:23:45 +01:00
e67a846fa4 better naming convention 2024-01-26 20:23:19 +01:00
617edfd0a2 initialize self role command 2024-01-26 19:29:20 +01:00
3f1495cd07 bot invite README 2024-01-26 14:34:15 +01:00
7b04f95444 ignore example commands 2024-01-26 14:30:35 +01:00
c222b0db1d Initial commit 2024-01-26 13:28:02 +00:00
12 changed files with 1382 additions and 338 deletions

View File

@ -4,6 +4,7 @@ node_modules
.env .env
.env.* .env.*
!.env.example !.env.example
docs
# Ignore files for PNPM, NPM and YARN # Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml pnpm-lock.yaml

View File

@ -8,5 +8,8 @@
"ecmaVersion": "latest", "ecmaVersion": "latest",
"sourceType": "module" "sourceType": "module"
}, },
"rules": {} "plugins": ["jsdoc"],
"rules": {
"jsdoc/no-undefined-types": 1
}
} }

4
.gitignore vendored
View File

@ -2,4 +2,6 @@
node_modules node_modules
.env .env
.env.* .env.*
!.env.example !.env.example
commands/examples
docs

7
.jsdoc.conf.json Normal file
View File

@ -0,0 +1,7 @@
{
"source": {
"include": ["."],
"exclude": ["node_modules", "commands/examples"],
"includePattern": ".+\\.js(doc|x)?$"
}
}

View File

@ -4,6 +4,7 @@ node_modules
.env .env
.env.* .env.*
!.env.example !.env.example
docs
# Ignore files for PNPM, NPM and YARN # Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml pnpm-lock.yaml

View File

@ -3,13 +3,17 @@ import { REST, Routes } from 'discord.js';
import { join, dirname } from 'path'; import { join, dirname } from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import { config } from 'dotenv'; import { config } from 'dotenv';
import Module from 'module';
config(); config();
// Construct and prepare an instance of the REST module // Construct and prepare an instance of the REST module
const rest = new REST().setToken(process.env.TOKEN); const rest = new REST().setToken(process.env.TOKEN);
// and deploy your commands! /**
* Calls HTTP PUT to register commands in discord.
* @param {Array<Object>} commands
*/
const putCommands = async (commands) => { const putCommands = async (commands) => {
try { try {
console.info(`[INFO] Started refreshing ${commands.length} application (/) commands.`); console.info(`[INFO] Started refreshing ${commands.length} application (/) commands.`);
@ -32,6 +36,7 @@ getFiles(cmdPath)
// For each command file // For each command file
.then(async (files) => .then(async (files) =>
(await Promise.all(files.map(importAndCheck))) (await Promise.all(files.map(importAndCheck)))
.filter((module) => module !== 0) .filter(/** @param {(Module|0)} module */ (module) => module !== 0)
.map((module) => module.data.toJSON()) .map(/** @param {Module} module */ (module) => module.data.toJSON())
).then(putCommands); )
.then(putCommands);

View File

@ -1,5 +1,11 @@
import { Events } from 'discord.js'; import { Events } from 'discord.js';
import Module from 'module';
/**
* A more precise execution function specifically to call the main property of a module.
* @param {import('discord.js').Interaction} interaction
* @param {Module} command
*/
const executeCommand = async (interaction, command) => { const executeCommand = async (interaction, command) => {
// Try executing command // Try executing command
try { try {
@ -21,9 +27,21 @@ const executeCommand = async (interaction, command) => {
} }
}; };
/**
* A generic execution function to call command methods.
* @param {import('discord.js').Interaction} interaction
* @param {Module} command
* @param {string} name
* @param {string=} description
* @param {string=} cmdName
*/
const genericExecute = async (interaction, command, name, description, cmdName) => { const genericExecute = async (interaction, command, name, description, cmdName) => {
try { try {
console.info(`[INFO] Command ${(cmdName ?? interaction.commandName) ?? 'anonymous'} ${description ?? `used "${name}"`}.`); console.info(
`[INFO] Command ${cmdName ?? interaction.commandName ?? 'anonymous'} ${
description ?? `used "${name}"`
}.`
);
await command[name](interaction); await command[name](interaction);
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -31,7 +49,9 @@ const genericExecute = async (interaction, command, name, description, cmdName)
}; };
export const name = Events.InteractionCreate; export const name = Events.InteractionCreate;
/** @param {import('discord.js').Interaction} interaction */
export async function execute(interaction) { export async function execute(interaction) {
/** @type {Module} */
let command = interaction.client.commands.get(interaction.commandName); let command = interaction.client.commands.get(interaction.commandName);
// Execute slash- and context-menu-commands // Execute slash- and context-menu-commands

View File

@ -1,7 +1,8 @@
import { Events } from 'discord.js'; import { Events, Client } from 'discord.js';
export const name = Events.ClientReady; export const name = Events.ClientReady;
export const once = true; export const once = true;
/** @param {Client} client */
export function execute(client) { export function execute(client) {
console.info(`[INFO] Ready! Logged in as ${client.user.tag}`); console.info(`[INFO] Ready! Logged in as ${client.user.tag}`);
} }

View File

@ -1,23 +1,38 @@
import { Client, Collection, GatewayIntentBits } from 'discord.js'; import { Client, Collection, GatewayIntentBits, Partials } from 'discord.js';
import { getFiles, importAndCheck } from './shared.js'; import { getFiles, importAndCheck } from './shared.js';
import { Partials } from 'discord.js';
import { join, dirname } from 'path'; import { join, dirname } from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import { config } from 'dotenv'; import { config } from 'dotenv';
import Module from 'module';
config(); config();
/**
* Main entry point, the bot logs on to discord.
* @param {Array<Module>} commands
* @param {Array<Module>} events
*/
const runClient = (commands, events) => { const runClient = (commands, events) => {
// Create a new client instance // Create a new client instance
const client = new Client({ const client = new Client({
intents: [ intents: [
GatewayIntentBits.Guilds, GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMembers,
GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.GuildMessageReactions
], ],
partials: [Partials.Message, Partials.Reaction] partials: [Partials.Message, Partials.Reaction]
}); });
/**
* The commands registered for this client.
* @type {Collection}
*/
client.commands = new Collection(); client.commands = new Collection();
commands.forEach((c) => client.commands.set(c.data.name, c)); commands.forEach((c) => client.commands.set(c.data.name, c));
// Register client events
events.forEach((e) => events.forEach((e) =>
e.once e.once
? client.once(e.name, (...args) => e.execute(...args)) ? client.once(e.name, (...args) => e.execute(...args))
@ -35,13 +50,10 @@ const evtPath = join(__dirname, 'events');
getFiles(cmdPath) getFiles(cmdPath)
// For each command file // For each command file
.then(async (files) => .then(async (files) =>
(await Promise.all(files.map(importAndCheck))) (await Promise.all(files.map(importAndCheck))).filter((module) => module !== 0)
.filter((module) => module !== 0) )
).then(async (commands) => { .then(async (commands) => {
const files = await getFiles(evtPath); const files = await getFiles(evtPath);
const events = await Promise.all( const events = await Promise.all(files.map(async (filePath) => await import(filePath)));
files.map(async (filePath) =>
await import(filePath)
));
runClient(commands, events); runClient(commands, events);
}); });

1536
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,18 +8,20 @@
"start": "node .", "start": "node .",
"deploy": "node deploy.js", "deploy": "node deploy.js",
"lint": "prettier --check . && eslint .", "lint": "prettier --check . && eslint .",
"format": "prettier --write ." "format": "prettier --write .",
"jsdoc": "rm -rf docs/ && jsdoc -c ./.jsdoc.conf.json -d docs/ -r ."
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"discord.js": "^14.14.1", "discord.js": "^14.14.1",
"dotenv": "^16.3.1", "dotenv": "^16.4.5",
"proxy-agent": "^6.3.1" "sqlite3": "^5.1.7"
}, },
"devDependencies": { "devDependencies": {
"eslint": "^8.56.0", "eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-jsdoc": "^48.0.6",
"prettier": "^3.1.1" "prettier": "^3.1.1"
}, },
"type": "module" "type": "module"

View File

@ -1,38 +1,52 @@
import { join } from 'path'; import { readdir } from 'fs/promises';
import { readdir } from 'fs/promises'; import { join } from 'path';
import Module from 'module';
const required = ['data', 'execute'];
const optional = ['autocomplete', 'modalSubmit']; // Lists of required and optional attributes of command modules
const required = ['data', 'execute'];
export const getFiles = async (dir) => { const optional = ['autocomplete', 'modalSubmit'];
const dirents = await readdir(dir, { withFileTypes: true });
const files = await Promise.all(dirents.map((dirent) => { /**
const res = join(dir, dirent.name); * Recursively scans a directory for all files in it.
return dirent.isDirectory() ? getFiles(res) : res; * @param {string} dir
})); * @returns {Promise<Array<string>>} Array of paths to the files within.
return Array.prototype.concat(...files); */
}; export const getFiles = async (dir) => {
const dirents = await readdir(dir, { withFileTypes: true });
export const importAndCheck = async (filePath) => { const files = await Promise.all(
if (!filePath.endsWith('.js') || filePath.endsWith('.example.js')) { dirents.map((dirent) => {
// Skip this file const res = join(dir, dirent.name);
return 0; return dirent.isDirectory() ? getFiles(res) : res;
} })
const command = await import(filePath); );
// Warn incomplete commands return Array.prototype.concat(...files);
if (!required.every((name) => name in command)) { };
console.error(
`[ERROR] The command at ${filePath} is missing a required "data" or "execute" property.` /**
); * Imports and checks a command from a path as a module.
return 0; * @param {string} filePath
} * @returns {Promise<Module|0>}
const properties = optional.filter((name) => !(name in command)); */
if (properties.length > 0) export const importAndCheck = async (filePath) => {
properties.forEach((name) => if (!filePath.endsWith('.js') || filePath.endsWith('.example.js')) {
console.warn( // Skip this file
`[WARNING] The command at ${filePath} is missing an optional "${name}" property.` return 0;
) }
); const command = await import(filePath);
// Add command to collection // Warn incomplete commands
return command; if (!required.every((name) => name in command)) {
}; console.error(
`[ERROR] The command at ${filePath} is missing a required "data" or "execute" property.`
);
return 0;
}
const properties = optional.filter((name) => !(name in command));
if (properties.length > 0)
properties.forEach((name) =>
console.warn(
`[WARNING] The command at ${filePath} is missing an optional "${name}" property.`
)
);
// Add command to collection
return command;
};