Skip to content

Commit

Permalink
Merge pull request idurar#424 from Aman-Gupta-404/create-file-uploade…
Browse files Browse the repository at this point in the history
…r-controller

Creating New Generic File Upload Controller
  • Loading branch information
salahlalami committed Sep 11, 2023
2 parents 5853b60 + 3bfdee3 commit 69af088
Show file tree
Hide file tree
Showing 6 changed files with 769 additions and 64 deletions.
124 changes: 62 additions & 62 deletions handlers/errorHandlers.js
Original file line number Diff line number Diff line change
@@ -1,62 +1,62 @@
/*
Catch Errors Handler
With async/await, you need some way to catch errors
Instead of using try{} catch(e) {} in each controller, we wrap the function in
catchErrors(), catch any errors they throw, and pass it along to our express middleware with next()
*/

exports.catchErrors = (fn) => {
return function (req, res, next) {
const resp = fn(req, res, next);
if (resp instanceof Promise) {
return resp.catch(next);
}
return resp;
};
};

/*
Not Found Error Handler
If we hit a route that is not found, we mark it as 404 and pass it along to the next error handler to display
*/
exports.notFound = (req, res, next) => {
res.status(404).json({
success: false,
message: "Api url doesn't exist ",
});
};

/*
Development Error Handler
In development we show good error messages so if we hit a syntax error or any other previously un-handled error, we can show good info on what happened
*/
exports.developmentErrors = (err, req, res, next) => {
err.stack = err.stack || '';
const errorDetails = {
message: err.message,
status: err.status,
stackHighlighted: err.stack.replace(/[a-z_-\d]+.js:\d+:\d+/gi, '<mark>$&</mark>'),
};

res.status(500).json({
success: false,
message: 'Oops ! Error in Server',
error: err,
});
};

/*
Production Error Handler
No stacktraces are leaked to admin
*/
exports.productionErrors = (err, req, res, next) => {
res.status(500).json({
success: false,
message: 'Oops ! Error in Server',
error: err,
});
};
/*
Catch Errors Handler
With async/await, you need some way to catch errors
Instead of using try{} catch(e) {} in each controller, we wrap the function in
catchErrors(), catch any errors they throw, and pass it along to our express middleware with next()
*/

exports.catchErrors = (fn) => {
return function (req, res, next) {
const resp = fn(req, res, next);
if (resp instanceof Promise) {
return resp.catch(next);
}
return resp;
};
};

/*
Not Found Error Handler
If we hit a route that is not found, we mark it as 404 and pass it along to the next error handler to display
*/
exports.notFound = (req, res, next) => {
res.status(404).json({
success: false,
message: "Api url doesn't exist ",
});
};

/*
Development Error Handler
In development we show good error messages so if we hit a syntax error or any other previously un-handled error, we can show good info on what happened
*/
exports.developmentErrors = (err, req, res, next) => {
err.stack = err.stack || '';
const errorDetails = {
message: err.message,
status: err.status,
stackHighlighted: err.stack.replace(/[a-z_-\d]+.js:\d+:\d+/gi, '<mark>$&</mark>'),
};

res.status(500).json({
success: false,
message: 'Oops ! Error in Server',
error: err,
});
};

/*
Production Error Handler
No stacktraces are leaked to admin
*/
exports.productionErrors = (err, req, res, next) => {
res.status(500).json({
success: false,
message: 'Oops ! Error in Server',
error: err,
});
};
156 changes: 156 additions & 0 deletions middlewares/uploadMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
const Upload = require('@/models/erpModels/Upload');
const multer = require('multer');
const fs = require('fs');
const path = require('path');
const { transliterate, slugify } = require('transliteration');

// middleware to upload the public document
const createPublicUpload = async (req, res, next) => {
const modelName = req.params.model;
const fieldId = req.params.fieldId;
const userID = req.admin._id;

if (req?.upload?.files?.length !== 0) {
let filesArr = req.upload.files;
let _uploadsArray = [];

filesArr.forEach((uploadItem) => {
// creating the object for individual upload document
let uploadObject = {
modelName: modelName,
fieldId: fieldId,
fileName: uploadItem.fileName,
fileType: uploadItem.fieldExt.slice(1), //removing the dot from the fileExt
enabled: true,
isPublic: true,
userID: userID,
isSecure: true,
removed: false,
path: `/upload/${modelName}/${uploadItem.fileName}${uploadItem.fieldExt}`,
};

_uploadsArray.push(uploadObject);
});

try {
const upload = await Upload.insertMany(_uploadsArray);
if (upload?.length !== 0) {
next();
} else {
return res.status(500).json({ success: false, message: 'Oops there is an Error' });
}
} catch (error) {
return res.status(500).json({ success: false, message: 'Oops there is an Error' });
}
} else {
return res.status(500).json({ success: false, message: 'Oops there is an Error' });
}
};

