Files
Epicnabbo-Catalogus-Updated…/src/actions/admin-guilds.ts
T
openhands 30c95b1a5c feat: comprehensive CMS improvements
- Fix DOMPurify SSR crash (use isomorphic-dompurify)
- Fix SanitizedHtml to sanitize by default
- Add auth guards to studio/catalog maintenance pages
- Add update/edit to vouchers CRUD
- Add update/edit to rare-values CRUD
- Add approve workflow to applications page
- Add edit form to guilds detail page
- Add SEO metadata to all public pages (21 pages)
- Fix mobile nav accessibility (focus trap, aria attributes)
- Fix missing labels and table accessibility
- Add dynamic imports for heavy client components (6 components)
- Fix silent error swallowing (40+ locations)
- Add content scheduling for articles (publishAt, status)
- Wire up 12 missing webhook notification triggers
- Add global search to admin panel
- Add bulk actions to admin users table
- Fix JSON formatting and a11y issues
2026-09-03 16:00:32 +02:00

113 lines
3.0 KiB
TypeScript

"use server";
import { eq, inArray } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import {
requirePermission,
requirePermissionRateLimited,
} from "@/lib/admin/guard";
import {
db,
GuildForumViews,
Guilds,
GuildsForumsComments,
GuildsForumsThreads,
GuildsMembers,
Items,
Rooms,
} from "@/lib/db";
import { PERMS } from "@/lib/permissions";
import { logStaffActivity } from "@/lib/services/staff-activity";
/** Disband a guild and clean related membership/forum rows. */
export async function disbandGuild(formData: FormData): Promise<void> {
const staff = await requirePermissionRateLimited(PERMS.USERS_EDIT);
const id = Number(formData.get("id"));
if (!(id > 0)) return;
const [guild] = await db
.select({
id: Guilds.id,
name: Guilds.name,
userId: Guilds.userId,
})
.from(Guilds)
.where(eq(Guilds.id, id))
.limit(1);
if (!guild) return;
await db.transaction(async (tx) => {
const threads = await tx
.select({ id: GuildsForumsThreads.id })
.from(GuildsForumsThreads)
.where(eq(GuildsForumsThreads.guildId, id));
const threadIds = threads.map((t) => t.id);
if (threadIds.length > 0) {
await tx
.delete(GuildsForumsComments)
.where(inArray(GuildsForumsComments.threadId, threadIds));
await tx
.delete(GuildsForumsThreads)
.where(eq(GuildsForumsThreads.guildId, id));
}
await tx.delete(GuildForumViews).where(eq(GuildForumViews.guildId, id));
await tx.delete(GuildsMembers).where(eq(GuildsMembers.guildId, id));
await tx.update(Rooms).set({ guildId: 0 }).where(eq(Rooms.guildId, id));
await tx.update(Items).set({ guildId: 0 }).where(eq(Items.guildId, id));
await tx.delete(Guilds).where(eq(Guilds.id, id));
});
await logStaffActivity({
staffId: staff.id,
action: "guild_disband",
description: `Disbanded guild #${id} (${guild.name}), owner #${guild.userId}`,
targetType: "guild",
targetId: id,
});
revalidatePath("/admin/guilds");
}
export async function updateGuild(formData: FormData): Promise<void> {
const staff = await requirePermission(PERMS.USERS_EDIT);
const id = Number(formData.get("id"));
if (!(id > 0)) return;
const name = String(formData.get("name") ?? "")
.trim()
.slice(0, 50);
const description = String(formData.get("description") ?? "")
.trim()
.slice(0, 250);
const state = Number(formData.get("state"));
const forum = String(formData.get("forum") ?? "0");
const readForum = String(formData.get("readForum") ?? "EVERYONE");
const postMessages = String(formData.get("postMessages") ?? "EVERYONE");
const postThreads = String(formData.get("postThreads") ?? "EVERYONE");
const modForum = String(formData.get("modForum") ?? "ADMINS");
await db
.update(Guilds)
.set({
name,
description,
state,
forum,
readForum,
postMessages,
postThreads,
modForum,
})
.where(eq(Guilds.id, id));
await logStaffActivity({
staffId: staff.id,
action: "guild_update",
description: `Updated guild #${id}`,
targetType: "guild",
targetId: id,
});
revalidatePath("/admin/guilds");
revalidatePath(`/admin/guilds/${id}`);
}