Add Telegram moderator application mini app
Some checks failed
Deploy MineGeo to Dokploy / deploy (push) Failing after 1m41s

This commit is contained in:
2026-11-01 10:21:05 +00:00
parent 05854818a0
commit 3afad02686
11 changed files with 753 additions and 17 deletions

View File

@@ -0,0 +1,80 @@
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<ModeratorApplicationResult> {
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}`,
};
}