Role buttons

This commit is contained in:
Tarrgon
2026-06-12 12:33:41 -04:00
parent 85f9eb7877
commit 38ddcde06c
5 changed files with 133 additions and 1 deletions
+32
View File
@@ -0,0 +1,32 @@
import { ButtonInteraction, Client, MessageFlags } from 'discord.js';
import { Database } from '../shared/Database';
export default {
name: 'role-button',
handler: async function (client: Client, interaction: ButtonInteraction) {
await interaction.deferReply({ flags: [MessageFlags.Ephemeral] });
const roleId = await Database.getRoleFromButton(interaction.message.id);
if (!roleId) await interaction.editReply({ content: 'Could not find role button.' });
const guild = await interaction.guild?.fetch();
const member = await guild?.members.fetch(interaction.user.id);
if (!member) return interaction.editReply({ content: 'Member not found.' });
try {
if (member.roles.cache.has(roleId!)) {
await member.roles.remove(roleId!);
interaction.editReply({ content: 'Role removed.' });
} else {
await member.roles.add(roleId!);
interaction.editReply({ content: 'Role added.' });
}
} catch (e) {
console.error(e);
interaction.editReply({ content: 'Could not add role. Is it higher than mine?' });
}
}
};
+66
View File
@@ -0,0 +1,66 @@
import { ActionRowBuilder, ApplicationIntegrationType, ButtonBuilder, ButtonStyle, ChatInputCommandInteraction, Client, InteractionContextType, MessageFlags, PermissionFlagsBits, SlashCommandBuilder } from 'discord.js';
import { Database } from '../shared/Database';
export default {
name: 'role-buttons',
data: new SlashCommandBuilder()
.setName('role-buttons')
.setDescription('Manage role buttons.')
.setIntegrationTypes(ApplicationIntegrationType.GuildInstall)
.setContexts(InteractionContextType.Guild)
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
.addSubcommand(subcommand =>
subcommand
.setName('create')
.setDescription('Create a role button')
.addRoleOption(option =>
option
.setName('role')
.setDescription('The role to give')
.setRequired(true)
)
.addStringOption(option =>
option
.setName('button-text')
.setDescription('The button text')
.setMaxLength(80)
.setRequired(true)
)
.addStringOption(option =>
option
.setName('message-text')
.setDescription('The message text')
.setRequired(true)
)
),
handler: async function (client: Client, interaction: ChatInputCommandInteraction) {
if (!interaction.guild) return interaction.reply({ flags: [MessageFlags.Ephemeral], content: 'Command must be ran in a guild.' });
const subcommand = interaction.options.getSubcommand();
if (subcommand == 'create') {
if (!interaction.channel || !interaction.channel.isSendable())
return interaction.reply({ flags: [MessageFlags.Ephemeral], content: 'Missing permissions to send to channel.' });
const bot = await interaction.guild.members.fetchMe();
const role = interaction.options.getRole('role', true);
const label = interaction.options.getString('button-text', true);
const content = interaction.options.getString('message-text', true);
if (role.position > bot.roles.highest.position)
return interaction.reply({ flags: [MessageFlags.Ephemeral], content: 'Role is higher than my highest role.' });
const button = new ButtonBuilder()
.setCustomId('role-button')
.setStyle(ButtonStyle.Primary)
.setLabel(label);
const row = new ActionRowBuilder<ButtonBuilder>()
.addComponents(button);
const message = await interaction.channel.send({ components: [row], content });
await Database.putRoleButton(message.id, role.id);
interaction.reply({ flags: [MessageFlags.Ephemeral], content: 'Created role button.' });
}
}
};
+16 -1
View File
@@ -3,7 +3,7 @@ import { open, Database as SqliteDatabase } from 'sqlite';
import sqlite3 from 'sqlite3';
import { fileURLToPath } from 'url';
import { Message } from '../events';
import { AppealMessage, Ban, GithubUserMapping, GuildArraySetting, GuildSetting, GuildSettings, KnowledgebaseItem, LoggedMessage, Note, PrivateHelpTicket, TicketMessage, TicketPhrase } from '../types';
import { AppealMessage, Ban, GithubUserMapping, GuildArraySetting, GuildSetting, GuildSettings, KnowledgebaseItem, LoggedMessage, Note, PrivateHelpTicket, RoleButton, TicketMessage, TicketPhrase } from '../types';
import { serializeMessage, wait } from '../utils';
import { readFileSync } from 'fs';
@@ -388,5 +388,20 @@ export class Database {
return await Database.db.all<PrivateHelpTicket[]>('SELECT * from private_help_tickets WHERE status = ?', PrivateHelpTicketStatus.OPEN);
}
//#endregion
//#region Role Buttons
static async putRoleButton(messageId: string, roleId: string) {
await Database.db.run('INSERT INTO role_buttons(message_id, role_id) VALUES (?, ?)', messageId, roleId);
}
static async getRoleFromButton(messageId: string): Promise<string | null> {
const data = await Database.db.get<Pick<RoleButton, 'role_id'>>('SELECT role_id from role_buttons WHERE message_id = ?', messageId);
return data?.role_id ?? null;
}
//#endregion
}
+6
View File
@@ -84,3 +84,9 @@ export type PrivateHelpTicket = {
status: PrivateHelpTicketStatus
timestamp: string
}
export type RoleButton = {
id: number
message_id: string
role_id: string
}