How do I upload a base64 image to firebase using Busboy (React)? - reactjs

I am having trouble uploading an image to the db after cropping. I am able to upload the file on Postman, but can't figure out how to do it after cropping and getting it returned as a base64.
Here is my route that works with uploading a raw file, but not the base64:
exports.uploadProfileMedia = (req, res) => {
const BusBoy = require("busboy")
const path = require("path")
const os = require("os")
const fs = require("fs")
let mediaFileName
let mediaToBeUploaded = {}
let generatedToken = uuidv4()
const busboy = new BusBoy({ headers: req.headers })
busboy.on("file", (fieldname, file, filename, encoding, mimetype) => {
console.log(file, "before")
if (
mimetype !== "image/jpeg" &&
mimetype !== "image/png" &&
mimetype !== "image/heic"
) {
return res.status(400).json({ error: "Wrong file type submitted" })
}
const mediaExtension = filename.split(".")[
filename.split(".").length - 1
]
mediaFileName = `${Math.round(
Math.random() * 100000000000
).toString()}.${mediaExtension}`
const filepath = path.join(os.tmpdir(), mediaFileName)
mediaToBeUploaded = { filepath, mimetype }
file.pipe(fs.createWriteStream(filepath))
console.log(file, "after")
})
busboy.on("finish", () => {
admin
.storage()
.bucket()
.upload(mediaToBeUploaded.filepath, {
resumable: false,
metadata: {
metadata: {
contentType: mediaToBeUploaded.mimetype,
firebaseStorageDownloadTokens: generatedToken
}
}
})
.then(() => {
const mediaUrl = `https://firebasestorage.googleapis.com/v0/b/${firebaseConfig.storageBucket}/o/${mediaFileName}?alt=media&token=${generatedToken}`
return db
.doc(`/users/${req.user.username}`)
.update({ mediaUrl })
})
.then(() => {
return res
.status(201)
.json({ message: "Media uploaded successfully" })
})
.catch((err) => {
console.error(err)
return res.status(500).json({ error: err.code })
})
})
busboy.end(req.rawBody)
}
Here is where I pass in a base64 after cropping:
const uploadProfileMedia = (formData) => {
axios.defaults.headers.common["Authorization"] = localStorage.getItem(
"FBIdToken"
)
axios
.post("/api/user/media", formData)
.then((res) => {})
.catch((err) => console.log(err))
console.log(formData, "form")
}
Here is a snippet of the above console.log():
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDREN
Here is the function which calls the uploadProfileMedia():
const showCroppedImage = useCallback(async () => {
console.log(imageSrc, "imgsrc")
try {
const croppedImage = await getCroppedImg(
imageSrc,
croppedAreaPixels
)
setCroppedImage(croppedImage)
uploadProfileMedia(croppedImage)
console.log(croppedImage, "showcroppedImage")
} catch (e) {
console.error(e)
}
}, [imageSrc, croppedAreaPixels])

Related

how can i save contentype/mimetype of a file/image to node.js using expess and multer

Still a beginner, I was currently learning how to upload images, save them to a database and then display them to a client, in the database, i m trying to save the filename, contentType and base64 Encoding, all with the type String, but i keep getting the error: error "uploads validation failed: ContentType: Path ContentType is required."
But I did specify the path, can anyone please help. find code below
schema.js
const mongoose = require('mongoose')
const uploadSchema = new mongoose.Schema({
filename: {
type: String,
unique: true,
required: true
},
ContentType: {
type: String,
required: true
},
imageBase64: {
type: String,
required: true
}
})
module.exports = mongoose.model('uploads', uploadSchema)
controller.js
const UploadModel = require('../model/schema')
const fs = require('fs')
const mongoose = require('mongoose')
exports.home = (req, res, next) => {
res.render('index')
}
exports.uploads = (req, res, next) => {
const files = req.files
if (!files) {
const err = new Error('Please choose files')
err.httpStatusCode = 400
return next(err)
}
// Convert images into based64 encoding
let imgArray = files.map((file) => {
let img = fs.readFileSync(file.path)
return encode_image = img.toString('base64')
})
let results = imgArray.map((src, index) => {
// Create object to store data in the collection
let finalImg = {
filename: files[index].originalname,
contentType: files[index].mimetype,
imageBase64: src
}
console.log(finalImg.contentType)
let newUpload = new UploadModel(finalImg)
return newUpload
.save()
.then(() => {
return {msg: `${files[index].originalname} Uploaded Sucessfully...!`}
})
.catch((err) => {
if(err) {
if(err.name === 'MongoError' && err.code === 11000) {
return Promise.reject({err: `Duplicate ${files[index].originalname}.File Already exists!`})
}
return Promise.reject({error: err.message || `Cannot Upload ${files[index].originalname} Something missing!`})
}
})
})
Promise.all(results)
.then(msg => {
//res.redirect('/')
res.json(msg)
})
.catch(err => {
res.json(err)
})
}

