fix: add missing google-sheets.js to repo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b44b4bb9e6
commit
685bb535f8
|
|
@ -0,0 +1,120 @@
|
|||
// Google Sheets sync helper
|
||||
// Non-blocking secondary write for team access and redundancy
|
||||
// Reads credentials from file (GOOGLE_SERVICE_ACCOUNT_FILE) or env var (GOOGLE_SERVICE_ACCOUNT)
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
let sheetsClient = null;
|
||||
let authClient = null;
|
||||
|
||||
function getCredentials() {
|
||||
if (!process.env.GOOGLE_SHEET_ID) return null;
|
||||
|
||||
// Prefer file-based credentials (cleaner for Docker)
|
||||
const filePath = process.env.GOOGLE_SERVICE_ACCOUNT_FILE;
|
||||
if (filePath) {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
||||
} catch (err) {
|
||||
console.error('[Google Sheets] Failed to read credentials file:', err.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to JSON string in env var
|
||||
const raw = process.env.GOOGLE_SERVICE_ACCOUNT;
|
||||
if (!raw) return null;
|
||||
try {
|
||||
return JSON.parse(raw.trim());
|
||||
} catch {
|
||||
console.error('[Google Sheets] Failed to parse service account JSON');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function getSheetsClient() {
|
||||
if (sheetsClient) return sheetsClient;
|
||||
|
||||
const creds = getCredentials();
|
||||
if (!creds) return null;
|
||||
|
||||
const { google } = require('googleapis');
|
||||
authClient = new google.auth.GoogleAuth({
|
||||
credentials: creds,
|
||||
scopes: ['https://www.googleapis.com/auth/spreadsheets'],
|
||||
});
|
||||
sheetsClient = google.sheets({ version: 'v4', auth: authClient });
|
||||
return sheetsClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a row to a specific sheet tab.
|
||||
* Non-blocking — logs errors but never throws.
|
||||
*/
|
||||
async function appendRow(sheetName, values) {
|
||||
try {
|
||||
const sheets = await getSheetsClient();
|
||||
if (!sheets) {
|
||||
console.log('[Google Sheets] Skipping sync — no credentials configured');
|
||||
return;
|
||||
}
|
||||
|
||||
await sheets.spreadsheets.values.append({
|
||||
spreadsheetId: process.env.GOOGLE_SHEET_ID,
|
||||
range: `${sheetName}!A:Z`,
|
||||
valueInputOption: 'USER_ENTERED',
|
||||
insertDataOption: 'INSERT_ROWS',
|
||||
resource: { values: [values] },
|
||||
});
|
||||
|
||||
console.log(`[Google Sheets] Synced row to "${sheetName}"`);
|
||||
} catch (error) {
|
||||
console.error(`[Google Sheets] Failed to sync to "${sheetName}":`, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync a waitlist signup to the "Waitlist" sheet tab.
|
||||
* Columns: Timestamp | Email | Name | Involvement
|
||||
*/
|
||||
function syncWaitlistSignup({ email, name, involvement }) {
|
||||
// Fire and forget — don't await in the request handler
|
||||
appendRow('Waitlist', [
|
||||
new Date().toISOString(),
|
||||
email,
|
||||
name,
|
||||
involvement || '',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync an application to the "Applications" sheet tab.
|
||||
* Columns: Timestamp | App ID | Status | First Name | Last Name | Email | Phone |
|
||||
* Country | City | Attendance | Motivation | Contribution | How Heard |
|
||||
* Referral | Scholarship | Scholarship Reason | Weeks/Dates
|
||||
*/
|
||||
function syncApplication(app) {
|
||||
appendRow('Applications', [
|
||||
new Date().toISOString(),
|
||||
app.id || '',
|
||||
'pending',
|
||||
app.first_name || '',
|
||||
app.last_name || '',
|
||||
app.email || '',
|
||||
app.phone || '',
|
||||
app.country || '',
|
||||
app.city || '',
|
||||
app.attendance_type || '',
|
||||
app.motivation || '',
|
||||
app.contribution || '',
|
||||
app.how_heard || '',
|
||||
app.referral_name || '',
|
||||
app.scholarship_needed ? 'Yes' : 'No',
|
||||
app.scholarship_reason || '',
|
||||
app.arrival_date && app.departure_date
|
||||
? `${app.arrival_date} to ${app.departure_date}`
|
||||
: '',
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports = { syncWaitlistSignup, syncApplication };
|
||||
Loading…
Reference in New Issue