From 8d2f647ffd015699dbd7aae3bd03fbf4340ea69f Mon Sep 17 00:00:00 2001 From: Baipyrus Date: Sun, 3 Mar 2024 01:44:27 +0100 Subject: [PATCH] find or create, then save guild on each interaction --- commands/admin/custom_vc/slash.js | 24 +++++++++++++++++++---- commands/admin/member_roles/slash.js | 29 +++++++++++++++++++++------- commands/admin/self_roles/slash.js | 21 ++++++++++++++++++-- events/members/guildMemberAdd.js | 13 +++++++++---- models/guilds.js | 1 + models/messages.js | 1 + models/roleEmojiPairs.js | 1 + models/roles.js | 1 + models/voiceChannels.js | 1 + shared.js | 8 ++++++++ 10 files changed, 83 insertions(+), 17 deletions(-) diff --git a/commands/admin/custom_vc/slash.js b/commands/admin/custom_vc/slash.js index 5692a92..b3fc6b6 100644 --- a/commands/admin/custom_vc/slash.js +++ b/commands/admin/custom_vc/slash.js @@ -4,7 +4,7 @@ import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'; -import { VoiceChannel } from '../../../database.js'; +import { Guild, VoiceChannel } from '../../../database.js'; export const data = new SlashCommandBuilder() .setName('custom_vc') @@ -52,6 +52,7 @@ export async function execute(interaction) { /** @type {string} */ let step; + const guildData = { id: guild.id }; try { switch (options.getSubcommand()) { case 'create': { @@ -65,10 +66,16 @@ export async function execute(interaction) { type: ChannelType.GuildVoice }); - // Save channel data step = 'save'; + // Create guild if not exists + await Guild.findOrCreate({ + where: guildData, + defaults: guildData + }); + // Save channel data await VoiceChannel.create({ id: channel.id, + guild: guild.id, create: true }); @@ -85,9 +92,18 @@ export async function execute(interaction) { // Get channel id from user input const { id } = options.getChannel('channel'); - // Save channel data step = 'save'; - await VoiceChannel.create({ id, create: true }); + // Create guild if not exists + await Guild.findOrCreate({ + where: guildData, + defaults: guildData + }); + // Save channel data + await VoiceChannel.create({ + id, + guild: guild.id, + create: true + }); // Reply success to acknowledge command await interaction.reply({ diff --git a/commands/admin/member_roles/slash.js b/commands/admin/member_roles/slash.js index 95cfeb9..181e108 100644 --- a/commands/admin/member_roles/slash.js +++ b/commands/admin/member_roles/slash.js @@ -1,5 +1,25 @@ import { SlashCommandBuilder, PermissionFlagsBits } from 'discord.js'; -import { Role } from '../../../database.js'; +import { Role, Guild } from '../../../database.js'; + +/** + * @param {Guild} guild + * @param {Role} role + */ +const registerRole = async (guild, role) => { + // Check if guild exists in database, otherwise create it + const guildData = { id: guild.id }; + await Guild.findOrCreate({ + where: guildData, + defaults: guildData + }); + + // Register role in database + await Role.create({ + guild: guild.id, + id: role.id, + assign: true + }); +}; export const data = new SlashCommandBuilder() .setName('member_roles') @@ -49,12 +69,7 @@ export async function execute(interaction) { found.assign = true; await found.save(); // Otherwise create new database entry - } else - await Role.create({ - id: role.id, - assign: true - }); - + } else await registerRole(interaction.guild, role); // Reply successfully to acknowledge command await interaction.reply({ content: 'Successfully registered role.', diff --git a/commands/admin/self_roles/slash.js b/commands/admin/self_roles/slash.js index 2821f51..560967c 100644 --- a/commands/admin/self_roles/slash.js +++ b/commands/admin/self_roles/slash.js @@ -1,6 +1,6 @@ import { PermissionFlagsBits, SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'; import { addSelfRoles, removeSelfRoles } from '../../../shared.js'; -import { Message } from '../../../database.js'; +import { Guild, Message } from '../../../database.js'; /** * Sends a `Message` in the current channel and registers for self roles. @@ -46,6 +46,13 @@ const registerSelfRoles = async (interaction) => { // Get message by id await channel.messages.fetch(id); + // Check if message is already registered + const found = await Message.findOne({ + where: { id } + }); + + if (found) throw new Error('Message already registered!'); + // Reply successfully to acknowledge command await interaction.reply({ content: 'Successfully fetched message!', @@ -186,8 +193,18 @@ export async function execute(interaction) { if (createNew) { try { + // Create guild if not exists + const guildData = { id: interaction.guild.id }; + await Guild.findOrCreate({ + where: guildData, + defaults: guildData + }); + // Create database entry - await Message.create({ id }); + await Message.create({ + id, + guild: interaction.guild.id + }); } catch (error) { console.error(error); diff --git a/events/members/guildMemberAdd.js b/events/members/guildMemberAdd.js index 69881c5..70aba56 100644 --- a/events/members/guildMemberAdd.js +++ b/events/members/guildMemberAdd.js @@ -15,8 +15,13 @@ export async function execute(member) { // Ignore if no none found if (roles.length === 0) return; - // Add roles to member - await member.roles.add(roles.map((role) => role.id)); - - console.info(`[INFO] Added ${roles.length} roles to user with ID '${member.user.id}'.`); + try { + // Add roles to member + await member.roles.add(roles.map((role) => role.id)); + } catch (error) { + // Missing permissions + console.error(error); + await member.user.send('Could not assign roles. Please contact server staff.'); + } + console.info(`[INFO] Added ${roles.length} roles to new member with ID '${member.user.id}'.`); } diff --git a/models/guilds.js b/models/guilds.js index 8460b8f..c537fbf 100644 --- a/models/guilds.js +++ b/models/guilds.js @@ -6,6 +6,7 @@ import { DataTypes, Sequelize } from 'sequelize'; * @property {(model: Object) => void} hasMany Defines an One-To-Many relationship. * @property {(conditions: Object) => Promise} findOne Finds one instance in the database matching the provided condition(-s). * @property {(conditions: Object) => Promise>} findAll Finds all instances in the database matching the provided condition(-s). + * @property {(conditions: Object) => Promise} findOrCreate Finds or creates an instance in the database matching the provided condition(-s) or default values. */ /** diff --git a/models/messages.js b/models/messages.js index 7dec9c6..ef3ac26 100644 --- a/models/messages.js +++ b/models/messages.js @@ -7,6 +7,7 @@ import { DataTypes, Deferrable, Sequelize } from 'sequelize'; * @property {(model: Object) => void} hasMany Defines an One-To-Many relationship. * @property {(conditions: Object) => Promise} findOne Finds one instance in the database matching the provided condition(-s). * @property {(conditions: Object) => Promise>} findAll Finds all instances in the database matching the provided condition(-s). + * @property {(conditions: Object) => Promise} findOrCreate Finds or creates an instance in the database matching the provided condition(-s) or default values. */ /** diff --git a/models/roleEmojiPairs.js b/models/roleEmojiPairs.js index 11a5946..51ee5c9 100644 --- a/models/roleEmojiPairs.js +++ b/models/roleEmojiPairs.js @@ -9,6 +9,7 @@ import { DataTypes, Deferrable, Sequelize } from 'sequelize'; * @property {(model: Object) => void} hasMany Defines an One-To-Many relationship. * @property {(conditions: Object) => Promise} findOne Finds one instance in the database matching the provided condition(-s). * @property {(conditions: Object) => Promise>} findAll Finds all instances in the database matching the provided condition(-s). + * @property {(conditions: Object) => Promise} findOrCreate Finds or creates an instance in the database matching the provided condition(-s) or default values. */ /** diff --git a/models/roles.js b/models/roles.js index 4eb70ef..fec00d9 100644 --- a/models/roles.js +++ b/models/roles.js @@ -8,6 +8,7 @@ import { DataTypes, Deferrable, Sequelize } from 'sequelize'; * @property {(model: Object) => void} hasMany Defines an One-To-Many relationship. * @property {(conditions: Object) => Promise} findOne Finds one instance in the database matching the provided condition(-s). * @property {(conditions: Object) => Promise>} findAll Finds all instances in the database matching the provided condition(-s). + * @property {(conditions: Object) => Promise} findOrCreate Finds or creates an instance in the database matching the provided condition(-s) or default values. */ /** diff --git a/models/voiceChannels.js b/models/voiceChannels.js index 84f04f8..f7f29de 100644 --- a/models/voiceChannels.js +++ b/models/voiceChannels.js @@ -9,6 +9,7 @@ import { DataTypes, Deferrable, Sequelize } from 'sequelize'; * @property {(model: Object) => void} hasMany Defines an One-To-Many relationship. * @property {(conditions: Object) => Promise} findOne Finds one instance in the database matching the provided condition(-s). * @property {(conditions: Object) => Promise>} findAll Finds all instances in the database matching the provided condition(-s). + * @property {(conditions: Object) => Promise} findOrCreate Finds or creates an instance in the database matching the provided condition(-s) or default values. */ /** diff --git a/shared.js b/shared.js index e3c21c4..ad45a61 100644 --- a/shared.js +++ b/shared.js @@ -65,10 +65,18 @@ const saveMessageData = async (id, role, emoji) => { `Existing RoleEmojiPair entry with (partial) data {message:${id},role:${role.id},emoji:${emoji}}!` ); + // Create guild if not exists + const guildData = { id: role.guild.id }; + await Guild.findOrCreate({ + where: guildData, + defaults: guildData + }); + // Create database entry for pair await RoleEmojiPair.create({ message: id, role: role.id, + guild: guildData.id, emoji: emoji.replace(/:(\s*[^:]*\s*):/, ':_:') }); };