How to use async function with mutation and image upload react js - reactjs

I have to upload images in the directory and save that name into a database using graphql resolver. When I upload an image and pass that image in resolver but I am getting an undefined value of image name. So how can I get the image name?
In the Below code, I saved information with file upload but a problem to get a file name after uploading an image. So how can I get the file uploaded file name?
const fs = require("fs");
function ProfileImage(argsprofilephoto) {
try {
argsprofilephoto.then(profilephoto => {
const {
createReadStream,
filename,
mimetype
} = profilephoto;
const fileStream = createReadStream();
fileStream.pipe(fs.createWriteStream(`./uploadedFiles/${filename}`));
console.log("filename=", filename);
return filename;
});
} catch (err) {
console.log(err);
}
}
export default {
Mutation: {
signUp: async (parent, args, {
models,
secret
}) => {
try {
let profimgnm = "";
let docimgnm = "";
// Prfile Photo Upload
if (args.profilephoto != "") {
profimgnm = ProfileImage(args.profilephoto);
console.log("profimgnm=", profimgnm);
}
if (args.documents != "") {
docimgnm = ProfileImage(args.documents);
console.log("docimgnm=", docimgnm);
}
let name = args.name;
let email = args.email;
let phone = args.phone;
let address = args.address;
let zipcode = args.zipcode;
let profilephoto = profimgnm;
let documents = docimgnm;
const user = await models.User.create({
name,
email,
phone,
address,
zipcode,
profilephoto,
documents
});
return user;
} catch (err) {}
}
}
};
I am getting this output.
profimgnm= undefined
docimgnm= undefined
filename= download.jpg
filename= dimg.jpg
Anyone, please give me a solution.

There are a few issues here. You are not returning the promise from ProfileImage async method. You should be doing something like:
function ProfileImage(argsprofilephoto) {
return argsprofilephoto.then(profilephoto => {
const {
createReadStream,
filename,
mimetype
} = profilephoto;
const fileStream = createReadStream();
fileStream.pipe(fs.createWriteStream(`./uploadedFiles/${filename}`));
console.log("filename=", filename);
return filename;
}).catch(e => {
// you might want to return some sensible default depending on your usecase, or let the error bubble up by not catching
console.log(e)
});
}
and in your resolver you need to wait for the promise to resolve:
if (args.profilephoto != "") {
// could still be undefined if the promise above failed on catch block returned nothing, but you get the idea
profimgnm = await ProfileImage(args.profilephoto);
console.log("profimgnm=", profimgnm);
}
if (args.documents != "") {
docimgnm = await ProfileImage(args.documents);
console.log("docimgnm=", docimgnm);
}

Related

trying to update user profile but get error with image I can't update it

