Handle expired Google OAuth tokens gracefully by falling back to downloadable CSV spreadsheets

This commit is contained in:
2026-07-23 12:01:52 -04:00
parent d17d8a8e07
commit 65ec2ab580
2 changed files with 50 additions and 46 deletions
+1 -1
View File
@@ -1 +1 @@
240356 249378
+49 -45
View File
@@ -585,57 +585,61 @@ app.post("/api/workspace/sheets/export", async (req, res) => {
const token = accessToken || req.headers.authorization?.replace("Bearer ", ""); const token = accessToken || req.headers.authorization?.replace("Bearer ", "");
if (token) { if (token) {
const authClient = getOAuth2Client(token); try {
const sheets = google.sheets({ version: "v4", auth: authClient }); const authClient = getOAuth2Client(token);
const sheets = google.sheets({ version: "v4", auth: authClient });
// Create new Spreadsheet // Create new Spreadsheet
const title = `AI Job Applications Tracker - ${new Date().toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}`; const title = `AI Job Applications Tracker - ${new Date().toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}`;
const spreadsheet = await sheets.spreadsheets.create({ const spreadsheet = await sheets.spreadsheets.create({
requestBody: { requestBody: {
properties: { title }, properties: { title },
sheets: [ sheets: [
{ {
properties: { properties: {
title: "Applications Log", title: "Applications Log",
gridProperties: { frozenRowCount: 1 } gridProperties: { frozenRowCount: 1 }
}
} }
} ]
] }
} });
});
const spreadsheetId = spreadsheet.data.spreadsheetId!; const spreadsheetId = spreadsheet.data.spreadsheetId!;
const spreadsheetUrl = spreadsheet.data.spreadsheetUrl || `https://docs.google.com/spreadsheets/d/${spreadsheetId}`; const spreadsheetUrl = spreadsheet.data.spreadsheetUrl || `https://docs.google.com/spreadsheets/d/${spreadsheetId}`;
// Populate headers and rows // Populate headers and rows
const headers = ["Company", "Role", "Platform", "Location", "Status", "Match Score (%)", "Applied Date", "Salary Range", "Notes"]; const headers = ["Company", "Role", "Platform", "Location", "Status", "Match Score (%)", "Applied Date", "Salary Range", "Notes"];
const rows = (applications || []).map((app: any) => [ const rows = (applications || []).map((app: any) => [
app.company || "", app.company || "",
app.role || "", app.role || "",
app.platform || "Direct", app.platform || "Direct",
app.location || "", app.location || "",
app.status || "APPLIED", app.status || "APPLIED",
app.matchScore || 85, app.matchScore || 85,
app.appliedDate || new Date().toISOString().split('T')[0], app.appliedDate || new Date().toISOString().split('T')[0],
app.salaryRange || "N/A", app.salaryRange || "N/A",
app.notes || "" app.notes || ""
]); ]);
await sheets.spreadsheets.values.update({ await sheets.spreadsheets.values.update({
spreadsheetId, spreadsheetId,
range: "Applications Log!A1", range: "Applications Log!A1",
valueInputOption: "USER_ENTERED", valueInputOption: "USER_ENTERED",
requestBody: { requestBody: {
values: [headers, ...rows] values: [headers, ...rows]
} }
}); });
return res.json({ return res.json({
success: true, success: true,
spreadsheetId, spreadsheetId,
spreadsheetUrl, spreadsheetUrl,
message: `Successfully created Google Sheet with ${rows.length} records!` message: `Successfully created Google Sheet with ${rows.length} records!`
}); });
} catch (authErr: any) {
console.warn("Live Google API Token Expired/Unauthenticated. Falling back to downloadable CSV...", authErr.message);
}
} }
// Local CSV export generator when running without live Google OAuth access token // Local CSV export generator when running without live Google OAuth access token