Skip to content

Commit

Permalink
Merge pull request #272 from nwplus/daniel/save-pronoun-messages
Browse files Browse the repository at this point in the history
Save pronoun messages
  • Loading branch information
daniel-panhead authored Aug 4, 2024
2 parents d62fdd9 + b212ca2 commit 99ed057
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 48 deletions.
22 changes: 18 additions & 4 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const { StringPrompt } = require('advanced-discord.js-prompts');
const Sentry = require('@sentry/node');
const Tracing = require('@sentry/tracing');
const { LogLevel, SapphireClient } = require('@sapphire/framework');
const Pronouns = require('./commands/a_utility/pronouns');

/**
* The Main App module houses the bot events, process events, and initializes
Expand Down Expand Up @@ -155,7 +156,8 @@ bot.once('ready', async () => {

// make sure all guilds have a botGuild, this is in case the bot goes offline and its added
// to a guild. If botGuild is found, make sure only the correct commands are enabled.
bot.guilds.cache.forEach(async (guild, key, guilds) => {
const guildsArr = Array.from(bot.guilds.cache);
for (const [_, guild] of guildsArr) {
// create the logger for the guild
createALogger(guild.id, guild.name, false, isLogToConsole);

Expand All @@ -171,11 +173,23 @@ bot.once('ready', async () => {

// await botGuild.setCommandStatus(bot);

guild.commandPrefix = botGuild.prefix;

mainLogger.verbose(`Found a botGuild for ${guild.id} - ${guild.name} on bot ready.`, { event: 'Ready Event' });

if (botGuild.isSetUpComplete) {
mainLogger.verbose('Trying to restore existing pronoun command message');
/** @type {Pronouns} */
const pronounsCommand = bot.stores.get('commands').get('pronouns');
const error = await pronounsCommand.tryRestoreReactionListeners(guild);
if (error) {
mainLogger.warning(error);
} else {
mainLogger.verbose('Restored pronoun command message');
}
}

guild.commandPrefix = botGuild.prefix;
}
});
}
});

/**
Expand Down
168 changes: 124 additions & 44 deletions commands/a_utility/pronouns.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
const { Command } = require('@sapphire/framework');
const { Interaction, MessageEmbed, PermissionFlagsBits } = require('discord.js');
const { Interaction, MessageEmbed, PermissionFlagsBits, Guild, Message, MessageManager } = require('discord.js');
const firebaseUtil = require('../../db/firebase/firebaseUtil');

const emojis = ['1️⃣', '2️⃣', '3️⃣', '4️⃣'];

/**
* The pronouns command sends a role reaction console for users to select a pronoun role out of 4 options:
* * she/her
* * he/him
* * they/them
* * other pronouns
* The roles must be already created on the server for this to work.
* @category Commands
* @subcategory Admin-Utility
* @extends Command
Expand Down Expand Up @@ -44,19 +45,15 @@ class Pronouns extends Command {
interaction.reply({ content: 'You do not have permissions to run this command!', ephemeral: true });
return;
}
const sheRole = interaction.guild.roles.cache.find(role => role.name === 'she/her');
const heRole = interaction.guild.roles.cache.find(role => role.name === 'he/him');
const theyRole = interaction.guild.roles.cache.find(role => role.name === 'they/them');
const otherRole = interaction.guild.roles.cache.find(role => role.name === 'other pronouns');

const { sheRole, heRole, theyRole, otherRole } = await getPronounRoles(guild);

// check to make sure all 4 roles are available
if (!sheRole || !heRole || !theyRole || !otherRole) {
interaction.reply('Could not find all four roles! Make sure the role names are exactly like stated on the documentation.');
return;
}

var emojis = ['1️⃣', '2️⃣', '3️⃣', '4️⃣'];

let embed = new MessageEmbed()
.setColor('#0DEFE1')
.setTitle('Set your pronouns by reacting to one or more of the emojis!')
Expand All @@ -69,47 +66,130 @@ class Pronouns extends Command {
let messageEmbed = await interaction.channel.send({embeds: [embed]});
emojis.forEach(emoji => messageEmbed.react(emoji));
interaction.reply({content: 'Pronouns selector started!', ephemeral: true});

listenToReactions(guild, messageEmbed);

let filter = (reaction, user) => {
return user.bot != true && emojis.includes(reaction.emoji.name);
};

// create collector
const reactionCollector = messageEmbed.createReactionCollector({filter, dispose: true});

// on emoji reaction
reactionCollector.on('collect', async (reaction, user) => {
if (reaction.emoji.name === emojis[0]) {
const member = interaction.guild.members.cache.get(user.id);
await member.roles.add(sheRole);
} if (reaction.emoji.name === emojis[1]) {
const member = interaction.guild.members.cache.get(user.id);
await member.roles.add(heRole);
} if (reaction.emoji.name === emojis[2]) {
const member = interaction.guild.members.cache.get(user.id);
await member.roles.add(theyRole);
} if (reaction.emoji.name === emojis[3]) {
const member = interaction.guild.members.cache.get(user.id);
await member.roles.add(otherRole);
}
const savedMessagesCol = firebaseUtil.getFactotumSubCol().doc(guild.id).collection('SavedMessages');
await savedMessagesCol.doc('pronouns').set({
messageId: messageEmbed.id,
channelId: messageEmbed.channel.id,
});
}

reactionCollector.on('remove', async (reaction, user) => {
if (reaction.emoji.name === emojis[0]) {
const member = interaction.guild.members.cache.get(user.id);
await member.roles.remove(sheRole);
} if (reaction.emoji.name === emojis[1]) {
const member = interaction.guild.members.cache.get(user.id);
await member.roles.remove(heRole);
} if (reaction.emoji.name === emojis[2]) {
const member = interaction.guild.members.cache.get(user.id);
await member.roles.remove(theyRole);
} if (reaction.emoji.name === emojis[3]) {
const member = interaction.guild.members.cache.get(user.id);
await member.roles.remove(otherRole);
/**
* Checks Firebase for an existing stored reaction listener -
* restores the listeners for the reaction if it exists, otherwise does nothing
* @param {Guild} guild
*/
async tryRestoreReactionListeners(guild) {
const savedMessagesSubCol = firebaseUtil.getSavedMessagesSubCol(guild.id);
const pronounDoc = await savedMessagesSubCol.doc('pronouns').get();
if (pronounDoc.exists) {
const { messageId, channelId } = pronounDoc.data();
const channel = await this.container.client.channels.fetch(channelId);
if (channel) {
try {
/** @type {Message} */
const message = await channel.messages.fetch(messageId);
listenToReactions(guild, message);
} catch (e) {
// message doesn't exist anymore
return e;
}
} else {
return 'Saved message channel does not exist';
}
});
} else {
return 'No existing saved message for pronouns command';
}
}
}

