| 1 | import { data } from "react-router"; |
| 2 | |
| 3 | import type { Route } from "./+types/ref"; |
| 4 | import { work } from "../../../lib/services.server"; |
| 5 | import { requireUser, roleIn } from "../../../lib/session.server"; |
| 6 | |
| 7 | /** What a reference chip's card shows (components/chat/ref-chip.tsx): an issue or pull request, as the viewer may see it. */ |
| 8 | export type RefCard = { kind: "issue" | "pull"; repo: string; number: number; title: string; state: string }; |
| 9 | |
| 10 | /** |
| 11 | * `-/chat/ref?repo=<namespace>/<name>&number=<n>`: the card that opens over |
| 12 | * an `owner/repo#12` chip in chat and in g1t's answers. Issues and pull |
| 13 | * requests share numbers: the issue if there is one, else the pull |
| 14 | * request. Only what the viewer may read; anything else is not found. |
| 15 | * Kept a minute by the browser. |
| 16 | */ |
| 17 | export async function loader({ params, context, request }: Route.LoaderArgs) { |
| 18 | const viewer = requireUser(context, request); |
| 19 | if (!roleIn(viewer, params.owner)) throw data(null, { status: 404 }); |
| 20 | const url = new URL(request.url); |
| 21 | const [namespace, name] = (url.searchParams.get("repo") ?? "").split("/"); |
| 22 | const number = Number(url.searchParams.get("number")); |
| 23 | const headers = { "cache-control": "private, max-age=60", vary: "Cookie" }; |
| 24 | if (!namespace || !name || !Number.isInteger(number) || number < 1) return Response.json({ error: "not_found" }, { status: 404, headers }); |
| 25 | const repo = { namespace: namespace.toLowerCase(), name }; |
| 26 | const issue = await work.getIssue(repo, number, viewer).catch(() => null); |
| 27 | let card: RefCard | null = issue?.ok |
| 28 | ? { kind: "issue", repo: `${repo.namespace}/${repo.name}`, number, title: issue.value.issue.title, state: String(issue.value.issue.state) } |
| 29 | : null; |
| 30 | if (!card) { |
| 31 | const pull = await work.getPull(repo, number, viewer).catch(() => null); |
| 32 | if (pull?.ok) card = { kind: "pull", repo: `${repo.namespace}/${repo.name}`, number, title: pull.value.pull.title, state: pull.value.pull.status }; |
| 33 | } |
| 34 | if (!card) return Response.json({ error: "not_found" }, { status: 404, headers }); |
| 35 | return Response.json(card, { headers }); |
| 36 | } |