Spaces:
Running
Running
File size: 5,135 Bytes
4865997 fdb7ab1 4865997 fdb7ab1 4865997 fdb7ab1 4865997 fdb7ab1 a835a2e fdb7ab1 9f45509 fdb7ab1 9f45509 fdb7ab1 4865997 a835a2e 3f6b45b 577130b fdb7ab1 4865997 fdb7ab1 a835a2e fdb7ab1 4865997 a835a2e fdb7ab1 4865997 a835a2e 4865997 a835a2e 9f45509 4865997 fdb7ab1 a835a2e fdb7ab1 4865997 fdb7ab1 9f45509 4865997 a835a2e 4865997 fdb7ab1 4865997 fdb7ab1 4e2a4d3 a835a2e 4e2a4d3 fdb7ab1 4e2a4d3 fdb7ab1 4e2a4d3 fdb7ab1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
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(`
<div style="font-family: sans-serif; text-align: center; padding-top: 50px;">
<h1 style="color: green;">QLVB Server is Running! 🚀</h1>
<p>Backend API đang hoạt động bình thường.</p>
<p>Trạng thái Google Auth: ${adminRefreshToken ? '<b style="color:blue">Đã kết nối</b>' : '<b style="color:red">Chưa đăng nhập</b>'}</p>
</div>
`);
});
// ================================================
// 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}`)); |