Skip to content

Commit

Permalink
Merge pull request #605 from idurar/feat/improve-upload-file-with-filter
Browse files Browse the repository at this point in the history
✨ Improve Upload Exp with file filter
  • Loading branch information
salahlalami authored Oct 26, 2023
2 parents 1e52be8 + 59b469d commit 8c4eea7
Show file tree
Hide file tree
Showing 17 changed files with 234 additions and 57 deletions.
4 changes: 2 additions & 2 deletions backend/handlers/errorHandlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ exports.developmentErrors = (error, req, res, next) => {

res.status(500).json({
success: false,
message: 'Oops ! Error in Server',
message: error.message,
error: error,
});
};
Expand All @@ -56,7 +56,7 @@ exports.developmentErrors = (error, req, res, next) => {
exports.productionErrors = (error, req, res, next) => {
res.status(500).json({
success: false,
message: 'Oops ! Error in Server',
message: error.message,
error: error,
});
};
103 changes: 76 additions & 27 deletions backend/middlewares/uploadMiddleware/fileFilter.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,80 @@
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',
];
const fileFilter =
(type = 'default') =>
(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);
let _flag = _fileType.includes(file.mimetype);

if (_flag) {
return cb(null, true);
} else {
return cb(new Error(`${file.mimetype} File type not supported!`));
}
};
if (type === 'image') {
if (!file.mimetype.startsWith('image/')) {
_flag = false;
}
} else if (type === 'pdf') {
if (!file.mimetype.startsWith('application/pdf')) {
_flag = false;
}
} else if (type === 'video') {
if (!file.mimetype.startsWith('video/')) {
_flag = false;
}
} else if (type === 'audio') {
if (!file.mimetype.startsWith('audio/')) {
_flag = false;
}
} else if (type === 'text') {
if (
!file.mimetype.startsWith('text/') &&
!file.mimetype.startsWith('application/vnd.ms-excel') &&
!file.mimetype.startsWith('application/msword') &&
!file.mimetype.startsWith(
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
)
) {
_flag = false;
}
} else if (type === 'excel') {
if (
!file.mimetype.startsWith('application/vnd.ms-excel') &&
!file.mimetype.startsWith(
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
)
) {
_flag = false;
}
} else if (type === 'compressed') {
if (
!file.mimetype.startsWith('application/zip') &&
!file.mimetype.startsWith('application/x-zip-compressed') &&
!file.mimetype.startsWith('application/x-zip-compressed') &&
!file.mimetype.startsWith('application/vnd.rar')
) {
_flag = false;
}
}

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

module.exports = fileFilter;
4 changes: 4 additions & 0 deletions backend/middlewares/uploadMiddleware/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ const createMultipleUpload = require('./createMultipleUpload');
const uploadMultipleToStorage = require('./uploadMultipleToStorage');
const createSingleUpload = require('./createSingleUpload');
const uploadSingleToStorage = require('./uploadSingleToStorage');
const singleStorageUpload = require('./singleStorageUpload');
const setFilePathToBody = require('./setFilePathToBody');

module.exports = {
singleStorageUpload,
uploadMultipleToStorage,
createMultipleUpload,
uploadSingleToStorage,
createSingleUpload,
setFilePathToBody,
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module.exports = (fieldName = 'filePath') => {
req.body[fieldName] = req.file.path;
}
// if (req.files) {
// req.body[req.files.fieldname] = req.files.path
// req.body[req.files.fieldName] = req.files.path
// }
next();
};
Expand Down
56 changes: 56 additions & 0 deletions backend/middlewares/uploadMiddleware/singleStorageUpload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
const multer = require('multer');
const fs = require('fs');
const path = require('path');
const { slugify } = require('transliteration');

const fileFilter = require('./fileFilter');

const singleStorageUpload = ({
entity,
filename = 'default',
fileType = 'default',
fieldName = 'file',
}) => {
var diskStorage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, `public/uploads/${entity}`);
},
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 = '';
if (req.body.seotitle) {
originalname = slugify(req.body.seotitle.toLocaleLowerCase()); //convert any language to english characters
} else {
originalname = slugify(file.originalname.split('.')[0].toLocaleLowerCase()); //convert any language to english characters
}

let _fileName = `${originalname}-${uniqueFileID}${fileExtension}`;

const filePath = `public/uploads/${entity}/${_fileName}`;
// saving file name and extention in request upload object
req.upload = {
fileName: _fileName,
fieldExt: fileExtension,
entity: entity,
fieldName: fieldName,
fileType: fileType,
filePath: filePath,
};

req.body[fieldName] = filePath;

return cb(null, _fileName);
},
});

let filterType = fileFilter(fileType);

const multerStorage = multer({ storage: diskStorage, fileFilter: filterType }).single('file');

return multerStorage;
};

module.exports = singleStorageUpload;
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ const storage = multer.diskStorage({
fileName: _fileName,
fieldExt: fileExtension,
};
console.log(req.upload);

return cb(null, _fileName);
},
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion backend/routes/appRoutes/appApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const router = express.Router();

const multer = require('multer');
const path = require('path');
const setFilePathToBody = require('@/middlewares/setFilePathToBody');
const setFilePathToBody = require('@/middlewares/uploadMiddleware/setFilePathToBody');

const { hasPermission } = require('@/middlewares/permission');

Expand Down
33 changes: 12 additions & 21 deletions backend/routes/coreRoutes/coreApi.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
const express = require('express');
const multer = require('multer');
const path = require('path');
const setFilePathToBody = require('@/middlewares/setFilePathToBody');

