"use server"; import config from "@payload-config"; import { isPayloadUser } from "@/utils/access-control/isPayloadUser"; import { getPayload } from "payload"; import type { User, WikiPage } from "@/payload-types"; import { hasIntelligenceQualification } from "@/utils/access-control/hasIntelligenceQualification"; import { emitGameEvent } from "@/utils/event-log/emit"; import { EventTypes } from "@/utils/event-log/eventTypes"; import { createPage, deletePage, restoreRevision, setPageLockdown as setPageLockdownService, updatePage, } from "@/lib/wiki/service"; interface ActionResult { success: boolean; error?: string; data?: T; } async function authenticate() { const payloadConfig = await config; const payload = await getPayload({ config: payloadConfig }); const { headers } = await import("next/headers"); const hdrs = await headers(); const { user } = await payload.auth({ headers: hdrs, canSetHeaders: false, }); if (!isPayloadUser(user)) { throw new Error("Unauthorized"); } return { payload, user }; } async function fetchPage( payload: Awaited>, id: number, ): Promise { try { return (await payload.findByID({ collection: "wiki-pages", id, depth: 0, overrideAccess: true, })) as unknown as WikiPage; } catch { return null; } } async function isWikiModerator( payload: Awaited>, user: User, ): Promise { return hasIntelligenceQualification(payload, user); } export async function createWikiPage(input: { title: string; category: string; tags?: string[]; body: string; summary?: string; }): Promise> { try { const { payload, user } = await authenticate(); const page = await createPage(payload, user, input); await emitGameEvent(payload, { type: EventTypes.WikiPageCreate, message: `${user.displayName ?? user.username} created wiki page "${input.title}"`, actor: user.id, targetCollection: "wiki-pages", targetId: page.id, data: { slug: page.slug }, }); return { success: true, data: { id: page.id, slug: page.slug } }; } catch (error) { const message = error instanceof Error ? error.message : "Unknown error"; if (message === "Unauthorized") { return { success: false, error: "You must be logged in." }; } return { success: false, error: message }; } } export async function updateWikiPage(input: { id: number; title?: string; body?: string; category?: string; tags?: string[]; summary?: string; }): Promise> { try { const { payload, user } = await authenticate(); const page = await fetchPage(payload, input.id); if (!page) return { success: false, error: "Wiki page not found." }; const updated = await updatePage(payload, user, page, input); await emitGameEvent(payload, { type: EventTypes.WikiPageEdit, message: `${user.displayName ?? user.username} edited wiki page "${updated.title}"`, actor: user.id, targetCollection: "wiki-pages", targetId: updated.id, data: { slug: updated.slug }, }); return { success: true, data: { id: updated.id, slug: updated.slug } }; } catch (error) { const message = error instanceof Error ? error.message : "Unknown error"; if (message === "Unauthorized") { return { success: false, error: "You must be logged in." }; } return { success: false, error: message }; } } export async function restoreWikiRevision(input: { id: number; revisionNumber: number; }): Promise> { try { const { payload, user } = await authenticate(); if (!(await isWikiModerator(payload, user))) { return { success: false, error: "You need intelligence division clearance to restore wiki pages.", }; } const page = await fetchPage(payload, input.id); if (!page) return { success: false, error: "Wiki page not found." }; const updated = await restoreRevision(payload, user, page, input.revisionNumber); await emitGameEvent(payload, { type: EventTypes.WikiPageRestore, message: `${user.displayName ?? user.username} restored wiki page "${updated.title}" to revision ${input.revisionNumber}`, actor: user.id, targetCollection: "wiki-pages", targetId: updated.id, data: { slug: updated.slug, revisionNumber: input.revisionNumber }, }); return { success: true, data: { id: updated.id, slug: updated.slug } }; } catch (error) { const message = error instanceof Error ? error.message : "Unknown error"; if (message === "Unauthorized") { return { success: false, error: "You must be logged in." }; } return { success: false, error: message }; } } export async function setPageLockdown(input: { id: number; lockdown: boolean; }): Promise> { try { const { payload, user } = await authenticate(); if (!(await isWikiModerator(payload, user))) { return { success: false, error: "You need intelligence division clearance to lock wiki pages.", }; } const page = await fetchPage(payload, input.id); if (!page) return { success: false, error: "Wiki page not found." }; const updated = await setPageLockdownService(payload, user, page, input.lockdown); await emitGameEvent(payload, { type: input.lockdown ? EventTypes.WikiPageLock : EventTypes.WikiPageUnlock, message: `${user.displayName ?? user.username} ${input.lockdown ? "locked" : "unlocked"} wiki page "${updated.title}"`, actor: user.id, targetCollection: "wiki-pages", targetId: updated.id, data: { slug: updated.slug, lockdown: input.lockdown }, }); return { success: true, data: { id: updated.id, slug: updated.slug, lockdown: input.lockdown }, }; } catch (error) { const message = error instanceof Error ? error.message : "Unknown error"; if (message === "Unauthorized") { return { success: false, error: "You must be logged in." }; } return { success: false, error: message }; } } export async function deleteWikiPage(input: { id: number }): Promise> { try { const { payload, user } = await authenticate(); if (!(await isWikiModerator(payload, user))) { return { success: false, error: "You need intelligence division clearance to delete wiki pages.", }; } const page = await fetchPage(payload, input.id); if (!page) return { success: false, error: "Wiki page not found." }; await deletePage(payload, user, page); await emitGameEvent(payload, { type: EventTypes.WikiPageDelete, message: `${user.displayName ?? user.username} deleted wiki page "${page.title}"`, actor: user.id, targetCollection: "wiki-pages", targetId: page.id, data: { slug: page.slug }, }); return { success: true, data: { ok: true } }; } catch (error) { const message = error instanceof Error ? error.message : "Unknown error"; if (message === "Unauthorized") { return { success: false, error: "You must be logged in." }; } return { success: false, error: message }; } } export async function uploadWikiImage( formData: FormData, ): Promise> { try { const { payload } = await authenticate(); const file = formData.get("file"); if (!(file instanceof File)) { return { success: false, error: "No image file provided." }; } if (!file.type.startsWith("image/")) { return { success: false, error: "Only image files can be uploaded." }; } if (file.size > 8 * 1024 * 1024) { return { success: false, error: "Images must be 8 MB or smaller." }; } const alt = file.name .replace(/\.[^/.]+$/, "") .replace(/[^a-zA-Z0-9 _-]/g, "") .trim() || "Image"; const doc = await payload.create({ collection: "media", data: { alt }, file: { data: Buffer.from(await file.arrayBuffer()), mimetype: file.type, name: file.name, size: file.size, }, overrideAccess: true, }); if (!doc.filename) { return { success: false, error: "Upload failed: no file was stored." }; } return { success: true, data: { url: doc.url ?? `/api/media/file/${doc.filename}`, filename: doc.filename, alt }, }; } catch (error) { const message = error instanceof Error ? error.message : "Unknown error"; if (message === "Unauthorized") { return { success: false, error: "You must be logged in." }; } return { success: false, error: message }; } }