Unsupported field value: undefined,Function addDoc() called with invalid data

so here I want to store the array of image URL from the firebase storage in firestore. I am getting an error of undefined as my ImageUrl is undefined. please help me to solve this.The images are stored on cloud storage.
The code below shows my onSubmit function where a copy of the formdata is created.I have tried with and without '.then' and both gives me this error
const onSubmit = async (e) => {
e.preventDefault();
setLoading(true);
if (discountedPrice >= regularPrice) {
setLoading(false);
toast.error("Discounted price should be less than regular price");
}
console.log(formData);
if (images.length > 6) {
setLoading(false);
toast.error("Max of 6 images");
}
let geolocation = {};
let location;
// if (address != null) {
try {
const response = await fetch(
`https://maps.googleapis.com/maps/api/geocode/json?address=${address}&key=${process.env.React_App_YOUR_GOOGLE_API_KEY}`
);
const data = await response.json();
console.log(data);
geolocation.lat = data.results[0].geometry.location.lat;
geolocation.lng = data.results[0].geometry.location.lng;
console.log(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
);
console.log(geolocation.lat);
console.log(data.status);
location =
data.status == "ZERO_RESULTS"
? undefined
: data.results[0].formatted_address;
if (location == undefined || location.includes("undefined")) {
setLoading(false);
toast.error("area does not match");
}
} catch (error) {
toast.error("area does not match");
}
//s store image to firebase
const storeImage = async (image) => {
return new Promise((resolve, reject) => {
const storage = getStorage();
const fileName = `${auth.currentUser.uid}-${image.name}-${uuidv4()}`;
const storageRef = ref(storage, "images/" + fileName);
const uploadTask = uploadBytesResumable(storageRef, image);
uploadTask.on(
"state_changed",
(snapshot) => {
// Observe state change events such as progress, pause, and resume
// Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log("Upload is " + progress + "% done");
switch (snapshot.state) {
case "paused":
console.log("Upload is paused");
break;
case "running":
console.log("Upload is running");
break;
}
},
(error) => {
// Handle unsuccessful uploads
reject(error);
},
() => {
// Handle successful uploads on complete
// For instance, get the download URL: https://firebasestorage.googleapis.com/...
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
resolve(downloadURL);
console.log("File available at", downloadURL);
});
}
);
});
};
const imageUrls = await Promise.all(
[...images].map((image) => {
storeImage(image);
})
)
.then(() => {
console.log("urlready " + imageUrls);
uploadingListings(imageUrls);
})
.catch((error) => {
console.log(error);
setLoading(false);
toast.error("Couldn't upload image");
return;
});
const uploadingListings = async (imageUrls) => {
console.log(imageUrls);
const formDataCopy = {
...formData,
imageUrls,
geolocation,
timestamp: serverTimestamp(),
};
formDataCopy.location = address;
delete formDataCopy.address;
delete formDataCopy.images;
!formDataCopy.offer && delete formDataCopy.discountedPrice;
console.log("this is" + formDataCopy);
const docRef = await addDoc(
collection(db, "listings"),
formDataCopy
setLoading(false);
toast.success("Created a listing");
navigate(`/category/${formDataCopy.type}/${docRef.id}`);
});
};
This is how I fixed it.
Realized I wasn't returning the url to imageUrls.
And also found it not helpful using the .then with imageUrls.
const imageUrls = await Promise.all(
[...images].map((image) => {
return storeImage(image);
})
)
// .then(() => {
// console.log("urlready " + imageUrls);
// return uploadingListings(imageUrls);
// })
.catch((error) => {
console.log(error);
setLoading(false);
toast.error("Couldn't upload listing");
return;
});
console.log("urlready " + imageUrls);
const formDataCopy = {
...formData,
imageUrls,
geolocation,
timestamp: serverTimestamp(),
};
console.log(formDataCopy);
formDataCopy.location = address;
delete formDataCopy.address;
delete formDataCopy.images;
!formDataCopy.offer && delete formDataCopy.discountedPrice;
console.log("this is" + formDataCopy);
const docRef = await addDoc(
collection(db, "listings"),
formDataCopy
)
console.log(docRef);
setLoading(false);
toast.success("Created a listing");
navigate(`/category/${formDataCopy.type}/${docRef.id}`);
};

