Unable to access filename in multer - reactjs

After looking through numerous documentation on Multer I believe that I have the proper setup on my express server. However, each time I attempt to access the req.files.filename attribute of my incoming file, the value is returned as undefined.
Here is my Express server side code:
const storage = multer.diskStorage({
destination: '../Uploads',
filename: (req, file, cb) => cb(null, file.originalname)
});
const upload = multer({
storage: storage
});
Router.post("/", upload.single("file"), async (req, res) => {
debug.log("connected");
debug.log(req.file);
debug.log(req.body);
if (!req.files) {
debug.log("receiving connection but file not found");
res.send({
status: false,
message: "No file uploaded",
});
} else {
debug.log("receiving connection and file found");
try {
debug.log(req.files.filename);
debug.log("attempting to save file" + req.files);
const post = await new Post({
title: req.files.filename,
owner: req.body.owner,
industry: req.body.industry,
});
If I understand correctly, calling upload.single should make req.file.filename a usable attribute, but it does not seem to be working.
EDIT:
I solved this problem FINALLY!
Apparently using the app.use(fileUpload()); middleware was somehow interfering with Multer.
Before when I had app.use(fileUpload()); enabled I could access the file through req.files, but the file wouldn't save.
After commenting out app.use(fileUpload()); I can access the file through req.file and it will save correctly.

When you upload a single file (upload.single), look at req.file, not req.files.

Related

Firebase Storage not displaying image properly (shows a small box)

EDIT: I've updated the CORS config but its still showing the same error.
I have a Tinymce RTE on my page, and when u drop an image into the editor, I have some functions that upload it to firebase storage, then swaps out the src of the text editor with the url fetched from firebase. It works kinda ok, but its being displayed as a broken link image icon.
When I check the link, its because originally it downloads the image when the link is clicked. I added a metadata property when it uploads it, but now its just showing a tiny box.
Here is the code where the image dropped into the editor is uploaded into firebase storage
const imagesUploadHandler = async (blobInfo, success, failure) => {
try {
const file = blobInfo.blob();
const storageRef = ref(storage, file.name);
const metadata = {
contentType: 'image/jpeg',
};
await uploadBytes(storageRef, file, metadata);
const url = await getDownloadURL(storageRef);
console.log(url);
return url;
} catch (error) {
// Call the failure callback with the error message
console.log(error.message);
}
};
Originally, i didnt include the contentType metadata, and it was just uploading as application/octet-stream, which i assume is why it prompts you to save the image.
Image link: https://firebasestorage.googleapis.com/v0/b/cloudnoise-news.appspot.com/o/ref.jpg?alt=media&token=1edc90e7-1668-4a06-92a3-965ce275798b
Currently its displaying this
Somethings i checked through
firebase storage rules is in test mode, so should be able to read and write by anyone.
i tried sticking in different MIME types but it either shows the tiny box, or it shows "undefined"
the files upload successfully and the "swap" in Tinymce editor is also all good.
Any idea why this is happening?
you need to set the metadata tag
const metadata = {
contentType: file.type,
};
This should ensure that the correct content type is set when the image is uploaded to Firebase Storage.
If this does not resolve the issue, you may need to check that the URL returned from getDownloadURL is valid and points to the correct image. You can try opening the URL in a new browser tab to verify that the image is accessible.
I fixed it by adding a blob, I created a blob object with the file data, then i just made it upload the blob object instead of the single file.
const imagesUploadHandler = async (blobInfo, success, failure) => {
try {
const file = blobInfo.blob();
const storageRef = ref(storage, file.name);
const metadata = {
contentType: file.type,
};
// Create a new Blob object with the file data
const blob2 = await new Blob([file], { type: file.type });
// Upload the Blob to Firebase Storage
await uploadBytes(storageRef, blob2, metadata);
const url = await getDownloadURL(storageRef);
console.log(url);
return url;
} catch (error) {
// Call the failure callback with the error message;;
console.log(error.message)
}
};

NestJS File Upload in chunks

Does anyone know how to upload a single file in chunks using NestJS?
I cannot find any working example related to that online.
Here's my current implementation
#Post()
#UseInterceptors(
FileInterceptor('file', {
storage: diskStorage({
destination: function (req, file, cb) {
const dir = path.join(ENV.MNT);
cb(null, dir);
},
filename: editFileName,
}),
fileFilter: fileFilter,
}),
)
uploadFile(#UploadedFile() file: Express.Multer.File) {
console.log(file);
return true;
}
file is undefined (I suppose because the file has not yet been fully received, so no metadata, etc...)
I have working example in my servers, it is similar to yours. Probably "storage: diskStorage" property in your options causes error.
I upload 350mb data without any problem, but it takes some time depends on your connection speed. I didn't test much bigger files, but i think it should work. The point is, uploadFile function runs after your upload finishes. You should see console.log after all upload finished.
#Post()
#UseInterceptors(
FileInterceptor('file', {
dest: './storage/uploads'
}),
)
uploadFile(#UploadedFile() file: Express.Multer.File) {
console.log(file);
return file;
}

Format to POST a file to the ImageKit server?

I've successfully built a React UI to select and upload N files. The key part of it is this:
<input type='file' accept='image/*' id='selectFiles' multiple onChange={handleFileChange} />
The selected files are stored in this state variable:
const [fileList, setFileList] = React.useState<FileList>();
I know they're correctly there because I iterate through them and show them in a preview DIV.
Following ImageKit's instructions, I successfully built an Auth endpoint which returns the auth credentials.
Then, within a useEffect I iterated through fileList to upload one photo at a time to the ImageKit server. But even trying just one file, I keep getting a 400 error informing me that the fileName parameter is missing. It definitely is not missing so I suspect that the problem lies with what I'm providing as the file parameter.
Here's the critical code (with some data obscured for privacy reasons) :
const uploadFile = async (file: File) => {
try {
const body = {
file: file,
publicKey: 'my_public_key',
signature: 'imageKit_signature',
expire: 'imageKit_expiry_value',
token: 'imageKit_token',
fileName: 'test123.jpg',
useUniqueFileName: false,
folder: userName,
overwriteFile: false,
};
const response = await axios.post('https://upload.imagekit.io/api/v1/files/upload', body);
console.log(response.status, response.data);
} catch (err) {
console.error(err);
}
};
Might anyone see what I'm doing wrong?
Robert
I solved the problem. If you're going to upload a file to ImageKit using their POST endpoint, you need to explicitly set the headers like this:
const response = await axios.post(
'https://upload.imagekit.io/api/v1/files/upload',
body,
{ headers: {'Content-Type': 'multipart/form-data'} }
);
For those wondering, here's the barebones body:
const body = {
file: base64File,
publicKey: imageKitPublicKey,
signature: authParams?.signature,
expire: authParams?.expire,
token: authParams?.token,
fileName: 'someFilename.ext',
};
But indeed, specifying Content-Type like above will allow you to upload a file to their server.

upload local image file to aws s3 without input field

I'm making a react app where I let the user upload a pdf file and then I convert the pdf file to a jpg file, store it locally then upload it to aws s3. However currently, when I upload the jpg file to aws s3 the file is not uploaded as an image file. I want to upload a local image file to aws s3 without having to use <input type="file" />
I tried this using fs.readFile() with s3.upload() but the file that is uploaded is not an image file. I also tried using multer-s3 but this requires the user to manually select the image file using a <input type="file" />, which I want to avoid.
Here is how I'm uploading the jpg file:
const aws = require("aws-sdk");
const multer = require("multer");
const fs = require("fs");
const convertPdf = require("pdf-poppler");
const s3 = new aws.S3({
accessKeyId: "<key>",
secretAccessKey: "<secret>",
Bucket: "<bucketName>"
});
const storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, path.join(__dirname + "/uploads/"));
},
filename: function(req, file, cb) {
// let pdfName = "samplePDF";
// req.body.file = pdfName;
cb(null, file.originalname);
}
});
const upload = multer({
storage: storage
}); //SAVING PDF TO DISK STORAGE
router.post("/pdf", upload.single("pdf"),(req, res, next) => {
const uploadPath = req.file.path;
var imagePath = req.file.destination + req.file.originalname.slice(0, -4) + "-1.jpg";
let opts = {
format: "jpg",
out_dir: req.file.destination,
out_prefix: path.basename(req.file.path).slice(0, -4),
page: null
}
//CONVERTING PDF TO JPG
convertPdf.convert(uploadPath, opts).then(() =>
{
fs.readFile(imagePath, (err, data) => {
if (err) throw err;// UPLOADING FILE BUT NOT IN IMAGE FORMAT
const params = {
Bucket: "<bucketName>",
Key: path.basename(imagePath),
Body: data
};
s3.upload(params, (s3Error, data) => {
if (s3Error) throw s3Error;
console.log(`File uploaded successfully at ${data.Location}`);
res.json({
image: data.key,
location: data.Location
});
});
});
});
});
I expected an image file to be uploaded but not the uploaded file is not an image file which is the problem. Is there any way to upload a local image file to aws s3 without requiring the use of an input field?
EDIT: turns out aws s3 makes the uploaded file private by default which is why the file could not be read, issue is resolved when I make the file public.
The uploaded file was an image file, it just didn't have the right permissions. I added the ACL: "public-read" param and now the file displays as expected.
Updated code:
fs.readFile(imagePath, (err, data) => {
if (err) throw err;
const params = {
Bucket: "flyingfishcattle",
Key: path.basename(imagePath),
Body: data,
ACL: "public-read"
};
s3.upload(params, (s3Error, data) => {
if (s3Error) throw s3Error;
console.log(`File uploaded successfully at ${data.Location}`);
res.json({
image: data.key,
location: data.Location
});
});
});

