From 38f7165806dbbf72ea3792db56e928ab95293937 Mon Sep 17 00:00:00 2001 From: Chaiwat Suwannarat Date: Thu, 2 May 2024 17:29:23 +0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=AD=20Now=20can=20manage=20messages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/commands/me/say.js | 75 --- source/commands/messages/attachment.js | 57 ++ source/commands/messages/crosspost.js | 76 +++ source/commands/messages/delete.js | 60 ++ source/commands/messages/embed.js | 823 +++++++++++++++++++++++++ source/commands/messages/message.js | 220 +++++++ source/commands/messages/pin.js | 141 +++++ source/commands/messages/react.js | 76 +++ 8 files changed, 1453 insertions(+), 75 deletions(-) delete mode 100644 source/commands/me/say.js create mode 100644 source/commands/messages/attachment.js create mode 100644 source/commands/messages/crosspost.js create mode 100644 source/commands/messages/delete.js create mode 100644 source/commands/messages/embed.js create mode 100644 source/commands/messages/message.js create mode 100644 source/commands/messages/pin.js create mode 100644 source/commands/messages/react.js diff --git a/source/commands/me/say.js b/source/commands/me/say.js deleted file mode 100644 index 9c3e7e75..00000000 --- a/source/commands/me/say.js +++ /dev/null @@ -1,75 +0,0 @@ -const { PermissionsBitField } = require("discord.js") - -module.exports = { - "enable": true, - "name": "say", - "description": "Let the bot print instead", - "category": "me", - "permissions": { - "user": [PermissionsBitField.Flags.ManageMessages], - "client": [PermissionsBitField.Flags.SendMessages] - }, - "usage": "say [channel]", - "function": { - "command": {} - } -}; - -module.exports.function.command = { - "data": { - "name": module.exports.name, - "name_localizations": { - "th": "พูด" - }, - "description": module.exports.description, - "description_localizations": { - "th": "ปล่อยให้บอทพิมพ์แทน" - }, - "options": [ - { - "type": 3, - "name": "text", - "name_localizations": { - "th": "ข้อความ" - }, - "description": "The message you want to send.", - "description_localizations": { - "th": "ข้อความที่คุณต้องการส่ง" - }, - "required": true - }, - { - "type": 7, - "name": "channel", - "name_localizations": { - "th": "ช่อง" - }, - "description": "The channel to send the message to", - "description_localizations": { - "th": "ช่องที่จะส่งข้อความ" - }, - "required": false, - "channel_types": [ - 0, - 5, - 10, - 11, - 12, - 15 - ] - } - ] - }, - async execute(interaction) { - const inputText = interaction.options.getString("text"); - const inputChannel = interaction.options.getChannel("channel") ?? ""; - - if (!inputChannel) { - await interaction.channel.send(inputText); - await interaction.reply({ "content": interaction.client.translate.commands.say.success, "ephemeral": true}); - } else { - await inputChannel.send(inputText); - await interaction.reply({ "content": interaction.client.translate.commands.say.success, "ephemeral": true}); - } - } -} \ No newline at end of file diff --git a/source/commands/messages/attachment.js b/source/commands/messages/attachment.js new file mode 100644 index 00000000..bb1b3fe1 --- /dev/null +++ b/source/commands/messages/attachment.js @@ -0,0 +1,57 @@ +const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js') + +module.exports = { + permissions: [ + PermissionFlagsBits.SendMessages, + PermissionFlagsBits.AttachFiles, + ], + data: new SlashCommandBuilder() + .setName('attachment') + .setDescription('Upload the file and send it in the chat.') + .setDescriptionLocalizations({ + th: 'อัปโหลดไฟล์แล้วส่งไปในแชท', + }) + .setDefaultMemberPermissions(PermissionFlagsBits.AttachFiles) + .setDMPermission(true) + .addAttachmentOption((option) => + option + .setName('attachment') + .setDescription('Things to be attached to the message to be sent.') + .setDescriptionLocalizations({ + th: 'สิ่งที่ต้องการแนบไปด้วยข้อความที่จะส่ง', + }) + .setRequired(true) + ) + .addChannelOption((option) => + option + .setName('channel') + .setDescription('The channel to send the attachment to') + .setDescriptionLocalizations({ + th: 'ช่องที่จะส่งไฟล์', + }) + .setRequired(false) + ), + async execute(interaction) { + const inputAttachment = interaction.options.getAttachment('attachment') + const inputChannel = interaction.options.getChannel('channel') ?? null + + if (!inputChannel) { + await interaction.channel.send({ + files: [inputAttachment], + }) + } else { + await inputChannel.send({ + files: [inputAttachment], + }) + } + + await interaction.reply({ + content: inputChannel + ? interaction.client.i18n.t('commands.attachment.sended_to_channel') + : interaction.client.i18n.t('commands.attachment.sended', { + id: inputChannel.id, + }), + ephemeral: true, + }) + }, +} diff --git a/source/commands/messages/crosspost.js b/source/commands/messages/crosspost.js new file mode 100644 index 00000000..a4f166a4 --- /dev/null +++ b/source/commands/messages/crosspost.js @@ -0,0 +1,76 @@ +const { + SlashCommandBuilder, + ChannelType, + PermissionFlagsBits, +} = require('discord.js') +const { catchError } = require('../../utils/consoleUtils') + +module.exports = { + permissions: [ + PermissionFlagsBits.SendMessages, + PermissionFlagsBits.ManageMessages, + ], + data: new SlashCommandBuilder() + .setName('crosspost') + .setDescription( + 'Publishes a message in an announcement channel to all channels following it.' + ) + .setDescriptionLocalizations({ + th: 'เผยแพร่ข้อความในช่องประกาศไปยังทุกช่องที่ติดตาม', + }) + .setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages) + .setDMPermission(true) + .addStringOption((option) => + option + .setName('id') + .setDescription('ID of message to be published') + .setDescriptionLocalizations({ + th: 'ไอดีของข้อความที่ต้องการเผยแพร่', + }) + .setRequired(true) + ), + async execute(interaction) { + const inputID = interaction.options.getString('id') + + if (interaction.channel.type !== ChannelType.GuildAnnouncement) + return await interaction.reply({ + content: interaction.client.i18n.t( + 'commands.crosspost.is_not_valid_type' + ), + ephemeral: true, + }) + + try { + const message = await interaction.channel.messages.fetch(inputID) + + if (!message) + return await interaction.reply({ + content: interaction.client.i18n.t( + 'commands.crosspost.message_not_found' + ), + ephemeral: true, + }) + if (!message.crosspostable) + return await interaction.reply({ + content: interaction.client.i18n.t( + 'commands.crosspost.can_not_published' + ), + ephemeral: true, + }) + + await message.crosspost() + } catch (error) { + catchError( + interaction.client, + interaction, + module.exports.data.name, + error + ) + } + + await interaction.reply({ + content: interaction.client.i18n.t('commands.crosspost.published'), + ephemeral: true, + }) + }, +} diff --git a/source/commands/messages/delete.js b/source/commands/messages/delete.js new file mode 100644 index 00000000..f4232dc1 --- /dev/null +++ b/source/commands/messages/delete.js @@ -0,0 +1,60 @@ +const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js') +const { catchError } = require('../../utils/consoleUtils') + +module.exports = { + permissions: [ + PermissionFlagsBits.SendMessages, + PermissionFlagsBits.ManageMessages, + ], + data: new SlashCommandBuilder() + .setName('delete') + .setDescription('Delete unwanted messages') + .setDescriptionLocalizations({ + th: 'ลบข้อความที่ไม่ต้องการ', + }) + .setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages) + .setDMPermission(true) + .addStringOption((option) => + option + .setName('id') + .setDescription('ID of the message you want to delete') + .setDescriptionLocalizations({ + th: 'ไอดีของข้อความที่ต้องการลบ', + }) + .setRequired(true) + ), + async execute(interaction) { + const inputID = interaction.options.getString('id') + + try { + const message = await interaction.channel.messages.fetch(inputID) + + if (!message) + return await interaction.reply({ + content: interaction.client.i18n.t( + 'commands.delete.message_not_found' + ), + ephemeral: true, + }) + if (!message.deleteable) + return await interaction.reply({ + content: interaction.client.i18n.t('commands.delete.can_not_delete'), + ephemeral: true, + }) + + await message.delete() + } catch (error) { + catchError( + interaction.client, + interaction, + module.exports.data.name, + error + ) + } + + await interaction.reply({ + content: interaction.client.i18n.t('commands.delete.deleted'), + ephemeral: true, + }) + }, +} diff --git a/source/commands/messages/embed.js b/source/commands/messages/embed.js new file mode 100644 index 00000000..09f20726 --- /dev/null +++ b/source/commands/messages/embed.js @@ -0,0 +1,823 @@ +const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js') +const { embedBuilder } = require('../../utils/clientUtils') +const { catchError } = require('../../utils/consoleUtils') + +module.exports = { + permissions: [PermissionFlagsBits.SendMessages], + data: new SlashCommandBuilder() + .setName('embed') + .setDescription('Create an embedded message') + .setDescriptionLocalizations({ + th: 'สร้างข้อความแบบฝัง', + }) + .setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages) + .setDMPermission(true) + .addSubcommand((subcommand) => + subcommand + .setName('send') + .setDescription('Send embedded message') + .setDescriptionLocalizations({ + th: 'ส่งข้อความแบบฝัง', + }) + .addStringOption((option) => + option + .setName('content') + .setDescription('Content of message.') + .setDescriptionLocalizations({ + th: 'เนื้อหาของข้อความ', + }) + ) + .addAttachmentOption((option) => + option + .setName('attachment') + .setDescription( + 'What needs to be attached to the embedded message to be sent.' + ) + .setDescriptionLocalizations({ + th: 'สิ่งที่ต้องการแนบไปด้วยข้อความแบบฝังที่จะส่ง', + }) + ) + .addStringOption((option) => + option + .setName('author_name') + .setDescription('The name of the author of the embedded text.') + .setDescriptionLocalizations({ + th: 'ชื่อของผู้เขียนในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('author_icon_url') + .setDescription('Author icon in embedded text') + .setDescriptionLocalizations({ + th: 'ไอคอนของผู้เขียนในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('author_url') + .setDescription('Author links in embedded text') + .setDescriptionLocalizations({ + th: 'ลิงค์ของผู้เขียนในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('color') + .setDescription('Embedded text border color') + .setDescriptionLocalizations({ + th: 'สีของขอบข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('title') + .setDescription('Topic of embedded message') + .setDescriptionLocalizations({ + th: 'หัวข้อของข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('url') + .setDescription( + 'The link to be attached to the topic of the embedded message.' + ) + .setDescriptionLocalizations({ + th: 'ลิงค์ที่จะแนบไว้กับหัวข้อของข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('description') + .setDescription('Description in embedded text') + .setDescriptionLocalizations({ + th: 'คำอธิบายในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('thumbnail') + .setDescription( + 'Link to thumbnail in upper right corner in embedded text' + ) + .setDescriptionLocalizations({ + th: 'ลิงค์ของรูปขนาดเล็กมุมขวาบนในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName(`first_field_name`) + .setDescription('The name of the field in the embedded text.') + .setDescriptionLocalizations({ + th: 'ชื่อของฟิลด์ในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName(`first_field_value`) + .setDescription('Field values in embedded text') + .setDescriptionLocalizations({ + th: 'ค่าของฟิลด์ในข้อความแบบฝัง', + }) + ) + .addBooleanOption((option) => + option + .setName(`first_field_inline`) + .setDescription( + 'Organized as a single line in a field of embedded text.' + ) + .setDescriptionLocalizations({ + th: 'จัดเป็นบรรทัดเดียวในฟิลด์ของข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName(`second_field_name`) + .setDescription('The name of the field in the embedded text.') + .setDescriptionLocalizations({ + th: 'ชื่อของฟิลด์ในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName(`second_field_value`) + .setDescription('Field values in embedded text') + .setDescriptionLocalizations({ + th: 'ค่าของฟิลด์ในข้อความแบบฝัง', + }) + ) + .addBooleanOption((option) => + option + .setName(`second_field_inline`) + .setDescription( + 'Organized as a single line in a field of embedded text.' + ) + .setDescriptionLocalizations({ + th: 'จัดเป็นบรรทัดเดียวในฟิลด์ของข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('image') + .setDescription('Links to accompanying images in embedded text') + .setDescriptionLocalizations({ + th: 'ลิงค์รูปภาพประกอบในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('timestamp') + .setDescription( + 'Timestamp on embedded text (We recommend using https://www.epochconverter.com/) e.g. "1701090235"' + ) + .setDescriptionLocalizations({ + th: 'เวลาประทับบนข้อความแบบฝัง (เราแนะนำให้ใช้ https://www.epochconverter.com/) เช่น "1701090235"', + }) + ) + .addStringOption((option) => + option + .setName('footer_text') + .setDescription('Embedded footer text') + .setDescriptionLocalizations({ + th: 'ข้อความส่วนท้ายของข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('footer_icon_url') + .setDescription('Icon link in footer of embedded message') + .setDescriptionLocalizations({ + th: 'ลิงค์ของไอคอนในส่วนท้ายของข้อความแบบฝัง', + }) + ) + .addChannelOption((option) => + option + .setName('channel') + .setDescription('channel to send the embedded message') + .setDescriptionLocalizations({ + th: 'ช่องที่จะส่งข้อความแบบฝัง', + }) + .setRequired(false) + ) + ) + .addSubcommand((subcommand) => + subcommand + .setName('reply') + .setDescription('Reply embedded message') + .setDescriptionLocalizations({ + th: 'ตอบกลับข้อความแบบฝัง', + }) + .addStringOption((option) => + option + .setName('id') + .setDescription('ID of the embedded message you want to rply') + .setDescriptionLocalizations({ + th: 'ไอดีของข้อความแบบฝังที่ต้องการตอบกลับ', + }) + .setRequired(true) + ) + .addStringOption((option) => + option + .setName('content') + .setDescription('Content of message.') + .setDescriptionLocalizations({ + th: 'เนื้อหาของข้อความ', + }) + ) + .addAttachmentOption((option) => + option + .setName('attachment') + .setDescription( + 'What needs to be attached to the embedded message to be sent.' + ) + .setDescriptionLocalizations({ + th: 'สิ่งที่ต้องการแนบไปด้วยข้อความแบบฝังที่จะส่ง', + }) + ) + .addStringOption((option) => + option + .setName('author_name') + .setDescription('The name of the author of the embedded text.') + .setDescriptionLocalizations({ + th: 'ชื่อของผู้เขียนในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('author_icon_url') + .setDescription('Author icon in embedded text') + .setDescriptionLocalizations({ + th: 'ไอคอนของผู้เขียนในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('author_url') + .setDescription('Author links in embedded text') + .setDescriptionLocalizations({ + th: 'ลิงค์ของผู้เขียนในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('color') + .setDescription('Embedded text border color') + .setDescriptionLocalizations({ + th: 'สีของขอบข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('title') + .setDescription('Topic of embedded message') + .setDescriptionLocalizations({ + th: 'หัวข้อของข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('url') + .setDescription( + 'The link to be attached to the topic of the embedded message.' + ) + .setDescriptionLocalizations({ + th: 'ลิงค์ที่จะแนบไว้กับหัวข้อของข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('description') + .setDescription('Description in embedded text') + .setDescriptionLocalizations({ + th: 'คำอธิบายในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('thumbnail') + .setDescription( + 'Link to thumbnail in upper right corner in embedded text' + ) + .setDescriptionLocalizations({ + th: 'ลิงค์ของรูปขนาดเล็กมุมขวาบนในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName(`first_field_name`) + .setDescription('The name of the field in the embedded text.') + .setDescriptionLocalizations({ + th: 'ชื่อของฟิลด์ในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName(`first_field_value`) + .setDescription('Field values in embedded text') + .setDescriptionLocalizations({ + th: 'ค่าของฟิลด์ในข้อความแบบฝัง', + }) + ) + .addBooleanOption((option) => + option + .setName(`first_field_inline`) + .setDescription( + 'Organized as a single line in a field of embedded text.' + ) + .setDescriptionLocalizations({ + th: 'จัดเป็นบรรทัดเดียวในฟิลด์ของข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName(`second_field_name`) + .setDescription('The name of the field in the embedded text.') + .setDescriptionLocalizations({ + th: 'ชื่อของฟิลด์ในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName(`second_field_value`) + .setDescription('Field values in embedded text') + .setDescriptionLocalizations({ + th: 'ค่าของฟิลด์ในข้อความแบบฝัง', + }) + ) + .addBooleanOption((option) => + option + .setName(`second_field_inline`) + .setDescription( + 'Organized as a single line in a field of embedded text.' + ) + .setDescriptionLocalizations({ + th: 'จัดเป็นบรรทัดเดียวในฟิลด์ของข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('image') + .setDescription('Links to accompanying images in embedded text') + .setDescriptionLocalizations({ + th: 'ลิงค์รูปภาพประกอบในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('timestamp') + .setDescription( + 'Timestamp on embedded text (We recommend using https://www.epochconverter.com/) e.g. "1701090235"' + ) + .setDescriptionLocalizations({ + th: 'เวลาประทับบนข้อความแบบฝัง (เราแนะนำให้ใช้ https://www.epochconverter.com/) เช่น "1701090235"', + }) + ) + .addStringOption((option) => + option + .setName('footer_text') + .setDescription('Embedded footer text') + .setDescriptionLocalizations({ + th: 'ข้อความส่วนท้ายของข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('footer_icon_url') + .setDescription('Icon link in footer of embedded message') + .setDescriptionLocalizations({ + th: 'ลิงค์ของไอคอนในส่วนท้ายของข้อความแบบฝัง', + }) + ) + ) + .addSubcommand((subcommand) => + subcommand + .setName('edit') + .setDescription('Edit embedded message') + .setDescriptionLocalizations({ + th: 'แก้ไขข้อความแบบฝัง', + }) + .addStringOption((option) => + option + .setName('id') + .setDescription('ID of the embedded message you want to edit') + .setDescriptionLocalizations({ + th: 'ไอดีของข้อความแบบฝังที่ต้องการแก้ไข', + }) + .setRequired(true) + ) + .addStringOption((option) => + option + .setName('content') + .setDescription('Content of message.') + .setDescriptionLocalizations({ + th: 'เนื้อหาของข้อความ', + }) + ) + .addAttachmentOption((option) => + option + .setName('attachment') + .setDescription( + 'What needs to be attached to the embedded message to be sent.' + ) + .setDescriptionLocalizations({ + th: 'สิ่งที่ต้องการแนบไปด้วยข้อความแบบฝังที่จะส่ง', + }) + ) + .addStringOption((option) => + option + .setName('author_name') + .setDescription('The name of the author of the embedded text.') + .setDescriptionLocalizations({ + th: 'ชื่อของผู้เขียนในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('author_icon_url') + .setDescription('Author icon in embedded text') + .setDescriptionLocalizations({ + th: 'ไอคอนของผู้เขียนในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('author_url') + .setDescription('Author links in embedded text') + .setDescriptionLocalizations({ + th: 'ลิงค์ของผู้เขียนในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('color') + .setDescription('Embedded text border color') + .setDescriptionLocalizations({ + th: 'สีของขอบข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('title') + .setDescription('Topic of embedded message') + .setDescriptionLocalizations({ + th: 'หัวข้อของข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('url') + .setDescription( + 'The link to be attached to the topic of the embedded message.' + ) + .setDescriptionLocalizations({ + th: 'ลิงค์ที่จะแนบไว้กับหัวข้อของข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('description') + .setDescription('Description in embedded text') + .setDescriptionLocalizations({ + th: 'คำอธิบายในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('thumbnail') + .setDescription( + 'Link to thumbnail in upper right corner in embedded text' + ) + .setDescriptionLocalizations({ + th: 'ลิงค์ของรูปขนาดเล็กมุมขวาบนในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName(`first_field_name`) + .setDescription('The name of the field in the embedded text.') + .setDescriptionLocalizations({ + th: 'ชื่อของฟิลด์ในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName(`first_field_value`) + .setDescription('Field values in embedded text') + .setDescriptionLocalizations({ + th: 'ค่าของฟิลด์ในข้อความแบบฝัง', + }) + ) + .addBooleanOption((option) => + option + .setName(`first_field_inline`) + .setDescription( + 'Organized as a single line in a field of embedded text.' + ) + .setDescriptionLocalizations({ + th: 'จัดเป็นบรรทัดเดียวในฟิลด์ของข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName(`second_field_name`) + .setDescription('The name of the field in the embedded text.') + .setDescriptionLocalizations({ + th: 'ชื่อของฟิลด์ในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName(`second_field_value`) + .setDescription('Field values in embedded text') + .setDescriptionLocalizations({ + th: 'ค่าของฟิลด์ในข้อความแบบฝัง', + }) + ) + .addBooleanOption((option) => + option + .setName(`second_field_inline`) + .setDescription( + 'Organized as a single line in a field of embedded text.' + ) + .setDescriptionLocalizations({ + th: 'จัดเป็นบรรทัดเดียวในฟิลด์ของข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('image') + .setDescription('Links to accompanying images in embedded text') + .setDescriptionLocalizations({ + th: 'ลิงค์รูปภาพประกอบในข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('timestamp') + .setDescription( + 'Timestamp on embedded text (We recommend using https://www.epochconverter.com/) e.g. "1701090235"' + ) + .setDescriptionLocalizations({ + th: 'เวลาประทับบนข้อความแบบฝัง (เราแนะนำให้ใช้ https://www.epochconverter.com/) เช่น "1701090235"', + }) + ) + .addStringOption((option) => + option + .setName('footer_text') + .setDescription('Embedded footer text') + .setDescriptionLocalizations({ + th: 'ข้อความส่วนท้ายของข้อความแบบฝัง', + }) + ) + .addStringOption((option) => + option + .setName('footer_icon_url') + .setDescription('Icon link in footer of embedded message') + .setDescriptionLocalizations({ + th: 'ลิงค์ของไอคอนในส่วนท้ายของข้อความแบบฝัง', + }) + ) + ) + .addSubcommand((subcommand) => + subcommand + .setName('suppress') + .setDescription('Suppresses or unsuppresses embeds on a message.') + .setDescriptionLocalizations({ + th: 'ระงับหรือยกเลิกการฝังข้อความ', + }) + .addStringOption((option) => + option + .setName('id') + .setDescription( + 'ID of the message for which you want to suppress or unembed the message.' + ) + .setDescriptionLocalizations({ + th: 'ไอดีของข้อความที่ต้องการระงับหรือยกเลิกการฝังข้อความ', + }) + .setRequired(true) + ) + .addBooleanOption((option) => + option + .setName('suppress') + .setDescription('Want to suppress message embedding?') + .setDescriptionLocalizations({ + th: 'ต้องการระงับการฝังข้อความหรือไม่', + }) + .setRequired(true) + ) + ), + async execute(interaction) { + const subcommand = interaction.options.getSubcommand() + const inputID = interaction.options.getString('id') + const inputContent = interaction.options.getString('content') ?? '' + const inputSuppress = interaction.options.getString('suppress') + const inputAttachment = + interaction.options.getAttachment('attachment') ?? null + const inputAuthorName = interaction.options.getString('author_name') ?? '' + const inputAuthorURL = interaction.options.getString('author_url') ?? '' + const inputAuthorIconURL = + interaction.options.getString('author_icon_url') ?? '' + const inputColor = interaction.options.getString('color') ?? '' + const inputTitle = interaction.options.getString('title') + const inputURL = interaction.options.getString('url') ?? '' + const inputDescription = interaction.options.getString('description') ?? '' + const inputThumbnail = interaction.options.getString('thumbnail') ?? '' + const inputFirstFieldName = + interaction.options.getString('first_field_name') ?? '' + const inputFirstFieldValue = + interaction.options.getString('first_field_value') ?? '' + const inputFirstFieldInline = + interaction.options.getBoolean('first_field_inline') ?? '' + const inputSecondFieldName = + interaction.options.getString('second_field_name') ?? '' + const inputSecondFieldValue = + interaction.options.getString('second_field_value') ?? '' + const inputSecondFieldInline = + interaction.options.getBoolean('second_field_inline') ?? '' + const inputImage = interaction.options.getString('image') ?? '' + const inputTimestamp = interaction.options.getString('timestamp') ?? null + const inputFooterText = interaction.options.getString('footer_text') ?? '' + const inputFooterIconURL = + interaction.options.getString('footer_icon_url') ?? '' + const inputChannel = interaction.options.getChannel('channel') ?? null + + if ( + interaction.options.data.length <= 0 || + (interaction.options.data.length <= 1 && + interaction.options.data[0].name === 'channel') + ) + return await interaction.reply( + interaction.client.i18n.t('commands.embed.no_option_provided') + ) + + const embed = embedBuilder( + interaction.client, + inputAuthorName, + inputAuthorURL, + inputAuthorIconURL, + inputColor, + inputTitle, + inputURL, + inputDescription, + inputThumbnail, + inputFirstFieldName, + inputFirstFieldValue, + inputFirstFieldInline, + inputSecondFieldName, + inputSecondFieldValue, + inputSecondFieldInline, + inputImage, + inputTimestamp, + inputFooterText, + inputFooterIconURL + ) + + if (embed.error) + return await interaction.reply({ + content: embed.data, + ephemeral: true, + }) + + switch (subcommand) { + case 'send': { + if (inputChannel) { + inputChannel.send({ + content: inputContent, + embeds: [embed.data], + files: [inputAttachment], + }) + } else { + await interaction.reply({ + content: inputContent, + embeds: [embed.data], + files: [inputAttachment], + }) + } + + await interaction.reply({ + content: inputChannel + ? interaction.client.i18n.t( + 'commands.embed.embedded_has_been_sent_to_channel', + { + id: inputChannel.id, + } + ) + : interaction.client.i18n.t( + 'commands.embed.embedded_has_been_sent' + ), + ephemeral: true, + }) + break + } + case 'reply': { + try { + const message = await interaction.channel.messages.fetch(inputID) + + if (!message) + return await interaction.reply({ + content: interaction.client.i18n.t( + 'commands.embed.message_not_found' + ), + ephemeral: true, + }) + + await message.reply({ + content: inputContent, + embeds: [embed.data], + files: [inputAttachment], + }) + } catch (error) { + catchError( + interaction.client, + interaction, + module.exports.data.name, + error + ) + } + + await interaction.reply({ + content: interaction.client.i18n.t( + 'commands.embed.embedded_has_been_replied' + ), + ephemeral: true, + }) + break + } + case 'edit': { + try { + const message = await interaction.channel.messages.fetch(inputID) + + if (!message) + return await interaction.reply({ + content: interaction.client.i18n.t( + 'commands.embed.message_not_found' + ), + ephemeral: true, + }) + if (!message.editable) + return await interaction.reply({ + content: interaction.client.i18n.t('commands.embed.can_not_edit'), + ephemeral: true, + }) + + await message.edit({ + content: inputContent, + embeds: [embed.data], + files: [inputAttachment], + }) + } catch (error) { + catchError( + interaction.client, + interaction, + module.exports.data.name, + error + ) + } + + await interaction.reply({ + content: interaction.client.i18n.t( + 'commands.embed.embedded_has_been_edited' + ), + ephemeral: true, + }) + break + } + case 'suppress': { + try { + const message = await interaction.channel.messages.fetch(inputID) + + if (!message) + return await interaction.reply({ + content: interaction.client.i18n.t( + 'commands.embed.message_not_found' + ), + ephemeral: true, + }) + if (!message.embeds) + return await interaction.reply({ + content: interaction.client.i18n.t('commands.embed.is_not_embed'), + ephemeral: true, + }) + + await message.suppressEmbeds(inputSuppress) + } catch (error) { + catchError( + interaction.client, + interaction, + module.exports.data.name, + error + ) + } + + await interaction.reply({ + content: inputSuppress + ? interaction.client.i18n.t('commands.embed.suppresses') + : interaction.client.i18n.t('commands.embed.unsuppresses'), + ephemeral: true, + }) + break + } + } + }, +} diff --git a/source/commands/messages/message.js b/source/commands/messages/message.js new file mode 100644 index 00000000..b42f9fb0 --- /dev/null +++ b/source/commands/messages/message.js @@ -0,0 +1,220 @@ +const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js') +const { catchError } = require('../../utils/consoleUtils') + +module.exports = { + permissions: [ + PermissionFlagsBits.SendMessages, + PermissionFlagsBits.ManageMessages, + ], + data: new SlashCommandBuilder() + .setName('message') + .setDescription('Let the bot print instead') + .setDescriptionLocalizations({ + th: 'ปล่อยให้บอทพิมพ์แทน', + }) + .setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages) + .setDMPermission(true) + .addSubcommand((subcommand) => + subcommand + .setName('send') + .setDescription('Send message.') + .setDescriptionLocalizations({ + th: 'ส่งข้อความ', + }) + .addStringOption((option) => + option + .setName('content') + .setDescription('The message you want to send.') + .setDescriptionLocalizations({ + th: 'ข้อความที่คุณต้องการส่ง', + }) + .setRequired(true) + ) + .addAttachmentOption((option) => + option + .setName('attachment') + .setDescription('Things to be attached to the message to be sent.') + .setDescriptionLocalizations({ + th: 'สิ่งที่ต้องการแนบไปด้วยข้อความที่จะส่ง', + }) + .setRequired(false) + ) + .addChannelOption((option) => + option + .setName('channel') + .setDescription('The channel to send the message to') + .setDescriptionLocalizations({ + th: 'ช่องที่จะส่งข้อความ', + }) + .setRequired(false) + ) + ) + .addSubcommand((subcommand) => + subcommand + .setName('reply') + .setDescription('Reply message.') + .setDescriptionLocalizations({ + th: 'ส่งข้อความ', + }) + .addStringOption((option) => + option + .setName('id') + .setDescription('ID of the message you want to reply') + .setDescriptionLocalizations({ + th: 'ไอดีของข้อความที่ต้องการตอบกลับ', + }) + .setRequired(true) + ) + .addStringOption((option) => + option + .setName('content') + .setDescription('The message you want to send.') + .setDescriptionLocalizations({ + th: 'ข้อความที่คุณต้องการส่ง', + }) + .setRequired(true) + ) + .addAttachmentOption((option) => + option + .setName('attachment') + .setDescription('Things to be attached to the message to be sent.') + .setDescriptionLocalizations({ + th: 'สิ่งที่ต้องการแนบไปด้วยข้อความที่จะส่ง', + }) + .setRequired(false) + ) + ) + .addSubcommand((subcommand) => + subcommand + .setName('edit') + .setDescription('Edit the desired text.') + .setDescriptionLocalizations({ + th: 'แก้ข้อความที่ต้องการ', + }) + .addStringOption((option) => + option + .setName('id') + .setDescription('ID of the message you want to edit') + .setDescriptionLocalizations({ + th: 'ไอดีของข้อความที่ต้องการแก้ไข', + }) + .setRequired(true) + ) + .addStringOption((option) => + option + .setName('content') + .setDescription('The text you want to change') + .setDescriptionLocalizations({ + th: 'ข้อความที่คุณต้องการเปลี่ยนแปลง', + }) + .setRequired(true) + ) + .addAttachmentOption((option) => + option + .setName('attachment') + .setDescription('Things to be attached to the message to be sent.') + .setDescriptionLocalizations({ + th: 'สิ่งที่ต้องการแนบไปด้วยข้อความที่จะส่ง', + }) + .setRequired(false) + ) + ), + async execute(interaction) { + const subcommand = interaction.options.getSubcommand() + const inputID = interaction.options.getString('id') + const inputContent = interaction.options.getString('content') + const inputAttachment = + interaction.options.getAttachment('attachment') ?? null + const inputChannel = interaction.options.getChannel('channel') ?? null + + switch (subcommand) { + case 'send': + if (!inputChannel) { + await interaction.channel.send({ + content: inputContent, + files: [inputAttachment], + }) + } else { + await inputChannel.send({ + content: inputContent, + files: [inputAttachment], + }) + } + + await interaction.reply({ + content: inputChannel + ? interaction.client.i18n.t('commands.message.sended_to_channel') + : interaction.client.i18n.t('commands.message.sended'), + ephemeral: true, + }) + break + case 'reply': + try { + const message = await interaction.channel.message.fetch(inputID) + + if (!message) + return await interaction.reply({ + content: interaction.client.i18n.t( + 'commands.message.message_not_found' + ), + ephemeral: true, + }) + + await message.reply({ + content: inputContent, + files: [inputAttachment], + }) + } catch (error) { + catchError( + interaction.client, + interaction, + module.exports.data.name, + error + ) + } + + await interaction.reply({ + content: interaction.client.i18n.t('commands.message.replied'), + ephemeral: true, + }) + break + case 'edit': + try { + const message = await interaction.channel.message.fetch(inputID) + + if (!message) + return await interaction.reply({ + content: interaction.client.i18n.t( + 'commands.message.message_not_found' + ), + ephemeral: true, + }) + if (!message.editable) + return await interaction.reply({ + content: interaction.client.i18n.t( + 'commands.message.can_not_edit' + ), + ephemeral: true, + }) + + await message.edit({ + content: inputContent, + files: [inputAttachment], + }) + } catch (error) { + catchError( + interaction.client, + interaction, + module.exports.data.name, + error + ) + } + + await interaction.reply({ + content: interaction.client.i18n.t('commands.message.edited'), + ephemeral: true, + }) + break + } + }, +} diff --git a/source/commands/messages/pin.js b/source/commands/messages/pin.js new file mode 100644 index 00000000..28ba8907 --- /dev/null +++ b/source/commands/messages/pin.js @@ -0,0 +1,141 @@ +const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js') +const { catchError } = require('../../utils/consoleUtils') + +module.exports = { + permissions: [ + PermissionFlagsBits.SendMessages, + PermissionFlagsBits.ManageMessages, + ], + data: new SlashCommandBuilder() + .setName('pin') + .setDescription('Manage message pinning') + .setDescriptionLocalizations({ + th: 'จัดการการปักหมุดข้อความ', + }) + .setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages) + .setDMPermission(false) + .addSubcommand((subcommand) => + subcommand + .setName('add') + .setDescription('Pin the desired message') + .setDescriptionLocalizations({ th: 'ปักหมุดข้อความที่ต้องการ' }) + .addStringOption((option) => + option + .setName('id') + .setDescription('ID of the message you want to edit') + .setDescriptionLocalizations({ + th: 'ไอดีของข้อความที่ต้องการปักหมุด', + }) + .setRequired(true) + ) + .addStringOption((option) => + option + .setName('reason') + .setDescription('Reason for pinning the message') + .setDescriptionLocalizations({ + th: 'เหตุผลที่ปักหมุดข้อความ', + }) + .setRequired(false) + ) + ) + .addSubcommand((subcommand) => + subcommand + .setName('remove') + .setDescription('Unpin pinned messages') + .setDescriptionLocalizations({ th: 'เลิกปักหมุดข้อความที่ปักหมุด' }) + .addStringOption((option) => + option + .setName('id') + .setDescription('ID of the message you want to unpin') + .setDescriptionLocalizations({ + th: 'ไอดีของข้อความที่ต้องการปักหมุด', + }) + .setRequired(true) + ) + .addStringOption((option) => + option + .setName('reason') + .setDescription('Reason for unpinning messages') + .setDescriptionLocalizations({ + th: 'เหตุผลที่เลิกปักหมุดข้อความ', + }) + .setRequired(false) + ) + ), + async execute(interaction) { + const subcommand = interaction.options.getSubcommand() + const inputID = interaction.options.getString('id') + const inputReason = interaction.options.getString('reason') ?? '' + + switch (subcommand) { + case 'add': { + try { + const message = await interaction.channel.messages.fetch(inputID) + + if (!message) + return await interaction.reply({ + content: interaction.client.i18n.t( + 'commands.pin.message_not_found' + ), + ephemeral: true, + }) + if (!message.pinnable) + return await interaction.reply({ + content: interaction.client.i18n.t('commands.pin.can_not_pin'), + ephemeral: true, + }) + + await message.pin({ reason: inputReason }) + } catch (error) { + catchError( + interaction.client, + interaction, + module.exports.data.name, + error + ) + } + + await interaction.reply({ + content: interaction.client.i18n.t('commands.pin.pinned'), + ephemeral: true, + }) + break + } + case 'remove': { + try { + const message = await interaction.channel.messages.fetchPinned( + (messages) => messages.id === inputID + ) + + if (!message) + return await interaction.reply({ + content: interaction.client.i18n.t( + 'commands.pin.message_not_found' + ), + ephemeral: true, + }) + if (!message.pinned) + return await interaction.reply({ + content: interaction.client.i18n.t('commands.pin.is_not_pinned'), + ephemeral: true, + }) + + await message.unpin({ reason: inputReason }) + } catch (error) { + catchError( + interaction.client, + interaction, + module.exports.data.name, + error + ) + } + + await interaction.reply({ + content: interaction.client.i18n.t('commands.pin.unpinned'), + ephemeral: true, + }) + break + } + } + }, +} diff --git a/source/commands/messages/react.js b/source/commands/messages/react.js new file mode 100644 index 00000000..e57f7721 --- /dev/null +++ b/source/commands/messages/react.js @@ -0,0 +1,76 @@ +const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js') +const { matchEmotes } = require('../../utils/miscUtils') +const { catchError } = require('../../utils/consoleUtils') + +module.exports = { + permissions: [ + PermissionFlagsBits.SendMessages, + PermissionFlagsBits.ManageMessages, + ], + data: new SlashCommandBuilder() + .setName('react') + .setDescription('Interact with the desired message') + .setDescriptionLocalizations({ + th: 'โต้ตอบกับข้อความที่ต้องการ', + }) + .setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages) + .setDMPermission(true) + .addStringOption((option) => + option + .setName('id') + .setDescription('ID of the message you want to interact') + .setDescriptionLocalizations({ + th: 'ไอดีของข้อความที่ต้องการโต้ตอบ', + }) + .setRequired(true) + ) + .addStringOption((option) => + option + .setName('emoji') + .setDescription('Emoji to interact with') + .setDescriptionLocalizations({ + th: 'อีโมจิที่ต้องการโต้ตอบ', + }) + .setRequired(true) + ), + async execute(interaction) { + const inputID = interaction.options.getString('id') + const inputEmoji = interaction.options.getString('emoji') + + try { + const message = await interaction.channel.messages.fetch(inputID) + const emojis = matchEmotes(inputEmoji) + + if (!message) + return await interaction.reply({ + content: interaction.client.i18n.t( + 'commands.react.message_not_found' + ), + ephemeral: true, + }) + if (!emojis.length) + return await interaction.reply({ + content: interaction.client.i18n.t( + 'commands.react.look_like_is_not_emoji' + ), + ephemeral: true, + }) + + for (let emoji in emojis) { + await message.react(emoji) + } + } catch (error) { + catchError( + interaction.client, + interaction, + module.exports.data.name, + error + ) + } + + await interaction.reply({ + content: interaction.client.i18n.t('commands.react.reacted'), + ephemeral: true, + }) + }, +}