104 lines
4.2 KiB
TypeScript
104 lines
4.2 KiB
TypeScript
import {
|
|
ChannelType,
|
|
GuildFeature,
|
|
GuildTextThreadCreateOptions,
|
|
ThreadAutoArchiveDuration,
|
|
ThreadChannel,
|
|
} from "discord.js";
|
|
import z from "zod";
|
|
import { TemplateSafeValueContainer, renderTemplate } from "../../../templateFormatter";
|
|
import { MINUTES, convertDelayStringToMS, noop, zBoundedCharacters, zDelayString } from "../../../utils";
|
|
import { savedMessageToTemplateSafeSavedMessage, userToTemplateSafeUser } from "../../../utils/templateSafeObjects";
|
|
import { automodAction } from "../helpers";
|
|
|
|
const validThreadAutoArchiveDurations: ThreadAutoArchiveDuration[] = [
|
|
ThreadAutoArchiveDuration.OneHour,
|
|
ThreadAutoArchiveDuration.OneDay,
|
|
ThreadAutoArchiveDuration.ThreeDays,
|
|
ThreadAutoArchiveDuration.OneWeek,
|
|
];
|
|
|
|
export const StartThreadAction = automodAction({
|
|
configSchema: z.strictObject({
|
|
name: zBoundedCharacters(1, 100).nullable(),
|
|
auto_archive: zDelayString,
|
|
private: z.boolean().default(false),
|
|
slowmode: zDelayString.nullable().default(null),
|
|
limit_per_channel: z.number().nullable().default(5),
|
|
}),
|
|
|
|
async apply({ pluginData, contexts, actionConfig }) {
|
|
// check if the message still exists, we don't want to create threads for deleted messages
|
|
const threads = contexts.filter((c) => {
|
|
if (!c.message || !c.user) return false;
|
|
const channel = pluginData.guild.channels.cache.get(c.message.channel_id);
|
|
if (channel?.type !== ChannelType.GuildText || !channel.isTextBased()) return false; // for some reason the typing here for channel.type defaults to ThreadChannelTypes (?)
|
|
// check against max threads per channel
|
|
if (actionConfig.limit_per_channel && actionConfig.limit_per_channel > 0) {
|
|
const threadCount = channel.threads.cache.filter(
|
|
(tr) => tr.ownerId === pluginData.client.user!.id && !tr.archived && tr.parentId === channel.id,
|
|
).size;
|
|
if (threadCount >= actionConfig.limit_per_channel) return false;
|
|
}
|
|
return true;
|
|
});
|
|
|
|
const guild = pluginData.guild;
|
|
const archiveSet = actionConfig.auto_archive
|
|
? Math.ceil(Math.max(convertDelayStringToMS(actionConfig.auto_archive) ?? 0, 0) / MINUTES)
|
|
: ThreadAutoArchiveDuration.OneDay;
|
|
const autoArchive = validThreadAutoArchiveDurations.includes(archiveSet)
|
|
? (archiveSet as ThreadAutoArchiveDuration)
|
|
: ThreadAutoArchiveDuration.OneHour;
|
|
|
|
for (const threadContext of threads) {
|
|
const channel = pluginData.guild.channels.cache.get(threadContext.message!.channel_id);
|
|
if (!channel || !("threads" in channel) || channel.type === ChannelType.GuildForum) continue;
|
|
|
|
const renderThreadName = async (str: string) =>
|
|
renderTemplate(
|
|
str,
|
|
new TemplateSafeValueContainer({
|
|
user: userToTemplateSafeUser(threadContext.user!),
|
|
msg: savedMessageToTemplateSafeSavedMessage(threadContext.message!),
|
|
}),
|
|
);
|
|
const threadName = await renderThreadName(actionConfig.name ?? "{user.renderedUsername}'s thread");
|
|
const threadOptions: GuildTextThreadCreateOptions<unknown> = {
|
|
name: threadName,
|
|
autoArchiveDuration: autoArchive,
|
|
startMessage:
|
|
!actionConfig.private && guild.features.includes(GuildFeature.PrivateThreads)
|
|
? threadContext.message!.id
|
|
: undefined,
|
|
};
|
|
|
|
let thread: ThreadChannel | undefined;
|
|
if (channel.type === ChannelType.GuildNews) {
|
|
thread = await channel.threads
|
|
.create({
|
|
...threadOptions,
|
|
type: ChannelType.AnnouncementThread,
|
|
})
|
|
.catch(() => undefined);
|
|
} else {
|
|
thread = await channel.threads
|
|
.create({
|
|
...threadOptions,
|
|
type: actionConfig.private ? ChannelType.PrivateThread : ChannelType.PublicThread,
|
|
startMessage:
|
|
!actionConfig.private && guild.features.includes(GuildFeature.PrivateThreads)
|
|
? threadContext.message!.id
|
|
: undefined,
|
|
})
|
|
.catch(() => undefined);
|
|
}
|
|
if (actionConfig.slowmode && thread) {
|
|
const dur = Math.ceil(Math.max(convertDelayStringToMS(actionConfig.slowmode) ?? 0, 0) / 1000);
|
|
if (dur > 0) {
|
|
await thread.setRateLimitPerUser(dur).catch(noop);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
});
|