React dropzone, how to upload image?

Using React dropzone, I've successfully accessed the image using the onDrop callback. However, I'm trying to upload to Amazon S3 by sending the image to my server, saving to an S3 bucket, and returning a signed url to the image back to the client.
I can't do this with the information I have so far and the docs don't seem to mention this to my knowledge.
onDrop triggers a function call in my redux actions with the files:
export function saveImageToS3 (files, user) {
file = files[0]
// file.name -> filename.png
// file -> the entire file object
// filepreview -> blob:http:localhost:3000/1ds3-sdfw2-23as2
return {
[CALL_API] : {
method:'post',
path: '/api/image',
successType: A.SAVE_IMAGE,
body: {
name: file.name,
file: file,
preview: file.preview,
username: user
}
}
}
}
However, when I get to my server, I'm not sure how to save this blob image (that's only referenced from the browser.)
server.post('/api/image', (req, res) => {
// req.body.preview --> blob:http://localhost:3000/1ds3-sdfw2-23as2
// req.body.file -> {preview:blob:http://localhost:3000/1ds3-sdfw2-23as2}, no other properties for some reason
})
React Dropzone returns an array of File objects which can be sent to a server with a multi-part request. Depend on the library you use it can be done differently.
Using Fetch API it looks as follows:
var formData = new FormData();
formData.append('file', files[0]);
fetch('http://server.com/api/upload', {
method: 'POST',
body: formData
})
Using Superagent you would do something like:
var req = request.post('/api/upload');
req.attach(file.name, files[0]);
req.end(callback);

Resources