diff --git a/Dockerfile b/Dockerfile index 30fbe83..3962a68 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,8 @@ FROM denoland/deno:latest WORKDIR /app COPY . . -RUN apt-get update && apt-get install -y \ +RUN apt-get update \ + && apt-get install -y \ build-essential \ libcairo2-dev \ libpango1.0-dev \ @@ -9,7 +10,6 @@ RUN apt-get update && apt-get install -y \ librsvg2-dev \ nodejs \ npm \ - && deno install --allow-scripts=npm:canvas \ + && deno install --allow-scripts \ && rm -rf /var/lib/apt/lists/* CMD ["deno", "run", "start"] - diff --git a/deno.json b/deno.json index e97a40b..42d30e3 100644 --- a/deno.json +++ b/deno.json @@ -1,10 +1,11 @@ { "tasks": { - "dev": "deno run --allow-ffi --allow-env --allow-read --allow-net --allow-ffi --watch src/main.ts", + "dev": "deno run --allow-ffi --allow-env --allow-read --allow-net --watch src/main.ts", "start": "deno run --allow-ffi --allow-env --allow-read --allow-net src/main.ts" }, "imports": { "@std/assert": "jsr:@std/assert@1", + "canvas": "npm:canvas@^3.0.0", "discord.js": "npm:discord.js@^14.16.3", "dotenv": "npm:dotenv@^16.4.7", "mysql": "npm:mysql@^2.18.1" diff --git a/src/commands/bye_message/byeexample.ts b/src/commands/bye_message/byeexample.ts new file mode 100644 index 0000000..ee1d0b9 --- /dev/null +++ b/src/commands/bye_message/byeexample.ts @@ -0,0 +1,72 @@ +import { SlashCommandBuilder, CommandInteraction, PermissionFlagsBits, EmbedBuilder, AttachmentBuilder } from "npm:discord.js"; +import { connectToDb, getGuild, getByeConfig } from "../../libs/mysql.ts"; +import { errorEmbed } from "../../libs/discord.ts"; +import { createWelcomeImage } from "../../libs/imageGeneration.ts" + +export default { + data: new SlashCommandBuilder() + .setName("byeexample") + .setDescription("Send an example of the goodbye message of the server."), + async execute(interaction: CommandInteraction) { + await interaction.deferReply() + const connection = await connectToDb(); + + const guild_id = interaction.guild?.id ? interaction.guild?.id : "" + + const guild = await getGuild(connection, guild_id) + + if (!guild[0]) { + const embed = errorEmbed("Your server must be registered to the bot, use /register to do so.", interaction.client.user.displayAvatarURL()); + + return interaction.editReply({embeds: [embed]}); + } + + const member = interaction.guild?.members.cache.get(interaction.user.id) + + if (!member?.permissions.has(PermissionFlagsBits.Administrator) && !member?.roles.cache.has(guild[0].admin_role_id)) { + const embed = errorEmbed("You are not allowed to use that command.", interaction.client.user.displayAvatarURL()); + + return await interaction.editReply({embeds: [embed]}); + } + + const config = await getByeConfig(connection, guild_id).catch(error => { + console.error(error) + }); + + connection.end(); + + if (!config[0]) { + const embed = errorEmbed("Your welcome message must be setup before using that command.", interaction.client.user.displayAvatarURL()); + + return interaction.editReply({embeds: [embed]}); + } + + const embed = new EmbedBuilder(); + + if (config[0].title) { + embed.setTitle(config[0].title); + } + + if (config[0].description_format) { + embed.setDescription(config[0].description_format.replace("{user}", `<@${interaction.user.id}>`).replace("{role}", `<@&${config[0].role_id ? config[0].role_id : ""}>`)); + } + + if (config[0].vignette_url) { + embed.setThumbnail(config[0].vignette_url); + } + + var files = []; + + if (config[0].background_url) { + const buffer = await createWelcomeImage(config[0].background_url, `https://cdn.discordapp.com/avatars/${interaction.user.id}/${interaction.user.avatar}.jpeg`, interaction.user.id); + + if (buffer) { + const attachement = new AttachmentBuilder(buffer, { name: `${interaction.user.id}.png` }) + files.push(attachement) + embed.setImage(`attachment://${interaction.user.id}.png`) + } + } + + interaction.editReply({content: config[0].message_format ? config[0].message_format.replace("{user}", `<@${interaction.user.id}>`).replace("{role}", `<@&${config[0].role_id ? config[0].role_id : ""}>`) : "", embeds: [embed], files: files}); + }, +}; diff --git a/src/commands/bye_message/setupbyemessage.ts b/src/commands/bye_message/setupbyemessage.ts new file mode 100644 index 0000000..b818382 --- /dev/null +++ b/src/commands/bye_message/setupbyemessage.ts @@ -0,0 +1,111 @@ +import { SlashCommandBuilder, ChatInputCommandInteraction, PermissionFlagsBits } from "npm:discord.js"; +import { connectToDb, getGuild, getByeConfig, addByeConfig, setFeatureProperty, addGuild } from "../../libs/mysql.ts"; +import { errorEmbed, successEmbed } from "../../libs/discord.ts"; + +export default { + data: new SlashCommandBuilder() + .setName("setupbyemessage") + .setDescription("Configure the Goodbye message.") + .setDMPermission(false) + .addChannelOption(option => + option.setName("channel") + .setDescription("The channel where the embed will be sent.") + .setRequired(true) + ) + .addRoleOption(option => + option.setName("role") + .setDescription("The role that will be ping if you put {role} in the message or the embed description.") + .setRequired(false) + ) + .addStringOption(option => + option.setName("message") + .setDescription("The message that will be sent with the embed.") + .setRequired(false) + ) + .addStringOption(option => + option.setName("title") + .setDescription("The title of the embed.") + .setRequired(false) + ) + .addStringOption(option => + option.setName("description") + .setDescription("The description of the embed.") + .setRequired(false) + ) + .addStringOption(option => + option.setName("background") + .setDescription("The url of background of the image of the embed.") + .setRequired(false) + ) + .addStringOption(option => + option.setName("vignette") + .setDescription("The url of vignette of the embed.") + .setRequired(false) + ), + async execute(interaction: ChatInputCommandInteraction) { + await interaction.deferReply() + const connection = await connectToDb(); + + const guild_id = interaction.guild?.id ? interaction.guild?.id : "" + + const guild = await getGuild(connection, guild_id) + + if (!guild[0]) { + await addGuild(connection, guild_id); + } + + const member = interaction.guild?.members.cache.get(interaction.user.id) + + if (!member?.permissions.has(PermissionFlagsBits.Administrator) && !member?.roles.cache.has(guild[0]?.admin_role_id)) { + const embed = errorEmbed("You are not allowed to use that command.", interaction.client.user.displayAvatarURL()); + + return await interaction.editReply({embeds: [embed]}); + } + + const config = await getByeConfig(connection, guild_id); + + if (!config[0]) { + await addByeConfig(connection, guild_id); + } + + const channel_id = interaction.options.getChannel("channel")?.id + const role_id = interaction.options.getRole("role")?.id + const message = interaction.options.getString("message") + const title = interaction.options.getString("title") + const description = interaction.options.getString("description") + const background_url = interaction.options.getString("background") + const vignette_url = interaction.options.getString("vignette") + + await setFeatureProperty(connection, guild_id, "bye_config", "channel_id", channel_id ? channel_id : ""); + + if (role_id) { + await setFeatureProperty(connection, guild_id, "bye_config", "role_id", role_id); + } + + if (message) { + await setFeatureProperty(connection, guild_id, "bye_config", "message_format", message); + } + + if (title) { + await setFeatureProperty(connection, guild_id, "bye_config", "title", title); + } + + if (description) { + await setFeatureProperty(connection, guild_id, "bye_config", "description_format", description); + } + + if (background_url) { + await setFeatureProperty(connection, guild_id, "bye_config", "background_url", background_url); + } + + if (vignette_url) { + await setFeatureProperty(connection, guild_id, "bye_config", "vignette_url", vignette_url); + } + + connection.end(); + + const embed = successEmbed("Your goodbye message has been successfully setup.", interaction.client.user.displayAvatarURL()); + + interaction.editReply({embeds: [embed]}); + }, +}; diff --git a/src/commands/guilds/disablefeature.ts b/src/commands/guilds/disablefeature.ts new file mode 100644 index 0000000..83014a9 --- /dev/null +++ b/src/commands/guilds/disablefeature.ts @@ -0,0 +1,47 @@ +import { SlashCommandBuilder, ChatInputCommandInteraction, PermissionFlagsBits } from "npm:discord.js"; +import { connectToDb, getGuild, setFeature, addGuild } from "../../libs/mysql.ts"; +import { errorEmbed, successEmbed } from "../../libs/discord.ts"; + +export default { + data: new SlashCommandBuilder() + .setName("disablefeature") + .setDescription("Disable a feature of the bot.") + .setDMPermission(false) + .addStringOption(option => + option.setName("feature") + .setDescription("The feature to be enabled.") + .setRequired(true) + .addChoices([ + {name: "Welcome message", value: "welcome_message"}, + {name: "Goodbye message", value: "bye_message"}, + ])), + async execute(interaction: ChatInputCommandInteraction) { + const connection = await connectToDb(); + + const guild_id = interaction.guild?.id ? interaction.guild?.id : "" + + const guild = await getGuild(connection, guild_id) + + if (!guild[0]) { + await addGuild(connection, guild_id); + } + + const member = interaction.guild?.members.cache.get(interaction.user.id) + + if (!member?.permissions.has(PermissionFlagsBits.Administrator) && (guild[0].admin_role_id && !member?.roles.cache.has(guild[0]?.admin_role_id))) { + const embed = errorEmbed("You are not allowed to use that command.", interaction.client.user.displayAvatarURL()); + + return await interaction.reply({embeds: [embed]}); + } + + const feature: string | null = interaction.options.getString("feature") + + setFeature(connection, guild_id, feature ? feature : "", "false"); + + await connection.end() + + const embed = successEmbed("The feature has been successfully disabled.", interaction.client.user.displayAvatarURL()) + + interaction.reply({embeds: [embed]}) + }, +}; diff --git a/src/commands/guilds/enablefeature.ts b/src/commands/guilds/enablefeature.ts index e27b99a..01f7600 100644 --- a/src/commands/guilds/enablefeature.ts +++ b/src/commands/guilds/enablefeature.ts @@ -1,5 +1,5 @@ import { SlashCommandBuilder, ChatInputCommandInteraction, PermissionFlagsBits } from "npm:discord.js"; -import { connectToDb, getGuild, setFeature } from "../../libs/mysql.ts"; +import { connectToDb, getGuild, setFeature, addGuild } from "../../libs/mysql.ts"; import { errorEmbed, successEmbed } from "../../libs/discord.ts"; export default { @@ -16,6 +16,7 @@ export default { {name: "Goodbye message", value: "bye_message"}, ])), async execute(interaction: ChatInputCommandInteraction) { + await interaction.deferReply() const connection = await connectToDb(); const guild_id = interaction.guild?.id ? interaction.guild?.id : "" @@ -23,27 +24,25 @@ export default { const guild = await getGuild(connection, guild_id) if (!guild[0]) { - const embed = errorEmbed("Your server must be registered to the bot, use /register to do so.", interaction.client.user.displayAvatarURL()); - - return interaction.reply({embeds: [embed]}); + await addGuild(connection, guild_id); } const member = interaction.guild?.members.cache.get(interaction.user.id) - if (!member?.permissions.has(PermissionFlagsBits.Administrator) && !member?.roles.cache.has(guild[0].admin_role_id)) { + if (!member?.permissions.has(PermissionFlagsBits.Administrator) && (guild[0].admin_role_id && !member?.roles.cache.has(guild[0]?.admin_role_id))) { const embed = errorEmbed("You are not allowed to use that command.", interaction.client.user.displayAvatarURL()); - return await interaction.reply({embeds: [embed]}); + return await interaction.editReply({embeds: [embed]}); } const feature: string | null = interaction.options.getString("feature") - setFeature(connection, guild_id, feature ? feature : "", "true"); + await setFeature(connection, guild_id, feature ? feature : "", "true"); connection.end() - const embed = successEmbed("The feature has been successfully activated.", interaction.client.user.displayAvatarURL()) + const embed = successEmbed("The feature has been successfully enabled.", interaction.client.user.displayAvatarURL()) - interaction.reply({embeds: [embed]}) + interaction.editReply({embeds: [embed]}) }, }; diff --git a/src/commands/guilds/register.ts b/src/commands/guilds/register.ts deleted file mode 100644 index 1c183dd..0000000 --- a/src/commands/guilds/register.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { SlashCommandBuilder, CommandInteraction, PermissionsBitField } from "npm:discord.js"; -import { connectToDb, getGuild, addGuild } from "../../libs/mysql.ts" -import { errorEmbed, successEmbed } from "../../libs/discord.ts"; - -export default { - data: new SlashCommandBuilder() - .setName("register") - .setDescription("Register the guild to the bot.") - .setDMPermission(false), - async execute(interaction: CommandInteraction) { - const guild_id: string = interaction.guildId ? interaction.guildId : ""; - const member = interaction.guild?.members.cache.get(interaction.user.id); - - if (!member?.permissions.has(PermissionsBitField.Flags.ManageGuild)) { - const embed = errorEmbed("You are not allowed to use that command.", interaction.client.user.displayAvatarURL()); - - return await interaction.reply({embeds: [embed]}); - } - - const connection = await connectToDb(); - - const guild: any[] = await getGuild(connection, guild_id); - - if (guild[0]) { - const embed = await errorEmbed("Your server is already registered.", interaction.client.user.displayAvatarURL()); - - return await interaction.reply({embeds: [embed]}); - } - - await addGuild(connection, guild_id); - - connection.end(); - - const embed = await successEmbed("your server has been added to the bot.", interaction.client.user.displayAvatarURL()); - - await interaction.reply({embeds: [embed]}); - }, -}; diff --git a/src/commands/guilds/setAdminRole.ts b/src/commands/guilds/setAdminRole.ts index fba4a40..afa1ecd 100644 --- a/src/commands/guilds/setAdminRole.ts +++ b/src/commands/guilds/setAdminRole.ts @@ -1,5 +1,5 @@ import { SlashCommandBuilder, ChatInputCommandInteraction, PermissionsBitField } from "npm:discord.js"; -import { connectToDb, getGuild, setAdminRole } from "../../libs/mysql.ts" +import { connectToDb, getGuild, setAdminRole, addGuild } from "../../libs/mysql.ts" import { errorEmbed, successEmbed } from "../../libs/discord.ts"; @@ -20,12 +20,10 @@ export default { const connection = await connectToDb(); - const guild: any[] = await getGuild(connection, guild_id); + const guild = await getGuild(connection, guild_id); if (!guild[0]) { - const embed = errorEmbed("Your server must be registered to the bot, use /register to do so.", interaction.client.user.displayAvatarURL()); - - return interaction.reply({embeds: [embed]}); + await addGuild(connection, guild_id); } const role_id: string | undefined = interaction.options.getRole("role")?.id diff --git a/src/commands/guilds/setupwelcomemessage.ts b/src/commands/welcome_message/setupwelcomemessage.ts similarity index 73% rename from src/commands/guilds/setupwelcomemessage.ts rename to src/commands/welcome_message/setupwelcomemessage.ts index a5ff1be..85c0848 100644 --- a/src/commands/guilds/setupwelcomemessage.ts +++ b/src/commands/welcome_message/setupwelcomemessage.ts @@ -1,11 +1,11 @@ import { SlashCommandBuilder, ChatInputCommandInteraction, PermissionFlagsBits } from "npm:discord.js"; -import { connectToDb, getGuild, getWelcomeConfig, addWelcomeConfig, setWelcomePropertiy } from "../../libs/mysql.ts"; +import { connectToDb, getGuild, getWelcomeConfig, addWelcomeConfig, setFeatureProperty, addGuild } from "../../libs/mysql.ts"; import { errorEmbed, successEmbed } from "../../libs/discord.ts"; export default { data: new SlashCommandBuilder() .setName("setupwelcomemessage") - .setDescription("Enable a feature of the bot.") + .setDescription("Configure the Welcome message.") .setDMPermission(false) .addChannelOption(option => option.setName("channel") @@ -14,7 +14,7 @@ export default { ) .addRoleOption(option => option.setName("role") - .setDescription("The role that will be ping if you put {welcomer} in the message or the embed description.") + .setDescription("The role that will be ping if you put {role} in the message or the embed description.") .setRequired(false) ) .addStringOption(option => @@ -43,6 +43,7 @@ export default { .setRequired(false) ), async execute(interaction: ChatInputCommandInteraction) { + await interaction.deferReply() const connection = await connectToDb(); const guild_id = interaction.guild?.id ? interaction.guild?.id : "" @@ -50,17 +51,15 @@ export default { const guild = await getGuild(connection, guild_id) if (!guild[0]) { - const embed = errorEmbed("Your server must be registered to the bot, use /register to do so.", interaction.client.user.displayAvatarURL()); - - return interaction.reply({embeds: [embed]}); + await addGuild(connection, guild_id); } const member = interaction.guild?.members.cache.get(interaction.user.id) - if (!member?.permissions.has(PermissionFlagsBits.Administrator) && !member?.roles.cache.has(guild[0].admin_role_id)) { + if (!member?.permissions.has(PermissionFlagsBits.Administrator) && !member?.roles.cache.has(guild[0]?.admin_role_id)) { const embed = errorEmbed("You are not allowed to use that command.", interaction.client.user.displayAvatarURL()); - return await interaction.reply({embeds: [embed]}); + return await interaction.editReply({embeds: [embed]}); } const config = await getWelcomeConfig(connection, guild_id); @@ -77,36 +76,36 @@ export default { const background_url = interaction.options.getString("background") const vignette_url = interaction.options.getString("vignette") - setWelcomePropertiy(connection, guild_id, "channel_id", channel_id ? channel_id : ""); + await setFeatureProperty(connection, guild_id, "welcome_config", "channel_id", channel_id ? channel_id : ""); if (role_id) { - setWelcomePropertiy(connection, guild_id, "welcomer_role_id", role_id); + await setFeatureProperty(connection, guild_id, "welcome_config", "role_id", role_id); } if (message) { - setWelcomePropertiy(connection, guild_id, "message_format", message); + await setFeatureProperty(connection, guild_id, "welcome_config", "message_format", message); } if (title) { - setWelcomePropertiy(connection, guild_id, "title", title); + await setFeatureProperty(connection, guild_id, "welcome_config", "title", title); } if (description) { - setWelcomePropertiy(connection, guild_id, "description_format", description); + await setFeatureProperty(connection, guild_id, "welcome_config", "description_format", description); } if (background_url) { - setWelcomePropertiy(connection, guild_id, "background_url", background_url); + await setFeatureProperty(connection, guild_id, "welcome_config", "background_url", background_url); } if (vignette_url) { - setWelcomePropertiy(connection, guild_id, "vignette_url", vignette_url); + await setFeatureProperty(connection, guild_id, "welcome_config", "vignette_url", vignette_url); } connection.end(); const embed = successEmbed("Your welcome message has been successfully setup.", interaction.client.user.displayAvatarURL()); - interaction.reply({embeds: [embed]}); + interaction.editReply({embeds: [embed]}); }, }; diff --git a/src/commands/guilds/welcomeexample.ts b/src/commands/welcome_message/welcomeexample.ts similarity index 77% rename from src/commands/guilds/welcomeexample.ts rename to src/commands/welcome_message/welcomeexample.ts index 440ac69..51143ee 100644 --- a/src/commands/guilds/welcomeexample.ts +++ b/src/commands/welcome_message/welcomeexample.ts @@ -1,5 +1,5 @@ import { SlashCommandBuilder, CommandInteraction, PermissionFlagsBits, EmbedBuilder, AttachmentBuilder } from "npm:discord.js"; -import { connectToDb, getGuild, getWelcomeConfig } from "../../libs/mysql.ts"; +import { connectToDb, getGuild, getWelcomeConfig, addGuild } from "../../libs/mysql.ts"; import { errorEmbed } from "../../libs/discord.ts"; import { createWelcomeImage } from "../../libs/imageGeneration.ts" @@ -13,17 +13,15 @@ export default { const guild_id = interaction.guild?.id ? interaction.guild?.id : "" - const guild = await getGuild(connection, guild_id) + const guild = await getGuild(connection, guild_id); if (!guild[0]) { - const embed = errorEmbed("Your server must be registered to the bot, use /register to do so.", interaction.client.user.displayAvatarURL()); - - return interaction.editReply({embeds: [embed]}); + await addGuild(connection, guild_id); } const member = interaction.guild?.members.cache.get(interaction.user.id) - if (!member?.permissions.has(PermissionFlagsBits.Administrator) && !member?.roles.cache.has(guild[0].admin_role_id)) { + if (!member?.permissions.has(PermissionFlagsBits.Administrator) && !member?.roles.cache.has(guild[0]?.admin_role_id)) { const embed = errorEmbed("You are not allowed to use that command.", interaction.client.user.displayAvatarURL()); return await interaction.editReply({embeds: [embed]}); @@ -46,7 +44,7 @@ export default { } if (config[0].description_format) { - embed.setDescription(config[0].description_format.replace("{user}", `<@${interaction.user.id}>`).replace("{welcomer}", `<@&${config[0].welcomer_role_id ? config[0].welcomer_role_id : ""}>`)); + embed.setDescription(config[0].description_format.replace("{user}", `<@${interaction.user.id}>`).replace("{role}", `<@&${config[0].welcomer_role_id ? config[0].welcomer_role_id : ""}>`)); } if (config[0].vignette_url) { @@ -65,6 +63,6 @@ export default { } } - interaction.editReply({content: config[0].message_format ? config[0].message_format.replace("{user}", `<@${interaction.user.id}>`).replace("{welcomer}", `<@&${config[0].welcomer_role_id ? config[0].welcomer_role_id : ""}>`) : "", embeds: [embed], files: files}); + interaction.editReply({content: config[0].message_format ? config[0].message_format.replace("{user}", `<@${interaction.user.id}>`).replace("{role}", `<@&${config[0].role_id ? config[0].role_id : ""}>`) : "", embeds: [embed], files: files}); }, }; diff --git a/src/events/guildMemberAdd.ts b/src/events/guildMemberAdd.ts index ae56ae0..5e2e437 100644 --- a/src/events/guildMemberAdd.ts +++ b/src/events/guildMemberAdd.ts @@ -4,7 +4,7 @@ import { createWelcomeImage } from "../libs/imageGeneration.ts" export default { name: Events.GuildMemberAdd, - async execute(member: GuildMember ) { + async execute(member: GuildMember) { const connection = await connectToDb(); const guild = await getGuild(connection, member.guild.id); const config = await getWelcomeConfig(connection, member.guild.id); @@ -19,20 +19,18 @@ export default { } if (config[0].description_format) { - embed.setDescription(config[0].description_format.replace("{user}", `<@${member.user.id}>`).replace("{welcomer}", `<@&${config[0].welcomer_role_id ? config[0].welcomer_role_id : ""}>`)); + embed.setDescription(config[0].description_format.replace("{user}", `<@${member.user.id}>`).replace("{role}", `<@&${config[0].role_id ? config[0].role_id : ""}>`)); } if (config[0].vignette_url) { embed.setThumbnail(config[0].vignette_url); } - - var attachement; - var buffer; + var files = []; if (config[0].background_url) { - buffer = await createWelcomeImage(config[0].background_url, `https://cdn.discordapp.com/avatars/${member.user.id}/${member.user.avatar}.jpeg`, member.user.id); - attachement = new AttachmentBuilder(buffer, { name: `${member.user.id}.png` }) + const buffer = await createWelcomeImage(config[0].background_url, `https://cdn.discordapp.com/avatars/${member.user.id}/${member.user.avatar}.jpeg`, member.user.id); + const attachement = new AttachmentBuilder(buffer, { name: `${member.user.id}.png` }) files.push(attachement) embed.setImage(`attachment://${member.user.id}.png`) } @@ -40,7 +38,7 @@ export default { const channel = member.guild.channels.cache.get(config[0].channel_id); if (channel?.isTextBased()) { - channel.send({content: config[0].message_format ? config[0].message_format.replace("{user}", `<@${member.user.id}>`).replace("{welcomer}", `<@&${config[0].welcomer_role_id ? config[0].welcomer_role_id : ""}>`) : "", embeds: [embed], files: files}); + channel.send({content: config[0].message_format ? config[0].message_format.replace("{user}", `<@${member.user.id}>`).replace("{role}", `<@&${config[0].role_id ? config[0].role_id : ""}>`) : "", embeds: [embed], files: files}); } } }, diff --git a/src/events/guildMemberRemove.ts b/src/events/guildMemberRemove.ts new file mode 100644 index 0000000..0f8614f --- /dev/null +++ b/src/events/guildMemberRemove.ts @@ -0,0 +1,45 @@ +import { Events, GuildMember, EmbedBuilder, AttachmentBuilder } from "npm:discord.js"; +import { connectToDb, getGuild, getByeConfig } from "../libs/mysql.ts"; +import { createWelcomeImage } from "../libs/imageGeneration.ts" + +export default { + name: Events.GuildMemberRemove, + async execute(member: GuildMember) { + const connection = await connectToDb(); + const guild = await getGuild(connection, member.guild.id); + const config = await getByeConfig(connection, member.guild.id); + + connection.end(); + + if (guild[0]?.welcome_message && config[0]) { + const embed = new EmbedBuilder(); + + if (config[0].title) { + embed.setTitle(config[0].title); + } + + if (config[0].description_format) { + embed.setDescription(config[0].description_format.replace("{user}", `<@${member.user.id}>`).replace("{role}", `<@&${config[0].role_id ? config[0].role_id : ""}>`)); + } + + if (config[0].vignette_url) { + embed.setThumbnail(config[0].vignette_url); + } + + var files = []; + + if (config[0].background_url) { + const buffer = await createWelcomeImage(config[0].background_url, `https://cdn.discordapp.com/avatars/${member.user.id}/${member.user.avatar}.jpeg`, member.user.id); + const attachement = new AttachmentBuilder(buffer, { name: `${member.user.id}.png` }) + files.push(attachement) + embed.setImage(`attachment://${member.user.id}.png`) + } + + const channel = member.guild.channels.cache.get(config[0].channel_id); + + if (channel?.isTextBased()) { + channel.send({content: config[0].message_format ? config[0].message_format.replace("{user}", `<@${member.user.id}>`).replace("{role}", `<@&${config[0].role_id ? config[0].role_id : ""}>`) : "", embeds: [embed], files: files}); + } + } + }, +}; diff --git a/src/libs/mysql.ts b/src/libs/mysql.ts index 154ba32..b29f9f0 100644 --- a/src/libs/mysql.ts +++ b/src/libs/mysql.ts @@ -1,6 +1,4 @@ import * as mysql from "npm:mysql"; -import { rejects } from "node:assert"; -import { resolve } from "node:path"; export interface User { id: number, @@ -20,7 +18,7 @@ export async function connectToDb(): Promise { connection.connect((error) => { if (error) { - reject(error) + reject(new Error(error)); } resolve(connection); @@ -32,7 +30,7 @@ export async function addUser(connection: mysql.Connection, username: string, us return new Promise((resolve, reject) => { connection.query(`INSERT INTO users (username, userid, quota) VALUES ("${username}", "${userid}", 0)`, (error, result) => { if (error) { - reject(error); + reject(new Error(error)); } resolve(result); @@ -44,7 +42,7 @@ export async function getUser(connection: mysql.Connection, userid: string): Pro return new Promise((resolve, reject) => { connection.query(`SELECT * FROM users WHERE userid = "${userid}"`, (error, result) => { if (error) { - reject(error); + reject(new Error(error)); } resolve(result); @@ -56,7 +54,7 @@ export async function incrementQuota(connection: mysql.Connection, userid: strin return new Promise((resolve, reject) => { connection.query(`UPDATE users SET quota = quota + ${value} WHERE userid = "${userid}"`, (error, result) => { if (error) { - reject(error); + reject(new Error(error)); } resolve(result); @@ -68,7 +66,7 @@ export function resetQuota(connection: mysql.Connection) { return new Promise((resolve, reject) => { connection.query(`UPDATE users SET quota = 0`, (error, result) => { if (error) { - reject(error); + reject(new Error(error)); } resolve(result); @@ -80,7 +78,7 @@ export function getGuild(connection: mysql.Connection, guild_id: string): Promis return new Promise((resolve, reject) => { connection.query(`SELECT * FROM guilds WHERE guild_id = "${guild_id}"`, (error, result) => { if (error) { - reject(error); + reject(new Error(error)); } resolve(result); @@ -92,7 +90,7 @@ export function addGuild(connection: mysql.Connection, guild_id: string) { return new Promise((resolve, reject) => { connection.query(`INSERT INTO guilds (guild_id) VALUES ("${guild_id}")`, (error, result) => { if (error) { - reject(error); + reject(new Error(error)); } resolve(result); @@ -104,7 +102,7 @@ export function setAdminRole(connection: mysql.Connection, guild_id: string, rol return new Promise((resolve, reject) => { connection.query(`UPDATE guilds SET admin_role_id = "${role_id}" WHERE guild_id = "${guild_id}"`, (error, result) => { if (error) { - reject(error); + reject(new Error(error)); } resolve(result); @@ -116,7 +114,7 @@ export function setFeature(connection: mysql.Connection, guild_id: string, featu return new Promise((resolve, reject) => { connection.query(`UPDATE guilds SET ${feature} = ${code} WHERE guild_id = "${guild_id}"`, (error, result) => { if (error) { - reject(error); + reject(new Error(error)); } resolve(result); @@ -128,7 +126,19 @@ export function getWelcomeConfig(connection: mysql.Connection, guild_id: string) return new Promise((resolve, reject) => { connection.query(`SELECT * FROM welcome_config WHERE guild_id = "${guild_id}"`, (error, result) => { if (error) { - reject(error); + reject(new Error(error)); + } + + resolve(result); + }) + }) +} + +export function getByeConfig(connection: mysql.Connection, guild_id: string): Promise { + return new Promise((resolve, reject) => { + connection.query(`SELECT * FROM bye_config WHERE guild_id = "${guild_id}"`, (error, result) => { + if (error) { + reject(new Error(error)); } resolve(result); @@ -140,7 +150,7 @@ export function addWelcomeConfig(connection: mysql.Connection, guild_id: string) return new Promise((resolve, reject) => { connection.query(`INSERT INTO welcome_config (guild_id) VALUES ("${guild_id}")`, (error, result) => { if (error) { - reject(error); + reject(new Error(error)); } resolve(result); @@ -148,11 +158,23 @@ export function addWelcomeConfig(connection: mysql.Connection, guild_id: string) }) } -export function setWelcomePropertiy(connection: mysql.Connection, guild_id: String, property: string, value: string) { +export function addByeConfig(connection: mysql.Connection, guild_id: string) { return new Promise((resolve, reject) => { - connection.query(`UPDATE welcome_config SET ${property} = "${value}" WHERE guild_id = "${guild_id}"`, (error, result) => { + connection.query(`INSERT INTO bye_config (guild_id) VALUES ("${guild_id}")`, (error, result) => { if (error) { - reject(error); + reject(new Error(error)); + } + + resolve(result); + }) + }) +} + +export function setFeatureProperty(connection: mysql.Connection, guild_id: String, feature: string, property: string, value: string) { + return new Promise((resolve, reject) => { + connection.query(`UPDATE ${feature} SET ${property} = "${value}" WHERE guild_id = "${guild_id}"`, (error, result) => { + if (error) { + reject(new Error(error)); } resolve(result); @@ -164,7 +186,7 @@ export function getLastReset(connection: mysql.Connection) { return new Promise((resolve, reject) => { connection.query("SELECT MAX(date) AS date FROM resets", (error, result) => { if (error) { - reject(error); + reject(new Error(error)); } resolve(result) @@ -176,7 +198,7 @@ export function addReset(connection: mysql.Connection, date: number) { return new Promise((resolve, reject) => { connection.query(`INSERT INTO resets (date) VALUES (${date})`, (error, result) => { if (error) { - reject(error); + reject(new Error(error)); } resolve(result) diff --git a/src/main.ts b/src/main.ts index 87eed77..c3e00b1 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,7 @@ import * as fs from 'node:fs'; -import * as path from 'node:path'; import "dotenv/config"; -import { Client, Collection, REST, Routes, RESTPutAPIApplicationCommandsResult, GatewayIntentBits, Partials } from 'npm:discord.js'; -import { sendLog } from './libs/discord.ts'; +import { Client, Collection, REST, Routes, GatewayIntentBits, Partials } from 'npm:discord.js'; +import process from 'node:process'; const client: Client = new Client({ intents: [ @@ -10,7 +9,8 @@ const client: Client = new Client({ GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent, GatewayIntentBits.DirectMessages, - GatewayIntentBits.GuildMembers + GatewayIntentBits.GuildMembers, + GatewayIntentBits.GuildPresences ], partials: [ Partials.Channel, @@ -72,7 +72,7 @@ const rest = new REST().setToken(process.env.DISCORD_TOKEN ? process.env.DISCORD try { console.log(`Started refreshing ${commands.length} application (/) commands.`); - const data = await rest.put( + await rest.put( Routes.applicationCommands(process.env.BOT_ID ? process.env.BOT_ID : ""), { body: commands } );