import { createServerFn } from "@tanstack/react-start";
import { isTakenDown } from "~/lib/account-disable";
import { z } from "zod";
import { requireViewer, viewerMiddleware } from "./middleware";
import { first, run } from "~/server/db";
import { limitBrowse, limitAccountWrite } from "~/server/limits";
import { notFoundError } from "~/server/errors";
import { contributionGraph, contributionYears, privateModeFor } from "~/server/contributions";
import { contributionDayDetail } from "~/server/contribution-day";
const MAX_PAGE = 500;
const dayString = z.string().regex(/^\d{4}-\d{2}-\d{2}$/);
export const contributionsInput = z.object({
name: z.string().min(1).max(64),
year: z.number().int().min(1970).max(9999).nullable(),
day: dayString.nullable(),
repoPage: z.number().int().min(1).max(MAX_PAGE).default(1),
activityPage: z.number().int().min(1).max(MAX_PAGE).default(1),
});
/** The profile graph, its year list and (when a day is selected) that day's paginated details. */
export const getContributions = createServerFn({ method: "GET" })
.middleware([viewerMiddleware])
.validator(contributionsInput)
.handler(async ({ data, context }) => {
await limitBrowse(context.viewer);
const account = await first<{
id: string;
kind: string;
show: number | null;
disabled_at: number | null;
disabled_reason: string | null;
}>(
`SELECT a.id, a.kind, u.show_private_contributions AS show, a.disabled_at, a.disabled_reason
FROM accounts a LEFT JOIN users u ON u.account_id = a.id WHERE a.name = ?`,
data.name,
);
if (!account || (isTakenDown(account) && !context.viewer?.isAdmin)) throw notFoundError("Account not found");
if (account.kind !== "user") return null;