feat: split text and voice channel selection

Separate text moderation and voice recording guild/channel state so each workflow can persist and operate independently.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
MythEclipse
2026-05-15 15:58:38 +07:00
co-authored by Claude Opus 4.7
parent 6859eb3f50
commit ed438e6fc0
12 changed files with 250 additions and 40 deletions
+40
View File
@@ -29,4 +29,44 @@ describe("loadConfig", () => {
expect(config.RECORDINGS_DIR).toBe("./recordings");
expect(config.NODE_ENV).toBe("test");
});
it("derives split text and voice guild defaults from legacy config", async () => {
process.env = {
...originalEnv,
DISCORD_TOKEN: "token",
MONITOR_GUILD_ID: "legacy-text-guild",
GUILD_ID: "legacy-voice-guild",
VOICE_CHANNEL_ID: "voice-channel",
NODE_ENV: "test",
};
const { loadConfig } = await import("../src/config");
const config = loadConfig(process.env);
expect(config.TEXT_GUILD_ID).toBeUndefined();
expect(config.EFFECTIVE_TEXT_GUILD_ID).toBe("legacy-text-guild");
expect(config.EFFECTIVE_VOICE_GUILD_ID).toBe("legacy-voice-guild");
expect(config.VOICE_CHANNEL_ID).toBe("voice-channel");
});
it("uses explicit split text and voice config before legacy values", async () => {
process.env = {
...originalEnv,
DISCORD_TOKEN: "token",
MONITOR_GUILD_ID: "legacy-text-guild",
GUILD_ID: "legacy-voice-guild",
TEXT_GUILD_ID: "text-guild",
TEXT_CHANNEL_ID: "text-channel",
VOICE_GUILD_ID: "voice-guild",
VOICE_CHANNEL_ID: "voice-channel",
NODE_ENV: "test",
};
const { loadConfig } = await import("../src/config");
const config = loadConfig(process.env);
expect(config.EFFECTIVE_TEXT_GUILD_ID).toBe("text-guild");
expect(config.TEXT_CHANNEL_ID).toBe("text-channel");
expect(config.EFFECTIVE_VOICE_GUILD_ID).toBe("voice-guild");
});
});
@@ -0,0 +1,27 @@
import { describe, expect, it } from "vitest";
import { shouldCaptureMessageLocation } from "../../src/moderation/messageCapture";
describe("shouldCaptureMessageLocation", () => {
it("matches only configured text guild and optional channel", () => {
expect(
shouldCaptureMessageLocation(
{ guildId: "guild-1", channelId: "channel-1" },
{ guildId: "guild-1", channelId: "channel-1" },
),
).toBe(true);
expect(
shouldCaptureMessageLocation(
{ guildId: "guild-1", channelId: "channel-2" },
{ guildId: "guild-1", channelId: "channel-1" },
),
).toBe(false);
expect(
shouldCaptureMessageLocation(
{ guildId: "guild-2", channelId: "channel-1" },
{ guildId: "guild-1", channelId: "channel-1" },
),
).toBe(false);
});
});
+47
View File
@@ -0,0 +1,47 @@
import type { Request, Response } from "express";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { createSyncRoutes } from "../../src/routes/syncRoutes";
const syncSelectedChannelBacklog = vi.hoisted(() => vi.fn());
vi.mock("../../src/moderation/backlogSync", () => ({
syncSelectedChannelBacklog,
}));
describe("createSyncRoutes", () => {
beforeEach(() => {
syncSelectedChannelBacklog.mockReset();
});
it("syncs the selected guild and channel from the request", async () => {
syncSelectedChannelBacklog.mockResolvedValue(3);
const router = createSyncRoutes({} as never);
const route = router.stack.find(
(layer) => layer.route?.path === "/backlog-sync",
);
const handler = route?.route?.stack[0]?.handle;
const json = vi.fn();
const next = vi.fn();
await handler?.(
{
body: { guildId: "selected-guild", channelId: "selected-channel" },
} as Request,
{ json } as unknown as Response,
next,
);
expect(syncSelectedChannelBacklog).toHaveBeenCalledWith(
{},
"selected-guild",
"selected-channel",
);
expect(json).toHaveBeenCalledWith({
success: true,
channelId: "selected-channel",
messagesSync: 3,
});
expect(next).not.toHaveBeenCalled();
});
});
+3 -3
View File
@@ -13,8 +13,8 @@ describe("Discord video stream workspace dependencies", () => {
expect(videoStreamPackage.devDependencies?.["discord.js-selfbot-v13"]).toBe(
"workspace:*",
);
expect(videoStreamPackage.peerDependencies?.["discord.js-selfbot-v13"]).toBe(
"^3.6.0",
);
expect(
videoStreamPackage.peerDependencies?.["discord.js-selfbot-v13"],
).toBe("^3.6.0");
});
});