forked from syntaxbullet/aurorabot
Implement service for managing per-guild configuration with methods for getting, upserting, updating, and deleting settings. Includes helpers for color role management.
159 lines
6.4 KiB
TypeScript
159 lines
6.4 KiB
TypeScript
import { eq } from "drizzle-orm";
|
|
import { guildSettings } from "@db/schema";
|
|
import { DrizzleClient } from "@shared/db/DrizzleClient";
|
|
import { UserError } from "@shared/lib/errors";
|
|
|
|
export interface GuildSettingsData {
|
|
guildId: string;
|
|
studentRoleId?: string;
|
|
visitorRoleId?: string;
|
|
colorRoleIds?: string[];
|
|
welcomeChannelId?: string;
|
|
welcomeMessage?: string;
|
|
feedbackChannelId?: string;
|
|
terminalChannelId?: string;
|
|
terminalMessageId?: string;
|
|
moderationLogChannelId?: string;
|
|
moderationDmOnWarn?: boolean;
|
|
moderationAutoTimeoutThreshold?: number;
|
|
featureOverrides?: Record<string, boolean>;
|
|
}
|
|
|
|
export const guildSettingsService = {
|
|
getSettings: async (guildId: string): Promise<GuildSettingsData | null> => {
|
|
const settings = await DrizzleClient.query.guildSettings.findFirst({
|
|
where: eq(guildSettings.guildId, BigInt(guildId)),
|
|
});
|
|
|
|
if (!settings) return null;
|
|
|
|
return {
|
|
guildId: settings.guildId.toString(),
|
|
studentRoleId: settings.studentRoleId?.toString(),
|
|
visitorRoleId: settings.visitorRoleId?.toString(),
|
|
colorRoleIds: settings.colorRoleIds ?? [],
|
|
welcomeChannelId: settings.welcomeChannelId?.toString(),
|
|
welcomeMessage: settings.welcomeMessage ?? undefined,
|
|
feedbackChannelId: settings.feedbackChannelId?.toString(),
|
|
terminalChannelId: settings.terminalChannelId?.toString(),
|
|
terminalMessageId: settings.terminalMessageId?.toString(),
|
|
moderationLogChannelId: settings.moderationLogChannelId?.toString(),
|
|
moderationDmOnWarn: settings.moderationDmOnWarn ?? true,
|
|
moderationAutoTimeoutThreshold: settings.moderationAutoTimeoutThreshold ?? undefined,
|
|
featureOverrides: settings.featureOverrides ?? {},
|
|
};
|
|
},
|
|
|
|
upsertSettings: async (data: Partial<GuildSettingsData> & { guildId: string }) => {
|
|
const values: typeof guildSettings.$inferInsert = {
|
|
guildId: BigInt(data.guildId),
|
|
studentRoleId: data.studentRoleId ? BigInt(data.studentRoleId) : null,
|
|
visitorRoleId: data.visitorRoleId ? BigInt(data.visitorRoleId) : null,
|
|
colorRoleIds: data.colorRoleIds ?? [],
|
|
welcomeChannelId: data.welcomeChannelId ? BigInt(data.welcomeChannelId) : null,
|
|
welcomeMessage: data.welcomeMessage ?? null,
|
|
feedbackChannelId: data.feedbackChannelId ? BigInt(data.feedbackChannelId) : null,
|
|
terminalChannelId: data.terminalChannelId ? BigInt(data.terminalChannelId) : null,
|
|
terminalMessageId: data.terminalMessageId ? BigInt(data.terminalMessageId) : null,
|
|
moderationLogChannelId: data.moderationLogChannelId ? BigInt(data.moderationLogChannelId) : null,
|
|
moderationDmOnWarn: data.moderationDmOnWarn ?? true,
|
|
moderationAutoTimeoutThreshold: data.moderationAutoTimeoutThreshold ?? null,
|
|
featureOverrides: data.featureOverrides ?? {},
|
|
updatedAt: new Date(),
|
|
};
|
|
|
|
const [result] = await DrizzleClient.insert(guildSettings)
|
|
.values(values)
|
|
.onConflictDoUpdate({
|
|
target: guildSettings.guildId,
|
|
set: values,
|
|
})
|
|
.returning();
|
|
|
|
return result;
|
|
},
|
|
|
|
updateSetting: async (
|
|
guildId: string,
|
|
key: string,
|
|
value: string | string[] | boolean | number | Record<string, boolean> | null
|
|
) => {
|
|
const keyMap: Record<string, keyof typeof guildSettings.$inferSelect> = {
|
|
studentRole: "studentRoleId",
|
|
visitorRole: "visitorRoleId",
|
|
colorRoles: "colorRoleIds",
|
|
welcomeChannel: "welcomeChannelId",
|
|
welcomeMessage: "welcomeMessage",
|
|
feedbackChannel: "feedbackChannelId",
|
|
terminalChannel: "terminalChannelId",
|
|
terminalMessage: "terminalMessageId",
|
|
moderationLogChannel: "moderationLogChannelId",
|
|
moderationDmOnWarn: "moderationDmOnWarn",
|
|
moderationAutoTimeoutThreshold: "moderationAutoTimeoutThreshold",
|
|
featureOverrides: "featureOverrides",
|
|
};
|
|
|
|
const column = keyMap[key];
|
|
if (!column) {
|
|
throw new UserError(`Unknown setting: ${key}`);
|
|
}
|
|
|
|
const updates: Record<string, unknown> = { updatedAt: new Date() };
|
|
|
|
if (column === "colorRoleIds" && Array.isArray(value)) {
|
|
updates[column] = value;
|
|
} else if (column === "featureOverrides" && typeof value === "object" && value !== null) {
|
|
updates[column] = value;
|
|
} else if (column === "moderationDmOnWarn" && typeof value === "boolean") {
|
|
updates[column] = value;
|
|
} else if (column === "moderationAutoTimeoutThreshold" && typeof value === "number") {
|
|
updates[column] = value;
|
|
} else if (typeof value === "string") {
|
|
updates[column] = BigInt(value);
|
|
} else if (value === null) {
|
|
updates[column] = null;
|
|
} else {
|
|
updates[column] = value;
|
|
}
|
|
|
|
const [result] = await DrizzleClient.update(guildSettings)
|
|
.set(updates)
|
|
.where(eq(guildSettings.guildId, BigInt(guildId)))
|
|
.returning();
|
|
|
|
if (!result) {
|
|
throw new UserError(`No settings found for guild ${guildId}. Use /settings set to create settings first.`);
|
|
}
|
|
|
|
return result;
|
|
},
|
|
|
|
deleteSettings: async (guildId: string) => {
|
|
const [result] = await DrizzleClient.delete(guildSettings)
|
|
.where(eq(guildSettings.guildId, BigInt(guildId)))
|
|
.returning();
|
|
|
|
return result;
|
|
},
|
|
|
|
addColorRole: async (guildId: string, roleId: string) => {
|
|
const settings = await guildSettingsService.getSettings(guildId);
|
|
const colorRoleIds = settings?.colorRoleIds ?? [];
|
|
|
|
if (colorRoleIds.includes(roleId)) {
|
|
return settings;
|
|
}
|
|
|
|
colorRoleIds.push(roleId);
|
|
return await guildSettingsService.upsertSettings({ guildId, colorRoleIds });
|
|
},
|
|
|
|
removeColorRole: async (guildId: string, roleId: string) => {
|
|
const settings = await guildSettingsService.getSettings(guildId);
|
|
if (!settings) return null;
|
|
|
|
const colorRoleIds = (settings.colorRoleIds ?? []).filter(id => id !== roleId);
|
|
return await guildSettingsService.upsertSettings({ guildId, colorRoleIds });
|
|
},
|
|
};
|