Files
DiscordClone/convex/serverSettings.ts
Bryan1029384756 593eaba82e 1.1.3
2026-04-18 15:41:51 -05:00

163 lines
4.6 KiB
TypeScript

import { query, mutation, internalMutation } from "./_generated/server";
import { v } from "convex/values";
import { getRolesForUser } from "./roles";
import { AUDIT_ACTIONS, logAudit } from "./audit";
export const get = query({
args: {},
returns: v.any(),
handler: async (ctx) => {
const settings = await ctx.db.query("serverSettings").first();
if (!settings) return null;
let iconUrl = null;
if (settings.iconStorageId) {
iconUrl = await ctx.storage.getUrl(settings.iconStorageId);
}
return { ...settings, iconUrl };
},
});
export const update = mutation({
args: {
userId: v.id("userProfiles"),
afkChannelId: v.optional(v.id("channels")),
afkTimeout: v.number(),
},
returns: v.null(),
handler: async (ctx, args) => {
// Permission check
const roles = await getRolesForUser(ctx, args.userId);
const canManage = roles.some(
(role) => (role.permissions as Record<string, boolean>)?.["manage_channels"]
);
if (!canManage) {
throw new Error("You don't have permission to manage server settings");
}
// Validate timeout range
if (args.afkTimeout < 60 || args.afkTimeout > 3600) {
throw new Error("AFK timeout must be between 60 and 3600 seconds");
}
// Validate AFK channel is a voice channel if provided
if (args.afkChannelId) {
const channel = await ctx.db.get(args.afkChannelId);
if (!channel) throw new Error("AFK channel not found");
if (channel.type !== "voice") throw new Error("AFK channel must be a voice channel");
}
const existing = await ctx.db.query("serverSettings").first();
if (existing) {
await ctx.db.patch(existing._id, {
afkChannelId: args.afkChannelId,
afkTimeout: args.afkTimeout,
});
} else {
await ctx.db.insert("serverSettings", {
afkChannelId: args.afkChannelId,
afkTimeout: args.afkTimeout,
});
}
await logAudit(ctx, {
actorId: args.userId,
action: AUDIT_ACTIONS.SERVER_SETTINGS_UPDATE,
targetType: "server",
metadata: { afkChannelId: args.afkChannelId, afkTimeout: args.afkTimeout },
});
return null;
},
});
export const updateName = mutation({
args: {
userId: v.id("userProfiles"),
serverName: v.string(),
},
returns: v.null(),
handler: async (ctx, args) => {
// Permission check
const roles = await getRolesForUser(ctx, args.userId);
const canManage = roles.some(
(role) => (role.permissions as Record<string, boolean>)?.["manage_channels"]
);
if (!canManage) {
throw new Error("You don't have permission to manage server settings");
}
// Validate name
const name = args.serverName.trim();
if (name.length === 0 || name.length > 100) {
throw new Error("Server name must be between 1 and 100 characters");
}
const existing = await ctx.db.query("serverSettings").first();
const oldName = existing?.serverName;
if (existing) {
await ctx.db.patch(existing._id, { serverName: name });
} else {
await ctx.db.insert("serverSettings", {
serverName: name,
afkTimeout: 300,
});
}
if (oldName !== name) {
await logAudit(ctx, {
actorId: args.userId,
action: AUDIT_ACTIONS.SERVER_SETTINGS_UPDATE,
targetType: "server",
targetName: name,
metadata: { field: "serverName", from: oldName, to: name },
});
}
return null;
},
});
export const updateIcon = mutation({
args: {
userId: v.id("userProfiles"),
iconStorageId: v.optional(v.id("_storage")),
},
returns: v.null(),
handler: async (ctx, args) => {
// Permission check
const roles = await getRolesForUser(ctx, args.userId);
const canManage = roles.some(
(role) => (role.permissions as Record<string, boolean>)?.["manage_channels"]
);
if (!canManage) {
throw new Error("You don't have permission to manage server settings");
}
const existing = await ctx.db.query("serverSettings").first();
if (existing) {
await ctx.db.patch(existing._id, {
iconStorageId: args.iconStorageId,
});
} else {
await ctx.db.insert("serverSettings", {
iconStorageId: args.iconStorageId,
afkTimeout: 300,
});
}
return null;
},
});
export const clearAfkChannel = internalMutation({
args: { channelId: v.id("channels") },
returns: v.null(),
handler: async (ctx, args) => {
const settings = await ctx.db.query("serverSettings").first();
if (settings && settings.afkChannelId === args.channelId) {
await ctx.db.patch(settings._id, { afkChannelId: undefined });
}
return null;
},
});