import { first } from "../db";
import { forbidden, notFoundError } from "../errors";
import { assertNotArchived, canAdministerAccount, requireRepoAccess } from "../repos";
import type { Viewer } from "~/lib/types";
export type ScopeRef = { owner: string; repo: string | null };
export type ResolvedScope = { scopeType: "repo" | "org"; scopeId: string; label: string; settingsPath: string };
/**
* Repo integrations need repo admin; org integrations need org ownership. `write` additionally refuses archived
* repositories; reads and removals pass `"read"`.
*/
export async function requireIntegrationScope(
ref: ScopeRef,
viewer: Viewer | null,
mode: "read" | "write" = "write",
): Promise<ResolvedScope> {
if (!viewer) throw forbidden("Sign in to manage integrations");
if (ref.repo) {
const { repo } = await requireRepoAccess(ref.owner, ref.repo, viewer, "admin");
if (mode === "write") assertNotArchived(repo);
return {
scopeType: "repo",
scopeId: repo.id,
label: `${repo.owner_name}/${repo.name}`,
settingsPath: `/${repo.owner_name}/${repo.name}/settings/integrations`,
};
}
const org = await first<{ id: string; name: string }>(
"SELECT id, name FROM accounts WHERE name = ? AND kind = 'org'",
ref.owner,
);
if (!org) throw notFoundError("Organization not found");
if (!(await canAdministerAccount(org.id, viewer))) throw forbidden();
return { scopeType: "org", scopeId: org.id, label: org.name, settingsPath: `/orgs/${org.name}/integrations` };
}