n8n-nodes-discord-dnd
Version:
n8n node to create triggers for Discord events
870 lines (869 loc) • 62.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ActionEventHandler = void 0;
const discord_js_1 = require("discord.js");
const types_1 = require("../../Interfaces/types");
class ActionEventHandler {
constructor(client, actionInstance) {
this.client = client;
this.actionInstance = actionInstance;
}
/**
* Fetch all users who have RSVP'd (interested) in a guild scheduled event
*/
async fetchEventInterestedUsers(guildId, eventId) {
var _a, _b;
const botToken = this.client.token;
if (!botToken) {
throw new Error("Bot token is not available");
}
const limit = 100;
let before = undefined;
const allUserIds = [];
try {
while (true) {
const params = new URLSearchParams({
limit: String(limit),
with_member: "false", // We only need user IDs
});
if (before) {
params.set("before", before);
}
const response = await fetch(`https://discord.com/api/v10/guilds/${guildId}/scheduled-events/${eventId}/users?${params.toString()}`, {
headers: {
Authorization: `Bot ${botToken}`,
"Content-Type": "application/json",
},
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Discord API error ${response.status}: ${errorText}`);
}
const chunk = await response.json();
// Extract user IDs from the response
if (Array.isArray(chunk)) {
const userIds = chunk
.map((item) => { var _a; return (_a = item.user) === null || _a === void 0 ? void 0 : _a.id; })
.filter((id) => id !== undefined);
allUserIds.push(...userIds);
// If we got fewer results than the limit, we've reached the end
if (chunk.length < limit) {
break;
}
// Use the last user ID for pagination
const lastUserId = (_b = (_a = chunk[chunk.length - 1]) === null || _a === void 0 ? void 0 : _a.user) === null || _b === void 0 ? void 0 : _b.id;
if (!lastUserId) {
break;
}
before = lastUserId;
}
else {
break;
}
}
}
catch (error) {
// Log error but don't fail the entire operation
console.error(`Failed to fetch interested users: ${error.message}`);
return [];
}
return allUserIds;
}
async setupEventHandler(action) {
var _a;
const data = {};
switch (action) {
case types_1.ActionEventType.SEND_TYPING:
const channelId = this.actionInstance.getNodeParameter("channelId", 0);
const channel = (await this.client.channels.fetch(channelId));
if (channel === null || channel === void 0 ? void 0 : channel.isTextBased()) {
await channel.sendTyping();
data.success = true;
data.message = "Typing indicator sent successfully.";
}
else {
throw new Error("The provided channel is not a text channel!");
}
break;
case types_1.ActionEventType.SEND_MESSAGE:
// Get message content
let messageContent = this.actionInstance.getNodeParameter("messageContent", 0, "");
let embeds = [];
let files = [];
// Process embeds
const embedsCollection = this.actionInstance.getNodeParameter("embeds", 0, { embed: [] });
if (embedsCollection &&
embedsCollection.embed &&
embedsCollection.embed.length > 0) {
embeds = embedsCollection.embed.map((embed) => {
const inputMethod = embed.inputMethod || "fields";
// Handle JSON embeds
if (inputMethod === "json") {
try {
return JSON.parse(embed.jsonPayload || "{}");
}
catch (error) {
throw new Error(`Invalid JSON in embed: ${error.message}`);
}
}
// Handle field-based embeds
const processedEmbed = {};
if (embed.description)
processedEmbed.description = embed.description;
if (embed.title)
processedEmbed.title = embed.title;
if (embed.url)
processedEmbed.url = embed.url;
if (embed.color)
processedEmbed.color = embed.color;
if (embed.timestamp) {
processedEmbed.timestamp = new Date(embed.timestamp).toISOString();
}
// Process thumbnail and image
if (embed.thumbnailUrl) {
processedEmbed.thumbnail = { url: embed.thumbnailUrl };
}
if (embed.imageUrl) {
processedEmbed.image = { url: embed.imageUrl };
}
// Process author
if (embed.authorName) {
processedEmbed.author = {
name: embed.authorName,
};
}
// Process video
if (embed.videoUrl) {
processedEmbed.video = { url: embed.videoUrl };
}
return processedEmbed;
});
// Filter out empty embeds
embeds = embeds.filter(e => Object.keys(e).length > 0);
}
// Process file uploads if any
const filesCollection = this.actionInstance.getNodeParameter("files", 0, { file: [] });
if (filesCollection.file && filesCollection.file.length > 0) {
for (const fileData of filesCollection.file) {
if (fileData.binaryProperty) {
const binaryData = this.actionInstance.helpers.getBinaryDataBuffer(0, fileData.binaryProperty);
files.push({
attachment: binaryData,
name: fileData.fileName || "file",
});
}
}
}
// Check if we have anything to send
if (!messageContent && embeds.length === 0 && files.length === 0) {
throw new Error("Cannot send an empty message! Please provide at least one of: Message Content, Embeds, or Files.");
}
// Get options
const options = this.actionInstance.getNodeParameter("options", 0, {});
// Get send to destination
const sendTo = this.actionInstance.getNodeParameter("sendTo", 0, "channel");
let messageChannel;
if (sendTo === "user") {
const userId = this.actionInstance.getNodeParameter("userId", 0);
try {
const user = await this.client.users.fetch(userId);
messageChannel = await user.createDM();
}
catch (error) {
throw new Error(`Failed to create DM channel: ${error.message}`);
}
}
else {
const channelId = this.actionInstance.getNodeParameter("channelId", 0);
messageChannel = (await this.client.channels.fetch(channelId));
if (!(messageChannel === null || messageChannel === void 0 ? void 0 : messageChannel.isTextBased())) {
throw new Error("The provided channel is not a text channel!");
}
}
const messageOptions = {
content: messageContent || undefined,
embeds: embeds.length > 0 ? embeds : undefined,
files: files.length > 0 ? files : undefined,
};
// Add flags if present
if (options.flags && Array.isArray(options.flags)) {
let flags = 0;
const flagsArray = options.flags;
if (flagsArray.includes("suppressEmbeds")) {
flags |= 1 << 2; // SUPPRESS_EMBEDS = 1 << 2
}
if (flagsArray.includes("suppressNotifications")) {
flags |= 1 << 12; // SUPPRESS_NOTIFICATIONS = 1 << 12
}
if (flags > 0) {
messageOptions.flags = flags;
}
}
// Add reply if present
if (options.messageId) {
messageOptions.reply = { messageReference: options.messageId };
}
try {
const message = await messageChannel.send(messageOptions);
data.success = true;
data.message = "Message sent successfully.";
data.messageId = message.id;
}
catch (error) {
console.error("Discord API Send Error:", error);
throw new Error(`Failed to send message: ${error.message}`);
}
break;
case types_1.ActionEventType.DELETE_MESSAGE:
const deleteChannelId = this.actionInstance.getNodeParameter("channelId", 0);
const messageId = this.actionInstance.getNodeParameter("messageId", 0);
const deleteChannel = (await this.client.channels.fetch(deleteChannelId));
if (!(deleteChannel === null || deleteChannel === void 0 ? void 0 : deleteChannel.isTextBased())) {
throw new Error("The provided channel is not a text channel!");
}
try {
const messageToDelete = await deleteChannel.messages.fetch(messageId);
await messageToDelete.delete();
data.success = true;
data.message = "Message deleted successfully.";
}
catch (error) {
throw new Error(`Failed to delete message: ${error.message}`);
}
break;
case types_1.ActionEventType.EDIT_MESSAGE:
const editChannelId = this.actionInstance.getNodeParameter("channelId", 0);
const editMessageId = this.actionInstance.getNodeParameter("messageId", 0);
const newContent = this.actionInstance.getNodeParameter("newContent", 0);
const editChannel = (await this.client.channels.fetch(editChannelId));
if (!(editChannel === null || editChannel === void 0 ? void 0 : editChannel.isTextBased())) {
throw new Error("The provided channel is not a text channel!");
}
try {
const messageToEdit = await editChannel.messages.fetch(editMessageId);
const editedMessage = await messageToEdit.edit(newContent);
data.success = true;
data.message = "Message edited successfully.";
data.editedMessageId = editedMessage.id;
}
catch (error) {
throw new Error(`Failed to edit message: ${error.message}`);
}
break;
case types_1.ActionEventType.REACT_TO_MESSAGE:
const reactChannelId = this.actionInstance.getNodeParameter("channelId", 0);
const reactMessageId = this.actionInstance.getNodeParameter("messageId", 0);
const emoji = this.actionInstance.getNodeParameter("emoji", 0);
const reactChannel = (await this.client.channels.fetch(reactChannelId));
if (!(reactChannel === null || reactChannel === void 0 ? void 0 : reactChannel.isTextBased())) {
throw new Error("The provided channel is not a text channel!");
}
try {
const messageToReact = await reactChannel.messages.fetch(reactMessageId);
await messageToReact.react(emoji);
data.success = true;
data.message = "Reaction added successfully.";
}
catch (error) {
throw new Error(`Failed to add reaction: ${error.message}`);
}
break;
case types_1.ActionEventType.PIN_MESSAGE:
const pinChannelId = this.actionInstance.getNodeParameter("channelId", 0);
const pinMessageId = this.actionInstance.getNodeParameter("messageId", 0);
const pinChannel = (await this.client.channels.fetch(pinChannelId));
if (!(pinChannel === null || pinChannel === void 0 ? void 0 : pinChannel.isTextBased())) {
throw new Error("The provided channel is not a text channel!");
}
try {
const messageToPin = await pinChannel.messages.fetch(pinMessageId);
await messageToPin.pin();
data.success = true;
data.message = "Message pinned successfully.";
}
catch (error) {
throw new Error(`Failed to pin message: ${error.message}`);
}
break;
case types_1.ActionEventType.UNPIN_MESSAGE:
const unpinChannelId = this.actionInstance.getNodeParameter("channelId", 0);
const unpinMessageId = this.actionInstance.getNodeParameter("messageId", 0);
const unpinChannel = (await this.client.channels.fetch(unpinChannelId));
if (!(unpinChannel === null || unpinChannel === void 0 ? void 0 : unpinChannel.isTextBased())) {
throw new Error("The provided channel is not a text channel!");
}
try {
const messageToUnpin = await unpinChannel.messages.fetch(unpinMessageId);
await messageToUnpin.unpin();
data.success = true;
data.message = "Message unpinned successfully.";
}
catch (error) {
throw new Error(`Failed to unpin message: ${error.message}`);
}
break;
case types_1.ActionEventType.REMOVE_REACTION:
const removeReactChannelId = this.actionInstance.getNodeParameter("channelId", 0);
const removeReactMessageId = this.actionInstance.getNodeParameter("messageId", 0);
const userId = this.actionInstance.getNodeParameter("userId", 0);
const removeEmoji = this.actionInstance.getNodeParameter("emoji", 0);
const all = this.actionInstance.getNodeParameter("all", 0);
const removeReactChannel = (await this.client.channels.fetch(removeReactChannelId));
if (!(removeReactChannel === null || removeReactChannel === void 0 ? void 0 : removeReactChannel.isTextBased())) {
throw new Error("The provided channel is not a text channel!");
}
try {
const messageToRemoveReact = await removeReactChannel.messages.fetch(removeReactMessageId);
// If 'all' is true, remove all reactions from the message
if (all) {
// Remove all reactions from user if userId is provided and removeEmoji is not specified
if (userId) {
try {
const reactions = messageToRemoveReact.reactions.cache.filter((reaction) => reaction.users.cache.has(userId));
for (const reaction of reactions.values()) {
await reaction.users.remove(userId);
}
data.success = true;
data.message = "All reactions from user removed successfully.";
return data;
}
catch (error) {
throw new Error(`Failed to remove reactions from user: ${error.message}`);
}
}
// If removeEmoji is specified, remove all reactions of that emoji
if (removeEmoji) {
try {
await ((_a = messageToRemoveReact.reactions.cache
.get(removeEmoji)) === null || _a === void 0 ? void 0 : _a.remove());
data.success = true;
data.message = `All reactions for emoji ${removeEmoji} removed successfully.`;
return data;
}
catch (error) {
throw new Error(`Failed to remove reactions for emoji ${removeEmoji}: ${error.message}`);
}
}
// If no emoji is specified, remove all reactions
// Remove all reactions from the message
await messageToRemoveReact.reactions
.removeAll()
.catch((error) => {
throw new Error(`Failed to remove all reactions: ${error.message}`);
});
data.success = true;
data.message = "All reactions removed successfully.";
return data;
}
// Remove a specific reaction
const reaction = messageToRemoveReact.reactions.cache.find((r) => r.emoji.name === removeEmoji || r.emoji.toString() === removeEmoji);
if (reaction) {
// If a user ID is provided, remove the reaction for that user
if (userId) {
await reaction.users.remove(userId).catch((error) => {
throw new Error(`Failed to remove reaction from user: ${error.message}`);
});
}
else {
// If no user ID is provided, remove the bot's reaction
if (!this.client.user)
throw new Error("Client user is not initialized");
await reaction.users
.remove(this.client.user.id)
.catch((error) => {
throw new Error(`Failed to remove reaction from the bot: ${error.message}`);
});
}
data.success = true;
data.message = "Reaction removed successfully.";
}
else {
throw new Error("Reaction not found on the message.");
}
}
catch (error) {
throw new Error(`Failed to remove reaction: ${error.message}`);
}
break;
case types_1.ActionEventType.GET_GUILD_SCHEDULED_EVENT:
const getGuildScheduledEventId = this.actionInstance.getNodeParameter("guildScheduledEventId", 0);
const getGuildId = this.actionInstance.getNodeParameter("guildId", 0);
try {
const guild = await this.client.guilds.fetch(getGuildId);
const guildScheduledEvent = await guild.scheduledEvents.fetch(getGuildScheduledEventId);
if (!guildScheduledEvent) {
throw new Error("Guild scheduled event not found.");
}
// Get all information about the event
data.id = guildScheduledEvent.id;
data.guildId = guildScheduledEvent.guildId;
data.channelId = guildScheduledEvent.channelId;
data.creatorId = guildScheduledEvent.creatorId;
data.name = guildScheduledEvent.name;
data.description = guildScheduledEvent.description;
data.scheduledStartTimestamp = guildScheduledEvent.scheduledStartTimestamp;
data.scheduledEndTimestamp = guildScheduledEvent.scheduledEndTimestamp;
data.privacyLevel = guildScheduledEvent.privacyLevel;
data.status = guildScheduledEvent.status;
data.entityType = guildScheduledEvent.entityType;
data.entityId = guildScheduledEvent.entityId;
data.entityMetadata = guildScheduledEvent.entityMetadata;
data.userCount = guildScheduledEvent.userCount;
data.image = guildScheduledEvent.image;
data.createdTimestamp = guildScheduledEvent.createdTimestamp;
data.url = guildScheduledEvent.url;
// Add creator information if available
if (guildScheduledEvent.creator) {
data.creator = {
id: guildScheduledEvent.creator.id,
username: guildScheduledEvent.creator.username,
discriminator: guildScheduledEvent.creator.discriminator,
avatar: guildScheduledEvent.creator.avatar,
bot: guildScheduledEvent.creator.bot,
};
}
// Fetch interested users (RSVPed users)
const interestedUserIds = await this.fetchEventInterestedUsers(getGuildId, getGuildScheduledEventId);
data.interestedUsers = interestedUserIds;
data.interestedUsersCount = interestedUserIds.length;
data.success = true;
}
catch (error) {
throw new Error(`Failed to get guild scheduled event: ${error.message}`);
}
break;
case types_1.ActionEventType.GUILD_SCHEDULED_EVENT_UPDATE:
const guildScheduledEventId = this.actionInstance.getNodeParameter("guildScheduledEventId", 0);
const guildId = this.actionInstance.getNodeParameter("guildId", 0);
const updateFields = this.actionInstance.getNodeParameter("updateFields", 0, {});
const name = updateFields.name;
const scheduledStartTime = updateFields.scheduledStartTime;
const scheduledEndTime = updateFields.scheduledEndTime;
const description = updateFields.description;
try {
const guild = await this.client.guilds.fetch(guildId);
const guildScheduledEvent = await guild.scheduledEvents.fetch(guildScheduledEventId);
if (!guildScheduledEvent) {
throw new Error("Guild scheduled event not found.");
}
const updateData = Object.fromEntries(Object.entries({
name,
scheduledStartTime,
scheduledEndTime,
description,
}).filter(([_, v]) => v !== undefined));
await guildScheduledEvent.edit(updateData);
data.success = true;
data.message = "Guild scheduled event updated successfully.";
}
catch (error) {
throw new Error(`Failed to update guild scheduled event: ${error.message}`);
}
break;
case types_1.ActionEventType.CREATE_GUILD_SCHEDULED_EVENT:
const createEventGuildId = this.actionInstance.getNodeParameter("guildId", 0);
const eventName = this.actionInstance.getNodeParameter("eventName", 0);
const eventStartTime = this.actionInstance.getNodeParameter("eventStartTime", 0);
const eventEntityType = this.actionInstance.getNodeParameter("eventEntityType", 0);
const eventPrivacyLevel = this.actionInstance.getNodeParameter("eventPrivacyLevel", 0);
const eventChannelId = this.actionInstance.getNodeParameter("eventChannelId", 0, "");
const eventOptions = this.actionInstance.getNodeParameter("eventOptions", 0, {});
try {
const createEventGuild = await this.client.guilds.fetch(createEventGuildId);
const createEventData = {
name: eventName,
scheduledStartTime: new Date(eventStartTime),
privacyLevel: eventPrivacyLevel,
entityType: eventEntityType,
};
// Add channel for Voice or Stage Instance
if ((eventEntityType === 1 || eventEntityType === 2) && eventChannelId) {
createEventData.channel = eventChannelId;
}
// Add optional fields
if (eventOptions.description) {
createEventData.description = eventOptions.description;
}
if (eventOptions.scheduledEndTime) {
createEventData.scheduledEndTime = new Date(eventOptions.scheduledEndTime);
}
if (eventOptions.entityMetadataLocation) {
createEventData.entityMetadata = {
location: eventOptions.entityMetadataLocation,
};
}
if (eventOptions.image) {
createEventData.image = eventOptions.image;
}
const createdEvent = await createEventGuild.scheduledEvents.create(createEventData);
data.success = true;
data.message = "Guild scheduled event created successfully.";
data.eventId = createdEvent.id;
data.eventUrl = createdEvent.url;
data.event = {
id: createdEvent.id,
name: createdEvent.name,
description: createdEvent.description,
scheduledStartTimestamp: createdEvent.scheduledStartTimestamp,
scheduledEndTimestamp: createdEvent.scheduledEndTimestamp,
status: createdEvent.status,
entityType: createdEvent.entityType,
url: createdEvent.url,
};
}
catch (error) {
throw new Error(`Failed to create guild scheduled event: ${error.message}`);
}
break;
case types_1.ActionEventType.GET_MANY_GUILD_SCHEDULED_EVENTS:
const getManyEventsGuildId = this.actionInstance.getNodeParameter("guildId", 0);
try {
const getManyEventsGuild = await this.client.guilds.fetch(getManyEventsGuildId);
const events = await getManyEventsGuild.scheduledEvents.fetch();
// Fetch interested users for each event
const eventsArray = await Promise.all(events.map(async (event) => {
const interestedUserIds = await this.fetchEventInterestedUsers(getManyEventsGuildId, event.id);
return {
id: event.id,
guildId: event.guildId,
channelId: event.channelId,
creatorId: event.creatorId,
name: event.name,
description: event.description,
scheduledStartTimestamp: event.scheduledStartTimestamp,
scheduledEndTimestamp: event.scheduledEndTimestamp,
privacyLevel: event.privacyLevel,
status: event.status,
entityType: event.entityType,
entityId: event.entityId,
entityMetadata: event.entityMetadata,
userCount: event.userCount,
image: event.image,
createdTimestamp: event.createdTimestamp,
url: event.url,
creator: event.creator ? {
id: event.creator.id,
username: event.creator.username,
discriminator: event.creator.discriminator,
avatar: event.creator.avatar,
bot: event.creator.bot,
} : null,
interestedUsers: interestedUserIds,
interestedUsersCount: interestedUserIds.length,
};
}));
data.success = true;
data.count = eventsArray.length;
data.events = eventsArray;
}
catch (error) {
throw new Error(`Failed to get guild scheduled events: ${error.message}`);
}
break;
case types_1.ActionEventType.UPDATE_GUILD_SCHEDULED_EVENT:
const updateEventGuildId = this.actionInstance.getNodeParameter("guildId", 0);
const updateEventId = this.actionInstance.getNodeParameter("guildScheduledEventId", 0);
const eventUpdateFields = this.actionInstance.getNodeParameter("eventUpdateFields", 0, {});
try {
const updateEventGuild = await this.client.guilds.fetch(updateEventGuildId);
const eventToUpdate = await updateEventGuild.scheduledEvents.fetch(updateEventId);
if (!eventToUpdate) {
throw new Error("Guild scheduled event not found.");
}
const updateEventData = {};
if (eventUpdateFields.name) {
updateEventData.name = eventUpdateFields.name;
}
if (eventUpdateFields.description !== undefined) {
updateEventData.description = eventUpdateFields.description;
}
if (eventUpdateFields.scheduledStartTime) {
updateEventData.scheduledStartTime = new Date(eventUpdateFields.scheduledStartTime);
}
if (eventUpdateFields.scheduledEndTime) {
updateEventData.scheduledEndTime = new Date(eventUpdateFields.scheduledEndTime);
}
if (eventUpdateFields.channelId) {
updateEventData.channel = eventUpdateFields.channelId;
}
if (eventUpdateFields.entityType !== undefined) {
updateEventData.entityType = eventUpdateFields.entityType;
}
if (eventUpdateFields.status !== undefined) {
updateEventData.status = eventUpdateFields.status;
}
if (eventUpdateFields.entityMetadataLocation) {
updateEventData.entityMetadata = {
location: eventUpdateFields.entityMetadataLocation,
};
}
if (eventUpdateFields.image) {
updateEventData.image = eventUpdateFields.image;
}
await eventToUpdate.edit(updateEventData);
data.success = true;
data.message = "Guild scheduled event updated successfully.";
data.eventId = eventToUpdate.id;
}
catch (error) {
throw new Error(`Failed to update guild scheduled event: ${error.message}`);
}
break;
case types_1.ActionEventType.DELETE_GUILD_SCHEDULED_EVENT:
const deleteEventGuildId = this.actionInstance.getNodeParameter("guildId", 0);
const deleteEventId = this.actionInstance.getNodeParameter("guildScheduledEventId", 0);
try {
const deleteEventGuild = await this.client.guilds.fetch(deleteEventGuildId);
const eventToDelete = await deleteEventGuild.scheduledEvents.fetch(deleteEventId);
if (!eventToDelete) {
throw new Error("Guild scheduled event not found.");
}
await eventToDelete.delete();
data.success = true;
data.message = "Guild scheduled event deleted successfully.";
data.deletedEventId = deleteEventId;
}
catch (error) {
throw new Error(`Failed to delete guild scheduled event: ${error.message}`);
}
break;
// Channel Actions
case types_1.ActionEventType.CREATE_CHANNEL:
const createGuildId = this.actionInstance.getNodeParameter("channelGuildId", 0);
const channelName = this.actionInstance.getNodeParameter("channelName", 0);
const channelType = this.actionInstance.getNodeParameter("channelType", 0);
const createChannelOptions = this.actionInstance.getNodeParameter("channelOptions", 0, {});
const createPermissionOverwrites = this.actionInstance.getNodeParameter("permissionOverwrites", 0, { permission: [] });
const createPermissionAdd = this.actionInstance.getNodeParameter("permissionAdd", 0, { permission: [] });
try {
const createGuild = await this.client.guilds.fetch(createGuildId);
const channelCreateOptions = {
name: channelName,
type: channelType,
};
// Add optional fields if provided
if (createChannelOptions.topic) {
channelCreateOptions.topic = createChannelOptions.topic;
}
if (createChannelOptions.position !== undefined) {
channelCreateOptions.position = createChannelOptions.position;
}
if (createChannelOptions.nsfw !== undefined) {
channelCreateOptions.nsfw = createChannelOptions.nsfw;
}
if (createChannelOptions.bitrate) {
channelCreateOptions.bitrate = createChannelOptions.bitrate;
}
if (createChannelOptions.userLimit !== undefined) {
channelCreateOptions.userLimit = createChannelOptions.userLimit;
}
if (createChannelOptions.rateLimitPerUser !== undefined) {
channelCreateOptions.rateLimitPerUser = createChannelOptions.rateLimitPerUser;
}
if (createChannelOptions.parent) {
channelCreateOptions.parent = createChannelOptions.parent;
}
// Prepare permission overwrites array
let finalPermissionOverwrites = [];
// Handle inherit parent permissions
if (createChannelOptions.inheritParentPermissions === true && createChannelOptions.parent) {
const parentChannel = await this.client.channels.fetch(createChannelOptions.parent);
if (parentChannel && !parentChannel.isDMBased()) {
const parentGuildChannel = parentChannel;
if (parentGuildChannel.permissionOverwrites) {
finalPermissionOverwrites = Array.from(parentGuildChannel.permissionOverwrites.cache.values()).map((overwrite) => ({
id: overwrite.id,
type: overwrite.type,
allow: overwrite.allow.bitfield,
deny: overwrite.deny.bitfield,
}));
}
}
}
// Process permission overwrites (will replace inherited permissions if both are set)
if (createPermissionOverwrites.permission && createPermissionOverwrites.permission.length > 0) {
finalPermissionOverwrites = createPermissionOverwrites.permission.map((perm) => {
const overwrite = {
id: perm.id,
type: perm.type === "role" ? 0 : 1,
};
// Convert permission names to PermissionsBitField flags
if (perm.allow && perm.allow.length > 0) {
overwrite.allow = perm.allow.map((p) => discord_js_1.PermissionsBitField.Flags[p]);
}
if (perm.deny && perm.deny.length > 0) {
overwrite.deny = perm.deny.map((p) => discord_js_1.PermissionsBitField.Flags[p]);
}
return overwrite;
});
}
// Handle permission add - add to existing overwrites
if (createPermissionAdd.permission && createPermissionAdd.permission.length > 0) {
for (const perm of createPermissionAdd.permission) {
// Find if this target already has an overwrite
const existingIndex = finalPermissionOverwrites.findIndex(ow => ow.id === perm.id);
if (existingIndex >= 0) {
// Target already exists, merge permissions
const existing = finalPermissionOverwrites[existingIndex];
// Get current bitfields
let currentAllow = typeof existing.allow === 'bigint' ? existing.allow : BigInt(0);
let currentDeny = typeof existing.deny === 'bigint' ? existing.deny : BigInt(0);
// If allow/deny is array, convert to bitfield
if (Array.isArray(existing.allow)) {
currentAllow = existing.allow.reduce((acc, flag) => acc | flag, BigInt(0));
}
if (Array.isArray(existing.deny)) {
currentDeny = existing.deny.reduce((acc, flag) => acc | flag, BigInt(0));
}
// Add new permissions
if (perm.allow && perm.allow.length > 0) {
for (const p of perm.allow) {
const flag = discord_js_1.PermissionsBitField.Flags[p];
currentAllow |= flag;
}
}
if (perm.deny && perm.deny.length > 0) {
for (const p of perm.deny) {
const flag = discord_js_1.PermissionsBitField.Flags[p];
currentDeny |= flag;
}
}
finalPermissionOverwrites[existingIndex] = {
id: perm.id,
type: perm.type === "role" ? 0 : 1,
allow: currentAllow,
deny: currentDeny,
};
}
else {
// New target, create new overwrite
let allowBitfield = BigInt(0);
let denyBitfield = BigInt(0);
if (perm.allow && perm.allow.length > 0) {
for (const p of perm.allow) {
const flag = discord_js_1.PermissionsBitField.Flags[p];
allowBitfield |= flag;
}
}
if (perm.deny && perm.deny.length > 0) {
for (const p of perm.deny) {
const flag = discord_js_1.PermissionsBitField.Flags[p];
denyBitfield |= flag;
}
}
finalPermissionOverwrites.push({
id: perm.id,
type: perm.type === "role" ? 0 : 1,
allow: allowBitfield,
deny: denyBitfield,
});
}
}
}
// Set final permission overwrites
if (finalPermissionOverwrites.length > 0) {
channelCreateOptions.permissionOverwrites = finalPermissionOverwrites;
}
const createdChannel = await createGuild.channels.create(channelCreateOptions);
data.success = true;
data.message = "Channel created successfully.";
data.channelId = createdChannel.id;
data.channelName = createdChannel.name;
data.channelType = createdChannel.type;
}
catch (error) {
throw new Error(`Failed to create channel: ${error.message}`);
}
break;
case types_1.ActionEventType.DELETE_CHANNEL:
const deleteChannelTargetId = this.actionInstance.getNodeParameter("targetChannelId", 0);
try {
const channelToDelete = await this.client.channels.fetch(deleteChannelTargetId);
if (!channelToDelete) {
throw new Error("Channel not found.");
}
if (!channelToDelete.isDMBased()) {
await channelToDelete.delete();
data.success = true;
data.message = "Channel deleted successfully.";
data.channelId = deleteChannelTargetId;
}
else {
throw new Error("Cannot delete DM channels.");
}
}
catch (error) {
throw new Error(`Failed to delete channel: ${error.message}`);
}
break;
case types_1.ActionEventType.UPDATE_CHANNEL:
const updateChannelTargetId = this.actionInstance.getNodeParameter("targetChannelId", 0);
const updateChannelOptions = this.actionInstance.getNodeParameter("channelOptions", 0, {});
const updatePermissionOverwrites = this.actionInstance.getNodeParameter("permissionOverwrites", 0, { permission: [] });
const updatePermissionAdd = this.actionInstance.getNodeParameter("permissionAdd", 0, { permission: [] });
const updatePermissionRemove = this.actionInstance.getNodeParameter("permissionRemove", 0, { permission: [] });
try {
const channelToUpdate = await this.client.channels.fetch(updateChannelTargetId);
if (!channelToUpdate) {
throw new Error("Channel not found.");
}
if (channelToUpdate.isDMBased()) {
throw new Error("Cannot update DM channels.");
}
const guildChannel = channelToUpdate;
const editOptions = {};
// Add fields to update if provided
if (updateChannelOptions.topic !== undefined) {
editOptions.topic = updateChannelOptions.topic;
}
if (updateChannelOptions.position !== undefined) {
editOptions.position = updateChannelOptions.position;
}
if (updateChannelOptions.nsfw !== undefined) {
editOptions.nsfw = updateChannelOptions.nsfw;
}
if (updateChannelOptions.bitrate !== undefined) {
editOptions.bitrate = updateChannelOptions.bitrate;
}
if (updateChannelOptions.userLimit !== undefined) {
editOptions.userLimit = updateChannelOptions.userLimit;
}
if (updateChannelOptions.rateLimitPerUser !== undefined) {
editOptions.rateLimitPerUser = updateChannelOptions.rateLimitPerUser;
}
if (updateChannelOptions.parent !== undefined) {
editOptions.parent = updateChannelOptions.parent;
}
// Prepare permission overwrites
let finalPermissionOverwrites;
let shouldUpdatePermissions = false;
// Handle inherit parent permissions for UPDATE
if (updateChannelOptions.inheritParentPermissions === true && updateChannelOptions.parent) {
const parentChannel = await this.client.channels.fetch(updateChannelOptions.parent);
if (parentChannel && !parentChannel.isDMBased()) {
const parentGuildChannel = parentChannel;
if (parentGuildChannel.permissionOverwrites) {
finalPermissionOverwrites = Array.from(parentGuildChannel.permissionOverwrites.cache.values()).map((overwrite) => ({
id: overwrite.id,
type: overwrite.type,
allow: overwrite.allow.bitfield,
deny: overwrite.deny.bitfield,
}));
shouldUpdatePermissions = true;
}
}
}
// Process permission overwrites (complete replacement)
if (updatePermissionOverwrites.permission && updatePermissionOverwrites.permission.length > 0) {
finalPermissionOverwrites = updatePermissionOverwrites.permission.map((perm) => {
const overwrite = {
id: perm.id,
type: perm.type === "role" ? 0 : 1,
};
// Convert permission names to PermissionsBitField flags
if (perm.allow && perm.allow.length > 0) {
overwrite.allow = perm.allow.map((p) => discord_js_1.PermissionsBitField.Flags[p]);
}
if (perm.deny && perm.deny.length > 0) {
overwrite.deny = perm.deny.map((p) => discord_js_1.PermissionsBitField.Flags[p]);
}