refactor: migrate all code to use getGuildConfig() for guild settings
- Update all commands and events to fetch guild config once per execution - Pass config to service methods that need it (ModerationService.issueWarning) - Update terminal service to use guildSettingsService for persistence - Remove direct imports of config for guild-specific settings This consolidates configuration to database-backed guild settings, eliminating the dual config system.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { createCommand } from "@shared/lib/utils";
|
import { createCommand } from "@shared/lib/utils";
|
||||||
import { SlashCommandBuilder, PermissionFlagsBits, AttachmentBuilder } from "discord.js";
|
import { SlashCommandBuilder, PermissionFlagsBits, AttachmentBuilder } from "discord.js";
|
||||||
import { config, saveConfig } from "@shared/lib/config";
|
import { getGuildConfig, invalidateGuildConfigCache } from "@shared/lib/config";
|
||||||
|
import { guildSettingsService } from "@shared/modules/guild-settings/guild-settings.service";
|
||||||
import { DrizzleClient } from "@shared/db/DrizzleClient";
|
import { DrizzleClient } from "@shared/db/DrizzleClient";
|
||||||
import { items } from "@db/schema";
|
import { items } from "@db/schema";
|
||||||
import { createSuccessEmbed, createErrorEmbed } from "@lib/embeds";
|
import { createSuccessEmbed, createErrorEmbed } from "@lib/embeds";
|
||||||
@@ -49,7 +50,7 @@ export const createColor = createCommand({
|
|||||||
// 2. Create Role
|
// 2. Create Role
|
||||||
const role = await interaction.guild?.roles.create({
|
const role = await interaction.guild?.roles.create({
|
||||||
name: name,
|
name: name,
|
||||||
color: colorInput as any, // Discord.js types are a bit strict on ColorResolvable, but string generally works or needs parsing
|
color: colorInput as any,
|
||||||
reason: `Created via /createcolor by ${interaction.user.tag}`
|
reason: `Created via /createcolor by ${interaction.user.tag}`
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -57,11 +58,9 @@ export const createColor = createCommand({
|
|||||||
throw new Error("Failed to create role.");
|
throw new Error("Failed to create role.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Update Config
|
// 3. Add to guild settings
|
||||||
if (!config.colorRoles.includes(role.id)) {
|
await guildSettingsService.addColorRole(interaction.guildId!, role.id);
|
||||||
config.colorRoles.push(role.id);
|
invalidateGuildConfigCache(interaction.guildId!);
|
||||||
saveConfig(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Create Item
|
// 4. Create Item
|
||||||
await DrizzleClient.insert(items).values({
|
await DrizzleClient.insert(items).values({
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
getModerationErrorEmbed,
|
getModerationErrorEmbed,
|
||||||
getUserWarningEmbed
|
getUserWarningEmbed
|
||||||
} from "@/modules/moderation/moderation.view";
|
} from "@/modules/moderation/moderation.view";
|
||||||
import { config } from "@shared/lib/config";
|
import { getGuildConfig } from "@shared/lib/config";
|
||||||
|
|
||||||
export const warn = createCommand({
|
export const warn = createCommand({
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
@@ -50,6 +50,9 @@ export const warn = createCommand({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch guild config for moderation settings
|
||||||
|
const guildConfig = await getGuildConfig(interaction.guildId!);
|
||||||
|
|
||||||
// Issue the warning via service
|
// Issue the warning via service
|
||||||
const { moderationCase, warningCount, autoTimeoutIssued } = await ModerationService.issueWarning({
|
const { moderationCase, warningCount, autoTimeoutIssued } = await ModerationService.issueWarning({
|
||||||
userId: targetUser.id,
|
userId: targetUser.id,
|
||||||
@@ -59,7 +62,11 @@ export const warn = createCommand({
|
|||||||
reason,
|
reason,
|
||||||
guildName: interaction.guild?.name || undefined,
|
guildName: interaction.guild?.name || undefined,
|
||||||
dmTarget: targetUser,
|
dmTarget: targetUser,
|
||||||
timeoutTarget: await interaction.guild?.members.fetch(targetUser.id)
|
timeoutTarget: await interaction.guild?.members.fetch(targetUser.id),
|
||||||
|
config: {
|
||||||
|
dmOnWarn: guildConfig.moderation?.cases?.dmOnWarn,
|
||||||
|
autoTimeoutThreshold: guildConfig.moderation?.cases?.autoTimeoutThreshold,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Send success message to moderator
|
// Send success message to moderator
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createCommand } from "@shared/lib/utils";
|
import { createCommand } from "@shared/lib/utils";
|
||||||
import { SlashCommandBuilder } from "discord.js";
|
import { SlashCommandBuilder } from "discord.js";
|
||||||
import { config } from "@shared/lib/config";
|
import { getGuildConfig } from "@shared/lib/config";
|
||||||
import { createErrorEmbed } from "@/lib/embeds";
|
import { createErrorEmbed } from "@/lib/embeds";
|
||||||
import { getFeedbackTypeMenu } from "@/modules/feedback/feedback.view";
|
import { getFeedbackTypeMenu } from "@/modules/feedback/feedback.view";
|
||||||
|
|
||||||
@@ -9,8 +9,10 @@ export const feedback = createCommand({
|
|||||||
.setName("feedback")
|
.setName("feedback")
|
||||||
.setDescription("Submit feedback, feature requests, or bug reports"),
|
.setDescription("Submit feedback, feature requests, or bug reports"),
|
||||||
execute: async (interaction) => {
|
execute: async (interaction) => {
|
||||||
|
const guildConfig = await getGuildConfig(interaction.guildId!);
|
||||||
|
|
||||||
// Check if feedback channel is configured
|
// Check if feedback channel is configured
|
||||||
if (!config.feedbackChannelId) {
|
if (!guildConfig.feedbackChannelId) {
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
embeds: [createErrorEmbed("Feedback system is not configured. Please contact an administrator.")],
|
embeds: [createErrorEmbed("Feedback system is not configured. Please contact an administrator.")],
|
||||||
ephemeral: true
|
ephemeral: true
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { createErrorEmbed } from "@lib/embeds";
|
|||||||
import { getItemUseResultEmbed } from "@/modules/inventory/inventory.view";
|
import { getItemUseResultEmbed } from "@/modules/inventory/inventory.view";
|
||||||
import type { ItemUsageData } from "@shared/lib/types";
|
import type { ItemUsageData } from "@shared/lib/types";
|
||||||
import { UserError } from "@shared/lib/errors";
|
import { UserError } from "@shared/lib/errors";
|
||||||
import { config } from "@shared/lib/config";
|
import { getGuildConfig } from "@shared/lib/config";
|
||||||
|
|
||||||
export const use = createCommand({
|
export const use = createCommand({
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
@@ -21,6 +21,9 @@ export const use = createCommand({
|
|||||||
execute: async (interaction) => {
|
execute: async (interaction) => {
|
||||||
await interaction.deferReply();
|
await interaction.deferReply();
|
||||||
|
|
||||||
|
const guildConfig = await getGuildConfig(interaction.guildId!);
|
||||||
|
const colorRoles = guildConfig.colorRoles ?? [];
|
||||||
|
|
||||||
const itemId = interaction.options.getNumber("item", true);
|
const itemId = interaction.options.getNumber("item", true);
|
||||||
const user = await userService.getOrCreateUser(interaction.user.id, interaction.user.username);
|
const user = await userService.getOrCreateUser(interaction.user.id, interaction.user.username);
|
||||||
if (!user) {
|
if (!user) {
|
||||||
@@ -42,7 +45,7 @@ export const use = createCommand({
|
|||||||
await member.roles.add(effect.roleId);
|
await member.roles.add(effect.roleId);
|
||||||
} else if (effect.type === 'COLOR_ROLE') {
|
} else if (effect.type === 'COLOR_ROLE') {
|
||||||
// Remove existing color roles
|
// Remove existing color roles
|
||||||
const rolesToRemove = config.colorRoles.filter(r => member.roles.cache.has(r));
|
const rolesToRemove = colorRoles.filter(r => member.roles.cache.has(r));
|
||||||
if (rolesToRemove.length > 0) await member.roles.remove(rolesToRemove);
|
if (rolesToRemove.length > 0) await member.roles.remove(rolesToRemove);
|
||||||
await member.roles.add(effect.roleId);
|
await member.roles.add(effect.roleId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,26 @@
|
|||||||
import { Events } from "discord.js";
|
import { Events } from "discord.js";
|
||||||
import type { Event } from "@shared/lib/types";
|
import type { Event } from "@shared/lib/types";
|
||||||
import { config } from "@shared/lib/config";
|
import { getGuildConfig } from "@shared/lib/config";
|
||||||
import { userService } from "@shared/modules/user/user.service";
|
import { userService } from "@shared/modules/user/user.service";
|
||||||
|
|
||||||
// Visitor role
|
|
||||||
const event: Event<Events.GuildMemberAdd> = {
|
const event: Event<Events.GuildMemberAdd> = {
|
||||||
name: Events.GuildMemberAdd,
|
name: Events.GuildMemberAdd,
|
||||||
execute: async (member) => {
|
execute: async (member) => {
|
||||||
console.log(`👤 New member joined: ${member.user.tag} (${member.id})`);
|
console.log(`👤 New member joined: ${member.user.tag} (${member.id})`);
|
||||||
|
|
||||||
|
const guildConfig = await getGuildConfig(member.guild.id);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const user = await userService.getUserById(member.id);
|
const user = await userService.getUserById(member.id);
|
||||||
|
|
||||||
if (user && user.class) {
|
if (user && user.class) {
|
||||||
console.log(`🔄 Returning student detected: ${member.user.tag}`);
|
console.log(`🔄 Returning student detected: ${member.user.tag}`);
|
||||||
await member.roles.remove(config.visitorRole);
|
if (guildConfig.visitorRole) {
|
||||||
await member.roles.add(config.studentRole);
|
await member.roles.remove(guildConfig.visitorRole);
|
||||||
|
}
|
||||||
|
if (guildConfig.studentRole) {
|
||||||
|
await member.roles.add(guildConfig.studentRole);
|
||||||
|
}
|
||||||
|
|
||||||
if (user.class.roleId) {
|
if (user.class.roleId) {
|
||||||
await member.roles.add(user.class.roleId);
|
await member.roles.add(user.class.roleId);
|
||||||
@@ -22,9 +28,11 @@ const event: Event<Events.GuildMemberAdd> = {
|
|||||||
}
|
}
|
||||||
console.log(`Restored student role to ${member.user.tag}`);
|
console.log(`Restored student role to ${member.user.tag}`);
|
||||||
} else {
|
} else {
|
||||||
await member.roles.add(config.visitorRole);
|
if (guildConfig.visitorRole) {
|
||||||
|
await member.roles.add(guildConfig.visitorRole);
|
||||||
console.log(`Assigned visitor role to ${member.user.tag}`);
|
console.log(`Assigned visitor role to ${member.user.tag}`);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
console.log(`User Roles: ${member.roles.cache.map(role => role.name).join(", ")}`);
|
console.log(`User Roles: ${member.roles.cache.map(role => role.name).join(", ")}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to handle role assignment for ${member.user.tag}:`, error);
|
console.error(`Failed to handle role assignment for ${member.user.tag}:`, error);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { Interaction } from "discord.js";
|
import type { Interaction } from "discord.js";
|
||||||
import { TextChannel, MessageFlags } from "discord.js";
|
import { TextChannel, MessageFlags } from "discord.js";
|
||||||
import { config } from "@shared/lib/config";
|
import { getGuildConfig } from "@shared/lib/config";
|
||||||
import { AuroraClient } from "@/lib/BotClient";
|
import { AuroraClient } from "@/lib/BotClient";
|
||||||
import { buildFeedbackMessage, getFeedbackModal } from "./feedback.view";
|
import { buildFeedbackMessage, getFeedbackModal } from "./feedback.view";
|
||||||
import { FEEDBACK_CUSTOM_IDS, type FeedbackType, type FeedbackData } from "./feedback.types";
|
import { FEEDBACK_CUSTOM_IDS, type FeedbackType, type FeedbackData } from "./feedback.types";
|
||||||
@@ -33,7 +33,13 @@ export const handleFeedbackInteraction = async (interaction: Interaction) => {
|
|||||||
throw new UserError("An error occurred processing your feedback. Please try again.");
|
throw new UserError("An error occurred processing your feedback. Please try again.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.feedbackChannelId) {
|
if (!interaction.guildId) {
|
||||||
|
throw new UserError("This action can only be performed in a server.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const guildConfig = await getGuildConfig(interaction.guildId);
|
||||||
|
|
||||||
|
if (!guildConfig.feedbackChannelId) {
|
||||||
throw new UserError("Feedback channel is not configured. Please contact an administrator.");
|
throw new UserError("Feedback channel is not configured. Please contact an administrator.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +58,7 @@ export const handleFeedbackInteraction = async (interaction: Interaction) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Get feedback channel
|
// Get feedback channel
|
||||||
const channel = await AuroraClient.channels.fetch(config.feedbackChannelId).catch(() => null) as TextChannel | null;
|
const channel = await AuroraClient.channels.fetch(guildConfig.feedbackChannelId).catch(() => null) as TextChannel | null;
|
||||||
|
|
||||||
if (!channel) {
|
if (!channel) {
|
||||||
throw new UserError("Feedback channel not found. Please contact an administrator.");
|
throw new UserError("Feedback channel not found. Please contact an administrator.");
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { temporaryRoleService } from "@shared/modules/system/temp-role.service";
|
import { temporaryRoleService } from "@shared/modules/system/temp-role.service";
|
||||||
|
import { terminalService } from "@shared/modules/terminal/terminal.service";
|
||||||
|
|
||||||
export const schedulerService = {
|
export const schedulerService = {
|
||||||
start: () => {
|
start: () => {
|
||||||
@@ -10,7 +11,6 @@ export const schedulerService = {
|
|||||||
}, 60 * 1000);
|
}, 60 * 1000);
|
||||||
|
|
||||||
// 2. Terminal Update Loop (every 60s)
|
// 2. Terminal Update Loop (every 60s)
|
||||||
const { terminalService } = require("@shared/modules/terminal/terminal.service");
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
terminalService.update();
|
terminalService.update();
|
||||||
}, 60 * 1000);
|
}, 60 * 1000);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ButtonInteraction, MessageFlags } from "discord.js";
|
import { ButtonInteraction, MessageFlags } from "discord.js";
|
||||||
import { config } from "@shared/lib/config";
|
import { getGuildConfig, invalidateGuildConfigCache } from "@shared/lib/config";
|
||||||
import { getEnrollmentSuccessMessage } from "./enrollment.view";
|
import { getEnrollmentSuccessMessage } from "./enrollment.view";
|
||||||
import { classService } from "@shared/modules/class/class.service";
|
import { classService } from "@shared/modules/class/class.service";
|
||||||
import { userService } from "@shared/modules/user/user.service";
|
import { userService } from "@shared/modules/user/user.service";
|
||||||
@@ -11,7 +11,8 @@ export async function handleEnrollmentInteraction(interaction: ButtonInteraction
|
|||||||
throw new UserError("This action can only be performed in a server.");
|
throw new UserError("This action can only be performed in a server.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const { studentRole, visitorRole } = config;
|
const guildConfig = await getGuildConfig(interaction.guildId);
|
||||||
|
const { studentRole, visitorRole, welcomeChannelId, welcomeMessage } = guildConfig;
|
||||||
|
|
||||||
if (!studentRole || !visitorRole) {
|
if (!studentRole || !visitorRole) {
|
||||||
throw new UserError("No student or visitor role configured for enrollment.");
|
throw new UserError("No student or visitor role configured for enrollment.");
|
||||||
@@ -67,10 +68,10 @@ export async function handleEnrollmentInteraction(interaction: ButtonInteraction
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 5. Send Welcome Message (if configured)
|
// 5. Send Welcome Message (if configured)
|
||||||
if (config.welcomeChannelId) {
|
if (welcomeChannelId) {
|
||||||
const welcomeChannel = interaction.guild.channels.cache.get(config.welcomeChannelId);
|
const welcomeChannel = interaction.guild.channels.cache.get(welcomeChannelId);
|
||||||
if (welcomeChannel && welcomeChannel.isTextBased()) {
|
if (welcomeChannel && welcomeChannel.isTextBased()) {
|
||||||
const rawMessage = config.welcomeMessage || "Welcome to Aurora, {user}! You have been enrolled as a **{class}**.";
|
const rawMessage = welcomeMessage || "Welcome to Aurora, {user}! You have been enrolled as a **{class}**.";
|
||||||
|
|
||||||
const processedMessage = rawMessage
|
const processedMessage = rawMessage
|
||||||
.replace(/{user}/g, member.toString())
|
.replace(/{user}/g, member.toString())
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ class LootdropService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Trigger Terminal Update
|
// Trigger Terminal Update
|
||||||
terminalService.update();
|
terminalService.update(channel.guildId);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to spawn lootdrop:", error);
|
console.error("Failed to spawn lootdrop:", error);
|
||||||
@@ -153,7 +153,7 @@ class LootdropService {
|
|||||||
`Claimed lootdrop in channel ${drop.channelId}`
|
`Claimed lootdrop in channel ${drop.channelId}`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Trigger Terminal Update
|
// Trigger Terminal Update (uses primary guild from env)
|
||||||
terminalService.update();
|
terminalService.update();
|
||||||
|
|
||||||
return { success: true, amount: drop.rewardAmount, currency: drop.currency };
|
return { success: true, amount: drop.rewardAmount, currency: drop.currency };
|
||||||
|
|||||||
@@ -2,10 +2,14 @@ import { moderationCases } from "@db/schema";
|
|||||||
import { eq, and, desc } from "drizzle-orm";
|
import { eq, and, desc } from "drizzle-orm";
|
||||||
import { DrizzleClient } from "@shared/db/DrizzleClient";
|
import { DrizzleClient } from "@shared/db/DrizzleClient";
|
||||||
import type { CreateCaseOptions, ClearCaseOptions, SearchCasesFilter } from "@/modules/moderation/moderation.types";
|
import type { CreateCaseOptions, ClearCaseOptions, SearchCasesFilter } from "@/modules/moderation/moderation.types";
|
||||||
import { config } from "@shared/lib/config";
|
|
||||||
import { getUserWarningEmbed } from "@/modules/moderation/moderation.view";
|
import { getUserWarningEmbed } from "@/modules/moderation/moderation.view";
|
||||||
import { CaseType } from "@shared/lib/constants";
|
import { CaseType } from "@shared/lib/constants";
|
||||||
|
|
||||||
|
export interface ModerationConfig {
|
||||||
|
dmOnWarn?: boolean;
|
||||||
|
autoTimeoutThreshold?: number;
|
||||||
|
}
|
||||||
|
|
||||||
export class ModerationService {
|
export class ModerationService {
|
||||||
/**
|
/**
|
||||||
* Generate the next sequential case ID
|
* Generate the next sequential case ID
|
||||||
@@ -62,6 +66,7 @@ export class ModerationService {
|
|||||||
guildName?: string;
|
guildName?: string;
|
||||||
dmTarget?: { send: (options: any) => Promise<any> };
|
dmTarget?: { send: (options: any) => Promise<any> };
|
||||||
timeoutTarget?: { timeout: (duration: number, reason: string) => Promise<any> };
|
timeoutTarget?: { timeout: (duration: number, reason: string) => Promise<any> };
|
||||||
|
config?: ModerationConfig;
|
||||||
}) {
|
}) {
|
||||||
const moderationCase = await this.createCase({
|
const moderationCase = await this.createCase({
|
||||||
type: CaseType.WARN,
|
type: CaseType.WARN,
|
||||||
@@ -77,9 +82,10 @@ export class ModerationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const warningCount = await this.getActiveWarningCount(options.userId);
|
const warningCount = await this.getActiveWarningCount(options.userId);
|
||||||
|
const config = options.config ?? {};
|
||||||
|
|
||||||
// Try to DM the user if configured
|
// Try to DM the user if configured
|
||||||
if (config.moderation.cases.dmOnWarn && options.dmTarget) {
|
if (config.dmOnWarn !== false && options.dmTarget) {
|
||||||
try {
|
try {
|
||||||
await options.dmTarget.send({
|
await options.dmTarget.send({
|
||||||
embeds: [getUserWarningEmbed(
|
embeds: [getUserWarningEmbed(
|
||||||
@@ -96,8 +102,8 @@ export class ModerationService {
|
|||||||
|
|
||||||
// Check for auto-timeout threshold
|
// Check for auto-timeout threshold
|
||||||
let autoTimeoutIssued = false;
|
let autoTimeoutIssued = false;
|
||||||
if (config.moderation.cases.autoTimeoutThreshold &&
|
if (config.autoTimeoutThreshold &&
|
||||||
warningCount >= config.moderation.cases.autoTimeoutThreshold &&
|
warningCount >= config.autoTimeoutThreshold &&
|
||||||
options.timeoutTarget) {
|
options.timeoutTarget) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -12,24 +12,36 @@ import { AuroraClient } from "@/lib/BotClient";
|
|||||||
import { DrizzleClient } from "@shared/db/DrizzleClient";
|
import { DrizzleClient } from "@shared/db/DrizzleClient";
|
||||||
import { users, transactions, lootdrops, inventory } from "@db/schema";
|
import { users, transactions, lootdrops, inventory } from "@db/schema";
|
||||||
import { desc, sql } from "drizzle-orm";
|
import { desc, sql } from "drizzle-orm";
|
||||||
import { config, saveConfig } from "@shared/lib/config";
|
import { getGuildConfig, invalidateGuildConfigCache } from "@shared/lib/config";
|
||||||
|
import { guildSettingsService } from "@shared/modules/guild-settings/guild-settings.service";
|
||||||
|
import { env } from "@shared/lib/env";
|
||||||
|
|
||||||
// Color palette for containers (hex as decimal)
|
|
||||||
const COLORS = {
|
const COLORS = {
|
||||||
HEADER: 0x9B59B6, // Purple - mystical
|
HEADER: 0x9B59B6,
|
||||||
LEADERS: 0xF1C40F, // Gold - achievement
|
LEADERS: 0xF1C40F,
|
||||||
ACTIVITY: 0x3498DB, // Blue - activity
|
ACTIVITY: 0x3498DB,
|
||||||
ALERT: 0xE74C3C // Red - active events
|
ALERT: 0xE74C3C
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getPrimaryGuildId(): string | null {
|
||||||
|
return env.DISCORD_GUILD_ID ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
export const terminalService = {
|
export const terminalService = {
|
||||||
init: async (channel: TextChannel) => {
|
init: async (channel: TextChannel) => {
|
||||||
// Limit to one terminal for now
|
const guildId = channel.guildId;
|
||||||
if (config.terminal) {
|
if (!guildId) {
|
||||||
|
console.error("Cannot initialize terminal: no guild ID");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up old terminal if exists
|
||||||
|
const currentConfig = await getGuildConfig(guildId);
|
||||||
|
if (currentConfig.terminal?.channelId && currentConfig.terminal?.messageId) {
|
||||||
try {
|
try {
|
||||||
const oldChannel = await AuroraClient.channels.fetch(config.terminal.channelId) as TextChannel;
|
const oldChannel = await AuroraClient.channels.fetch(currentConfig.terminal.channelId).catch(() => null) as TextChannel | null;
|
||||||
if (oldChannel) {
|
if (oldChannel) {
|
||||||
const oldMsg = await oldChannel.messages.fetch(config.terminal.messageId);
|
const oldMsg = await oldChannel.messages.fetch(currentConfig.terminal.messageId).catch(() => null);
|
||||||
if (oldMsg) await oldMsg.delete();
|
if (oldMsg) await oldMsg.delete();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -39,25 +51,37 @@ export const terminalService = {
|
|||||||
|
|
||||||
const msg = await channel.send({ content: "🔄 Initializing Aurora Station..." });
|
const msg = await channel.send({ content: "🔄 Initializing Aurora Station..." });
|
||||||
|
|
||||||
config.terminal = {
|
// Save to database
|
||||||
channelId: channel.id,
|
await guildSettingsService.upsertSettings({
|
||||||
messageId: msg.id
|
guildId,
|
||||||
};
|
terminalChannelId: channel.id,
|
||||||
saveConfig(config);
|
terminalMessageId: msg.id,
|
||||||
|
});
|
||||||
|
invalidateGuildConfigCache(guildId);
|
||||||
|
|
||||||
await terminalService.update();
|
await terminalService.update(guildId);
|
||||||
},
|
},
|
||||||
|
|
||||||
update: async () => {
|
update: async (guildId?: string) => {
|
||||||
if (!config.terminal) return;
|
const effectiveGuildId = guildId ?? getPrimaryGuildId();
|
||||||
|
if (!effectiveGuildId) {
|
||||||
|
console.warn("No guild ID available for terminal update");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const guildConfig = await getGuildConfig(effectiveGuildId);
|
||||||
|
|
||||||
|
if (!guildConfig.terminal?.channelId || !guildConfig.terminal?.messageId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const channel = await AuroraClient.channels.fetch(config.terminal.channelId).catch(() => null) as TextChannel;
|
const channel = await AuroraClient.channels.fetch(guildConfig.terminal.channelId).catch(() => null) as TextChannel | null;
|
||||||
if (!channel) {
|
if (!channel) {
|
||||||
console.warn("Terminal channel not found");
|
console.warn("Terminal channel not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const message = await channel.messages.fetch(config.terminal.messageId).catch(() => null);
|
const message = await channel.messages.fetch(guildConfig.terminal.messageId).catch(() => null);
|
||||||
if (!message) {
|
if (!message) {
|
||||||
console.warn("Terminal message not found");
|
console.warn("Terminal message not found");
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user