Skip to content

Commit

Permalink
Bot greeting command (#45)
Browse files Browse the repository at this point in the history
* Added a command to create a greeting message. Added support for button interactions. Updated link command to have a button to veify account link status

* Update package.json version

* Tabs to spaces
  • Loading branch information
igor-sikachyna authored Jul 25, 2024
1 parent 0f3a529 commit 0e201d4
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 13 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ultra-discord-uniq-roles-bot",
"version": "1.2.0",
"version": "1.2.3",
"description": "Ultra Uniq Bot for Discord Servers",
"scripts": {
"build": "tsc --build --clean && tsc ",
Expand Down
101 changes: 101 additions & 0 deletions src/services/discord/commands/hello.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { ChatInputCommandInteraction, SlashCommandBuilder, PermissionFlagsBits, ButtonBuilder, ButtonStyle, ActionRowBuilder, ButtonInteraction, EmbedBuilder } from 'discord.js';
import * as Services from '../..';
import * as link from './link';

const commandName = 'hello';
const commandDescription = "Allows an admin to print bot's welcome message";
const command = new SlashCommandBuilder()
.setName(commandName)
.setDescription(commandDescription)
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator);

async function handleInteraction(interaction: ChatInputCommandInteraction) {
if (!interaction.isRepliable()) {
return;
}

if (!interaction.member) {
return interaction.reply({
content: 'Could not find user in ultra server.',
ephemeral: true, // Makes responses 'only you can see this'
});
}
if (!interaction.channel) {
return interaction.reply({
content: 'Not in a channel',
ephemeral: true, // Makes responses 'only you can see this'
});
}

try {
const link = new ButtonBuilder()
.setCustomId('link')
.setLabel('Link Ultra Wallet')
.setStyle(ButtonStyle.Primary);

// const embed = new EmbedBuilder()
// .setColor(0x876CE4)
// .setTitle('Some title')
// .setURL('https://discord.js.org/')
// .setAuthor({ name: 'Some name', iconURL: 'https://i.imgur.com/AfFp7pu.png', url: 'https://discord.js.org' })
// .setDescription('Click on the button bellow to verify your assets!')
// .setThumbnail('https://i.imgur.com/AfFp7pu.png')
// .addFields(
// { name: 'Regular field title', value: 'Some value here' },
// { name: '\u200B', value: '\u200B' },
// { name: 'Inline field title', value: 'Some value here', inline: true },
// )
// .addFields({ name: 'Inline field title', value: 'Some value here', inline: true })
// .setImage('https://i.imgur.com/AfFp7pu.png')
// .setTimestamp()
// .setFooter({ text: 'Some footer text here', iconURL: 'https://i.imgur.com/AfFp7pu.png' });

await interaction.channel.send({
content: `Click on the button bellow to verify your assets!`,
//embeds: [embed],
components: [new ActionRowBuilder<ButtonBuilder>().addComponents(link)],
});

return interaction.reply({
content: `Posted a welcome message`,
ephemeral: true
});

} catch (error) {
return interaction.reply({
content: `❌ Something went wrong. Error: ${error}`,
ephemeral: true
});
}
}

async function handleButtonInteraction(interaction: ButtonInteraction) {
if (!interaction.member) {
return interaction.reply({
content: 'Could not find user in ultra server.',
ephemeral: true, // Makes responses 'only you can see this'
});
}

try {
const link = new ButtonBuilder()
.setCustomId('link')
.setLabel('Link Ultra Account')
.setStyle(ButtonStyle.Primary);

await interaction.reply({
content: `Welcome message`,
components: [new ActionRowBuilder<ButtonBuilder>({
components: [link]
})],
});

} catch (error) {
return interaction.reply({
content: `❌ Something went wrong. Error: ${error}`,
ephemeral: true
});
}
}

Services.discord.register(command, handleInteraction, [{customId: 'link', callback: link.handleInteraction}]);
3 changes: 2 additions & 1 deletion src/services/discord/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ import './removefactory';
import './adduosthreshold';
import './removeuosthreshold';
import './deleterole';
import './printrole';
import './printrole';
import './hello';
35 changes: 31 additions & 4 deletions src/services/discord/commands/link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function generateSigningURL(hash: string, message: string): string {
return encodeURI(url.toString());
}

async function handleInteraction(interaction: Interaction) {
export async function handleInteraction(interaction: Interaction) {
if (!interaction.isRepliable()) {
return;
}
Expand All @@ -68,7 +68,7 @@ async function handleInteraction(interaction: Interaction) {
const discordUserDocument = await getUser(interaction.user.id);
if (discordUserDocument.status) {
return interaction.reply({
content: 'You have already linked some other blockchain account to your Discord account. Unlink existing link first.',
content: 'You have already linked some Ultra Account to your Discord account. Unlink existing link first.',
ephemeral: true, // Makes responses 'only you can see this'
});
}
Expand All @@ -88,12 +88,39 @@ async function handleInteraction(interaction: Interaction) {

const encodedUrl = generateSigningURL(messageRequest, originalMessage);
const button = new ButtonBuilder().setLabel('Open Link').setURL(encodedUrl).setStyle(ButtonStyle.Link);
const verify = new ButtonBuilder().setCustomId('verify').setLabel('Is my account linked?').setStyle(ButtonStyle.Secondary);

return interaction.reply({
content: `Click the button to begin linking to Ultra Blockchain.`,
ephemeral: true, // Makes responses 'only you can see this'
components: [new ActionRowBuilder<ButtonBuilder>().addComponents(button)],
components: [new ActionRowBuilder<ButtonBuilder>().addComponents(button, verify)],
});
}

Services.discord.register(command, handleInteraction);
async function handleButtonInteraction(interaction: Interaction) {
if (!interaction.isRepliable()) {
return;
}

if (!interaction.member) {
return interaction.reply({
content: 'Could not find user in ultra server.',
ephemeral: true, // Makes responses 'only you can see this'
});
}

const discordUserDocument = await getUser(interaction.user.id);
if (discordUserDocument.status) {
return interaction.reply({
content: '✅ Your Ultra Account is linked',
ephemeral: true, // Makes responses 'only you can see this'
});
} else {
return interaction.reply({
content: '❌ Your Ultra Account is not linked',
ephemeral: true, // Makes responses 'only you can see this'
});
}
}

Services.discord.register(command, handleInteraction, [{customId: 'verify', callback: handleButtonInteraction}]);
35 changes: 30 additions & 5 deletions src/services/discord/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as Utility from '../../utility';
import { updateAllCommands } from './update';
import { deleteRole } from '../database/role';
import {
ButtonInteraction,
ChatInputCommandInteraction,
Client,
Guild,
Expand All @@ -15,6 +16,11 @@ import {

type InteractionCallback = (interaction: Interaction) => Promise<any>;
type ChatInputCommandInteractionCallback = (interaction: ChatInputCommandInteraction) => Promise<any>;
type ButtonInteractionCallback = (interaction: ButtonInteraction) => Promise<any>;
interface CommandButtonCallback {
customId: string;
callback: InteractionCallback | ButtonInteractionCallback;
}

const client: Client = new Client({
intents: ['Guilds', 'GuildMessages', 'GuildMembers', 'GuildModeration'],
Expand All @@ -24,26 +30,43 @@ const commands: {
[name: string]: {
original: SlashCommandBuilder;
callback: InteractionCallback | ChatInputCommandInteractionCallback;
buttonCallbacks: CommandButtonCallback[];
};
} = {};

/**
* Handles slash command interactions.
* Handles slash command and button interactions.
*
* @param {Interaction} interaction
*/
async function handleInteraction(interaction: Interaction) {
if (!interaction.isChatInputCommand()) {
if (!interaction.isChatInputCommand() && !interaction.isButton()) {
return;
}

const existingCommand = commands[interaction.commandName];
let commandName: string = '';
let buttonCallback: CommandButtonCallback = {customId:'', callback: async()=>{}};
if (interaction.isChatInputCommand()) {
commandName = interaction.commandName;
} else if (interaction.isButton()) {
Object.keys(commands).forEach((key) => {
let button = commands[key].buttonCallbacks.findIndex(c => c.customId === interaction.customId);
if (button >= 0) {
commandName = key;
buttonCallback = commands[key].buttonCallbacks[button];
}
});
}
if (commandName === '') return;

const existingCommand = commands[commandName];
if (!existingCommand) {
return;
}

try {
await existingCommand.callback(interaction);
if (interaction.isChatInputCommand() && existingCommand.callback) await existingCommand.callback(interaction);
if (interaction.isButton()) await buttonCallback.callback(interaction);
} catch (err) {
Utility.log.warn(`Error while executing command ${existingCommand.original.name}: ${err}`);
if (interaction.replied || interaction.deferred) {
Expand Down Expand Up @@ -89,12 +112,14 @@ async function handleRoleDelete(role: Role) {
*/
export function register(
command: SlashCommandBuilder,
callback: InteractionCallback | ChatInputCommandInteractionCallback
callback: InteractionCallback | ChatInputCommandInteractionCallback,
buttonCallbacks: CommandButtonCallback[] = [],
) {
Utility.log.info(`Added Command: ${command.name}`);
commands[command.name] = {
original: command,
callback,
buttonCallbacks
};
}

Expand Down

0 comments on commit 0e201d4

Please sign in to comment.