54 lines
2 KiB
TypeScript
54 lines
2 KiB
TypeScript
|
|
// /app/api/support/kofi/claim/verify/route.ts
|
||
|
|
import { NextRequest, NextResponse } from "next/server";
|
||
|
|
|
||
|
|
const DIRECTUS = (process.env.DIRECTUS_URL || "").replace(/\/$/, "");
|
||
|
|
const BOT_TOKEN = process.env.DIRECTUS_TOKEN_ADMIN_SUPPORTER!;
|
||
|
|
const COLLECTION = "user_memberships";
|
||
|
|
|
||
|
|
// Default redirects; can be overridden by env
|
||
|
|
const SUCCESS_REDIRECT = process.env.KOFI_LINK_SUCCESS_URL || "/portal/account?linked=kofi&ok=1";
|
||
|
|
const FAIL_REDIRECT = process.env.KOFI_LINK_FAIL_URL || "/portal/account?linked=kofi&error=1";
|
||
|
|
|
||
|
|
export async function GET(req: NextRequest) {
|
||
|
|
const token = req.nextUrl.searchParams.get("token") || "";
|
||
|
|
const to = (path: string) => NextResponse.redirect(new URL(path, req.url));
|
||
|
|
|
||
|
|
if (!token) return to(FAIL_REDIRECT);
|
||
|
|
|
||
|
|
// Find the claim row by token
|
||
|
|
const filter = encodeURIComponent(JSON.stringify({ claim_token: { _eq: token } }));
|
||
|
|
const res = await fetch(`${DIRECTUS}/items/${COLLECTION}?filter=${filter}&limit=1`, {
|
||
|
|
headers: { Authorization: `Bearer ${BOT_TOKEN}` },
|
||
|
|
cache: "no-store",
|
||
|
|
});
|
||
|
|
if (!res.ok) return to(FAIL_REDIRECT);
|
||
|
|
|
||
|
|
const json = await res.json().catch(() => ({} as any));
|
||
|
|
const rec = json?.data?.[0];
|
||
|
|
if (!rec) return to(FAIL_REDIRECT);
|
||
|
|
|
||
|
|
// Validate expiry and sanity
|
||
|
|
const exp = rec.claim_expires_at ? new Date(rec.claim_expires_at).getTime() : 0;
|
||
|
|
if (!exp || Date.now() > exp) return to(FAIL_REDIRECT);
|
||
|
|
if (!rec.claim_user_id) return to(FAIL_REDIRECT);
|
||
|
|
|
||
|
|
// Finalize: set app_user to claim_user_id; clear claim fields
|
||
|
|
const patch = await fetch(`${DIRECTUS}/items/${COLLECTION}/${rec.id}`, {
|
||
|
|
method: "PATCH",
|
||
|
|
headers: {
|
||
|
|
"Content-Type": "application/json",
|
||
|
|
Authorization: `Bearer ${BOT_TOKEN}`,
|
||
|
|
},
|
||
|
|
body: JSON.stringify({
|
||
|
|
app_user: rec.claim_user_id,
|
||
|
|
claim_token: null,
|
||
|
|
claim_expires_at: null,
|
||
|
|
claim_user_id: null,
|
||
|
|
last_event_at: new Date().toISOString(),
|
||
|
|
}),
|
||
|
|
});
|
||
|
|
|
||
|
|
if (!patch.ok) return to(FAIL_REDIRECT);
|
||
|
|
return to(SUCCESS_REDIRECT);
|
||
|
|
}
|