Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/app/api/cv/analyze/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { NextResponse } from "next/server";
import { getAccessToken } from "@/lib/get-session-token";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { supabaseAdmin } from "@/lib/supabase";
Expand All @@ -25,6 +26,7 @@ export async function POST() {
try {
/* ── 1. Auth ─────────────────────────────────────────────── */
const session = await getServerSession(authOptions);
const accessToken = await getAccessToken();

if (!session?.githubId) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
Expand Down Expand Up @@ -83,7 +85,7 @@ export async function POST() {
);

const contributionData = await fetchContributionData(
session.accessToken as string,
accessToken as string,
session.githubId
);

Expand Down
30 changes: 16 additions & 14 deletions src/app/api/goals/sync/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { getServerSession } from "next-auth";
import { getAccessToken } from "@/lib/get-session-token";
import { authOptions } from "@/lib/auth";
import { supabaseAdmin } from "@/lib/supabase";
import { extractValidRepoFromGoal, type ActivityGoal } from "@/lib/goals-sync-utils";
Expand Down Expand Up @@ -36,15 +37,16 @@ const GITHUB_API = "https://api.github.com";

export async function POST() {
const session = await getServerSession(authOptions);
if (!session?.accessToken || !session.githubId || !session.githubLogin) {
const accessToken = await getAccessToken();
if (!accessToken || !session?.githubId || !session?.githubLogin) {
return Response.json({ error: "Unauthorized" }, { status: 401 });
}

// ── 1. Fetch user from DB ─────────────────────────────────────────────────
const { data: user } = await supabaseAdmin
.from("users")
.select("id")
.eq("github_id", session.githubId)
.eq("github_id", session?.githubId)
.single();

if (!user) return Response.json({ error: "User not found" }, { status: 404 });
Expand Down Expand Up @@ -97,7 +99,7 @@ export async function POST() {
// Build the GitHub Search query using URLSearchParams so that the
// combined qualifier string is URL-encoded as a single atomic value
// and cannot be split by embedded special characters.
const qParts = [`author:${session.githubLogin}`];
const qParts = [`author:${session?.githubLogin}`];
if (repo) qParts.push(`repo:${repo}`);
qParts.push(`author-date:${weekStart}..${weekEnd}`);

Expand All @@ -111,7 +113,7 @@ export async function POST() {
`${GITHUB_API}/search/commits?${commitSearchParams.toString()}`,
{
headers: {
Authorization: `Bearer ${session.accessToken}`,
Authorization: `Bearer ${accessToken}`,
Accept: "application/vnd.github+json",
},
cache: "no-store",
Expand Down Expand Up @@ -169,15 +171,15 @@ export async function POST() {
// Count PRs for the current week
if (prGoalsToUpdate.length > 0) {
const prSearchParams = new URLSearchParams({
q: `author:${session.githubLogin} type:pr is:merged merged:${weekStart}..${weekEnd}`,
q: `author:${session?.githubLogin} type:pr is:merged merged:${weekStart}..${weekEnd}`,
per_page: "100",
});

const prRes = await fetch(
`${GITHUB_API}/search/issues?${prSearchParams.toString()}`,
{
headers: {
Authorization: `Bearer ${session.accessToken}`,
Authorization: `Bearer ${accessToken}`,
Accept: "application/vnd.github+json",
},
cache: "no-store",
Expand Down Expand Up @@ -216,9 +218,9 @@ export async function POST() {
// ── Reviews sync ──────────────────────────────────────────────────────────
if (reviewGoals.length > 0) {
const reviewRes = await fetch(
`${GITHUB_API}/search/issues?q=reviewed-by:${session.githubLogin}+type:pr+updated:${weekStart}..${weekEnd}&per_page=1`,
`${GITHUB_API}/search/issues?q=reviewed-by:${session?.githubLogin}+type:pr+updated:${weekStart}..${weekEnd}&per_page=1`,
{
headers: { Authorization: `Bearer ${session.accessToken}`, Accept: "application/vnd.github+json" },
headers: { Authorization: `Bearer ${accessToken}`, Accept: "application/vnd.github+json" },
cache: "no-store",
}
);
Expand All @@ -232,9 +234,9 @@ export async function POST() {
// ── Issues closed sync ────────────────────────────────────────────────────
if (issuesClosedGoals.length > 0) {
const icRes = await fetch(
`${GITHUB_API}/search/issues?q=assignee:${session.githubLogin}+type:issue+state:closed+closed:${weekStart}..${weekEnd}&per_page=1`,
`${GITHUB_API}/search/issues?q=assignee:${session?.githubLogin}+type:issue+state:closed+closed:${weekStart}..${weekEnd}&per_page=1`,
{
headers: { Authorization: `Bearer ${session.accessToken}`, Accept: "application/vnd.github+json" },
headers: { Authorization: `Bearer ${accessToken}`, Accept: "application/vnd.github+json" },
cache: "no-store",
}
);
Expand All @@ -248,9 +250,9 @@ export async function POST() {
// ── Issues opened sync ────────────────────────────────────────────────────
if (issuesOpenedGoals.length > 0) {
const ioRes = await fetch(
`${GITHUB_API}/search/issues?q=author:${session.githubLogin}+type:issue+created:${weekStart}..${weekEnd}&per_page=1`,
`${GITHUB_API}/search/issues?q=author:${session?.githubLogin}+type:issue+created:${weekStart}..${weekEnd}&per_page=1`,
{
headers: { Authorization: `Bearer ${session.accessToken}`, Accept: "application/vnd.github+json" },
headers: { Authorization: `Bearer ${accessToken}`, Accept: "application/vnd.github+json" },
cache: "no-store",
}
);
Expand All @@ -264,9 +266,9 @@ export async function POST() {
// ── Open source PRs sync (PRs to repos the user doesn't own) ─────────────
if (openSourcePrGoals.length > 0) {
const osRes = await fetch(
`${GITHUB_API}/search/issues?q=author:${session.githubLogin}+type:pr+is:merged+merged:${weekStart}..${weekEnd}+-user:${session.githubLogin}&per_page=1`,
`${GITHUB_API}/search/issues?q=author:${session?.githubLogin}+type:pr+is:merged+merged:${weekStart}..${weekEnd}+-user:${session?.githubLogin}&per_page=1`,
{
headers: { Authorization: `Bearer ${session.accessToken}`, Accept: "application/vnd.github+json" },
headers: { Authorization: `Bearer ${accessToken}`, Accept: "application/vnd.github+json" },
cache: "no-store",
}
);
Expand Down
8 changes: 5 additions & 3 deletions src/app/api/metrics/achievement-progress/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getServerSession } from "next-auth";
import { NextRequest } from "next/server";
import { getAccessToken } from "@/lib/get-session-token";
import { authOptions } from "@/lib/auth";
import { GitHubAuthError, githubAuthErrorResponse } from "@/lib/github-fetch";
import {
Expand Down Expand Up @@ -96,12 +97,13 @@ async function fetchAchievementMetrics(

export async function GET(req: NextRequest) {
const session = await getServerSession(authOptions);
const accessToken = await getAccessToken();

if (!session?.accessToken || !session.githubId || !session.githubLogin) {
if (!accessToken || !session?.githubId || !session?.githubLogin) {
return Response.json({ error: "Unauthorized" }, { status: 401 });
}

const user = await resolveAppUser(session.githubId, session.githubLogin);
const user = await resolveAppUser(session?.githubId, session?.githubLogin);
if (!user) {
return Response.json({ error: "Unauthorized" }, { status: 401 });
}
Expand All @@ -110,7 +112,7 @@ export async function GET(req: NextRequest) {

let metrics: { mergedPRs: number; acceptedAnswers: number } | null;
try {
metrics = await fetchAchievementMetrics(session.accessToken, user.id, bypass);
metrics = await fetchAchievementMetrics(accessToken, user.id, bypass);
} catch (err) {
if (err instanceof GitHubAuthError) {
return githubAuthErrorResponse();
Expand Down
10 changes: 6 additions & 4 deletions src/app/api/metrics/commit-times/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { getServerSession } from "next-auth";
import { getAccessToken } from "@/lib/get-session-token";
import { NextRequest } from "next/server";
import { authOptions } from "@/lib/auth";
import { GITHUB_API } from "@/lib/github";
Expand All @@ -13,13 +14,14 @@ export const dynamic = "force-dynamic";

export async function GET(req: NextRequest) {
const session = await getServerSession(authOptions);
if (!session?.accessToken || !session.githubLogin) {
const accessToken = await getAccessToken();
if (!accessToken || !session?.githubLogin) {
return Response.json({ error: "Unauthorized" }, { status: 401 });
}

const bypass = isMetricsCacheBypassed(req);
const key = metricsCacheKey(
session.githubId ?? session.githubLogin,
session?.githubId ?? session?.githubLogin,
"commit-times",
{ days: 90 }
);
Expand All @@ -40,10 +42,10 @@ export async function GET(req: NextRequest) {
let page = 1;
while (true) {
const res = await fetch(
`${GITHUB_API}/search/commits?q=author:${session.githubLogin}+author-date:>=${sinceStr}&per_page=100&page=${page}&sort=author-date&order=desc`,
`${GITHUB_API}/search/commits?q=author:${session?.githubLogin}+author-date:>=${sinceStr}&per_page=100&page=${page}&sort=author-date&order=desc`,
{
headers: {
Authorization: `Bearer ${session.accessToken}`,
Authorization: `Bearer ${accessToken}`,
Accept: "application/vnd.github+json",
},
cache: "no-store",
Expand Down
10 changes: 6 additions & 4 deletions src/app/api/metrics/community-engagement/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { getServerSession } from "next-auth";
import { getAccessToken } from "@/lib/get-session-token";
import { NextRequest } from "next/server";
import { authOptions } from "@/lib/auth";
import { resolveAppUser } from "@/lib/resolve-user";
Expand Down Expand Up @@ -198,11 +199,12 @@ async function fetchUserStats(

export async function GET(req: NextRequest) {
const session = await getServerSession(authOptions);
if (!session?.accessToken || !session.githubId || !session.githubLogin) {
const accessToken = await getAccessToken();
if (!accessToken || !session?.githubId || !session?.githubLogin) {
return Response.json({ error: "Unauthorized" }, { status: 401 });
}

const user = await resolveAppUser(session.githubId, session.githubLogin);
const user = await resolveAppUser(session?.githubId, session?.githubLogin);
if (!user) return Response.json({ error: "User not found" }, { status: 404 });

const bypass = isMetricsCacheBypassed(req);
Expand All @@ -213,8 +215,8 @@ export async function GET(req: NextRequest) {
async () => {
const stats = await fetchUserStats(
user.id,
session.githubLogin!,
session.accessToken!
session?.githubLogin!,
accessToken!
);

// Fetch previously-earned badge timestamps from DB
Expand Down
16 changes: 9 additions & 7 deletions src/app/api/metrics/compare/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { getServerSession } from "next-auth";
import { getAccessToken } from "@/lib/get-session-token";
import { NextRequest } from "next/server";
import { authOptions } from "@/lib/auth";
import { toDateStr } from "@/lib/date-utils";
Expand All @@ -12,7 +13,8 @@ const GITHUB_API = "https://api.github.com";

export async function GET(req: NextRequest) {
const session = await getServerSession(authOptions);
if (!session?.accessToken || !session.githubLogin) {
const accessToken = await getAccessToken();
if (!accessToken || !session?.githubLogin) {
return Response.json({ error: "Unauthorized" }, { status: 401 });
}

Expand All @@ -27,7 +29,7 @@ export async function GET(req: NextRequest) {
}

if (username === "me") {
username = session.githubLogin as string;
username = session?.githubLogin as string;
}

const normalizedUsername = normalizeGitHubUsername(username);
Expand All @@ -41,7 +43,7 @@ export async function GET(req: NextRequest) {
// be served to a different authenticated user.
// Use githubId (stable numeric ID) with githubLogin as fallback.
const today = toDateStr(new Date());
const viewerId = session.githubId ?? session.githubLogin;
const viewerId = session?.githubId ?? session?.githubLogin;
const cacheKey = `${viewerId}::${normalizedUsername}::${today}`;

const { data: cached } = await supabaseAdmin
Expand All @@ -58,7 +60,7 @@ export async function GET(req: NextRequest) {

// 1. Verify user exists
const userRes = await fetch(`${GITHUB_API}/users/${encodedUsername}`, {
headers: { Authorization: `Bearer ${session.accessToken}` },
headers: { Authorization: `Bearer ${accessToken}` },
cache: "no-store",
});

Expand Down Expand Up @@ -91,7 +93,7 @@ export async function GET(req: NextRequest) {

const commitsRes = await fetch(commitsUrl.toString(), {
headers: {
Authorization: `Bearer ${session.accessToken}`,
Authorization: `Bearer ${accessToken}`,
Accept: "application/vnd.github+json",
},
cache: "no-store",
Expand Down Expand Up @@ -144,7 +146,7 @@ export async function GET(req: NextRequest) {
reposUrl.searchParams.set("sort", "pushed");

const reposRes = await fetch(reposUrl.toString(), {
headers: { Authorization: `Bearer ${session.accessToken}` },
headers: { Authorization: `Bearer ${accessToken}` },
cache: "no-store",
});

Expand All @@ -167,7 +169,7 @@ export async function GET(req: NextRequest) {
prsUrl.searchParams.set("per_page", "1");

const prsRes = await fetch(prsUrl.toString(), {
headers: { Authorization: `Bearer ${session.accessToken}` },
headers: { Authorization: `Bearer ${accessToken}` },
cache: "no-store",
});
let prs = 0;
Expand Down
26 changes: 14 additions & 12 deletions src/app/api/metrics/consistency-score/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { getServerSession } from "next-auth";
import { getAccessToken } from "@/lib/get-session-token";
import { NextRequest } from "next/server";
import { authOptions } from "@/lib/auth";
import { getAccountToken, getAllAccounts } from "@/lib/github-accounts";
Expand Down Expand Up @@ -105,14 +106,15 @@ async function getConsistencyScoreForDates(

export async function GET(req: NextRequest) {
const session = await getServerSession(authOptions);
if (!session?.accessToken || !session.githubLogin || !session.githubId) {
const accessToken = await getAccessToken();
if (!accessToken || !session?.githubLogin || !session?.githubId) {
return Response.json({ error: "Unauthorized" }, { status: 401 });
}

const accountId = req.nextUrl.searchParams.get("accountId");
const bypass = isMetricsCacheBypassed(req);

const userRow = await resolveAppUser(session.githubId, session.githubLogin);
const userRow = await resolveAppUser(session?.githubId, session?.githubLogin);
const appUserId = userRow?.id ?? null;

if (accountId && !appUserId) {
Expand All @@ -132,14 +134,14 @@ export async function GET(req: NextRequest) {
if (!accountId) {
try {
const activeDates = await fetchActiveDates(
session.githubLogin,
session.accessToken,
{ bypass, userId: session.githubId },
session?.githubLogin,
accessToken,
{ bypass, userId: session?.githubId },
timeZone,
);
const result = await getConsistencyScoreForDates(activeDates, timeZone, {
bypass,
userId: session.githubId,
userId: session?.githubId,
accountKey: "default",
});
return Response.json(result);
Expand All @@ -155,9 +157,9 @@ export async function GET(req: NextRequest) {
if (accountId === "combined") {
const accounts = await getAllAccounts(
{
token: session.accessToken,
githubId: session.githubId,
githubLogin: session.githubLogin,
token: accessToken,
githubId: session?.githubId,
githubLogin: session?.githubLogin,
},
appUserId,
);
Expand Down Expand Up @@ -189,10 +191,10 @@ export async function GET(req: NextRequest) {
return Response.json(scoreData);
}

let resolvedToken = session.accessToken;
let resolvedLogin = session.githubLogin;
let resolvedToken = accessToken;
let resolvedLogin = session?.githubLogin;

if (accountId !== session.githubId) {
if (accountId !== session?.githubId) {
const accountToken = await getAccountToken(appUserId, accountId);

if (!accountToken) {
Expand Down
Loading
Loading