From 9e0d6850e1eaa51460feca3c7c3d51f882476446 Mon Sep 17 00:00:00 2001 From: Backend Developer Date: Tue, 10 Mar 2026 08:31:15 +0000 Subject: [PATCH] =?UTF-8?q?=E5=90=8E=E7=AB=AF:=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E9=A2=84=E8=A7=88API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/index.js | 2 + backend/src/routes/preview.js | 84 +++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 backend/src/routes/preview.js diff --git a/backend/src/index.js b/backend/src/index.js index 5220d8c..e3965d3 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -4,6 +4,7 @@ const authRoutes = require('./routes/auth'); const fileRoutes = require('./routes/files'); const shareRoutes = require('./routes/share'); const syncRoutes = require('./routes/sync'); +const previewRoutes = require('./routes/preview'); const errorHandler = require('./middleware/errorHandler'); const app = express(); @@ -17,6 +18,7 @@ app.use('/api/auth', authRoutes); app.use('/api/files', fileRoutes); app.use('/api/share', shareRoutes); app.use('/api/sync', syncRoutes); +app.use('/api/preview', previewRoutes); // Error handler app.use(errorHandler); diff --git a/backend/src/routes/preview.js b/backend/src/routes/preview.js new file mode 100644 index 0000000..627b590 --- /dev/null +++ b/backend/src/routes/preview.js @@ -0,0 +1,84 @@ +const express = require('express'); +const path = require('path'); +const fs = require('fs'); +const db = require('../db'); + +const router = express.Router(); + +// Get preview info +router.get('/:id', (req, res) => { + const token = req.headers.authorization?.replace('Bearer ', ''); + if (!token) return res.status(401).json({ error: 'No token' }); + + try { + const jwt = require('jsonwebtoken'); + const decoded = jwt.verify(token, process.env.JWT_SECRET || 'clouddisk-secret-key'); + + const file = db.query( + 'SELECT * FROM files WHERE id = ? AND user_id = ? AND is_folder = 0', + [req.params.id, decoded.userId] + ); + + if (file.length === 0) { + return res.status(404).json({ error: 'File not found' }); + } + + const f = file[0]; + + // Determine if file is previewable + const previewableTypes = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'txt', 'md']; + const ext = f.name.split('.').pop().toLowerCase(); + const isPreviewable = previewableTypes.includes(ext); + + res.json({ + fileId: f.id, + filename: f.name, + size: f.size, + type: ext, + isPreviewable, + canDownload: true + }); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}); + +// Get preview content (for text files) +router.get('/:id/content', (req, res) => { + const token = req.headers.authorization?.replace('Bearer ', ''); + if (!token) return res.status(401).json({ error: 'No token' }); + + try { + const jwt = require('jsonwebtoken'); + const decoded = jwt.verify(token, process.env.JWT_SECRET || 'clouddisk-secret-key'); + + const file = db.query( + 'SELECT * FROM files WHERE id = ? AND user_id = ? AND is_folder = 0', + [req.params.id, decoded.userId] + ); + + if (file.length === 0) { + return res.status(404).json({ error: 'File not found' }); + } + + const f = file[0]; + const ext = f.name.split('.').pop().toLowerCase(); + + // Only allow text files + if (!['txt', 'md', 'json', 'js', 'ts', 'html', 'css'].includes(ext)) { + return res.status(400).json({ error: 'File type not supported for preview' }); + } + + // Limit preview size (100KB) + if (f.size > 100 * 1024) { + return res.status(400).json({ error: 'File too large for preview' }); + } + + const content = fs.readFileSync(f.path, 'utf8'); + res.json({ content }); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}); + +module.exports = router;