const { ChannelType, PermissionFlagsBits } = require('discord.js'); const { Categories } = require('../config'); const { stmts } = require('../database'); const { successEmbed, infoEmbed } = require('../utils/embeds'); module.exports = { name: 'create channels', async execute(client, message) { const guildId = process.env.GUILD_ID; const guild = await client.guilds.fetch(guildId); await message.reply({ embeds: [infoEmbed('Creating Channels', 'Setting up categories and channels...')] }); const results = []; // Build a role map for permission overwrites const roleMap = new Map(); roleMap.set('everyone', guild.roles.everyone); guild.roles.cache.forEach(r => roleMap.set(r.name, r)); for (const catDef of Categories) { // Check if category already exists let category = guild.channels.cache.find( c => c.type === ChannelType.GuildCategory && c.name === catDef.name ); if (!category) { // Build category-level permission overwrites const catOverwrites = buildCategoryOverwrites(catDef, roleMap); category = await guild.channels.create({ name: catDef.name, type: ChannelType.GuildCategory, permissionOverwrites: catOverwrites, reason: 'WSB Setup', }); results.push(`📁 **${catDef.name}** — category created`); } else { results.push(`📁 **${catDef.name}** — already exists`); } // Create child channels for (const chDef of catDef.channels) { const existing = guild.channels.cache.find( c => c.name === chDef.name && c.parentId === category.id ); if (existing) { // Store channel ID in bot state for later reference stmts.setState.run(`channel_${chDef.name}`, existing.id); results.push(` └ **${chDef.name}** — already exists`); continue; } const channelType = chDef.type === 'voice' ? ChannelType.GuildVoice : ChannelType.GuildText; // Build channel-specific permission overwrites const channelOverwrites = buildChannelOverwrites(catDef, chDef, roleMap); const channel = await guild.channels.create({ name: chDef.name, type: channelType, parent: category.id, permissionOverwrites: channelOverwrites, reason: 'WSB Setup', }); // Store in bot state stmts.setState.run(`channel_${chDef.name}`, channel.id); results.push(` └ **${chDef.name}** — created`); } } await message.reply({ embeds: [successEmbed('Channels Created', results.join('\n'))], }); }, }; /** * Build permission overwrites for a category. */ function buildCategoryOverwrites(catDef, roleMap) { const overrideMap = catDef.permOverrides(roleMap); const overwrites = []; for (const [roleName, perms] of Object.entries(overrideMap)) { const role = roleName === 'everyone' ? roleMap.get('everyone') : roleMap.get(roleName); if (!role) continue; const allow = []; const deny = []; if (perms.view === true) allow.push(PermissionFlagsBits.ViewChannel); if (perms.view === false) deny.push(PermissionFlagsBits.ViewChannel); if (perms.send === true) allow.push(PermissionFlagsBits.SendMessages); if (perms.send === false) deny.push(PermissionFlagsBits.SendMessages); overwrites.push({ id: role.id || role, allow, deny }); } return overwrites; } /** * Build channel-specific overwrites, handling readOnly, staffOnly, noEmbeds, and special flags. */ function buildChannelOverwrites(catDef, chDef, roleMap) { const overrideMap = catDef.permOverrides(roleMap); const overwrites = []; for (const [roleName, perms] of Object.entries(overrideMap)) { const role = roleName === 'everyone' ? roleMap.get('everyone') : roleMap.get(roleName); if (!role) continue; const allow = []; const deny = []; // Public channels: @everyone can view (overrides category deny) if (chDef.public && roleName === 'everyone') { allow.push(PermissionFlagsBits.ViewChannel); allow.push(PermissionFlagsBits.ReadMessageHistory); allow.push(PermissionFlagsBits.AddReactions); } else { if (perms.view === true) allow.push(PermissionFlagsBits.ViewChannel); if (perms.view === false) deny.push(PermissionFlagsBits.ViewChannel); } // hideFromVerified: deny view for @@ Verified (verify channel after verification) if (chDef.hideFromVerified && roleName === '@@ Verified') { // Override: verified users cannot see this channel const viewIdx = allow.indexOf(PermissionFlagsBits.ViewChannel); if (viewIdx !== -1) allow.splice(viewIdx, 1); deny.push(PermissionFlagsBits.ViewChannel); } if (chDef.ownerOnly) { // Only Owner and Co-Owner can send if (['@@ Owner', '@@ Co-Owner'].includes(roleName)) { allow.push(PermissionFlagsBits.SendMessages); } else { deny.push(PermissionFlagsBits.SendMessages); } } else if (chDef.readOnly) { // Only Staff and Owner can send in read-only channels if (['@@ Staff', '@@ Server Manager', '@@ Owner', '@@ Co-Owner'].includes(roleName)) { if (perms.send === true) allow.push(PermissionFlagsBits.SendMessages); } else { deny.push(PermissionFlagsBits.SendMessages); } } else if (chDef.staffOnly) { // Only Staff and Owner can see/send if (['@@ Staff', '@@ Server Manager', '@@ Owner', '@@ Co-Owner'].includes(roleName)) { allow.push(PermissionFlagsBits.ViewChannel, PermissionFlagsBits.SendMessages); } else { deny.push(PermissionFlagsBits.ViewChannel); } } else if (chDef.special === 'owner-chat') { // Only Owner, Co-Owner, and Server Manager can see/send if (['@@ Owner', '@@ Co-Owner', '@@ Server Manager'].includes(roleName)) { allow.push(PermissionFlagsBits.ViewChannel, PermissionFlagsBits.SendMessages); } else { deny.push(PermissionFlagsBits.ViewChannel); } } else if (chDef.special === 'community-content') { // Known + Helper + Staff + Owner can send; everyone else view-only if (['@@ Known', '@@ Helper', '@@ Staff', '@@ Owner', '@@ Co-Owner'].includes(roleName)) { allow.push(PermissionFlagsBits.SendMessages); } else { if (perms.view === true) { // Can view but not send deny.push(PermissionFlagsBits.SendMessages); } } } else { if (perms.send === true) allow.push(PermissionFlagsBits.SendMessages); if (perms.send === false) deny.push(PermissionFlagsBits.SendMessages); } // noEmbeds: block attachments, embeds, and external emojis (text-only channel) if (chDef.noEmbeds && !['@@ Staff', '@@ Server Manager', '@@ Owner', '@@ Co-Owner'].includes(roleName)) { deny.push(PermissionFlagsBits.AttachFiles); deny.push(PermissionFlagsBits.EmbedLinks); deny.push(PermissionFlagsBits.UseExternalEmojis); } // Add reactions for verify and ticket channels if (chDef.special === 'verify' || chDef.special === 'ticket') { allow.push(PermissionFlagsBits.AddReactions); allow.push(PermissionFlagsBits.ReadMessageHistory); } overwrites.push({ id: role.id || role, allow, deny }); } // For community-content, add Known and Helper overwrites if they aren't in the category overrides if (chDef.special === 'community-content') { for (const extraRole of ['@@ Known', '@@ Helper']) { if (!overrideMap[extraRole]) { const role = roleMap.get(extraRole); if (role) { overwrites.push({ id: role.id, allow: [PermissionFlagsBits.ViewChannel, PermissionFlagsBits.SendMessages], deny: [], }); } } } } return overwrites; }