Skip to content
Merged
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
13 changes: 5 additions & 8 deletions src/app/api/photos/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,16 @@ import { fetchPhotosWithMetadata, getFolders, getTags } from "@/lib/photos";
export const revalidate = 30;

export async function GET(request: NextRequest) {
console.log("[v0] /api/photos GET request received");
console.log("[v0] ENV CHECK - GOOGLE_CLIENT_EMAIL:", process.env.GOOGLE_CLIENT_EMAIL ? `SET (${process.env.GOOGLE_CLIENT_EMAIL.length} chars)` : "MISSING");
console.log("[v0] ENV CHECK - GOOGLE_PRIVATE_KEY:", process.env.GOOGLE_PRIVATE_KEY ? `SET (${process.env.GOOGLE_PRIVATE_KEY.length} chars)` : "MISSING");
console.log("[v0] ENV CHECK - GOOGLE_API_KEY:", process.env.GOOGLE_API_KEY ? `SET (${process.env.GOOGLE_API_KEY.length} chars)` : "MISSING");
console.log("[v0] ENV CHECK - GOOGLE_DRIVE_FOLDER_ID:", process.env.GOOGLE_DRIVE_FOLDER_ID || "MISSING");
console.log("[v0] GATE 1: /api/photos request received");
console.log("[v0] GATE 2: ENV - email:", !!process.env.GOOGLE_CLIENT_EMAIL, "key:", !!process.env.GOOGLE_PRIVATE_KEY, "apiKey:", !!process.env.GOOGLE_API_KEY, "folder:", !!process.env.GOOGLE_DRIVE_FOLDER_ID);
try {
const { searchParams } = new URL(request.url);
const limit = Number(searchParams.get("limit")) || 0;
const offset = Number(searchParams.get("offset")) || 0;

console.log("[v0] Calling fetchPhotosWithMetadata...");
console.log("[v0] GATE 3: calling fetchPhotosWithMetadata");
const allPhotos = await fetchPhotosWithMetadata();
console.log("[v0] fetchPhotosWithMetadata returned", allPhotos.length, "photos");
console.log("[v0] GATE 4: got", allPhotos.length, "photos");
const folders = getFolders(allPhotos);
const tags = getTags(allPhotos);
const total = allPhotos.length;
Expand All @@ -35,7 +32,7 @@ export async function GET(request: NextRequest) {
}, allPhotos[0].processedAt)
: "";

console.log("[v0] /api/photos responding with", photos.length, "photos,", folders.length, "folders,", tags.length, "tags");
console.log("[v0] GATE 5: responding with", photos.length, "photos");
return NextResponse.json({
photos,
folders,
Expand Down
25 changes: 12 additions & 13 deletions src/lib/drive-sa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,13 @@ let cachedToken: { token: string; expiry: number } | null = null;
async function getAccessToken(): Promise<string> {
// Return cached token if still valid (with 5 min buffer)
if (cachedToken && cachedToken.expiry > Date.now() + 5 * 60 * 1000) {
console.log("[v0] Using cached access token");
console.log("[v0] GATE T1: using cached token");
return cachedToken.token;
}

console.log("[v0] Creating new JWT for token exchange...");
console.log("[v0] GATE T2: creating JWT");
const jwt = await createJWT();
console.log("[v0] JWT created, exchanging for access token...");
console.log("[v0] GATE T3: exchanging for token");

const res = await fetch("https://oauth2.googleapis.com/token", {
method: "POST",
Expand All @@ -90,12 +90,12 @@ async function getAccessToken(): Promise<string> {

if (!res.ok) {
const error = await res.text();
console.error("[v0] Token exchange FAILED:", res.status, error);
console.error("[v0] GATE T4: token FAILED", res.status);
throw new Error(`Failed to get access token: ${error}`);
}

const data = await res.json();
console.log("[v0] Token exchange SUCCESS, expires in", data.expires_in, "seconds");
console.log("[v0] GATE T5: token SUCCESS");
cachedToken = {
token: data.access_token,
expiry: Date.now() + data.expires_in * 1000,
Expand All @@ -105,18 +105,17 @@ async function getAccessToken(): Promise<string> {
}

export function isServiceAccountConfigured(): boolean {
const hasEmail = !!process.env.GOOGLE_CLIENT_EMAIL;
const hasKey = !!process.env.GOOGLE_PRIVATE_KEY;
console.log("[v0] isServiceAccountConfigured - email:", hasEmail, "key:", hasKey);
return hasEmail && hasKey;
const configured = !!(process.env.GOOGLE_CLIENT_EMAIL && process.env.GOOGLE_PRIVATE_KEY);
console.log("[v0] GATE SA:", configured);
return configured;
}

export async function listDriveImagesWithServiceAccount(
folderId: string
): Promise<DriveFile[]> {
console.log("[v0] listDriveImagesWithServiceAccount - folderId:", folderId);
console.log("[v0] GATE L1: listImages start");
const accessToken = await getAccessToken();
console.log("[v0] Got access token:", accessToken ? "YES" : "NO");
console.log("[v0] GATE L2: got token");
const files: DriveFile[] = [];
let pageToken: string | undefined;

Expand All @@ -140,12 +139,12 @@ export async function listDriveImagesWithServiceAccount(

const data: { files?: DriveFile[]; nextPageToken?: string } =
await res.json();
console.log("[v0] Drive API returned", data.files?.length || 0, "files");
console.log("[v0] GATE L3: got", data.files?.length || 0, "files");
if (data.files) files.push(...data.files);
pageToken = data.nextPageToken;
} while (pageToken);

console.log("[v0] Total files from Service Account:", files.length);
console.log("[v0] GATE L4: total", files.length);
return files;
}

Expand Down
28 changes: 8 additions & 20 deletions src/lib/photos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,25 +123,14 @@ export async function fetchPhotosFromDriveFolder(): Promise<PhotoRecord[]> {
const { driveFolderId, googleApiKey } = config;
const useServiceAccount = isServiceAccountConfigured();

console.log("[v0] fetchPhotosFromDriveFolder START");
console.log("[v0] - driveFolderId:", driveFolderId || "MISSING");
console.log("[v0] - useServiceAccount:", useServiceAccount);
console.log("[v0] - googleApiKey:", googleApiKey ? "SET" : "MISSING");
console.log("[v0] GATE A: fetchPhotos - SA:", useServiceAccount, "folder:", !!driveFolderId, "apiKey:", !!googleApiKey);

if (!driveFolderId) {
console.log("[v0] No driveFolderId, returning empty");
return [];
}

// Must have either Service Account or API Key configured
if (!useServiceAccount && !googleApiKey) {
console.log("[v0] No auth method configured, returning empty");
return [];
}
if (!driveFolderId) return [];
if (!useServiceAccount && !googleApiKey) return [];

try {
const opts = { revalidate: 30 };
console.log("[v0] Fetching from Drive with", useServiceAccount ? "Service Account" : "API Key");
console.log("[v0] GATE B: fetching with", useServiceAccount ? "ServiceAccount" : "APIKey");

// Use Service Account if configured, otherwise fall back to API Key
const [rootFiles, subfolders] = useServiceAccount
Expand All @@ -154,8 +143,7 @@ export async function fetchPhotosFromDriveFolder(): Promise<PhotoRecord[]> {
listDriveSubfolders(driveFolderId, googleApiKey, opts),
]);

console.log("[v0] Root files found:", rootFiles.length);
console.log("[v0] Subfolders found:", subfolders.length);
console.log("[v0] GATE C: root files:", rootFiles.length, "subfolders:", subfolders.length);

const allPhotos = driveFilesToPhotos(rootFiles, "Root");

Expand All @@ -176,10 +164,10 @@ export async function fetchPhotosFromDriveFolder(): Promise<PhotoRecord[]> {
);
allPhotos.forEach((p, i) => { p.id = String(i + 1); });

console.log("[v0] fetchPhotosFromDriveFolder COMPLETE - total photos:", allPhotos.length);
console.log("[v0] GATE D: total photos:", allPhotos.length);
return allPhotos;
} catch (error) {
console.error("[v0] fetchPhotosFromDriveFolder ERROR:", error);
} catch (err) {
console.error("[v0] GATE E: ERROR", err);
return [];
}
}
Expand Down
Loading