import "server-only"; import { createHash, randomBytes } from "node:crypto"; import { admin } from "@/lib/supabase"; const clean = (value: unknown) => String(value ?? "") .replace(/[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/gu, " ") .slice(0, 80); export type ModeratorApplicationResult = | { ok: true; url: string } | { ok: false; message: string }; /** * Creates a moderator application for a confirmed platform identity (Telegram * or Discord user verified by the caller). The applicant still has to open the * returned link while signed in to the matching MineGeo account. */ export async function createModeratorApplication(input: { platform: "telegram" | "discord"; platformUserId: string; platformUsername?: string | undefined; requestedUsername: string; origin: string; }): Promise { const username = input.requestedUsername.trim().toLowerCase(); if (!/^[a-z0-9_]{3,32}$/.test(username)) return { ok: false, message: "Use your MineGeo username (3–32 letters, numbers or underscores). Set it in MineGeo settings first.", }; const database = admin(); const { data: allowed, error: rateError } = await database.rpc("check_rate", { p_key: `mod-apply:${input.platform}:${input.platformUserId}`, p_limit: 5, p_seconds: 3600, }); if (rateError || !allowed) return { ok: false, message: "Too many attempts. Try again later." }; const { data: profile, error } = await database .from("profiles") .select("id,role,account_status") .eq("username", username) .maybeSingle(); if (error) return { ok: false, message: "MineGeo is unavailable. Try again later." }; if (!profile || profile.account_status !== "active") return { ok: false, message: "MineGeo username not found. Check the username in your account settings.", }; if (profile.role !== "contributor") return { ok: false, message: "This account already has staff permissions." }; const { data: existing } = await database .from("moderator_applications") .select("id") .eq("platform", input.platform) .eq("platform_user_id", input.platformUserId) .eq("status", "pending") .limit(1); if (existing?.length) return { ok: false, message: "You already have an application waiting for review." }; const token = randomBytes(32).toString("hex"); const hash = createHash("sha256").update(token).digest("hex"); const insert = await database.from("moderator_applications").insert({ platform: input.platform, platform_user_id: input.platformUserId, platform_username: clean(input.platformUsername), requested_username: username, confirmation_hash: hash, }); if (insert.error) { console.error("Moderator application insert failed", insert.error); return { ok: false, message: "MineGeo is unavailable. Try again later." }; } return { ok: true, url: `${new URL(input.origin).origin}/moderator-application/${token}`, }; }