import { forbidden } from "./errors";
import { canAdministerAccount, canCreateInAccount, hasPermission, repoPermission } from "./repos";
import type { RepoRow, Viewer } from "~/lib/types";
/**
* Who may fork `source` into `target` (GIT-A8 / AZ-A7). Public repositories fork like before. A private
* repository is only forkable by writers, or by readers when its owner enabled `allow_forking`; and the
* copy may only land in the forker's own account or in an organization they administer, so no plain org
* member can hand a private history to every member of an unrelated org.
*/
export async function assertCanFork(source: RepoRow, target: { id: string }, viewer: Viewer): Promise<void> {
if (!(await canCreateInAccount(target.id, viewer))) throw forbidden("You cannot create repositories here");
if (source.visibility === "public") return;
const permission = await repoPermission(source, viewer);
if (!hasPermission(permission, "write") && !(source.allow_forking === 1 && hasPermission(permission, "read"))) {
throw forbidden("Forking this private repository is not allowed");
}
if (target.id !== viewer.id && !(await canAdministerAccount(target.id, viewer))) {
throw forbidden("Private repositories can only be forked into your account or an organization you administer");
}
}
/**
* Who may move `repo` into `target` (authz-P1/P2). Transfers need admin on the current owner (a
* collaborator's repo-level admin is not enough to give the repository away) and on the target, since a
* plain org member landing a repository in an org hands it to every member. The admin requirement on the
* target also satisfies the private-fork placement rule of `assertCanFork`.
*/
export async function assertCanTransfer(
repo: Pick<RepoRow, "owner_id">,
target: { id: string },
viewer: Viewer,
): Promise<void> {
if (!(await canAdministerAccount(repo.owner_id, viewer))) {
throw forbidden("Only the owner can transfer this repository");
}
if (!(await canAdministerAccount(target.id, viewer))) {
throw forbidden("Repositories can only be transferred to your account or an organization you administer");
}
}