// middleware to upload the private document
const createPrivateUpload = async (req, res, next) => {
const modelName = req.params.model;
const fieldId = req.params.fieldId;
const userID = req.admin._id;

if (req?.upload?.files?.length !== 0) {
let filesArr = req.upload.files;
let _uploadsArray = [];

filesArr.forEach((uploadItem) => {
// creating the object for individual upload document
let uploadObject = {
modelName: modelName,
fieldId: fieldId,
fileName: uploadItem.fileName,
fileType: uploadItem.fieldExt.slice(1), //removing the dot from the fileExt
enabled: true,
isPublic: false,
userID: userID,
isSecure: true,
removed: false,
path: `/upload/${modelName}/${uploadItem.fileName}${uploadItem.fieldExt}`,
};

_uploadsArray.push(uploadObject);
});

try {
const upload = await Upload.insertMany(_uploadsArray);

if (upload?.length !== 0) {
next();
} else {
return res.status(500).json({ success: false, message: 'Oops there is an Error' });
}
} catch (error) {
return res.status(500).json({ success: false, message: 'Oops there is an Error' });
}
} else {
return res.status(500).json({ success: false, message: 'Oops there is an Error' });
}
};

const storage = multer.diskStorage({
//--> public/upload/:model/:fieldId.
destination: function (req, file, cb) {
const modelName = req.params.model;
fs.mkdir(`upload/${modelName}`, (err) => {
return cb(null, `upload/${modelName}`);
});
},
filename: function (req, file, cb) {
// fetching the file extention of the uploaded file
let fileExtension = path.extname(file.originalname);
let uniqueFileID = Math.random().toString(36).slice(2, 7); //generates unique ID of length 5

let originalname = slugify(file.originalname.split('.')[0].toLocaleLowerCase()); //convert any language to english characters
let _fileName = `${originalname}-${uniqueFileID}${fileExtension}`;

// saving file name and extention in request upload object
let files = req?.upload?.files ?? [];
const _data = {
fileName: _fileName,
fieldExt: fileExtension,
};
files.push(_data);
req.upload = {
files: files,
};
return cb(null, _fileName);
},
});

const fileFilter = (req, file, cb) => {
// array containing all the possible file types
const _fileType = [
'image/jpeg',
'image/png',
'image/gif',
'image/webp',
'application/msword',
'text/plain',
'text/csv',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-excel',
'application/pdf',
'application/zip',
'application/vnd.rar',
'video/mp4',
'video/x-msvideo',
'audio/mpeg',
'video/webm',
];

let _flag = _fileType.includes(file.mimetype);

if (_flag) {
return cb(null, true);
} else {
return cb(new Error(`${file.mimetype} File type not supported!`));
}
};

const uploadMiddleware = multer({ storage: storage, fileFilter: fileFilter });

module.exports = { createPublicUpload, createPrivateUpload, uploadMiddleware };
71 changes: 71 additions & 0 deletions models/erpModels/Upload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;

const uploadSchema = new mongoose.Schema({
modelName: {
type: String,
trim: true,
},
fieldId: {
type: String,
required: true,
},
fileName: {
type: String,
required: true,
},
fileType: {
type: String,
enum: [
'jpeg',
'jpg',
'png',
'gif',
'webp',
'doc',
'txt',
'csv',
'docx',
'xls',
'xlsx',
'pdf',
'zip',
'rar',
'mp4',
'mov',
'avi',
'mp3',
'm4a',
'webm',
],
required: true,
},
enabled: {
type: Boolean,
default: true,
},
isPublic: {
type: Boolean,
required: true,
},
userID: {
type: mongoose.SchemaTypes.ObjectId,
required: true,
},
isSecure: {
type: Boolean,
required: true,
},
removed: {
type: Boolean,
default: false,
required: true,
},
path: {
type: String,
unique: true,
required: true,
},
});

module.exports = mongoose.model('Upload ', uploadSchema);

0 comments on commit 69af088

Please sign in to comment.