Skip to content

Commit

Permalink
modmail
Browse files Browse the repository at this point in the history
  • Loading branch information
Nazeofel committed Apr 24, 2024
1 parent b230b67 commit 3799814
Show file tree
Hide file tree
Showing 6 changed files with 279 additions and 0 deletions.
37 changes: 37 additions & 0 deletions packages/plugin-modtools/src/commands/modmail/channel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ChannelType, CommandInteraction, PermissionFlagsBits } from "discord.js"
import { CommandConfig, CommandResult, Flashcore, client } from "robo.js"

export const config: CommandConfig = {
defaultMemberPermissions: PermissionFlagsBits.ModerateMembers,
dmPermission: false,
description: `Set the forum channel in which modmail will send the mails.`,
options: [
{
name: 'modmail',
description: 'id of the Forum channel for modmail',
type: 'string',
required: true
}
]
}



export default async (interaction: CommandInteraction): Promise<CommandResult> => {
const option = interaction.options.get('modmail')?.value


if(option){
const channel = await client.channels.fetch(option.toString())

if(channel && channel.type !== ChannelType.GuildForum){
return {content: 'Please, input the id of a Forum channel.', ephemeral: true};
}

await Flashcore.set<string>('modmail_forum', option.toString());

return {content: 'Modmail Forum has been correctly set !.', ephemeral: true}
}

return {content: 'An error happened while executing the command, please try again or contact an Administrator.'}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { ActionRowBuilder, ChatInputCommandInteraction, ModalBuilder, TextInputBuilder, TextInputStyle } from "discord.js";
import { CommandConfig, CommandResult } from "robo.js";

export const config: CommandConfig = {
description: "Customise the Title and Footer of mod DMs",
sage: {
defer: false
}
};

export default async (interaction: ChatInputCommandInteraction): Promise<CommandResult> => {
if (interaction.guild === null) return;

const modal = new ModalBuilder()
.setCustomId('modmail_modal_chatting')

const one = new TextInputBuilder()
.setCustomId('title')
.setLabel("The Title")
.setMaxLength(100)
.setPlaceholder('Title of the embed that get sent')
.setRequired(true)
.setStyle(TextInputStyle.Short);

const two = new TextInputBuilder()
.setCustomId('footer')
.setLabel("The Footer")
.setMaxLength(100)
.setPlaceholder('footer of embeds that get sent')
.setRequired(true)
.setStyle(TextInputStyle.Short);


const firstActionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(one);
const secondActionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(two);


modal.addComponents(firstActionRow, secondActionRow);
await interaction.showModal(modal);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { ActionRowBuilder, ChatInputCommandInteraction, ModalBuilder, TextInputBuilder, TextInputStyle } from "discord.js";
import { CommandConfig, CommandResult } from "robo.js";

export const config: CommandConfig = {
description: "Customise the Title and Footer of mod DMs",
sage: {
defer: false
}
};

export default async (interaction: ChatInputCommandInteraction): Promise<CommandResult> => {
if (interaction.guild === null) return;

const modal = new ModalBuilder()
.setCustomId('modmail_modal_intro')
.setTitle('Customise the title and footer');

const one = new TextInputBuilder()
.setCustomId('title')
.setLabel("The Title")
.setMaxLength(100)
.setPlaceholder('Title of the embed that get sent')
.setRequired(true)
.setStyle(TextInputStyle.Short);

const two = new TextInputBuilder()
.setCustomId('description')
.setLabel("The description")
.setMaxLength(100)
.setPlaceholder('description of embeds that get sent')
.setRequired(true)
.setStyle(TextInputStyle.Short);

const three = new TextInputBuilder()
.setCustomId('footer')
.setLabel("The Footer")
.setMaxLength(100)
.setPlaceholder('footer of embeds that get sent')
.setRequired(true)
.setStyle(TextInputStyle.Short);


const firstActionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(one);
const secondActionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(two);
const thirdActionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(three);



modal.addComponents(firstActionRow, secondActionRow, thirdActionRow);
await interaction.showModal(modal);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ModalSubmitInteraction, } from 'discord.js';
import { Flashcore } from 'robo.js';
import { ModalProperties } from '../../types';

export default async (interaction: ModalSubmitInteraction) => {

if (!interaction.isModalSubmit()) return;
if (interaction.customId === 'modmail_modal_chatting') {
const title = interaction.fields.getTextInputValue('title');
const footer = interaction.fields.getTextInputValue('footer');

await Flashcore.set<ModalProperties>('modmail_modal_custom_message', {
title,
footer,
})
return await interaction.reply({content: 'Custom embed for the modmail message has been defined.', ephemeral: true})
}
if (interaction.customId === 'modmail_modal_intro') {
const title = interaction.fields.getTextInputValue('title');
const footer = interaction.fields.getTextInputValue('footer');
const description = interaction.fields.getTextInputValue('description')

await Flashcore.set<ModalProperties>('modmail_modal_custom_intro', {
title,
description,
footer,
})

return await interaction.reply({content: 'Custom embed for the intro modmail message has been defined.', ephemeral: true})
}

}
114 changes: 114 additions & 0 deletions packages/plugin-modtools/src/events/messageCreate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { Channel, ChannelType , EmbedBuilder, ForumChannel, Message, MessagePayload, ThreadChannel } from "discord.js";
import { Flashcore, client, logger } from "robo.js";
import { ModalProperties } from "../types";

export default async (message: Message) => {
if(message.channel.type === ChannelType.PublicThread || message.channel.type === ChannelType.PrivateThread){
if(message.author.bot){
return;
}
const threadUserData = await retrieveModmailDataFromFlashcore(message.channelId, "")

if(threadUserData){
const modalOptions = await Flashcore.get<ModalProperties>('modmail_modal_custom_message');

const embedded = new EmbedBuilder()
.setTitle(modalOptions?.title ? modalOptions.title : 'Moderation')
.setColor("Blue")
.setDescription(message.content.length > 0 ? message.content : ' ')
.setFooter({
 text: modalOptions?.footer ? modalOptions?.footer : "The lovely moderation team ^.^"
})


const user = await client.users.fetch(threadUserData.userId)
if(user){
user.send({embeds: [embedded], files: [...message.attachments.map((attach) => attach.url)]});
}
}
return;
}
if(message.channel.type === ChannelType.DM && !message.author.bot){
const modmailChannel = await Flashcore.get<string>('modmail_forum');

if(!modmailChannel) {
return message.reply({content: 'Please contact the adminstrators of the server to set a modmail channel using the /modmail channel command.', options: {ephemeral: true}})
}

const ForumMail = await client.channels.fetch(modmailChannel);
if(ForumMail && ForumMail.type === ChannelType.GuildForum){
const hasAlreadyAThread = await createOrFetchThreadChannel(message, ForumMail);

if(!hasAlreadyAThread){
const modalOptions = await Flashcore.get<ModalProperties>('modmail_modal_custom_intro');

const embedded = new EmbedBuilder()
.setTitle(modalOptions?.title ? modalOptions?.title : 'Thread created')
.setColor("Blue")
.setDescription(modalOptions?.description ? modalOptions.description : 'Please state your issues.')
.setFooter({
 text: modalOptions?.footer ? modalOptions?.footer : "The lovely moderation team ^.^"
})
return message.reply({embeds: [embedded]})
} else {
if(hasAlreadyAThread instanceof ThreadChannel){
return hasAlreadyAThread.send({
content: message.content.length > 0 ? message.content : ' ',
files: [...message.attachments.map((attach) => attach.url)]
})
}
}
}

}

}

const createOrFetchThreadChannel = async (message: Message, Forum: any): Promise<ThreadChannel | boolean> => {
const user = await retrieveModmailDataFromFlashcore("", message.author.id)

if(!user){
const newThread = await Forum.threads.create({
name: message.author.displayName,
message: {content: message.content}
})
await saveModmailDataToFlashcore(newThread.id, message.author.id)
return false;
} else {
const threads = (await Forum.threads.fetch()).threads
const userThread = threads.find((thread: ThreadChannel) => thread.id === user.threadId)
return userThread;
}
}



type ModMailUserData = {
threadId: string,
userId: string
}

const retrieveModmailDataFromFlashcore = async (thread: string, userId: string) => {
const user = await Flashcore.get<ModMailUserData>(thread ? thread : userId, {
namespace: 'modmail_thread'
})

return user;
}


const saveModmailDataToFlashcore = async (threadId: string, userId: string) => {
await Flashcore.set<ModMailUserData>(threadId, {
threadId: threadId,
userId: userId
}, {
namespace: 'modmail_thread'
})
await Flashcore.set<ModMailUserData>(userId, {
threadId: threadId,
userId: userId
}, {
namespace: 'modmail_thread'
})

}
5 changes: 5 additions & 0 deletions packages/plugin-modtools/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type ModalProperties = {
title: string,
description?: string,
footer: string
}

0 comments on commit 3799814

Please sign in to comment.