How to remove all file uploaded with upload component of ant design

Is there a way to delete all uploaded files at once? When I uploaded success. I want to call event remove all files. I didn't find any solution for this. Tks for all the help !
Here is my code:
upload file
const [fileDatas, setFileDatas] = useState([]);
const dummyRequest = ({ file, onSuccess }) => {};
const beforeUpload = (file, fileList) => {return false};
const { Dragger } = Upload;
const props = {
accept: 'image/png, image/jpeg, image/svg, image/gif, .xlsx,.xls,image/*,.doc, .docx,.ppt, .pptx,.txt,.pdf',
name: 'file',
multiple: true,
beforeUpload: beforeUpload,
action: dummyRequest,
onChange({ file, fileList }) {
if (file.status !== 'uploading') {
setFileUploads(fileList);
}
},
onDrop(e) {
console.log('Dropped files', e.dataTransfer.files);
setFileUploads(e.dataTransfer.files);
},
};
handle event submit upload file
const handleUploadFile = () => {
if (fileUploads.length === 0) {
toastActionWarning('No files to upload');
}else{
setFileUploads([]);
const formDatas = new FormData();
fileUploads.forEach((file) => {
formDatas.append(file.name, file.originFileObj);
});
axios
.post('files', formDatas, { withCredentials: true })
.then((res) => {
let newList = [...fileDatas];
res.data.data.forEach(element => {
element.author = window.userDisplayName;
newList = [element, ...newList]
});
setFileDatas(newList);
//I want to clear all file here
toastActionSuccess('Upload successfully');
})
.catch((error) => {
toastActionFailed('There was an error in processing');
});
}
};

Unable to post image to imgur api with axios.post

I'm posting an image to imgur, via their API. This is a ReactJS app on TS.
Here base64 is base64 string of the image, usually between 50 to 100kb
const imgurApi = axios.create({
headers: {
'Authorization': 'Client-ID xxx'
}
})
export async function postImgurImage(base64: string, username: string, desc: string) {
try {
const data = {
"image": base64,
"title": username,
"description": desc
}
const res = await imgurApi.post('https://api.imgur.com/3/image', data)
if (res.status === 200) {
console.log(res.data);
return res.data
} else {
return `Error: ${res.statusText}`
}
} catch (err) {
console.log(err);
return err
}
}
This works on postman, but when I try this on the browser, I get this error
Error: Request failed with status code 429
at createError (createError.js:16)
at settle (settle.js:17)
at XMLHttpRequest.handleLoad (xhr.js:62)
EDIT 1
This is how the postImgurImage is being called.
const handleImg = (e: React.ChangeEvent < HTMLInputElement > ) => {
e.preventDefault();
if (e.target.files !== null) {
let reader = new FileReader();
let file = e.target.files[0];
reader.onloadend = () => {
setPostImgPreview(reader.result ? .toString())
}
reader.readAsDataURL(file);
}
}
const handlePost = (e: React.MouseEvent < HTMLButtonElement, MouseEvent > ) => {
e.preventDefault();
const postNameVal = postname.current ? .value
const postContentVal = postcontent.current ? .value
if (postNameVal && postContentVal && postImgPreview) {
const base64 = postImgPreview.split(',')[1];
postImgurImage(base64, currentUser ? .username ? ? '', postContentVal).then(data => {
console.log(data);
})
}
}
<input type="file" name="post-image" id="post-image" accept="image/x-png,image/jpeg" onChange={e=> handleImg(e)} />
<button className="post-button" onClick={handlePost}>Post</button>

