I have a simple HTML form that lets the user upload a file. That than gets posted with auth/post/ on submission.
My route looks like this:
const express = require('express');
const authController = require('../controllers/auth');
const router = express.Router();
const multer = require('multer');
function checkFileType(file, cb){
const filetypes = /jpeg|jpg|png|gif|mp3|ogg|aac|wav/;
if (req.fileValidationError) {
return res.send(fileValidationError);
}
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = filetypes.test(file.mimetype);
if(mimetype && extname){
return cb(null,true);
} else {
cb('Format not allowed!');
}
}
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null,'./user_uploads/')
},
fileFilter: function(req, file, cb){
checkFileType(file, cb);
},
filename: function (req, file, cb) {
let ext = file.originalname.substring(file.originalname.lastIndexOf('.'), file.originalname.length);
cb(null, Date.now() + ext)
}
});
const upload = multer({
storage: storage
}).single('user_file');
router.post('/post', upload, function(req, res, next){ res.locals.storage = storage; next();}, authController.post);
module.exports = router;
It checks that you actually put something in, that it's in the right formats, changes the filename and saves it to a temporary folder when you use 'upload'.
I now want to get the storage variable aka the filepath/name/extension to my authController.post.
It's a controller with exports where everything else gets saved to the database. How would I pass the path variable to it?
For reference, it looks like this (I need to put the path into user_path: _______):
exports.post = (req, res, next) => {
let { name, title, cat, con, user_file } = req.body;
const time = new Date().toJSON().slice(0, 19).replace('T', ' ');
let cat_id = 0;
if(req.files) user_file.fileName = req.file.filename;
db.query("SELECT id FROM cat WHERE cat_name = ?", [cat], async function(err, results) {
if (!err)
cat_id = results[0].id;
else
console.log(err);
const ID = await promisify(jwt.verify)(req.cookies.scrooc, process.env.jwtsecret);
const id = ID.id;
db.query('INSERT INTO posts SET ?', {user_id: id, cat_id: cat_id, time: time, title: title, content: con, user_file: res.locals.storage, reply: 0 }, (error, results) => {
if(error)
console.log(error);
else
res.status(200).redirect('/post');
});
});
};
I think you should try writing a textfield (QLineEdit in Python), setting the filename path to the textfield and then saving the content of the textfield to your database using an insert statement during insertion of values into your databse. For example, using Python, here is one way you can achieve that: the getfile is the name of my function, you can name yours anything but remember to call it. The photoinfo is the name of my QLineEdit, in Java, it is called a JTextField if I still remember. So try to use the logic in my code to see if it can resolve yours.
''' def getfile(self):
self.file_name = QtWidgets.QFileDialog.getOpenFileName(None, "Open", "", "All Files (*);;JPG Files(*.jpg)")
try:
if self.file_name[0] != '':
print("success")
self.photoInfo.setText(self.file_name[0])
else:
print("error")
except Exception as e:
print(e)
I ended up just doing the full function in the route. Might not be that clean but it worked.
Related
I have many files which are stored in upload_file collection in mongodb and they have relations with related content types. However when I open Strapi CMS UI, I cannot see the file attached on its content type.
I am using Strapi v3.4.6 — Community Edition.
In the first picture is showing the my one of upload_file collection item. Its relation is shown in red circle.
In the second picture is showing the my main content type collection item. You see that its id and upload_file rel id is matching.
But in Strapi UI, this file is not linked to model. The file exists in file system of Strapi. However it is not visible
I can add this file manually, but is there any quick way to do this?
You need to migrate the database. We solved with a basic script.
Run http://localhost:3000/migrate
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017";
var dbName = "YOURDBNAME";
const express = require('express')
const app = express()
const port = 3000
var _db;
var _dbo;
var tables = {
"table1": "TabLE1",
"table2": "TABle2",
}
app.get('/migrate', (req, res) => {
res.send('Started!')
_dbo.collection("upload_file").find({}).toArray(function(err, result) {
if (err) throw err;
result.forEach(function (item) {
if (item.related.length > 0) {
var related = item.related[0];
var query = { '_id': related.ref };
var newvalues = { $set: {} };
newvalues.$set[related.field] = item._id;
var tableName = related.kind.toLowerCase();
_dbo.collection(tables[tableName]).updateOne(query, newvalues, function(err, res) {
if (err) throw err;
console.log(res != null ? res.ops : null);
});
}
})
// db.close();
});
})
MongoClient.connect(url, function(err, db) {
if (err) throw err;
_dbo = db.db(dbName);
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
// Run http://localhost:3000/migrate
When uploading your image to strapi make sure your formData has these fields
const formData = new FormData();
formData.append('files', image);
formData.append('ref', 'contentTypeName');
formData.append('refId', dataItemId);
formData.append('field', 'image');
I am trying to create a route through which I can upload photos. However as I made so,e changes it stopped working and I am not sure how to make it work.
const multer = require('multer');
// MULTER STORAGE
const multerStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, '/upload');
},
filename: (req, file, cb) => {
const ext = file.mimetype.split('/')[1];
// Saving format: user-UserId-DateStamp.ext
//e.g user-608d55c7e512b74ee00791de-1621992912638.jpeg
cb(null, `user-${req.body.userId}-${Date.now()}.${ext}`);
},
});
//MULTER FILTER
const multerFilter = (req, file, cb) => {
//mimetype always starts with image/ then png or jpeg or..
if (file.mimetype.startsWith('image')) {
cb(null, true);
} else {
cb(new AppError('You are only allowed to upload image files.', 400), false);
}
};
const uploadDirectory = multer({
storage: multerStorage,
fileFilter: multerFilter,
});
//exports.uploadPhoto = uploadDirectory.single('photo');
//app.use(express.static('./uploads'));
// INCLUDE ERROR CLASS AND ERROR CONTROLLER
const AppError = require('../utils/appError.js');
const errorController = require('./errorController.js');
const { Mongoose } = require('mongoose');
The main problem Im guessing is in this block
//UPLOAD PHOTO
exports.uploadPhoto = uploadDirectory(async (req, res) => {
console.log(req.body);
console.log(req.file);
try {
const newPhoto = await photoModel.create(req.file);
newPhoto.save().then((result) => {
console.log('Saved');
res.status(201).json({
status: 'success',
// data: JSON.parse(JSON.stringify(newPhoto.file)),
});
});
} catch (err) {
console.log('Error in upload');
errorController.sendError(err, req, res);
}
}).single('photo');
Can anybody let me know how to correctly write the exports.uploadPhoto
Originally the last function looked like this
exports.uploadPhoto = async (req, res) => {
console.log(req.body);
console.log(req.file);
try {
const newPhoto = await photoModel.create(req.file);
newPhoto.save().then((result) => {
console.log('Saved');
res.status(201).json({
status: 'success',
// data: JSON.parse(JSON.stringify(newPhoto.file)),
});
});
} catch (err) {
console.log('Error in upload');
errorController.sendError(err, req, res);
}
};
The multer middleware function, in your case uploadDirectory, is usually used before other middleware functions/controllers where you have your business logic (e.g. uploadPhoto).
app.post('/upload', uploadDirectory.single('photo'), uploadPhoto);
Keep your original uploadPhoto function and with the above code you'll have access to the data and file through reg.body and req.file, respectively.
This Request Parsing in Node.js Guide (it's free) will help you with file uploads in Node.js.
Hello sorry for my english, i have a little problem. i try to upload many images but in back side i have just one image, (i use React express formidable cloudinary) here is my code front :
const [arrayFiles, setArrayFiles] = useState([]);
const handleFiles = (e) => {
let arrayUpload = [...arrayFiles];
arrayUpload.push(e.target.files[0]);
setArrayFiles(arrayUpload);
};
const handleSubmit = async (e) => {
arrayFiles.forEach((file) => {
formData.append("image", file);
});
const response = await axios.post(
"http://localhost:3100/offer/publish",
formData
);
here is my code back but req.files => just one image
my page route :
router.post("/offer/publish", async (req, res) => {
console.log(req.files);
const result = await cloudinary.uploader.upload(req.files.image.path, {
folder: `api/leboncoin/offers/${newOffer._id}`, // _id vient de la création du newOffer au dessus
public_id: "preview",
cloud_name: process.env.CLOUDINARY_NAME,
});
my page index.js:
page index.js :
const express = require("express");
const formidable = require("express-formidable");
const mongoose = require("mongoose");
const cloudinary = require("cloudinary").v2;
const cors = require("cors");
const app = express();
app.use(cors());
app.use(formidable({ multiples: true }));
You only get one file in req.file as you've set your multer.single
Using multer
There are 3 ways you can handle multiple file upload, each with a slightly different taste.
Assume you have a base multer
const storage = multer.diskStorage({
destination: "public/data/",
filename: function(req, file, cb){
// You may change this to however you want, only affect your file name
crypto.randomBytes(20, (err, buf) => {
cb(null, buf.toString("hex") + path.extname(file.originalname))
})
}
});
const upload = multer({ storage: storage });
Use .any()
Accepts all files that comes over the wire. An array of files will be stored in req.files.
WARNING: Make sure that you always handle the files that a user uploads. Never add multer as a global middleware since a malicious user could upload files to a route that you didn't anticipate. Only use this function on routes where you are handling the uploaded files.
router.post("/offer/publish",upload.any(), async (req, res) => {
console.log(req.files); // Should give you an array of files
// Do anything else
});
Use .array(fieldname[, maxCount])
Accept an array of files, all with the name fieldname. Optionally error out if more than maxCount files are uploaded. The array of files will be stored in req.files.
router.post("/offer/publish",upload.array('someFieldName', 10), async (req, res) => {
console.log(req.files); // Should give you an array of files
// Do anything else
});
Use .fields(fields)
Accept a mix of files, specified by fields. An object with arrays of files will be stored in req.files.
fields should be an array of objects with name and optionally a maxCount. Example:
router.post(
"/offer/publish",
upload.fields([
{
name: "image",
maxCount: 1,
},
{
name: "audio",
maxCount: 1,
},
]),
async (req, res) => {
console.log(req.files.image[0]);
console.log(req.files.audio[0]);
// Do anything else
}
);
For your case, I would recommend going with Option 2.
I want to Use multer function in controller file But the problem is req.body got undefine when I use postman form-data body to upload images This is link to code that how I am using multer Function but I want use it in my controller
how I want to use it as you can see in below code
const multerHelper = require("../helpers/multer_helper");
Documents: async (req, res) => {
console.log(req.body)
if (!req.body.id) {
console.log(req.body)
logger.warn(error.MANDATORY_FIELDS);
return res.status(500).send(error.MANDATORY_FIELDS)
}
try {
multerHelper.createUserImage
let result = error.OK
logger.info(result);
return res.status(200).send(result)
} catch (err) {
logger.warn(err);
console.log(err);
return res.status(500).send(error.SERVER_ERROR)
}
}
but it throws error like req.body undefine
req.body empty image
postman form-data image
Anyone know how to do it
You can use multer functions and objects in only routes not in controller if you want to use it in controller you have to write storage and upload functions in controllers, here I have used multer error handling and I am uploading multiple images
Documents: async (req, res) => {
if (!req.headers.room_id) {
logger.warn(error.MANDATORY_FIELDS);
return res.status(500).send(error.MANDATORY_FIELDS)
}
try {
let storage = multer.diskStorage({
destination: function (req, file, cb) {
let id = req.headers.room_id;
let path = `tmp/daily_gasoline_report/${id}`;
fsextra.mkdirsSync(path);
cb(null, path);
},
filename: function (req, file, cb) {
// console.log(file);
let extArray = file.mimetype.split("/");
let extension = extArray[extArray.length - 1];
cb(null, file.fieldname + '-' + Date.now() + "." + extension);
}
})
var upload = multer({ storage: storage }).array('images', 100);
upload(req, res, function (err) {
if (err) {
console.log(err);
return res.end("Error uploading file.");
} else {
res.end("File has been uploaded");
}
});
let result = error.OK
logger.info(result);
return res.status(200).send(result)
} catch (err) {
logger.warn(err);
console.log(err);
return res.status(500).send(error.SERVER_ERROR)
}
}
Do you have a parser?
How do you parse the data?
Your gonna need to use something that gives you this data something like:
https://www.npmjs.com/package/express-fileupload
this package helps you to parse the form data and the files data itself.
I'm using Node.JS + Express.JS + Multer to handle file uploads. The problem is that I need to query the database to see if a file with this name has been uploaded in the past. If it hasn't been uploaded, then it should be accepted. Otherwise, the file should not be accepted. I'm trying to get this to work using the onFileUploadStart function; however, the database query is asynchronous and I see no way to return false given that the result of the query appears in a callback. If there is a way to execute the query synchronously, my goal will be easy to accomplish. Here is the code:
var express = require('express');
var router = express.Router();
var mysql = require('mysql');
var connection = mysql.createConnection({
//connection details
});
router.post('/upload', multer({
onFileUploadStart: function(file, req, res) {
var queryString = "SELECT count(fileName) as count FROM table WHERE fileName = ?;",
queryInserts = [file.originalname];
queryString = mysql.format(queryString, queryInserts);
connection.query(queryString, function(err, rows) {
if (err) {
// handle error
} else {
if (rows[0].count > 0) {
// file should not be accepted
} else {
// file should be accepted
}
}
});
},
dest: "./uploads/"
}), function(req, res) {
// do other stuff
});
Any ideas of how I can accomplish this will be greatly appreciated. Thanks.
My quick reaction would be to use promises. You could have your onFileUploadStart handler create a deferred, assign its promise to the active request object and handle the resolution or rejection of the promise. Then in the main handler for the upload route, you could use then.
I believe this would basically be the new code as applied to your current code. I Note that I am using the Q promises library, but there are other options (promises are also built into ES6 if you are using it).
var express = require('express');
var router = express.Router();
var mysql = require('mysql');
var Q = requires('q');
var connection = mysql.createConnection({
//connection details
});
router.post('/upload', multer({
onFileUploadStart: function(file, req, res) {
var deferred = Q.defer();
req.fileUploadPromise = deferred.promise;
var queryString = "SELECT count(fileName) as count FROM table WHERE fileName = ?;",
queryInserts = [file.originalname];
queryString = mysql.format(queryString, queryInserts);
connection.query(queryString, function(err, rows) {
if (err) {
// handle error
deferred.reject('You had an error...');
} else {
if (rows[0].count > 0) {
// file should not be accepted
deferred.reject('You had a duplicate file');
} else {
deferred.resolve(file); // ?? or something useful
// file should be accepted
}
}
});
},
dest: "./uploads/"
}), function(req, res) {
req.fileUploadPromise
.then(function(successResult){
// do other stuff
res.status(200).send('success');
})
.catch(function(errorResult){
// read the error result to provide correct code & error message for user
})
.done();
});