213 lines
6.0 KiB
TypeScript
213 lines
6.0 KiB
TypeScript
import { z } from "zod";
|
|
import { ToolContext, ToolResponse } from "./types.js";
|
|
import {
|
|
AddReactionSchema,
|
|
AddMultipleReactionsSchema,
|
|
RemoveReactionSchema,
|
|
DeleteMessageSchema
|
|
} from "../schemas.js";
|
|
import { handleDiscordError } from "../errorHandler.js";
|
|
|
|
// Add reaction handler
|
|
export async function addReactionHandler(
|
|
args: unknown,
|
|
context: ToolContext
|
|
): Promise<ToolResponse> {
|
|
const { channelId, messageId, emoji } = AddReactionSchema.parse(args);
|
|
try {
|
|
if (!context.client.isReady()) {
|
|
return {
|
|
content: [{ type: "text", text: "Discord client not logged in. Please use discord_login tool first." }],
|
|
isError: true
|
|
};
|
|
}
|
|
|
|
const channel = await context.client.channels.fetch(channelId);
|
|
if (!channel || !channel.isTextBased() || !('messages' in channel)) {
|
|
return {
|
|
content: [{ type: "text", text: `Cannot find text channel with ID: ${channelId}` }],
|
|
isError: true
|
|
};
|
|
}
|
|
|
|
const message = await channel.messages.fetch(messageId);
|
|
if (!message) {
|
|
return {
|
|
content: [{ type: "text", text: `Cannot find message with ID: ${messageId}` }],
|
|
isError: true
|
|
};
|
|
}
|
|
|
|
// Add the reaction
|
|
await message.react(emoji);
|
|
|
|
return {
|
|
content: [{
|
|
type: "text",
|
|
text: `Successfully added reaction ${emoji} to message ID: ${messageId}`
|
|
}]
|
|
};
|
|
} catch (error) {
|
|
return handleDiscordError(error);
|
|
}
|
|
}
|
|
|
|
// Add multiple reactions handler
|
|
export async function addMultipleReactionsHandler(
|
|
args: unknown,
|
|
context: ToolContext
|
|
): Promise<ToolResponse> {
|
|
const { channelId, messageId, emojis } = AddMultipleReactionsSchema.parse(args);
|
|
try {
|
|
if (!context.client.isReady()) {
|
|
return {
|
|
content: [{ type: "text", text: "Discord client not logged in. Please use discord_login tool first." }],
|
|
isError: true
|
|
};
|
|
}
|
|
|
|
const channel = await context.client.channels.fetch(channelId);
|
|
if (!channel || !channel.isTextBased() || !('messages' in channel)) {
|
|
return {
|
|
content: [{ type: "text", text: `Cannot find text channel with ID: ${channelId}` }],
|
|
isError: true
|
|
};
|
|
}
|
|
|
|
const message = await channel.messages.fetch(messageId);
|
|
if (!message) {
|
|
return {
|
|
content: [{ type: "text", text: `Cannot find message with ID: ${messageId}` }],
|
|
isError: true
|
|
};
|
|
}
|
|
|
|
// Add each reaction sequentially
|
|
for (const emoji of emojis) {
|
|
await message.react(emoji);
|
|
// Small delay to prevent rate limiting
|
|
await new Promise(resolve => setTimeout(resolve, 300));
|
|
}
|
|
|
|
return {
|
|
content: [{
|
|
type: "text",
|
|
text: `Successfully added ${emojis.length} reactions to message ID: ${messageId}`
|
|
}]
|
|
};
|
|
} catch (error) {
|
|
return handleDiscordError(error);
|
|
}
|
|
}
|
|
|
|
// Remove reaction handler
|
|
export async function removeReactionHandler(
|
|
args: unknown,
|
|
context: ToolContext
|
|
): Promise<ToolResponse> {
|
|
const { channelId, messageId, emoji, userId } = RemoveReactionSchema.parse(args);
|
|
try {
|
|
if (!context.client.isReady()) {
|
|
return {
|
|
content: [{ type: "text", text: "Discord client not logged in. Please use discord_login tool first." }],
|
|
isError: true
|
|
};
|
|
}
|
|
|
|
const channel = await context.client.channels.fetch(channelId);
|
|
if (!channel || !channel.isTextBased() || !('messages' in channel)) {
|
|
return {
|
|
content: [{ type: "text", text: `Cannot find text channel with ID: ${channelId}` }],
|
|
isError: true
|
|
};
|
|
}
|
|
|
|
const message = await channel.messages.fetch(messageId);
|
|
if (!message) {
|
|
return {
|
|
content: [{ type: "text", text: `Cannot find message with ID: ${messageId}` }],
|
|
isError: true
|
|
};
|
|
}
|
|
|
|
// Get the reactions
|
|
const reactions = message.reactions.cache;
|
|
|
|
// Find the specific reaction
|
|
const reaction = reactions.find(r => r.emoji.toString() === emoji || r.emoji.name === emoji);
|
|
|
|
if (!reaction) {
|
|
return {
|
|
content: [{ type: "text", text: `Reaction ${emoji} not found on message ID: ${messageId}` }],
|
|
isError: true
|
|
};
|
|
}
|
|
|
|
if (userId) {
|
|
// Remove a specific user's reaction
|
|
await reaction.users.remove(userId);
|
|
return {
|
|
content: [{
|
|
type: "text",
|
|
text: `Successfully removed reaction ${emoji} from user ID: ${userId} on message ID: ${messageId}`
|
|
}]
|
|
};
|
|
} else {
|
|
// Remove bot's reaction
|
|
await reaction.users.remove(context.client.user.id);
|
|
return {
|
|
content: [{
|
|
type: "text",
|
|
text: `Successfully removed bot's reaction ${emoji} from message ID: ${messageId}`
|
|
}]
|
|
};
|
|
}
|
|
} catch (error) {
|
|
return handleDiscordError(error);
|
|
}
|
|
}
|
|
|
|
// Delete message handler
|
|
export async function deleteMessageHandler(
|
|
args: unknown,
|
|
context: ToolContext
|
|
): Promise<ToolResponse> {
|
|
const { channelId, messageId, reason } = DeleteMessageSchema.parse(args);
|
|
try {
|
|
if (!context.client.isReady()) {
|
|
return {
|
|
content: [{ type: "text", text: "Discord client not logged in. Please use discord_login tool first." }],
|
|
isError: true
|
|
};
|
|
}
|
|
|
|
const channel = await context.client.channels.fetch(channelId);
|
|
if (!channel || !channel.isTextBased() || !('messages' in channel)) {
|
|
return {
|
|
content: [{ type: "text", text: `Cannot find text channel with ID: ${channelId}` }],
|
|
isError: true
|
|
};
|
|
}
|
|
|
|
// Fetch the message
|
|
const message = await channel.messages.fetch(messageId);
|
|
if (!message) {
|
|
return {
|
|
content: [{ type: "text", text: `Cannot find message with ID: ${messageId}` }],
|
|
isError: true
|
|
};
|
|
}
|
|
|
|
// Delete the message
|
|
await message.delete();
|
|
|
|
return {
|
|
content: [{
|
|
type: "text",
|
|
text: `Successfully deleted message with ID: ${messageId} from channel: ${channelId}`
|
|
}]
|
|
};
|
|
} catch (error) {
|
|
return handleDiscordError(error);
|
|
}
|
|
}
|