2024-04-04 05:42:25 +00:00
|
|
|
import {
|
2024-04-04 18:23:26 +00:00
|
|
|
ModalBuilder,
|
|
|
|
TextInputBuilder,
|
|
|
|
ActionRowBuilder,
|
2024-04-04 05:42:25 +00:00
|
|
|
SlashCommandBuilder,
|
|
|
|
PermissionFlagsBits,
|
|
|
|
ModalSubmitInteraction,
|
|
|
|
AutocompleteInteraction,
|
2024-04-04 18:23:26 +00:00
|
|
|
ChatInputCommandInteraction,
|
|
|
|
TextInputStyle
|
2024-04-04 05:42:25 +00:00
|
|
|
} from 'discord.js';
|
2024-04-04 18:23:26 +00:00
|
|
|
import { Guilds, Keywords, Responses } from '../../database.js';
|
2024-04-04 05:42:25 +00:00
|
|
|
|
|
|
|
/** @param {ChatInputCommandInteraction} interaction */
|
2024-04-04 18:32:43 +00:00
|
|
|
async function createResponse(interaction) {
|
|
|
|
const { options } = interaction;
|
|
|
|
|
|
|
|
// Get command options
|
|
|
|
const keyword = options.getString('keyword');
|
|
|
|
|
|
|
|
// Abort if keyword already exists or is empty
|
|
|
|
/** @type {import('../../models/keywords.js').Keyword|null} */
|
|
|
|
const found = await Keywords.findOne({
|
|
|
|
where: {
|
|
|
|
guild: interaction.guildId,
|
|
|
|
name: keyword
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Reply with error
|
|
|
|
if (found !== null || !keyword) {
|
|
|
|
await interaction.reply({
|
|
|
|
content: 'Invalid parameters or keyword already exists!',
|
|
|
|
ephemeral: true
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create guild if not exists
|
|
|
|
const guildData = { id: interaction.guildId };
|
|
|
|
await Guilds.findOrCreate({
|
|
|
|
where: guildData,
|
|
|
|
defaults: guildData
|
|
|
|
});
|
|
|
|
|
|
|
|
// Create new keyword
|
|
|
|
await Keywords.create({
|
|
|
|
guild: interaction.guildId,
|
|
|
|
name: keyword
|
|
|
|
});
|
|
|
|
|
|
|
|
// Reply successfully to acknowledge command
|
|
|
|
await interaction.reply({
|
|
|
|
content: `Keyword for '${keyword}' successfully created!`,
|
|
|
|
ephemeral: true
|
|
|
|
});
|
|
|
|
|
|
|
|
console.info(`[INFO] Keyword for '${keyword}' successfully created.`);
|
|
|
|
}
|
2024-04-04 05:42:25 +00:00
|
|
|
|
|
|
|
/** @param {ChatInputCommandInteraction} interaction */
|
2024-04-04 18:32:59 +00:00
|
|
|
async function addResponse(interaction) {
|
|
|
|
const { options } = interaction;
|
|
|
|
|
|
|
|
// Get command options
|
|
|
|
const current = options.getString('keyword');
|
|
|
|
|
|
|
|
// Abort if keyword doesn't exist
|
|
|
|
/** @type {import('../../models/keywords.js').Keyword|null} */
|
|
|
|
const found = await Keywords.findOne({
|
|
|
|
where: {
|
|
|
|
guild: interaction.guildId,
|
|
|
|
name: current
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Reply with error
|
|
|
|
if (found === null) {
|
|
|
|
await interaction.reply({
|
|
|
|
content: 'Keyword has not been registered yet!',
|
|
|
|
ephemeral: true
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const modal = new ModalBuilder().setCustomId('response-pair').setTitle('Response Content');
|
|
|
|
|
|
|
|
const keyword = new ActionRowBuilder().addComponents(
|
|
|
|
new TextInputBuilder()
|
|
|
|
.setLabel('The keyword this command is run for.')
|
|
|
|
.setStyle(TextInputStyle.Short)
|
|
|
|
.setCustomId('keyword')
|
|
|
|
.setRequired(true)
|
|
|
|
.setValue(current)
|
|
|
|
);
|
|
|
|
|
|
|
|
const name = new ActionRowBuilder().addComponents(
|
|
|
|
new TextInputBuilder()
|
|
|
|
.setLabel('The name of the response.')
|
|
|
|
.setStyle(TextInputStyle.Short)
|
|
|
|
.setCustomId('name')
|
|
|
|
.setRequired(true)
|
|
|
|
);
|
|
|
|
|
|
|
|
const response = new ActionRowBuilder().addComponents(
|
|
|
|
new TextInputBuilder()
|
|
|
|
.setLabel('The data to respond with.')
|
|
|
|
.setStyle(TextInputStyle.Paragraph)
|
|
|
|
.setCustomId('response')
|
|
|
|
.setRequired(true)
|
|
|
|
);
|
|
|
|
|
|
|
|
modal.addComponents(keyword, name, response);
|
|
|
|
|
|
|
|
await interaction.showModal(modal);
|
|
|
|
}
|
2024-04-04 05:42:25 +00:00
|
|
|
|
2024-04-05 09:19:12 +00:00
|
|
|
/** @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
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-04-04 05:42:25 +00:00
|
|
|
/** @param {ChatInputCommandInteraction} interaction */
|
2024-04-04 18:33:18 +00:00
|
|
|
async function removeResponse(interaction) {
|
|
|
|
const { options } = interaction;
|
|
|
|
|
|
|
|
// Get command options
|
2024-04-05 09:19:12 +00:00
|
|
|
const keyword = options.getString('keyword');
|
2024-04-04 18:33:18 +00:00
|
|
|
const name = options.getString('name');
|
|
|
|
|
2024-04-05 09:19:12 +00:00
|
|
|
// Find keyword in database
|
|
|
|
/** @type {import('../../models/keywords.js').Keyword} */
|
|
|
|
const found = await Keywords.findOne({
|
|
|
|
where: {
|
|
|
|
guild: interaction.guildId,
|
|
|
|
name: keyword
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Try deleting response from database
|
|
|
|
await Responses.destroy({
|
|
|
|
where: {
|
|
|
|
keyword: found.id,
|
|
|
|
name
|
|
|
|
}
|
|
|
|
});
|
2024-04-04 18:33:18 +00:00
|
|
|
}
|
2024-04-04 05:42:25 +00:00
|
|
|
|
|
|
|
/** @param {ChatInputCommandInteraction} interaction */
|
2024-04-04 18:33:31 +00:00
|
|
|
async function listResponse(interaction) {
|
|
|
|
// Get list of keywords from database
|
|
|
|
/** @type {import('../../models/keywords.js').Keyword[]} */
|
|
|
|
const keywords = await Keywords.findAll({
|
|
|
|
where: {
|
|
|
|
guild: interaction.guildId
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Abort if no keywords registered
|
|
|
|
if (keywords.length === 0) {
|
|
|
|
await interaction.reply({
|
|
|
|
content: 'No keywords have been registered yet!',
|
|
|
|
ephemeral: true
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Join list of keyword names
|
|
|
|
const joined = keywords.map((keyword) => keyword.name).join('\n- ');
|
|
|
|
|
|
|
|
// Reply with list of keywords
|
|
|
|
await interaction.reply({
|
|
|
|
content: `List of known keywords:\n- ${joined}`,
|
|
|
|
ephemeral: true
|
|
|
|
});
|
|
|
|
}
|
2024-04-04 05:42:25 +00:00
|
|
|
|
|
|
|
/** @param {ChatInputCommandInteraction} interaction */
|
2024-04-04 18:33:44 +00:00
|
|
|
async function infoResponse(interaction) {
|
|
|
|
const { options } = interaction;
|
|
|
|
|
|
|
|
// Get command options
|
|
|
|
const keyword = options.getString('keyword');
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get list of responses from database
|
|
|
|
/** @type {import('../../models/responses.js').Response[]} */
|
|
|
|
const responses = await Responses.findAll({
|
|
|
|
where: {
|
2024-04-05 08:51:01 +00:00
|
|
|
keyword: found.id
|
2024-04-04 18:33:44 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-04-05 08:51:17 +00:00
|
|
|
// Abort if no responses registered
|
|
|
|
if (responses.length === 0) {
|
|
|
|
await interaction.reply({
|
|
|
|
content: 'No responses have been registered yet!',
|
|
|
|
ephemeral: true
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-04-04 18:33:44 +00:00
|
|
|
// Join list of responses
|
2024-04-05 08:51:36 +00:00
|
|
|
const joined = responses.map((response) => response.name).join('\n- ');
|
2024-04-04 18:33:44 +00:00
|
|
|
|
|
|
|
// Reply with list of responses
|
|
|
|
await interaction.reply({
|
|
|
|
content: `List of responses for ${keyword}:\n- ${joined}`,
|
|
|
|
ephemeral: true
|
|
|
|
});
|
|
|
|
}
|
2024-04-04 05:42:25 +00:00
|
|
|
|
2024-04-05 08:16:59 +00:00
|
|
|
/** @param {AutocompleteInteraction} interaction */
|
|
|
|
async function keywordAutocomplete(interaction) {
|
|
|
|
const { options, guildId } = interaction;
|
|
|
|
|
|
|
|
// Get command options
|
|
|
|
const focused = options.getFocused();
|
|
|
|
|
2024-04-04 18:27:00 +00:00
|
|
|
// Get list of keywords from database
|
|
|
|
/** @type {import('../../models/keywords.js').Keyword[]} */
|
|
|
|
const keywords = await Keywords.findAll({
|
|
|
|
where: {
|
|
|
|
guild: guildId
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Filter total list of keywords
|
|
|
|
const filtered = keywords.filter((choice) => choice.name.startsWith(focused));
|
|
|
|
|
|
|
|
// Respond with possible suggestions
|
|
|
|
await interaction.respond(filtered.map((choice) => ({ name: choice.name, value: choice.name })));
|
|
|
|
}
|
|
|
|
|
2024-04-05 09:12:43 +00:00
|
|
|
/**
|
|
|
|
* @param {AutocompleteInteraction} interaction
|
|
|
|
* @param {string} focused
|
|
|
|
*/
|
|
|
|
async function completeResponses(interaction, focused) {
|
2024-04-05 08:16:59 +00:00
|
|
|
const { options, guildId } = interaction;
|
|
|
|
|
|
|
|
// Get command options
|
|
|
|
const keyword = options.getString('keyword');
|
|
|
|
|
2024-04-04 18:34:10 +00:00
|
|
|
// Get keyword
|
|
|
|
/** @type {import('../../models/keywords.js').Keyword} */
|
|
|
|
const found = await Keywords.findOne({
|
|
|
|
where: {
|
|
|
|
guild: guildId,
|
|
|
|
name: keyword
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Get list of responses from database
|
|
|
|
/** @type {import('../../models/responses.js').Response[]} */
|
|
|
|
const responses =
|
|
|
|
found === null
|
|
|
|
? []
|
|
|
|
: await Responses.findAll({
|
|
|
|
where: {
|
|
|
|
keyword: found.id
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Filter total list of responses
|
|
|
|
const filtered = responses.filter((choice) => choice.name.startsWith(focused));
|
|
|
|
|
|
|
|
// Respond with possible suggestions
|
|
|
|
await interaction.respond(
|
|
|
|
filtered.map((choice) => ({ name: choice.name, value: choice.response }))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-04-05 09:12:43 +00:00
|
|
|
/**
|
|
|
|
* @param {AutocompleteInteraction} interaction
|
|
|
|
* @param {string} focused
|
|
|
|
*/
|
|
|
|
async function completeKeywords(interaction, focused) {
|
|
|
|
const { guildId } = interaction;
|
|
|
|
|
|
|
|
// Get list of keywords from database
|
|
|
|
/** @type {import('../../models/keywords.js').Keyword[]} */
|
|
|
|
const keywords = await Keywords.findAll({
|
|
|
|
where: {
|
|
|
|
guild: guildId
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Filter total list of keywords
|
|
|
|
const filtered = keywords.filter((choice) => choice.name.startsWith(focused));
|
|
|
|
|
|
|
|
// Respond with possible suggestions
|
|
|
|
await interaction.respond(filtered.map((choice) => ({ name: choice.name, value: choice.name })));
|
|
|
|
}
|
|
|
|
|
2024-04-04 05:42:25 +00:00
|
|
|
/** @param {AutocompleteInteraction} interaction */
|
2024-04-05 09:12:43 +00:00
|
|
|
async function responseAutocomplete(interaction) {
|
2024-04-04 18:29:01 +00:00
|
|
|
const { options } = interaction;
|
|
|
|
|
2024-04-05 09:12:43 +00:00
|
|
|
// Get command options
|
|
|
|
const focused = options.getFocused(true);
|
|
|
|
const { value } = focused;
|
|
|
|
switch (focused.name) {
|
2024-04-04 18:29:01 +00:00
|
|
|
case 'keyword':
|
2024-04-05 09:12:43 +00:00
|
|
|
completeKeywords(interaction, value);
|
2024-04-04 18:29:01 +00:00
|
|
|
break;
|
2024-04-05 09:12:43 +00:00
|
|
|
case 'name':
|
|
|
|
completeResponses(interaction, value);
|
2024-04-04 18:29:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2024-04-04 05:42:25 +00:00
|
|
|
|
|
|
|
export const data = new SlashCommandBuilder()
|
|
|
|
.setName('response')
|
|
|
|
.setDMPermission(false)
|
|
|
|
.setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages)
|
|
|
|
.setDescription('Event based responses to specific messages with keywords.')
|
|
|
|
.addSubcommand((subcommand) =>
|
|
|
|
subcommand
|
|
|
|
.setName('create')
|
|
|
|
.setDescription('Creates a new event based response.')
|
|
|
|
.addStringOption((option) =>
|
|
|
|
option
|
|
|
|
.setName('keyword')
|
|
|
|
.setDescription('The keyword to trigger the response.')
|
|
|
|
.setRequired(true)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.addSubcommand((subcommand) =>
|
|
|
|
subcommand
|
|
|
|
.setName('add')
|
|
|
|
.setDescription('Registers a response to a keyword.')
|
|
|
|
.addStringOption((option) =>
|
|
|
|
option
|
|
|
|
.setName('keyword')
|
|
|
|
.setDescription('The keyword to trigger the response.')
|
|
|
|
.setAutocomplete(true)
|
|
|
|
.setRequired(true)
|
|
|
|
)
|
|
|
|
)
|
2024-04-05 08:54:49 +00:00
|
|
|
.addSubcommandGroup((group) =>
|
|
|
|
group
|
2024-04-04 05:42:25 +00:00
|
|
|
.setName('remove')
|
2024-04-05 08:54:49 +00:00
|
|
|
.setDescription('Unregisters a response or a keyword.')
|
|
|
|
.addSubcommand((subcommand) =>
|
|
|
|
subcommand
|
|
|
|
.setName('keyword')
|
|
|
|
.setDescription('Deletes a keyword completely.')
|
|
|
|
.addStringOption((option) =>
|
|
|
|
option
|
2024-04-05 09:19:12 +00:00
|
|
|
.setName('name')
|
2024-04-05 08:54:49 +00:00
|
|
|
.setDescription('The keyword to be deleted.')
|
|
|
|
.setAutocomplete(true)
|
|
|
|
.setRequired(true)
|
2024-04-04 05:42:25 +00:00
|
|
|
)
|
|
|
|
)
|
2024-04-05 08:54:49 +00:00
|
|
|
.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)
|
|
|
|
)
|
2024-04-04 05:42:25 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
.addSubcommand((subcommand) =>
|
|
|
|
subcommand.setName('list').setDescription('Lists all registered keywords.')
|
|
|
|
)
|
|
|
|
.addSubcommand((subcommand) =>
|
|
|
|
subcommand
|
|
|
|
.setName('info')
|
2024-04-04 18:27:00 +00:00
|
|
|
.setDescription('Shows responses of a registered keyword.')
|
2024-04-04 05:42:25 +00:00
|
|
|
.addStringOption((option) =>
|
|
|
|
option
|
|
|
|
.setName('keyword')
|
|
|
|
.setDescription('The keyword to show the details of.')
|
|
|
|
.setAutocomplete(true)
|
|
|
|
.setRequired(true)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
/** @param {ModalSubmitInteraction} interaction */
|
|
|
|
export async function modalSubmit(interaction) {
|
2024-04-04 18:34:47 +00:00
|
|
|
const { fields } = interaction;
|
|
|
|
|
|
|
|
// Get text inputs from modal
|
|
|
|
const name = fields.getTextInputValue('name');
|
|
|
|
const keyword = fields.getTextInputValue('keyword');
|
|
|
|
const response = fields.getTextInputValue('response');
|
|
|
|
|
|
|
|
// Get id of keyword
|
|
|
|
/** @type {import('../../models/keywords.js').Keyword} */
|
|
|
|
const found = await Keywords.findOne({
|
|
|
|
where: {
|
|
|
|
name: keyword
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-04-05 08:57:32 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2024-04-04 18:34:47 +00:00
|
|
|
// Create new response data with keyword attached
|
|
|
|
await Responses.create({ keyword: found.id, name, response });
|
2024-04-05 08:52:53 +00:00
|
|
|
|
|
|
|
// Reply with success
|
|
|
|
await interaction.reply({
|
|
|
|
content: `Successfully registered '${name}' as response to '${keyword}'!`,
|
|
|
|
ephemeral: true
|
|
|
|
});
|
2024-04-04 05:42:25 +00:00
|
|
|
}
|
|
|
|
/** @param {AutocompleteInteraction} interaction */
|
|
|
|
export async function autocomplete(interaction) {
|
|
|
|
const { options } = interaction;
|
|
|
|
|
2024-04-05 09:12:43 +00:00
|
|
|
const command = options.getSubcommand();
|
|
|
|
const group = options.getSubcommandGroup();
|
|
|
|
const joined = group === null ? command : `${group} ${command}`;
|
|
|
|
|
|
|
|
switch (joined) {
|
|
|
|
case 'remove keyword':
|
|
|
|
await keywordAutocomplete(interaction);
|
|
|
|
break;
|
|
|
|
case 'remove response':
|
|
|
|
await responseAutocomplete(interaction);
|
2024-04-04 05:42:25 +00:00
|
|
|
break;
|
2024-04-04 18:27:00 +00:00
|
|
|
case 'add':
|
2024-04-04 05:42:25 +00:00
|
|
|
case 'info':
|
2024-04-05 08:31:06 +00:00
|
|
|
keywordAutocomplete(interaction);
|
2024-04-04 05:42:25 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/** @param {ChatInputCommandInteraction} interaction */
|
|
|
|
export async function execute(interaction) {
|
|
|
|
const { options } = interaction;
|
|
|
|
|
2024-04-05 09:19:12 +00:00
|
|
|
const command = options.getSubcommand();
|
|
|
|
const group = options.getSubcommandGroup();
|
|
|
|
const joined = group === null ? command : `${group} ${command}`;
|
|
|
|
|
|
|
|
switch (joined) {
|
2024-04-04 05:42:25 +00:00
|
|
|
case 'create':
|
|
|
|
createResponse(interaction);
|
|
|
|
break;
|
|
|
|
case 'add':
|
|
|
|
addResponse(interaction);
|
|
|
|
break;
|
2024-04-05 09:19:12 +00:00
|
|
|
case 'remove keyword':
|
|
|
|
removeKeyword(interaction);
|
|
|
|
break;
|
|
|
|
case 'remove response':
|
2024-04-04 05:42:25 +00:00
|
|
|
removeResponse(interaction);
|
|
|
|
break;
|
|
|
|
case 'list':
|
|
|
|
listResponse(interaction);
|
|
|
|
break;
|
|
|
|
case 'info':
|
|
|
|
infoResponse(interaction);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|