require('dotenv').config(); const express = require('express'); const multer = require('multer'); const { google } = require('googleapis'); const fs = require('fs'); const cors = require('cors'); const app = express(); const upload = multer({ dest: 'uploads/' }); app.use(cors({ origin: '*', credentials: true, allowedHeaders: ['Content-Type', 'Authorization', 'x-refresh-token'] })); app.use(express.json()); const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID; const GOOGLE_CLIENT_SECRET = process.env.GOOGLE_CLIENT_SECRET; const REDIRECT_URI = process.env.REDIRECT_URI; let adminRefreshToken = null; const oauth2Client = new google.auth.OAuth2(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, REDIRECT_URI); async function getAccessToken(req) { if (!adminRefreshToken && req && req.headers['x-refresh-token']) { console.log('Restoring session from client header...'); adminRefreshToken = req.headers['x-refresh-token']; } if (!adminRefreshToken) throw new Error('Chưa đăng nhập Admin (Session expired)'); oauth2Client.setCredentials({ refresh_token: adminRefreshToken }); const { credentials } = await oauth2Client.refreshAccessToken(); return credentials.access_token; } // Hàm Tìm hoặc Tạo Folder (Đã khôi phục) async function findOrCreateFolder(drive, name, parentId = 'root') { const q = `mimeType='application/vnd.google-apps.folder' and name='${name}' and '${parentId}' in parents and trashed=false`; const res = await drive.files.list({ q, fields: 'files(id, name)' }); if (res.data.files.length > 0) return res.data.files[0]; const folder = await drive.files.create({ resource: { name, mimeType: 'application/vnd.google-apps.folder', parents: [parentId] }, fields: 'id, name' }); return folder.data; } // === CẤU HÌNH CHO UPTIMEROBOT & TRANG CHỦ === // 1. Xử lý HEAD request (UptimeRobot ping): Trả về 200 OK nhanh, không tốn tài nguyên render HTML app.head('/', (req, res) => { res.status(200).end(); }); // 2. Xử lý GET request (Người dùng truy cập): Hiển thị giao diện chào mừng app.get('/', (req, res) => { res.send(`

QLVB Server is Running! 🚀

Backend API đang hoạt động bình thường.

Trạng thái Google Auth: ${adminRefreshToken ? 'Đã kết nối' : 'Chưa đăng nhập'}

`); }); // ================================================ // 1. Login app.post('/api/oauth/token', async (req, res) => { try { const { code, redirect_uri } = req.body; const client = new google.auth.OAuth2(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, redirect_uri || REDIRECT_URI); const { tokens } = await client.getToken(code); if (tokens.refresh_token) adminRefreshToken = tokens.refresh_token; res.json(tokens); } catch (error) { res.status(500).json({ error: error.message }); } }); // 2. Upload (Đã sửa logic tạo thư mục lồng nhau) app.post('/api/upload', upload.array('files'), async (req, res) => { try { await getAccessToken(req); // Khôi phục session const drive = google.drive({ version: 'v3', auth: oauth2Client }); const { docName, type, month } = req.body; // Tạo cấu trúc thư mục const rootFolder = await findOrCreateFolder(drive, 'QLVB-DATA'); const typeFolder = await findOrCreateFolder(drive, type === 'incoming' ? 'VanBanDen' : 'VanBanDi', rootFolder.id); const monthFolder = await findOrCreateFolder(drive, month || 'Khac', typeFolder.id); const docFolder = await findOrCreateFolder(drive, `${docName} - ${Date.now()}`, monthFolder.id); const uploadedFiles = []; for (const file of req.files) { const media = { mimeType: file.mimetype, body: fs.createReadStream(file.path) }; const driveFile = await drive.files.create({ resource: { name: file.originalname, parents: [docFolder.id] }, media: media, fields: 'id, name, webViewLink, webContentLink' }); uploadedFiles.push(driveFile.data); fs.unlinkSync(file.path); } res.json({ folderId: docFolder.id, files: uploadedFiles }); } catch (error) { console.error(error); res.status(500).json({ error: error.message }); } }); // 3. Delete app.delete('/api/delete/:fileId', async (req, res) => { try { await getAccessToken(req); const drive = google.drive({ version: 'v3', auth: oauth2Client }); await drive.files.delete({ fileId: req.params.fileId }); res.json({ success: true }); } catch (error) { console.error(error); res.status(500).json({ error: error.message }); } }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => console.log(`Server running on port ${PORT}`));