How to make Async Await Function in React Native?

I want to create a function that is about uploading photo to Firebase Storage with react-native-fetch-blob. I'm using Redux and you can find action functions below:
My problem is that uploadImage function is not running like asynchronous. Firebase function is running before uploadImage, so application give me an error.
I think i can't make a asynchronous function. How can i fix it ?
uploadImage() function:
const uploadImage = async (imageSource, whereToUpload) => {
let imageURL = '';
const mime = 'image/jpg';
const { Blob } = RNFetchBlob.polyfill;
const { fs } = RNFetchBlob;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
console.log('URI =>', imageSource.uri);
let imgUri = imageSource.uri;
let uploadBlob = null;
const imageRef = firebase.storage().ref(whereToUpload + '/' + imageSource.fileName);
const uploadUri = Platform.OS === 'ios' ? imgUri.replace('file://', '') : imgUri;
await fs.readFile(uploadUri, 'base64')
.then((data) => Blob.build(data, { type: `${mime};BASE64` }))
.then((blob) => {
uploadBlob = blob;
return imageRef.put(blob, { contentType: mime });
})
.then(() => {
uploadBlob.close();
// eslint-disable-next-line no-return-assign
return imageURL = imageRef.getDownloadURL();
})
.catch((error) => {
console.log(error);
});
return imageURL;
};
and the main action is:
export const addProjectGroup = (
myUser,
groupName,
groupDescription,
groupProfilePic,
) => dispatch => {
const groupProfileFinalPic = async () => {
let finalGroupPicture = { landscape: '' };
if (_.isEmpty(groupProfilePic.src)) {
await uploadImage(groupProfilePic, 'groupPictures').then((imageURL) => {
console.log('İŞLEM TAMAM!');
console.log('SELECTED IMAGE URL =>', imageURL);
finalGroupPicture.landscape = imageURL;
});
} else {
finalGroupPicture.landscape = groupProfilePic.src.landscape;
}
return finalGroupPicture;
};
console.log("final group profile pic =>", groupProfileFinalPic());
// Önce grubu yaratalım..
// eslint-disable-next-line prefer-destructuring
const key = firebase
.database()
.ref()
.child('groups')
.push().key;
firebase
.database()
.ref('/groups/' + key)
.set({
admin: {
email: myUser.email,
name: myUser.name,
uid: myUser.uid,
},
groupName,
groupDescription,
groupProfilePic: groupProfileFinalPic(),
projects: '',
})
.then(() => {
console.log('Groups oluşturuldu.');
})
.catch(e => {
Alert.alert('Hata', 'Beklenmedik bir hata meydana geldi.');
console.log(e.message);
});
dispatch({
type: ADD_PROJECT_GROUP,
});
};
You are not awaiting groupProfileFinalPic(). This should be done before creating the action you want to dispatch.
groupProfileFinalPic().then(groupProfilePic => {
return firebase
.database()
.ref("/groups/" + key)
.set({
admin: {
email: myUser.email,
name: myUser.name,
uid: myUser.uid
},
groupName,
groupDescription,
groupProfilePic,
projects: ""
})
.then(() => {
console.log("Groups oluşturuldu.");
})
.catch(e => {
Alert.alert("Hata", "Beklenmedik bir hata meydana geldi.");
console.log(e.message);
});
});
I have no clue what the last dispatch is for, you might want to do that in one of the callbacks. Your code is to verbose for an SO question, but I hope this helps anyways.
You are using both await and then on the same call. To use await, you can arrange it something like
const uploadImage = async (imageSource, whereToUpload) => {
...
try {
let data = await RNFS.fs.readFile(uploadUri, 'base64')
let uploadBlob = await Blob.build(data, { type: `${mime};BASE64` }))
...etc...
return finalResult
catch (e) {
// handle error
}
}

Resources