const { catchErrors } = require('@/handlers/errorHandlers');

const router = express.Router();
Expand All @@ -15,35 +13,28 @@ const {
createMultipleUpload,
uploadSingleToStorage,
createSingleUpload,
singleStorageUpload,
setFilePathToBody,
} = require('@/middlewares/uploadMiddleware');

const { hasPermission } = require('@/middlewares/permission');
// //_______________________________ Admin management_______________________________

var adminPhotoStorage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/uploads/admin');
},
filename: function (req, file, cb) {
console.log('🚀 ~ file: coreApi.js:28 ~ file:', file.originalname);
cb(null, Date.now() + path.extname(file.originalname));
},
});
const adminPhotoUpload = multer({ storage: adminPhotoStorage });

router
.route('/admin/create')
.post(
hasPermission(),
[adminPhotoUpload.single('photo'), setFilePathToBody('photo')],
singleStorageUpload({ entity: 'admin', fieldName: 'file' }),
setFilePathToBody('photo'),
catchErrors(adminController.create)
);
router.route('/admin/read/:id').get(hasPermission('read'), catchErrors(adminController.read));
router
.route('/admin/update/:id')
.patch(
hasPermission(),
[adminPhotoUpload.single('photo'), setFilePathToBody('photo')],
singleStorageUpload({ entity: 'admin', fieldName: 'file' }),
setFilePathToBody('photo'),
catchErrors(adminController.update)
);
router.route('/admin/delete/:id').delete(hasPermission(), catchErrors(adminController.delete));
Expand All @@ -55,7 +46,8 @@ router
.route('/admin/photo')
.post(
hasPermission(),
[adminPhotoUpload.single('photo'), setFilePathToBody('photo')],
singleStorageUpload({ entity: 'admin', fieldName: 'file' }),
setFilePathToBody('photo'),
catchErrors(adminController.photo)
);
router
Expand All @@ -66,8 +58,7 @@ router
.route('/profile/update/:id')
.patch(
hasPermission('read'),
adminPhotoUpload.single('file'),
setFilePathToBody('photo'),
catchErrors(singleStorageUpload({ entity: 'admin', fieldName: 'photo', fileType: 'image' })),
catchErrors(adminController.updateProfile)
);

Expand Down Expand Up @@ -111,7 +102,7 @@ router.route('/email/filter').get(hasPermission('read'), catchErrors(emailContro

// //____________________________________________ API for Upload controller _________________

router.route('/multiple/upload/:model/:fieldId').post(
router.route('/upload/multiple/:model/:fieldId').post(
hasPermission('upload'),
uploadMultipleToStorage.array('upload', 100),
createMultipleUpload,
Expand All @@ -128,7 +119,7 @@ router.route('/multiple/upload/:model/:fieldId').post(
})
);

router.route('/single/upload/:model/:fieldId').post(
router.route('upload/single/:model/:fieldId').post(
hasPermission('upload'),
uploadSingleToStorage.single('upload'),
createSingleUpload,
Expand Down
14 changes: 14 additions & 0 deletions backend/setup/config/appConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@
"valueType": "string",
"isCoreSetting": true
},
{
"settingCategory": "app_icon",
"settingKey": "app_name",
"settingValue": "https://www.idurarapp.com/Theme/idurar-no-code-app/assets/img/idurar-ai-no-code-app-logo.svg",
"valueType": "image",
"isCoreSetting": true
},
{
"settingCategory": "app_logo",
"settingKey": "app_name",
"settingValue": "https://www.idurarapp.com/Theme/idurar-no-code-app/assets/img/idurar-ai-no-code-app-logo.svg",
"valueType": "image",
"isCoreSetting": true
},
{
"settingCategory": "app_settings",
"settingKey": "language",
Expand Down
2 changes: 1 addition & 1 deletion backend/setup/config/companyConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"settingCategory": "company_settings",
"settingKey": "company_logo",
"settingValue": "https://www.idurarapp.com/Theme/idurar-no-code-app/assets/img/idurar-ai-no-code-app-logo.svg",
"valueType": "string",
"valueType": "image",
"isCoreSetting": true
},
{
Expand Down
29 changes: 29 additions & 0 deletions backend/setup/config/financeConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,35 @@
"valueType": "number",
"isCoreSetting": true
},
{
"settingCategory": "finance_settings",
"settingKey": "invoice_prefix",
"settingValue": "inv-",
"valueType": "string",
"isCoreSetting": true
},
{
"settingCategory": "finance_settings",
"settingKey": "quote_prefix",
"settingValue": "qt-",
"valueType": "string",
"isCoreSetting": true
},
{
"settingCategory": "finance_settings",
"settingKey": "offer_prefix",
"settingValue": "ofr-",
"valueType": "string",
"isCoreSetting": true
},
{
"settingCategory": "finance_settings",
"settingKey": "payment_prefix",
"settingValue": "pm-",
"valueType": "string",
"isCoreSetting": true
},

{
"settingCategory": "finance_settings",
"settingKey": "current_invoice_year",
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/forms/AdminForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export default function AdminForm({ isUpdateForm = false }) {
</Form.Item>
<Form.Item
name="file"
label="File"
label="Photo"
valuePropName="fileList"
getValueFromEvent={(e) => e.fileList}
>
Expand Down
Loading

0 comments on commit 8c4eea7

Please sign in to comment.