"use server"; import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { approve, deniedRedirect, disconnectApp, parseAuthorizeRequest } from "@/lib/oauth"; import { grantableRepoIds, viewerOrThrow } from "./guard"; import type { FormState } from "./types"; /** * The consent form on /oauth/authorize. The request is checked again here, since the parameters * come back from the browser. Either way, the user ends up back at the application. */ export async function authorizeAction(params: Record, _prev: FormState, formData: FormData): Promise { const viewer = await viewerOrThrow(); const parsed = await parseAuthorizeRequest(params); if ("fatal" in parsed) return { error: parsed.fatal }; if ("redirect" in parsed) redirect(parsed.redirect); const { request } = parsed; if (formData.get("decision") !== "allow") redirect(await deniedRedirect(request)); // The user may narrow what the application asked for, but not widen it. const permission = request.permission === "write" && formData.get("permission") !== "read" ? "write" : "read"; let repoIds: string[] | null = null; if (formData.get("scope") === "selected") { repoIds = await grantableRepoIds(viewer.id, formData.getAll("repos").map(String), permission); if (repoIds.length === 0) return { error: "Select at least one repository." }; } redirect(await approve(request, viewer.id, { permission, repoIds })); } export async function disconnectAppAction(grantId: string) { const viewer = await viewerOrThrow(); await disconnectApp(viewer.id, String(grantId)); revalidatePath("/settings/applications"); }