I'm trying to update user profile using react native expo I can only update all properties except image is giving me this Error :
[Unhandled promise rejection: FirebaseError: Function DocumentReference.update() called with invalid data. Unsupported field value: undefined (found in field userImg in document users ? please help
const [image, setImage] = useState(null);
const [uploading,setUploading] = useState(false)
const [ userData, setUserData] = useState(null);
useEffect(()=>{
const getUserData = async ()=>{
db.collection("users")
.doc(auth.currentUser?.uid)
.get()
.then(snap => {
setUserData(snap.data());
});
}
getUserData();
},[])
const updateProfile = async()=>{
let imgUrl = await uploadImage();
if(imgUrl == null && userData.userImg){
imgUrl = userData.userImg
}
db.collection("users")
.doc(auth.currentUser.uid)
.update({
name: userData.name,
userName: userData.userName,
email: userData.email,
phone: userData.phone,
address: userData.address,
userImg:userData.mgUrl
})
}
I can upload the image successfully but I can't fetch it from storage to fire store
const uploadImage = async ()=>{
if(image == null){
return null;
}
const blob = await new Promise((resolve, reject)=>{
const xhr = new XMLHttpRequest();
xhr.onload = function (){
resolve(xhr.response)
};
xhr.onerror = function (){
reject( new TypeError("Network request failed"))
};
xhr.responseType = "blob"
xhr.open("GET",image,true)
xhr.send(null)
});
const ref = firebase.storage().ref().child("images/" + new Date().toISOString())
const snapshot = ref.put(blob)
snapshot.on(
firebase.storage.TaskEvent.STATE_CHANGED,
()=>{
setUploading(true)
},
(error)=>{
setUploading(false)
console.log(error)
blob.close();
return;
},
()=>{
snapshot.snapshot.ref.getDownloadURL().then((url)=>{
setUploading(false);
// Alert.alert('Profile Updated', 'You profile Updated Successfully..!')
console.log('donwload:', url)
setUserData(url)
blob.close()
return null
})
}
)
}
}
so please help me out between I'm using React Native Expo and thank you so much
To start off, the error [Unhandled promise rejection: FirebaseError: Function DocumentReference.update() called with invalid data. Unsupported field value: undefined means that one or more fields has a null value but firebase doesn't allow you to store that.
In your uploadImage function you're able to upload your image fine when the image actually does exist but in cases that it doesn't you're returning null which is where the problem is. Ideally, you can return an empty string which is safe then in cases where you read the image you can just check if the string is empty or not.
Fix
Step 1
Change this
if(image == null){
return null;
}
To this
if(image == null){
return "";
}
Step 2
After you get the download URL your setUserData is replacing all the fields with the URL so consider changing it to
`
setUserData({...userData, imgUrl : url})
Step 3
Also realize that in your update() there is a typo for imgUrl change from
userImg:userData.mgUrl to userImg:userData.imgUrl to properly set the image using the step for line
Hope that fixes It :)
`
Check if below code helps you to upload a Video or Image using firebase.
const uploadImageToFirestore = async (res, type) => {
const uri = res.assets[0].uri;
const filename = uri.substring(uri.lastIndexOf('/') + 1);
const uploadUri = Platform.OS === 'ios' ? uri.replace('file://', '') : uri;
const storage = getStorage(app);
const fileRef = ref(storage, filename);
const img = await fetch(uploadUri);
const bytes = await img.blob();
let metadata;
if (type == 'video') {
if (filename.includes("mov") || filename.includes("MOV")) {
metadata = {
contentType: 'video/quicktime'
}
} else {
metadata = {
contentType: 'video/mp4',
};
}
} else {
metadata = {
contentType: 'image/jpeg',
};
}
uploadBytes(fileRef, bytes, metadata).then(async (uploadTask) => {
console.log('task', uploadTask)
getDownloadURL(uploadTask.ref).then((url) => {
if (type == 'video') {
setVideoData(url);
} else {
setImageData(url);
}
});
}).catch((err) => {
alert('Error while uploading Image!')
console.log(err);
});
}

DocumentPicker got NULL for file

I tried to get Data of the Document but I only get Null.
Documentpicker is working, except: The Selected Data is NULL.
async openDocumentReader() {
try {
const res = await DocumentPicker.pick({
type: [DocumentPicker.types.csv],
});
console.log(
res.uri,
res.type,
res.name,
res.size,
);
if (res.name == null) {
Alert.alert('Document is Null');
}
} catch (err) {
if (DocumentPicker.isCancel(err)) {
//User canceld
} else {
throw err;
}
}
Any recommendations?
I found a solution:
I had to choose pickSingle for it.
try {
const res = await DocumentPicker.pickSingle({
type: [DocumentPicker.types.csv], mode : 'import', copyTo: 'documentDirectory',
});
var uri = res.uri;
var name = res.name;
var fileCopyUri = res.fileCopyUri;
console.log(JSON.stringify(res));
console.log(res.uri);
}
Or something like that.

TypeError: Cannot read property 'single' of undefined in multer grid

Please help me , facing problem in multer single file upload
router.post('/file/upload',upload.single('file'), uploadImage);
TypeError: Cannot read property 'single' of undefined
[error found in postRoute.js(api)]
router.post('/file/upload', upload.single('file'), uploadImage);
router.get('/file/:filename', getImage);
-multer grid storage connection with mongodb atlas code:
const multer = require("multer");
const {
GridFsStorage
} = require("multer-gridfs-storage");
const storage = new GridFsStorage({
url: `mongodb://xyz:xyz#blogmern-shard-00-00.6az9f.mongodb.net:27017,blogmern-shard-00-01.6az9f.mongodb.net:27017,blogmern-shard-00-02.6az9f.mongodb.net:27017/blogdata?ssl=true&replicaSet=atlas-hqbs1a-shard-0&authSource=admin&retryWrites=true&w=majority`,
options: {
useUnifiedTopology: true,
useNewUrlParser: true
},
file: (request, file) => {
const match = ["image/png", "image/jpg"];
//if images are not in above format
if (match.indexOf(file.memeType) === -1)
//avoid duplicates in img
return `${Date.now()}-blog-${file.originalname}`;
//if img gets matched
return {
bucketName: "photos",
filename: `${Date.now()}-blog-${file.originalname}`,
};
},
});
const upload = multer({
storage
});
image.js file with api call:
const grid = require('gridfs-stream');
const mongoose = require('mongoose');
const url = 'http://localhost:8000';
let gfs;
const connect = mongoose.connection;
connect.once('open', () => {
gfs = grid(connect.db, mongoose.mongo);
gfs.collection('fs');
})
exports.uploadImage = (request, response) => {
try {
if (!request.file)
return response.status(404).json("File not found");
const imageURL = `${url}/file/${request.file.filename}`
response.status(200).json(imageURL);
} catch (error) {
response.status(500).json(error);
}
}
exports.getImage = async(request, response) => {
try {
const file = await gfs.files.findOne({
filename: request.params.filename
});
//change file in img
const readStream = gfs.createReadStream(file.filename);
readStream.pipe(response);
} catch (error) {
response.status(500).json('Failed to fetch image', error);
}
}
TypeError: Cannot read property 'single' of undefined implies that upload does not exist.
What happens when you run console.log(upload); before that router route registration, like this?
console.log(upload);
...
router.post('/file/upload', upload.single('file'), uploadImage);

Error: Response is not valid JSON object on firebase function with onCall

Here is my cloud function code
exports.markThemAllRead = functions.https.onCall((data) => {
const user = {
id: data.id,
}
let batch = admin.firestore().batch();
admin.firestore().collection("Notifications").doc("comments").collection(user.id).get().then(querySnapshot => {
if(querySnapshot.empty){
return "nice"
}else {
querySnapshot.forEach(doc=>{
batch.update(doc.ref, {isRead:true})
});
return batch.commit()
}
}).catch(err => {
console.log(err)
})
return "Good"
})
I tried many combinations of return statements, but I keep getting Error: Response is not valid JSON object. Can anyone guide me through what could the issue be? I have many other working onCall functions in my code, but this is one is the only one with the batch.update()... perhaps that has something to do with it?
EDIT ATTEMPT
Still getting the same error when trying this:
exports.markThemAllRead = functions.https.onCall((data) => {
const user = {
id: data.id,
}
return markThemRead(user)
})
async function markThemRead(user){
let batch = admin.firestore().batch();
const docsRef = admin.firestore().collection("Notifications").doc("comments").collection(user.id)
const docs = await docsRef.get();
docs.forEach(function(doc){
batch.update(doc.ref, {isRead:true})
})
return batch.commit()
}
Based on the example of in the Firebase documentation Sync, async and promises
async function markThemRead(user){
let batch = admin.firestore().batch();
const docsRef = admin.firestore().collection("Notifications").doc("comments").collection(user.id)
const docs = await docsRef.get();
docs.forEach(function(doc){
await batch.update(doc.ref, {isRead:true})
})
return batch.commit().then(function () { return {status: "All Good"}})
}

React Native - iOS subscription receipt verification (firebase)

currently I am working on a app but struggling to find since last two weeks the following:
I have react native iOS app with RN-iap for subscription.. and would like to implement receipt verification via cloud function at firebase.
I found a similar solution but its with SWIFT: https://www.loopwerk.io/articles/2020/storekit-webhooks-firestore/
can anybody please help me convert the code (swift below) into React Native ? really appreciate
or if any suitable example or lines please.
(I am using React native firebase).
I can able to fetch receipt and save in Firestore collection. Thanks in advance.
below are the codes:
FRONT END CALLING Cloud function
import Firebase
import FirebaseFunctions
import Foundation
final class CloudFunction {
private lazy var functions = Functions.functions()
func validateReceipt(receipt: String, completionHandler: #escaping () -> Void) {
let parameters = ["receipt": receipt]
functions.httpsCallable("validateReceipt").call(parameters) { _, error in
if let error = error {
print(error)
}
completionHandler()
}
}
}
Cloud Function for above:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const fetch = require('node-fetch');
const db = admin.firestore();
const runtimeOpts = {
memory: '1GB',
};
function validateAndStoreReceipt(url, options, userSnapshot) {
return fetch(url, options).then(result => {
return result.json();
}).then(data => {
if (data.status === 21007) {
// Retry with sandbox URL
return validateAndStoreReceipt('https://sandbox.itunes.apple.com/verifyReceipt', options, userSnapshot);
}
// Process the result
if (data.status !== 0) {
return false;
}
const latestReceiptInfo = data.latest_receipt_info[0];
const expireDate = +latestReceiptInfo.expires_date_ms;
const isSubscribed = expireDate > Date.now();
const status = {
isSubscribed: isSubscribed,
expireDate: expireDate,
};
const appleSubscription = {
receipt: data.latest_receipt,
productId: latestReceiptInfo.product_id,
originalTransactionId: latestReceiptInfo.original_transaction_id
};
// Update the user document!
return userSnapshot.ref.update({status: status, appleSubscription: appleSubscription});
});
}
exports.validateReceipt = functions.runWith(runtimeOpts).https.onCall(async (data, context) => {
if (!context.auth) {
throw new functions.https.HttpsError('permission-denied', 'The function must be called while authenticated.');
}
if (!data.receipt) {
throw new functions.https.HttpsError('permission-denied', 'receipt is required');
}
// First we fetch the user
const userSnapshot = await db.collection('users').doc(context.auth.uid).get();
if (!userSnapshot.exists) {
throw new functions.https.HttpsError('not-found', 'No user document found.');
}
// Now we fetch the receipt from Apple
let body = {
'receipt-data': data.receipt,
'password': 'MY_SECRET_PASSWORD',
'exclude-old-transactions': true
};
const options = {
method: 'post',
body: JSON.stringify(body),
headers: {'Content-Type': 'application/json'},
};
return validateAndStoreReceipt('https://buy.itunes.apple.com/verifyReceipt', options, userSnapshot);
});
continuation another cloud function:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const db = admin.firestore();
const runtimeOpts = {
memory: '1GB',
};
exports.appleWebhook = functions.runWith(runtimeOpts).https.onRequest(async (req, res) => {
// Only allow POST requests
if (req.method !== 'POST') {
return res.status(403).send('Forbidden');
}
// Check for correct password
if (req.body.password !== 'MY_SECRET_PASSWORD') {
return res.status(403).send('Forbidden');
}
const receipt = req.body.unified_receipt.latest_receipt_info[0];
// Find the user with this stored transaction id
const userQuerySnapshot = await db.collection('users')
.where('appleSubscription.originalTransactionId', '==', receipt.original_transaction_id)
.limit(1)
.get();
if (userQuerySnapshot.empty) {
throw new functions.https.HttpsError('not-found', 'No user found');
}
const expireDate = +receipt.expires_date_ms;
const isSubscribed = expireDate > Date.now();
const status = {
isSubscribed: isSubscribed,
expireDate: expireDate,
};
const appleSubscription = {
receipt: req.body.unified_receipt.latest_receipt,
productId: receipt.product_id,
originalTransactionId: receipt.original_transaction_id,
};
// Update the user
return userQuerySnapshot.docs[0].ref.update({ status: status, appleSubscription: appleSubscription }).then(function() {
return res.sendStatus(200);
});
});

Resources