/**
*
* @param {Guild} guild
*/
async function getPronounRoles(guild) {
const sheRole = guild.roles.cache.find(role => role.name === 'she/her') || await createRole(guild, 'she/her', '#99AAB5');
const heRole = guild.roles.cache.find(role => role.name === 'he/him') || await createRole(guild, 'he/him', '#99AAB5');
const theyRole = guild.roles.cache.find(role => role.name === 'they/them') || await createRole(guild, 'they/them', '#99AAB5');
const otherRole = guild.roles.cache.find(role => role.name === 'other pronouns') || await createRole(guild, 'other pronouns', '#99AAB5');
return { sheRole, heRole, theyRole, otherRole };
}

/**
* Creates a role in the guild with the specified name and color.
* @param {Guild} guild
* @param {string} name
* @param {string} color
*/
async function createRole(guild, name, color) {
try {
const role = await guild.roles.create({
name: name,
color: color,
reason: `Creating ${name} role for pronoun selector`
});
return role;
} catch (error) {
console.error(`Failed to create role ${name}:`, error);
throw new Error(`Could not create role ${name}`);
}
}

/**
* Adds reaction listeners to a message to add/remove pronoun rules from users upon reacting
* @param {Guild} guild
* @param {Message} message
*/
async function listenToReactions(guild, message) {
const { sheRole, heRole, theyRole, otherRole } = await getPronounRoles(guild);

let filter = (reaction, user) => {
return user.bot != true && emojis.includes(reaction.emoji.name);
};

// create collector
const reactionCollector = message.createReactionCollector({filter, dispose: true});

// on emoji reaction
reactionCollector.on('collect', async (reaction, user) => {
if (reaction.emoji.name === emojis[0]) {
const member = guild.members.cache.get(user.id);
await member.roles.add(sheRole);
}
if (reaction.emoji.name === emojis[1]) {
const member = guild.members.cache.get(user.id);
await member.roles.add(heRole);
}
if (reaction.emoji.name === emojis[2]) {
const member = guild.members.cache.get(user.id);
await member.roles.add(theyRole);
}
if (reaction.emoji.name === emojis[3]) {
const member = guild.members.cache.get(user.id);
await member.roles.add(otherRole);
}
});

reactionCollector.on('remove', async (reaction, user) => {
if (reaction.emoji.name === emojis[0]) {
const member = guild.members.cache.get(user.id);
await member.roles.remove(sheRole);
}
if (reaction.emoji.name === emojis[1]) {
const member = guild.members.cache.get(user.id);
await member.roles.remove(heRole);
}
if (reaction.emoji.name === emojis[2]) {
const member = guild.members.cache.get(user.id);
await member.roles.remove(theyRole);
}
if (reaction.emoji.name === emojis[3]) {
const member = guild.members.cache.get(user.id);
await member.roles.remove(otherRole);
}
});
}

module.exports = Pronouns;
7 changes: 7 additions & 0 deletions db/firebase/firebaseUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ module.exports = {
}
return externalProjectsCol.doc('Factotum').collection('InitBotInfo');
},
/**
* @param {string} guildId
*/
getSavedMessagesSubCol(guildId) {
const factotumSubCol = this.getFactotumSubCol();
return factotumSubCol.doc(guildId).collection('SavedMessages');
},

/**
* @param {String} appName
Expand Down

0 comments on commit 99ed057

Please sign in to comment.