"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<string, string>, _prev: FormState, formData: FormData): Promise<FormState> {
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");
}