Compare commits

...

11 Commits

2 changed files with 297 additions and 19 deletions

View File

@ -1,34 +1,298 @@
import {
ModalBuilder,
TextInputBuilder,
ActionRowBuilder,
SlashCommandBuilder,
PermissionFlagsBits,
ModalSubmitInteraction,
AutocompleteInteraction,
ChatInputCommandInteraction
ChatInputCommandInteraction,
TextInputStyle
} from 'discord.js';
import { Guilds, Keywords, Responses } from '../../database.js';
/** @param {ChatInputCommandInteraction} interaction */
async function createResponse(interaction) {}
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.`);
}
/** @param {ChatInputCommandInteraction} interaction */
async function addResponse(interaction) {}
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);
}
/** @param {ChatInputCommandInteraction} interaction */
async function removeResponse(interaction) {}
async function removeResponse(interaction) {
const { options } = interaction;
// Get command options
/** @type {'keyword'|'response'} */
const type = options.getString('type');
const name = options.getString('name');
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
}
});
}
}
/** @param {ChatInputCommandInteraction} interaction */
async function listResponse(interaction) {}
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
});
}
/** @param {ChatInputCommandInteraction} interaction */
async function infoResponse(interaction) {}
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: {
guild: interaction.guildId,
name: found.id
}
});
// Join list of responses
const joined = responses.map((response) => response.response).join('\n- ');
// Reply with list of responses
await interaction.reply({
content: `List of responses for ${keyword}:\n- ${joined}`,
ephemeral: true
});
}
/**
* @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({
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 })));
}
/**
* @param {string} guildId
* @param {string} focused
* @param {string} keyword
*/
async function responseAutocomplete(guildId, focused, keyword) {
// 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: {
guild: guildId,
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 }))
);
}
/** @param {AutocompleteInteraction} interaction */
async function addAutocomplete(interaction) {}
async function removeAutocomplete(interaction) {
const { options } = interaction;
/** @param {AutocompleteInteraction} interaction */
async function removeAutocomplete(interaction) {}
const type = options.getString('type');
/** @param {AutocompleteInteraction} interaction */
async function infoAutocomplete(interaction) {}
switch (type) {
case 'keyword':
await keywordAutocomplete(interaction.guildId, options.getFocused());
break;
case 'response':
await responseAutocomplete(
interaction.guildId,
options.getFocused(),
options.getString('keyword')
);
break;
}
}
export const data = new SlashCommandBuilder()
.setName('response')
@ -86,7 +350,7 @@ export const data = new SlashCommandBuilder()
.addSubcommand((subcommand) =>
subcommand
.setName('info')
.setDescription('Shows information about a registered keyword.')
.setDescription('Shows responses of a registered keyword.')
.addStringOption((option) =>
option
.setName('keyword')
@ -97,21 +361,35 @@ export const data = new SlashCommandBuilder()
);
/** @param {ModalSubmitInteraction} interaction */
export async function modalSubmit(interaction) {
// Only executable in 'add' subcommand
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
}
});
// Create new response data with keyword attached
await Responses.create({ keyword: found.id, name, response });
}
/** @param {AutocompleteInteraction} interaction */
export async function autocomplete(interaction) {
const { options } = interaction;
switch (options.getSubcommand()) {
case 'add':
addAutocomplete(interaction);
break;
case 'remove':
removeAutocomplete(interaction);
break;
case 'add':
case 'info':
infoAutocomplete(interaction);
keywordAutocomplete(interaction.guildId, interaction.options.getFocused());
break;
}
}

View File

@ -196,7 +196,7 @@ export async function execute(interaction) {
if (createNew) {
try {
// Create guild if not exists
const guildData = { id: interaction.guild.id };
const guildData = { id: interaction.guildId };
await Guilds.findOrCreate({
where: guildData,
defaults: guildData
@ -205,7 +205,7 @@ export async function execute(interaction) {
// Create database entry
await Messages.create({
id,
guild: interaction.guild.id
guild: interaction.guildId
});
} catch (error) {
console.error(error);