huge changes
This commit is contained in:
96
services/staffThread.js
Normal file
96
services/staffThread.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Staff discussion threads — creates a private thread on each ticket channel
|
||||
* for staff-only communication.
|
||||
*
|
||||
* Notes:
|
||||
* - The bot requires CREATE_PRIVATE_THREADS and SEND_MESSAGES_IN_THREADS
|
||||
* permissions on every ticket category.
|
||||
* - Private threads (type: 12) require the server to have Community features
|
||||
* OR the channel to be in a server with Boost level that unlocks private
|
||||
* threads. If thread creation fails with code 50024 or 160004, a warning
|
||||
* is logged via logWarn.
|
||||
* - invitable: false means only staff with MANAGE_THREADS can add additional
|
||||
* members — this is intentional for privacy.
|
||||
* - guild.members.fetch() in addRoleMembersToThread can be slow on large
|
||||
* servers. The 300ms delay between adds avoids the thread member add rate
|
||||
* limit (approximately 5/second).
|
||||
*/
|
||||
const { CONFIG } = require('../config');
|
||||
const { logError, logWarn } = require('./debugLog');
|
||||
|
||||
/**
|
||||
* Create a private staff thread on a ticket channel.
|
||||
* @param {import('discord.js').TextChannel} channel
|
||||
* @param {import('discord.js').Client} client
|
||||
* @returns {Promise<import('discord.js').ThreadChannel|null>}
|
||||
*/
|
||||
async function createStaffThread(channel, client) {
|
||||
if (!CONFIG.STAFF_THREAD_ENABLED) return null;
|
||||
|
||||
try {
|
||||
const threadName = CONFIG.STAFF_THREAD_NAME.slice(0, 100);
|
||||
|
||||
const thread = await channel.threads.create({
|
||||
name: threadName,
|
||||
type: 12, // ChannelType.PrivateThread
|
||||
invitable: false,
|
||||
reason: 'Staff discussion thread for ticket'
|
||||
});
|
||||
|
||||
if (CONFIG.STAFF_THREAD_AUTO_ADD_ROLE && CONFIG.STAFF_THREAD_ROLE_ID) {
|
||||
await addRoleMembersToThread(thread, channel.guild, client);
|
||||
}
|
||||
|
||||
return thread;
|
||||
} catch (err) {
|
||||
// Detect permission / channel type errors
|
||||
if (err.code === 50024 || err.code === 160004) {
|
||||
logWarn('staffThread', `Cannot create private thread in ${channel.name}: server may lack Community features or required boost level (code ${err.code}).`).catch(() => {});
|
||||
}
|
||||
await logError('staffThread:create', err, null, client).catch(() => {});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all members of the staff role to the thread.
|
||||
*/
|
||||
async function addRoleMembersToThread(thread, guild, client) {
|
||||
try {
|
||||
const role = await guild.roles.fetch(CONFIG.STAFF_THREAD_ROLE_ID).catch(() => null);
|
||||
if (!role) return;
|
||||
|
||||
await guild.members.fetch();
|
||||
const members = guild.members.cache.filter(m =>
|
||||
m.roles.cache.has(CONFIG.STAFF_THREAD_ROLE_ID) && !m.user.bot
|
||||
);
|
||||
|
||||
for (const [, member] of members) {
|
||||
await thread.members.add(member.id).catch(() => {});
|
||||
await new Promise(r => setTimeout(r, 300));
|
||||
}
|
||||
} catch (err) {
|
||||
await logError('staffThread:addMembers', err, null, client).catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single member to the staff thread for a ticket channel.
|
||||
* Call this when a ticket is claimed.
|
||||
*/
|
||||
async function addMemberToStaffThread(channel, memberId) {
|
||||
if (!CONFIG.STAFF_THREAD_ENABLED) return;
|
||||
|
||||
try {
|
||||
const threads = await channel.threads.fetchActive();
|
||||
const staffThread = threads.threads.find(t =>
|
||||
t.name === CONFIG.STAFF_THREAD_NAME && t.type === 12
|
||||
);
|
||||
if (!staffThread) return;
|
||||
await staffThread.members.add(memberId);
|
||||
} catch {
|
||||
// non-critical, ignore
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { createStaffThread, addMemberToStaffThread };
|
||||
Reference in New Issue
Block a user