linguabot's picture
Upload folder using huggingface_hub
e080d3e verified
Raw
History Blame Contribute Delete
6.16 kB
const express = require('express');
const router = express.Router();
const { authenticateToken } = require('./auth');
const GroupDoc = require('../models/GroupDoc');
const fs = require('fs');
// Helpers to load Google auth via service account
function loadServiceAccount() {
if (process.env.GOOGLE_SERVICE_ACCOUNT_JSON) {
try {
const obj = JSON.parse(process.env.GOOGLE_SERVICE_ACCOUNT_JSON);
if (obj && obj.private_key && typeof obj.private_key === 'string') {
obj.private_key = obj.private_key.replace(/\\n/g, '\n');
}
return obj;
} catch (_) {}
}
const path = process.env.SA_JSON_PATH || process.env.GOOGLE_APPLICATION_CREDENTIALS || '/workspace/service-account.json';
try {
const obj = JSON.parse(fs.readFileSync(path, 'utf-8'));
if (obj && obj.private_key && typeof obj.private_key === 'string') {
obj.private_key = obj.private_key.replace(/\\n/g, '\n');
}
return obj;
} catch (_) { return null; }
}
function parseFolderId(input) {
if (!input) return null;
const m = String(input).match(/folders\/([A-Za-z0-9_-]+)/);
return m ? m[1] : input;
}
async function createDriveClient() {
const { google } = require('googleapis');
const sa = loadServiceAccount();
if (!sa || !sa.client_email || !sa.private_key) {
throw new Error('Service account credentials not configured');
}
const scopes = ['https://www.googleapis.com/auth/drive'];
const auth = new google.auth.JWT(sa.client_email, undefined, sa.private_key, scopes);
await auth.authorize();
const drive = google.drive({ version: 'v3', auth });
return drive;
}
// List docs for a week
router.get('/list', authenticateToken, async (req, res) => {
try {
const weekNumber = parseInt(req.query.weekNumber);
if (!weekNumber) return res.status(400).json({ error: 'weekNumber is required' });
const docs = await GroupDoc.find({ weekNumber }).sort({ groupNumber: 1 });
res.json({ success: true, docs });
} catch (e) {
res.status(500).json({ error: 'Failed to list docs' });
}
});
// Create a blank Google Doc for a week + group if not exists
router.post('/create', authenticateToken, async (req, res) => {
try {
const { weekNumber, groupNumber, docUrl, title: providedTitle } = req.body || {};
if (!weekNumber || !groupNumber) return res.status(400).json({ error: 'weekNumber and groupNumber are required' });
const wn = parseInt(weekNumber);
const gn = parseInt(groupNumber);
// Return existing if present
let existing = await GroupDoc.findOne({ weekNumber: wn, groupNumber: gn });
if (existing) return res.json({ success: true, doc: existing });
// If a docUrl is provided, treat as manual link fallback
if (docUrl) {
const m = String(docUrl).match(/document\/d\/([A-Za-z0-9_-]+)/);
const baseDocId = m ? m[1] : `external-${Date.now()}`;
// Avoid unique conflicts on docId across weeks/groups by namespacing if needed
let docId = baseDocId;
const conflict = await GroupDoc.findOne({ docId });
if (conflict) {
if (conflict.weekNumber === wn && conflict.groupNumber === gn) {
return res.json({ success: true, doc: conflict });
}
docId = `${baseDocId}-${wn}-${gn}`;
}
const payload = {
weekNumber: wn,
groupNumber: gn,
docId,
docUrl,
title: providedTitle || `Week ${wn} - Group ${gn} Translation`
};
try {
const savedManual = await GroupDoc.create(payload);
return res.status(201).json({ success: true, doc: savedManual });
} catch (err) {
// If unique error somehow still occurs, fall back to returning/creating a uniquely suffixed id
if (err && err.code === 11000) {
const fallbackId = `${baseDocId}-${wn}-${gn}-${Date.now()}`;
const savedManual = await GroupDoc.create({ ...payload, docId: fallbackId });
return res.status(201).json({ success: true, doc: savedManual });
}
throw err;
}
}
// Auto-creation disabled per request
return res.status(400).json({ error: 'Auto creation disabled. Please provide docUrl.' });
} catch (e) {
console.error('Create group doc error:', e);
res.status(500).json({ error: 'Failed to create doc', message: e?.message });
}
});
// Fallback: save an existing Google Doc link for a week + group (no Drive API usage)
router.post('/link', authenticateToken, async (req, res) => {
try {
const { weekNumber, groupNumber, docUrl, title } = req.body || {};
if (!weekNumber || !groupNumber || !docUrl) return res.status(400).json({ error: 'weekNumber, groupNumber and docUrl are required' });
const m = String(docUrl).match(/document\/d\/([A-Za-z0-9_-]+)/);
const docId = m ? m[1] : `external-${Date.now()}`;
// If exists, update URL/title
let existing = await GroupDoc.findOne({ weekNumber: parseInt(weekNumber), groupNumber: parseInt(groupNumber) });
if (existing) {
existing.docId = docId;
existing.docUrl = docUrl;
if (title) existing.title = title;
await existing.save();
return res.json({ success: true, doc: existing });
}
const saved = await GroupDoc.create({ weekNumber, groupNumber, docId, docUrl, title: title || `Week ${weekNumber} - Group ${groupNumber} Translation` });
res.status(201).json({ success: true, doc: saved });
} catch (e) {
console.error('Link group doc error:', e);
res.status(500).json({ error: 'Failed to save doc link', message: e?.message });
}
});
// Delete a saved Google Doc link by id
router.delete('/:id', authenticateToken, async (req, res) => {
try {
const id = req.params.id;
if (!id) return res.status(400).json({ error: 'id is required' });
const found = await GroupDoc.findById(id);
if (!found) return res.status(404).json({ error: 'Doc not found' });
await GroupDoc.deleteOne({ _id: id });
return res.json({ success: true, removed: id });
} catch (e) {
console.error('Delete group doc error:', e);
res.status(500).json({ error: 'Failed to delete doc', message: e?.message });
}
});
module.exports = router;