Compare commits

..

No commits in common. "1336ee7d0dfedc2395f6fd356f1b2de4ed23ad99" and "c61a6fd28219d57add9ae6d51f30c22964218c64" have entirely different histories.

10 changed files with 91 additions and 275 deletions

View File

@ -4,7 +4,7 @@ import {
SlashCommandBuilder,
ChatInputCommandInteraction
} from 'discord.js';
import { Guilds, VoiceChannels } from '../../database.js';
import { Guilds, VoiceChannels } from '../../../database.js';
export const data = new SlashCommandBuilder()
.setName('custom_vc')

View File

@ -1,5 +1,5 @@
import { SlashCommandBuilder, PermissionFlagsBits, ChatInputCommandInteraction } from 'discord.js';
import { Roles, Guilds } from '../../database.js';
import { Roles, Guilds } from '../../../database.js';
/**
* @param {Guilds} guild

View File

@ -115,67 +115,34 @@ async function addResponse(interaction) {
await interaction.showModal(modal);
}
/** @param {ChatInputCommandInteraction} interaction */
async function removeKeyword(interaction) {
const { options } = interaction;
// Get command options
const keyword = options.getString('name');
// Try deleting keyword from database
await Keywords.destroy({
where: {
guild: interaction.guildId,
name: keyword
}
});
// Reply with success
await interaction.reply({
content: `Keyword '${keyword}' was successfully deleted!`,
ephemeral: true
});
}
/** @param {ChatInputCommandInteraction} interaction */
async function removeResponse(interaction) {
const { options } = interaction;
// Get command options
const keyword = options.getString('keyword');
/** @type {'keyword'|'response'} */
const type = options.getString('type');
const name = options.getString('name');
// Find keyword in database
/** @type {import('../../models/keywords.js').Keyword|null} */
const found = await Keywords.findOne({
where: {
guild: interaction.guildId,
name: keyword
}
});
// Abort if keyword not found
if (found === null) {
await interaction.reply({
content: 'Unknown keyword was specified!',
ephemeral: true
});
return;
switch (type) {
case 'keyword':
// Try removing keyword
await Keywords.destroy({
where: {
guild: interaction.guildId,
name
}
});
break;
case 'response':
// Try removing response
await Responses.destroy({
where: {
guild: interaction.guildId,
name
}
});
}
// Try deleting response from database
await Responses.destroy({
where: {
keyword: found.id,
name
}
});
// Reply with success
await interaction.reply({
content: `Response with name '${name}' was successfully deleted!`,
ephemeral: true
});
}
/** @param {ChatInputCommandInteraction} interaction */
@ -208,62 +175,11 @@ async function listResponse(interaction) {
}
/** @param {ChatInputCommandInteraction} interaction */
async function responseInfos(interaction) {
async function infoResponse(interaction) {
const { options } = interaction;
// Get command options
const keyword = options.getString('keyword');
const name = options.getString('name');
// Find keyword in database
/** @type {import('../../models/keywords.js').Keyword|null} */
const found = await Keywords.findOne({
where: {
guild: interaction.guildId,
name: keyword
}
});
// Abort if keyword not found
if (found === null) {
await interaction.reply({
content: 'Unknown keyword was specified!',
ephemeral: true
});
return;
}
// Find response in database
/** @type {import('../../models/responses.js').Response|null} */
const response = await Responses.findOne({
where: {
keyword: found.id,
name
}
});
// Abort if response not found
if (response === null) {
await interaction.reply({
content: 'Unknown response was specified!',
ephemeral: true
});
return;
}
// Reply with success
await interaction.reply({
content: `Response with name '${name}' has data of \`${response.response}\`!`,
ephemeral: true
});
}
/** @param {ChatInputCommandInteraction} interaction */
async function keywordInfos(interaction) {
const { options } = interaction;
// Get command options
const keyword = options.getString('name');
// Find keyword in database
/** @type {import('../../models/keywords.js').Keyword|null} */
@ -287,21 +203,13 @@ async function keywordInfos(interaction) {
/** @type {import('../../models/responses.js').Response[]} */
const responses = await Responses.findAll({
where: {
keyword: found.id
guild: interaction.guildId,
name: found.id
}
});
// Abort if no responses registered
if (responses.length === 0) {
await interaction.reply({
content: 'No responses have been registered yet!',
ephemeral: true
});
return;
}
// Join list of responses
const joined = responses.map((response) => response.name).join('\n- ');
const joined = responses.map((response) => response.response).join('\n- ');
// Reply with list of responses
await interaction.reply({
@ -310,13 +218,11 @@ async function keywordInfos(interaction) {
});
}
/** @param {AutocompleteInteraction} interaction */
async function keywordAutocomplete(interaction, focused) {
const { options, guildId } = interaction;
// Get command options
if (!focused) focused = options.getFocused();
/**
* @param {string} guildId
* @param {string} focused
*/
async function keywordAutocomplete(guildId, focused) {
// Get list of keywords from database
/** @type {import('../../models/keywords.js').Keyword[]} */
const keywords = await Keywords.findAll({
@ -333,15 +239,11 @@ async function keywordAutocomplete(interaction, focused) {
}
/**
* @param {AutocompleteInteraction} interaction
* @param {string} guildId
* @param {string} focused
* @param {string} keyword
*/
async function completeResponses(interaction, focused) {
const { options, guildId } = interaction;
// Get command options
const keyword = options.getString('keyword');
async function responseAutocomplete(guildId, focused, keyword) {
// Get keyword
/** @type {import('../../models/keywords.js').Keyword} */
const found = await Keywords.findOne({
@ -358,6 +260,7 @@ async function completeResponses(interaction, focused) {
? []
: await Responses.findAll({
where: {
guild: guildId,
keyword: found.id
}
});
@ -366,22 +269,27 @@ async function completeResponses(interaction, focused) {
const filtered = responses.filter((choice) => choice.name.startsWith(focused));
// Respond with possible suggestions
await interaction.respond(filtered.map((choice) => ({ name: choice.name, value: choice.name })));
await interaction.respond(
filtered.map((choice) => ({ name: choice.name, value: choice.response }))
);
}
/** @param {AutocompleteInteraction} interaction */
async function responseAutocomplete(interaction) {
async function removeAutocomplete(interaction) {
const { options } = interaction;
// Get command options
const focused = options.getFocused(true);
const { name, value } = focused;
switch (name) {
const type = options.getString('type');
switch (type) {
case 'keyword':
keywordAutocomplete(interaction, value);
await keywordAutocomplete(interaction.guildId, options.getFocused());
break;
case 'name':
completeResponses(interaction, value);
case 'response':
await responseAutocomplete(
interaction.guildId,
options.getFocused(),
options.getString('keyword')
);
break;
}
}
@ -414,79 +322,41 @@ export const data = new SlashCommandBuilder()
.setRequired(true)
)
)
.addSubcommandGroup((group) =>
group
.addSubcommand((subcommand) =>
subcommand
.setName('remove')
.setDescription('Unregisters a response or a keyword.')
.addSubcommand((subcommand) =>
subcommand
.setName('keyword')
.setDescription('Deletes a keyword completely.')
.addStringOption((option) =>
option
.setName('name')
.setDescription('The keyword to be deleted.')
.setAutocomplete(true)
.setRequired(true)
.setDescription('Unregisters a response to a keyword.')
.addStringOption((option) =>
option
.setName('type')
.setDescription('The type of data to be removed.')
.setRequired(true)
.addChoices(
{ name: 'Keyword', value: 'keyword' },
{ name: 'Response', value: 'response' }
)
)
.addSubcommand((subcommand) =>
subcommand
.setName('response')
.setDescription('Unregisters a response of a keyword.')
.addStringOption((option) =>
option
.setName('keyword')
.setDescription('The keyword that would trigger the response.')
.setAutocomplete(true)
.setRequired(true)
)
.addStringOption((option) =>
option
.setName('name')
.setDescription('The name of the data to be removed.')
.setAutocomplete(true)
.setRequired(true)
)
.addStringOption((option) =>
option
.setName('name')
.setDescription('The name of the data to be removed.')
.setAutocomplete(true)
.setRequired(true)
)
)
.addSubcommand((subcommand) =>
subcommand.setName('list').setDescription('Lists all registered keywords.')
)
.addSubcommandGroup((group) =>
group
.addSubcommand((subcommand) =>
subcommand
.setName('info')
.setDescription('Lists information about a response or a keyword.')
.addSubcommand((subcommand) =>
subcommand
.setDescription('Shows responses of a registered keyword.')
.addStringOption((option) =>
option
.setName('keyword')
.setDescription('Lists registered responses of a keyword.')
.addStringOption((option) =>
option
.setName('name')
.setDescription('The keyword to be shown the details of.')
.setAutocomplete(true)
.setRequired(true)
)
)
.addSubcommand((subcommand) =>
subcommand
.setName('response')
.setDescription('Lists the data being sent by a response.')
.addStringOption((option) =>
option
.setName('keyword')
.setDescription('The keyword that would trigger the response.')
.setAutocomplete(true)
.setRequired(true)
)
.addStringOption((option) =>
option
.setName('name')
.setDescription('The name of the data to be listed.')
.setAutocomplete(true)
.setRequired(true)
)
.setDescription('The keyword to show the details of.')
.setAutocomplete(true)
.setRequired(true)
)
);
/** @param {ModalSubmitInteraction} interaction */
@ -494,9 +364,9 @@ export async function modalSubmit(interaction) {
const { fields } = interaction;
// Get text inputs from modal
const name = fields.getTextInputValue('name');
const keyword = fields.getTextInputValue('keyword');
const response = fields.getTextInputValue('response');
const name = fields.getTextInputValue('name').toLowerCase();
// Get id of keyword
/** @type {import('../../models/keywords.js').Keyword} */
@ -506,50 +376,20 @@ export async function modalSubmit(interaction) {
}
});
// Abort if response exists
if (
(await Responses.findOne({
where: {
keyword: found.id,
name
}
})) !== null
) {
await interaction.reply({
content: `Response with name '${name}' already exists!`,
ephemeral: true
});
return;
}
// Create new response data with keyword attached
await Responses.create({ keyword: found.id, name, response });
// Reply with success
await interaction.reply({
content: `Successfully registered '${name}' as response to '${keyword}'!`,
ephemeral: true
});
}
/** @param {AutocompleteInteraction} interaction */
export async function autocomplete(interaction) {
const { options } = interaction;
const command = options.getSubcommand();
const group = options.getSubcommandGroup();
const joined = group === null ? command : `${group} ${command}`;
switch (joined) {
case 'info keyword':
case 'remove keyword':
await keywordAutocomplete(interaction);
break;
case 'info response':
case 'remove response':
await responseAutocomplete(interaction);
switch (options.getSubcommand()) {
case 'remove':
removeAutocomplete(interaction);
break;
case 'add':
keywordAutocomplete(interaction);
case 'info':
keywordAutocomplete(interaction.guildId, interaction.options.getFocused());
break;
}
}
@ -557,31 +397,21 @@ export async function autocomplete(interaction) {
export async function execute(interaction) {
const { options } = interaction;
const command = options.getSubcommand();
const group = options.getSubcommandGroup();
const joined = group === null ? command : `${group} ${command}`;
switch (joined) {
switch (options.getSubcommand()) {
case 'create':
createResponse(interaction);
break;
case 'add':
addResponse(interaction);
break;
case 'remove keyword':
removeKeyword(interaction);
break;
case 'remove response':
case 'remove':
removeResponse(interaction);
break;
case 'list':
listResponse(interaction);
break;
case 'info keyword':
keywordInfos(interaction);
break;
case 'info response':
responseInfos(interaction);
case 'info':
infoResponse(interaction);
break;
}
}

View File

@ -9,7 +9,7 @@ import {
ContextMenuCommandBuilder,
ContextMenuCommandInteraction
} from 'discord.js';
import { addSelfRoles } from '../../../shared.js';
import { addSelfRoles } from '../../../../shared.js';
export const data = new ContextMenuCommandBuilder()
.setDMPermission(false)

View File

@ -4,7 +4,7 @@ import {
PermissionFlagsBits,
ContextMenuCommandInteraction
} from 'discord.js';
import { Messages } from '../../../database.js';
import { Messages } from '../../../../database.js';
export const data = new ContextMenuCommandBuilder()
.setDMPermission(false)

View File

@ -4,7 +4,7 @@ import {
PermissionFlagsBits,
ContextMenuCommandInteraction
} from 'discord.js';
import { removeSelfRoles } from '../../../shared.js';
import { removeSelfRoles } from '../../../../shared.js';
export const data = new ContextMenuCommandBuilder()
.setDMPermission(false)

View File

@ -1,6 +1,6 @@
import { PermissionFlagsBits, SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js';
import { addSelfRoles, removeSelfRoles } from '../../shared.js';
import { Guilds, Messages } from '../../database.js';
import { addSelfRoles, removeSelfRoles } from '../../../shared.js';
import { Guilds, Messages } from '../../../database.js';
/**
* Sends a `Message` in the current channel and registers for self roles.

View File

@ -9,7 +9,7 @@ import Module from 'module';
const executeCommand = async (interaction, command) => {
// Try executing command
try {
console.info(`[INFO] Command '${interaction.commandName}' was executed.`);
console.info(`[INFO] Command ${interaction.commandName} was executed.`);
await command.execute(interaction);
} catch (error) {
console.error(error);
@ -38,7 +38,7 @@ const executeCommand = async (interaction, command) => {
const genericExecute = async (interaction, command, name, description, cmdName) => {
try {
console.info(
`[INFO] Command '${cmdName ?? interaction.commandName ?? 'anonymous'}' ${
`[INFO] Command ${cmdName ?? interaction.commandName ?? 'anonymous'} ${
description ?? `used "${name}"`
}.`
);

View File

@ -1,13 +0,0 @@
import { Keywords, Responses, sequelize } from '../../database.js';
import { Events, Message } from 'discord.js';
import { Op } from 'sequelize';
export const name = Events.MessageCreate;
/** @param {Message} message */
export async function execute(message) {
// Ignore direct messages
if (!message.inGuild()) return;
// Split message content into words
const words = message.content.split(/\s+/);
}

View File

@ -19,7 +19,6 @@ const runClient = (commands, events) => {
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMembers,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.GuildMessageReactions
],