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 ", "");
if (token) {
const authClient = getOAuth2Client(token);
const sheets = google.sheets({ version: "v4", auth: authClient });
try {
const authClient = getOAuth2Client(token);
const sheets = google.sheets({ version: "v4", auth: authClient });
// Create new Spreadsheet
const title = `AI Job Applications Tracker - ${new Date().toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}`;
const spreadsheet = await sheets.spreadsheets.create({
requestBody: {
properties: { title },
sheets: [
{
properties: {
title: "Applications Log",
gridProperties: { frozenRowCount: 1 }
// Create new Spreadsheet
const title = `AI Job Applications Tracker - ${new Date().toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}`;
const spreadsheet = await sheets.spreadsheets.create({
requestBody: {
properties: { title },
sheets: [
{
properties: {
title: "Applications Log",
gridProperties: { frozenRowCount: 1 }
}
}
}
]
}
});
]
}
});
const spreadsheetId = spreadsheet.data.spreadsheetId!;
const spreadsheetUrl = spreadsheet.data.spreadsheetUrl || `https://docs.google.com/spreadsheets/d/${spreadsheetId}`;
const spreadsheetId = spreadsheet.data.spreadsheetId!;
const spreadsheetUrl = spreadsheet.data.spreadsheetUrl || `https://docs.google.com/spreadsheets/d/${spreadsheetId}`;
// Populate headers and rows
const headers = ["Company", "Role", "Platform", "Location", "Status", "Match Score (%)", "Applied Date", "Salary Range", "Notes"];
const rows = (applications || []).map((app: any) => [
app.company || "",
app.role || "",
app.platform || "Direct",
app.location || "",
app.status || "APPLIED",
app.matchScore || 85,
app.appliedDate || new Date().toISOString().split('T')[0],
app.salaryRange || "N/A",
app.notes || ""
]);
// Populate headers and rows
const headers = ["Company", "Role", "Platform", "Location", "Status", "Match Score (%)", "Applied Date", "Salary Range", "Notes"];
const rows = (applications || []).map((app: any) => [
app.company || "",
app.role || "",
app.platform || "Direct",
app.location || "",
app.status || "APPLIED",
app.matchScore || 85,
app.appliedDate || new Date().toISOString().split('T')[0],
app.salaryRange || "N/A",
app.notes || ""
]);
await sheets.spreadsheets.values.update({
spreadsheetId,
range: "Applications Log!A1",
valueInputOption: "USER_ENTERED",
requestBody: {
values: [headers, ...rows]
}
});
await sheets.spreadsheets.values.update({
spreadsheetId,
range: "Applications Log!A1",
valueInputOption: "USER_ENTERED",
requestBody: {
values: [headers, ...rows]
}
});
return res.json({
success: true,
spreadsheetId,
spreadsheetUrl,
message: `Successfully created Google Sheet with ${rows.length} records!`
});
return res.json({
success: true,
spreadsheetId,
spreadsheetUrl,
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