162 lines
5.2 KiB
JavaScript
162 lines
5.2 KiB
JavaScript
// backend/controllers/fileController.js
|
|
import multer from 'multer';
|
|
import path from 'path';
|
|
import fs from 'fs';
|
|
import pool from '../config/db.js';
|
|
import File from '../models/File.js';
|
|
|
|
// Configure Multer storage with a dynamic destination based on req.userId
|
|
const storage = multer.diskStorage({
|
|
destination: (req, file, cb) => {
|
|
// Create a directory like "documents/user_{userId}"
|
|
const userId = req.userId;
|
|
const dest = path.join(process.cwd(), 'documents', `user_${userId}`);
|
|
fs.mkdirSync(dest, { recursive: true });
|
|
cb(null, dest);
|
|
},
|
|
filename: (req, file, cb) => {
|
|
// Sanitize the original file name and append a timestamp to avoid collisions
|
|
const parsed = path.parse(file.originalname);
|
|
const sanitizedName = parsed.name.replace(/[^a-zA-Z0-9]/g, '_');
|
|
const fileName = `${sanitizedName}_${Date.now()}${parsed.ext}`;
|
|
cb(null, fileName);
|
|
},
|
|
});
|
|
|
|
const upload = multer({
|
|
storage,
|
|
limits: { fileSize: 5 * 1024 * 1024 }, // 5MB max file size
|
|
});
|
|
|
|
const allowedExtensions = ['txt', 'md'];
|
|
|
|
/**
|
|
* Upload multiple files.
|
|
* The files will be stored in a directory based on the authenticated user's ID.
|
|
*/
|
|
export const uploadFiles = (req, res) => {
|
|
// Use multer's array middleware to handle multiple files under the field 'files'
|
|
upload.array('files')(req, res, async (err) => {
|
|
if (err) {
|
|
return res.status(400).json({ message: err.message });
|
|
}
|
|
|
|
try {
|
|
// Process each uploaded file
|
|
for (let file of req.files) {
|
|
console.log('Uploaded file:', file);
|
|
console.log('User ID from token:', req.userId);
|
|
|
|
// Check if the file extension is allowed
|
|
const fileExtension = path.extname(file.originalname)
|
|
.substring(1)
|
|
.toLowerCase();
|
|
if (!allowedExtensions.includes(fileExtension)) {
|
|
return res.status(400).json({ message: 'Only .txt and .md files are allowed' });
|
|
}
|
|
|
|
// Prepare file data for the database; file_path includes the user-specific folder
|
|
const fileData = {
|
|
user_id: req.userId,
|
|
file_name: file.filename,
|
|
file_path: file.path,
|
|
file_type: fileExtension,
|
|
status: 'uploaded',
|
|
};
|
|
|
|
await File.createFile(fileData);
|
|
}
|
|
res.json({
|
|
message: 'Files uploaded successfully',
|
|
files: req.files.map(file => file.filename)
|
|
});
|
|
} catch (error) {
|
|
console.error('Error uploading files:', error);
|
|
res.status(500).json({ message: 'Database error. Please try again.' });
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Get all files for the authenticated user.
|
|
*/
|
|
export const getUserFiles = async (req, res) => {
|
|
try {
|
|
const files = await File.getUserFiles(req.userId);
|
|
if (!files.length) {
|
|
return res.status(404).json({ message: 'No files found' });
|
|
}
|
|
res.json(files);
|
|
} catch (error) {
|
|
console.error('Error retrieving files:', error);
|
|
res.status(500).json({ message: 'Database error. Please try again.' });
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get a single file by its ID (if needed).
|
|
*/
|
|
export const getFileById = async (req, res) => {
|
|
const { id } = req.params;
|
|
try {
|
|
const file = await File.findById(id, req.userId);
|
|
if (!file) {
|
|
return res.status(404).json({ message: 'File not found or unauthorized' });
|
|
}
|
|
res.json(file);
|
|
} catch (error) {
|
|
console.error('Error retrieving file:', error);
|
|
res.status(500).json({ message: 'Database error. Please try again.' });
|
|
}
|
|
};
|
|
|
|
export const previewFile = (req, res) => {
|
|
// Use the authenticated user's ID from the token
|
|
const userId = req.userId;
|
|
// Get the filename from the route parameter
|
|
const { filename } = req.params;
|
|
// Construct the full file path (matches the location used in the multer storage)
|
|
const filePath = path.join(process.cwd(), 'documents', `user_${userId}`, filename);
|
|
console.log(`Previewing file for user ${userId} from path: ${filePath}`);
|
|
|
|
res.sendFile(filePath, (err) => {
|
|
if (err) {
|
|
console.error('Error sending file:', err);
|
|
return res.status(404).send('File not found');
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Delete a file.
|
|
* This endpoint removes the file from the filesystem and then deletes its record from the database.
|
|
*/
|
|
export const deleteFile = async (req, res) => {
|
|
const { id } = req.params;
|
|
const user_id = req.userId;
|
|
try {
|
|
// Retrieve the file's path from the database
|
|
const [file] = await pool.execute(
|
|
'SELECT file_path FROM files WHERE id = ? AND user_id = ?',
|
|
[id, user_id]
|
|
);
|
|
if (file.length === 0) {
|
|
return res.status(404).json({ message: 'File not found or unauthorized' });
|
|
}
|
|
// Remove the file from the filesystem
|
|
fs.unlink(path.resolve(file[0].file_path), async (err) => {
|
|
if (err) {
|
|
console.error('Error deleting file from disk:', err);
|
|
return res.status(500).json({ message: 'Error deleting file from disk' });
|
|
}
|
|
// Delete the file record from the database
|
|
await pool.execute('DELETE FROM files WHERE id = ? AND user_id = ?', [id, user_id]);
|
|
res.json({ message: 'File deleted successfully' });
|
|
});
|
|
} catch (error) {
|
|
console.error('Error deleting file:', error);
|
|
res.status(500).json({ message: 'Database error. Please try again.' });
|
|
}
|
|
};
|
|
|