Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
PORT=3001
ATLAS_URI="mongodb://localhost:27017/file-upload"
18 changes: 15 additions & 3 deletions config.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
const mongoose = require("mongoose");

// Configure mongoose for serverless
mongoose.set('strictQuery', false);

const connectDB = async () => {
// If already connected, return
if (mongoose.connection.readyState >= 1) {
console.log("MongoDB already connected");
return;
}

try {
await mongoose.connect(process.env.ATLAS_URI);
await mongoose.connect(process.env.ATLAS_URI, {
serverSelectionTimeoutMS: 5000, // Timeout after 5s instead of 30s
socketTimeoutMS: 45000,
});
console.log("MongoDB connected");
} catch (err) {
console.error(err.message);
process.exit(1);
console.error("MongoDB connection error:", err.message);
throw err; // Throw error to be caught by middleware
}
};

Expand Down
181 changes: 181 additions & 0 deletions controllers/fileController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
const mongoose = require("mongoose");
const archiver = require("archiver");
const { Transform } = require("stream");
const FileModel = require("../models/File");

class FileController {
// Upload single file
async uploadFile(req, res) {
try {
res.status(201).json({
text: "File uploaded successfully !",
file: req.file
});
} catch (error) {
console.log(error);
res.status(400).json({
error: { text: "Unable to upload the file", error },
});
}
}

// Upload multiple files
async uploadFiles(req, res) {
try {
res.status(201).json({
text: "Files uploaded successfully !",
files: req.files
});
} catch (error) {
console.log(error);
res.status(400).json({
error: { text: `Unable to upload files`, error },
});
}
}

// Get all files
async getAllFiles(req, res) {
try {
const files = await FileModel.getAllFiles();
res.status(200).json(files);
} catch (error) {
console.log(error);
res.status(400).json({
error: { text: `Unable to retrieve files`, error },
});
}
}

// Download a single file by id
async downloadFile(req, res) {
try {
const { fileId } = req.params;

// Check if file exists
const file = await FileModel.getFileById(fileId);
if (file.length === 0) {
return res.status(404).json({ error: { text: "File not found" } });
}

// Set the headers
res.set("Content-Type", file[0].contentType);
res.set("Content-Disposition", `attachment; filename=${file[0].filename}`);

// Create a stream to read from the bucket
const downloadStream = FileModel.openDownloadStream(fileId);

// Pipe the stream to the response
downloadStream.pipe(res);
} catch (error) {
console.log(error);
res.status(400).json({ error: { text: `Unable to download file`, error } });
}
}

// Download multiple files in a zip file
async downloadFilesZip(req, res) {
try {
const files = await FileModel.getAllFiles();
if (files.length === 0) {
return res.status(404).json({ error: { text: "No files found" } });
}

res.set("Content-Type", "application/zip");
res.set("Content-Disposition", `attachment; filename=files.zip`);
res.set("Access-Control-Allow-Origin", "*");

const archive = archiver("zip", {
zlib: { level: 9 },
});

archive.pipe(res);

files.forEach((file) => {
const downloadStream = FileModel.openDownloadStream(file._id);
archive.append(downloadStream, { name: file.filename });
});

archive.finalize();
} catch (error) {
console.log(error);
res.status(400).json({
error: { text: `Unable to download files`, error },
});
}
}

// Download multiple files in base64 format
async downloadFilesBase64(req, res) {
try {
const files = await FileModel.getAllFiles();

const filesData = await Promise.all(
files.map((file) => {
return new Promise((resolve, _reject) => {
FileModel.openDownloadStream(file._id).pipe(
(() => {
const chunks = [];
return new Transform({
transform(chunk, encoding, done) {
chunks.push(chunk);
done();
},
flush(done) {
const fbuf = Buffer.concat(chunks);
const fileBase64String = fbuf.toString("base64");
resolve({
filename: file.filename,
contentType: file.contentType,
data: fileBase64String,
size: file.length,
uploadDate: file.uploadDate
});
done();
},
});
})()
);
});
})
);
res.status(200).json(filesData);
} catch (error) {
console.log(error);
res.status(400).json({
error: { text: `Unable to retrieve files`, error },
});
}
}

// Rename a file
async renameFile(req, res) {
try {
const { fileId } = req.params;
const { filename } = req.body;
await FileModel.renameFile(fileId, filename);
res.status(200).json({ text: "File renamed successfully !" });
} catch (error) {
console.log(error);
res.status(400).json({
error: { text: `Unable to rename file`, error },
});
}
}

// Delete a file
async deleteFile(req, res) {
try {
const { fileId } = req.params;
await FileModel.deleteFile(fileId);
res.status(200).json({ text: "File deleted successfully !" });
} catch (error) {
console.log(error);
res.status(400).json({
error: { text: `Unable to delete file`, error },
});
}
}
}

module.exports = new FileController();
Loading