How to Save Payload after sending a notifications in cloud functions? - javascript

How I can save a payload after sending them to specific Token in the specific node " Notifications/" to retrieve it in single screen later,
and it saves very well,
but when I got a notification I see providerName as a undefined when I declare a variable "providerName"
const functions = require("firebase-functions");
const admin = require("firebase-admin");
var serviceAccount = require("./serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://khadamatiapp-42657.firebaseio.com"
});
exports.acceptedOrder = functions.database
.ref("/AcceptedOrders/{pid}/{orderid}")
.onCreate(async (snapshot, context) => {
const registrationTokens = snapshot.val().userToken;
// const event = context.params;
const pid = context.params.pid;
console.log("#pid", pid);
const username = snapshot.val().username;
const userUid = snapshot.val().userUid;
var providerName;
admin
.database()
.ref(`providers/${pid}`)
.once("value")
.then(snapshot => {
providerName = snapshot.val().username;
console.log("pName", providerName); // here i got ProviderOne
});
console.log("#providerName", providerName); //here i got undefined
const payload = {
notification: {
from: pid,
to: userUid,
title: "New Order",
body: `Hi ${username}, You Order is Accepted from ${providerName}, check it now! `
//Hi userOne, You Order is Accepted from ***Undefined***, check it now!
}
};
try {
let notification = payload.notification;
const response = await admin
.messaging()
.sendToDevice(registrationTokens, payload)
.then(() => {
admin
.database()
.ref(`Notifications/${userUid}`)
.push({ notification });
});
console.log("Successfully sent message:", response);
} catch (error) {
console.log("Error sending message:", error);
}
return null;
});
Update
I have three functions and it's a trigger in the same root,
now acceptedOrderFromProvider that's invoked when I create new Element in the "AcceptedOrders" Root and send a push notification
and another function is CompletedOrderFromProvider that's trigger if the status changed, send a notification I use an onUpdate rigger but doesn't work well,
it's invoked when every element created or updated,
so how to force it to invoke just when some field "status" changed?
check here image
exports.acceptedOrderFromProvider = functions.database
.ref("/AcceptedOrders/{pid}/{orderid}")
.onCreate(async (snapshot, context) => {
const registrationTokens = snapshot.val().userToken;
// const event = context.params;
const pid = context.params.pid;
// console.log("#pid", pid);
const username = snapshot.val().username;
const userUid = snapshot.val().userUid;
var providerName;
admin
.database()
.ref(`providers/${pid}`)
.once("value")
.then(async snapshot => {
providerName = snapshot.val().username;
const payload = {
notification: {
from: pid,
to: userUid,
title: "Accepted Order",
body: `Hi ${username}, You Order is Accepted from ${providerName}, check it now! `
}
};
try {
let notification = payload.notification;
const response = await admin
.messaging()
.sendToDevice(registrationTokens, payload)
.then(() => {
admin
.database()
.ref(`Notifications/${userUid}`)
.push({ notification });
});
console.log("Successfully sent message:", response);
} catch (error) {
console.log("Error sending message:", error);
}
});
return null;
});
exports.cancelledOrderFromProvider = functions.database
.ref("/AcceptedOrders/{pid}/{orderid}")
.onDelete(async (snapshot, context) => {
const registrationTokens = snapshot.val().userToken;
// const event = context.params;
const pid = context.params.pid;
// console.log("#pid", pid);
const afterData = snapshot.val();
// console.log(afterData);
const username = snapshot.val().username;
const userUid = snapshot.val().userUid;
const nameOfProblem = snapshot.val().nameOfProblem;
var providerName;
admin
.database()
.ref(`providers/${pid}`)
.once("value")
.then(async snapshot => {
providerName = snapshot.val().username;
const payload = {
notification: {
from: pid,
to: userUid,
title: "Order Cancelled",
body: `Hi ${username}, ${providerName} Cancelled your Order "${nameOfProblem}"!`
}
};
try {
let notification = payload.notification;
const response = await admin
.messaging()
.sendToDevice(registrationTokens, payload)
.then(() => {
admin
.database()
.ref(`Notifications/${userUid}`)
.push({ notification });
});
console.log("Successfully sent message:", response);
} catch (error) {
console.log("Error sending message:", error);
}
});
return null;
});
exports.CompletedOrderFromProvider = functions.database
.ref("/AcceptedOrders/{pid}/{orderid}")
.onUpdate(async (snapshot, context) => {
console.log(snapshot.after.val());
const registrationTokens = snapshot.after.val().userToken;
const pid = context.params.pid;
const username = snapshot.after.val().username;
const userUid = snapshot.after.val().userUid;
const nameOfProblem = snapshot.after.val().nameOfProblem;
var providerName;
admin
.database()
.ref(`providers/${pid}`)
.once("value")
.then(async snapshot => {
providerName = snapshot.val().username;
const payload = {
notification: {
from: pid,
to: userUid,
title: "Order Completed",
body: `Hi ${username}, ${providerName} Completed your Order "${nameOfProblem}"! Check it Now`
}
};
try {
let notification = payload.notification;
const response = await admin
.messaging()
.sendToDevice(registrationTokens, payload)
.then(() => {
admin
.database()
.ref(`Notifications/${userUid}`)
.push({ notification });
});
console.log("Successfully sent message:", response);
} catch (error) {
console.log("Error sending message:", error);
}
});
return null;
});

Code inside a .then() is run asynchronously, so even though it appears above the rest of the code in the function, it may not be called until much later. Put all code that works with providerName inside the .then() callback to ensure it is called only after providerName has been retrieved:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
var serviceAccount = require("./serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://khadamatiapp-42657.firebaseio.com"
});
exports.acceptedOrder = functions.database
.ref("/AcceptedOrders/{pid}/{orderid}")
.onCreate(async (snapshot, context) => {
const registrationTokens = snapshot.val().userToken;
// const event = context.params;
const pid = context.params.pid;
console.log("#pid", pid);
const username = snapshot.val().username;
const userUid = snapshot.val().userUid;
var providerName;
admin
.database()
.ref(`providers/${pid}`)
.once("value")
.then(snapshot => {
providerName = snapshot.val().username;
const payload = {
notification: {
from: pid,
to: userUid,
title: "New Order",
body: `Hi ${username}, You Order is Accepted from ${providerName}, check it now! `
}
};
try {
let notification = payload.notification;
const response = await admin
.messaging()
.sendToDevice(registrationTokens, payload)
.then(() => {
admin
.database()
.ref(`Notifications/${userUid}`)
.push({ notification });
});
console.log("Successfully sent message:", response);
} catch (error) {
console.log("Error sending message:", error);
}
});
return null;
});

Related

How can i send different type of Notificaton with FirebaseCloud sendNotification Function

I have this function which sends notification once there is certain change in my Db node. but i want to send multiple type of notifications for different actions. but when i deploy my function it overrides prior one and then i have tried all functions in single script but its not working properly
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/All_Users/{reciever_user_id}/CouponsUsedNotifications/{notification_id}')
.onWrite((data, context ) => {
const reciever_user_id = context.params.reciever_user_id;
const notification_id = context.params.notification_id;
console.log('Notification sent to : ', reciever_user_id)
if(!data.after.val()){
console.log('Notification Deleted : ', notification_id)
return null;
}
const deviceToken = admin.database().ref(`/All_Users/${reciever_user_id}/Credentials/device_token`).once('value');
return deviceToken.then(result =>
{
const token_id = result.val()
const payload = {
notification:
{
title: "Coupon Used",
body: `Your Coupon has been used..!!`,
icon: "default"
}
}
return admin.messaging().sendToDevice(token_id, payload).then(
Response => {
console.log('Notification Sent')
}
)
})})
exports.sendNotification = functions.database.ref('/All_Users/{reciever_user_id}/UserApprovalNotifications/{notification_id}')
.onWrite((data, context ) => {
const reciever_user_id = context.params.reciever_user_id;
const notification_id = context.params.notification_id;
console.log('Notification sent to : ', reciever_user_id)
if(!data.after.val()){
console.log('Notification Deleted : ', notification_id)
return null;
}
const deviceToken = admin.database().ref(`/All_Users/${reciever_user_id}/Credentials/device_token`).once('value');
return deviceToken.then(result =>
{
const token_id = result.val()
const payload = {
notification:
{
title: "Profile Approved",
body: `Your Profile has been Approved..!!`,
icon: "default"
}
}
return admin.messaging().sendToDevice(token_id, payload).then(
Response => {
console.log('Notification Sent')
}
)
})})
Found the solution...as i am not javascript developer thats why i was struggling but the solution i found is pretty simple. just install the files to new folder.
exports.sendNotification = function.
the sendNotification is the name of function just change it and deploy it

Firestore Cloud Function - Send E-Mail onCreate with SendGrid

I have a contact form which submits data to the Firestore Database. My intention is, that as soon as there's another entry in the collection requests, Firestore shall fire a function via Cloud Function, which contains the configuration for SendGrid, which again is supposed to send the data of this specific entry to an e-mail.
I've also tried to deploy this function, which was successful - but the console shows the following errors, which I reckon won't be the only one:
Cannot read property 'requestId' of undefined
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const SENDGRID_API_KEY = functions.config().sendgrid.key;
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(SENDGRID_API_KEY);
exports.firestoreEmail = functions.firestore
.document('requests/{requestId}')
.onCreate(event => {
const requestId = event.params.requestId;
const db = admin.firestore();
return db.collection('requests').doc(requestId)
.get()
.then(doc => {
const requestId = event.params.requestId;
const request = doc.data();
const msg = {
to: 'fuh#gmx.net',
from: 'hello#angularfirebase.com',
templateId: 'd-',
substitutionWrappers: ['{{', '}}'],
substitutions: {
name: request.name,
lastname: request.lastname,
email: request.email,
package: request.package,
date: request.date,
text: request.text
// and other custom properties here
}
};
return sgMail.send(msg)
})
.then(() => console.log('email sent!') )
.catch(err => console.log(err) )
});
Edit:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const SENDGRID_API_KEY = functions.config().sendgrid.key;
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(SENDGRID_API_KEY);
exports.request = functions.firestore
.document('requests/{requestId}')
.onCreate((snap, context) => {
const db = admin.firestore();
return db.collection('requests').doc(requestId)
.get()
.then(doc => {
const requestId = snap.id;
const request = doc.data();
const msg = {
to: 'fuhr#gmx.net',
from: 'hello#angularfirebase.com',
templateId: 'd-3cd6b40ad6674f33702107d2',
substitutionWrappers: ['{{', '}}'],
substitutions: {
name: request.name,
lastname: request.lastname,
email: request.email,
package: request.package,
date: request.date,
text: request.text
// and other custom properties here
}
};
return sgMail.send(msg)
})
.then(() => console.log('email sent!') )
.catch(err => console.log(err) )
});
The .onCreate() method doesn't return event, it returns the snapshot of the object and from it you get the id of the new object.
So in your case, it has to be:
exports.firestoreEmail = functions.firestore.document('requests/{requestId}')
.onCreate((snap, context) => {
const requestId = snap.id; // get the id
const db = admin.firestore();
return db.collection('requests').doc(requestId)
.get()
.then(doc => {
const request = doc.data();
const msg = {
to: 'fuhr#gmx.net',
from: 'hello#angularfirebase.com',
templateId: 'd-3cd6b40ad6674f33702107d2',
substitutionWrappers: ['{{', '}}'],
substitutions: {
name: request.name,
lastname: request.lastname,
email: request.email,
package: request.package,
date: request.date,
text: request.text
// and other custom properties here
}
};
return sgMail.send(msg)
})
.then(() => console.log('email sent!') )
.catch(err => console.log(err) )
});

Firebase Cloud Messaging Cannot read property 'receiver_id' of undefined

I've got a problem with Firebase Cloud Messaging notifications. When I want to send friend request in my Android app the other client doesn't receive a notification about this. And Firebase Functions log says:
TypeError: Cannot read property 'receiver_id' of undefined
at exports.sendNotification.functions.database.ref.onWrite.event (/user_code/index.js:9:35)
at cloudFunctionNewSignature (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:109:23)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:139:20)
at /var/tmp/worker/worker.js:730:24
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
Here is JavaScript code:
'use strict'
const functions = require('firebase-functions');
const admin = require ('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/Notifications/{receiver_id}/{notification_id}')
.onWrite(event => {
const receiver_id = event.params.receiver_id;
const notification_id = event.params.notification_id;
console.log('We have a notification to send to: ', receiver_id);
if (!event.data.val) {
return console.log('A notification has been deleted from database: ', notification_id);
}
const deviceToken = admin.database().ref(`/Users/${receiver_id}/device_token`).once('value');
return deviceToken.then(result => {
const token_id = result.val();
const payload = {
notification:
{
title: "Friend Request",
body: "you have received a new friend request",
icon: "default"
}
};
return admin.messaging().sendToDevice(token_id, payload).then(response => {
console.log('This was the notification feature.');
});
});
});
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotification = functions.database.ref('/Notifications/{receiver_id}/{notification_id}').onWrite((change, context) => {
const user_id = context.params.user_id;
const notification_id = context.params.notification_id;
console.log('We have a notification : ', user_id);
const afterData = change.after.val();
if (!afterData){
return null;
}
const fromUser = admin.database().ref(`/Notifications/${user_id}/${notification_id}`).once('value');
return fromUser.then(fromUserResult => {
const from_user_id = fromUserResult.val().from;
console.log('You have a new notification from: ', from_user_id);
const deviceToken = admin.database().ref(`/Users/${user_id}/device_token`).once('value');
return deviceToken.then(result => {
const token_id = result.val();
const payload = {
notification: {
title: "New Friend Request",
body: "You've received a new Friend Request",
icon: "default"
}
};
return admin.messaging().sendToDevice(token_id, payload).then(response => {
console.log('This was the notification feature');
});
});
});
});
Try this code. It is taken from here uploaded by #xxxQDAxxx.

Firebase: Cloud Firestore trigger not working for FCM

I wrote this to detect a docment change,when it changes i want to send notifications to all the users who all are inside the Collection "users"
the problem is How to choose all docments inside a collection??
/*eslint-disable */
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification23 = functions.firestore.document("student/anbu").onWrite(event => {
//now i'm returning to my personal document and fetched my username only because i don't want to send a notification to myself,
const fromUser = admin.firestore().collection("users").doc("iamrajesh#gmail.com").get();
//here i want to fetch all documents in the "users" collection
const toUser = admin.firestore().collection("users").document.get();//if i replace "docmument" with "doc("xxxxxxx#gmail.com")" it works it fetches his FCM but how to fetch all documents??
//All documents has a "username",and a fcm "token"
return Promise.all([fromUser, toUser]).then(result => {
const fromUserName = result[0].data().userName;
const toUserName = result[1].data().userName;
const tokenId = result[1].data().tokenId;
const notificationContent = {
notification: {
title: fromUserName + " is shopping",
body: toUserName,
icon: "default",
sound : "default"
}
};
return admin.messaging().sendToDevice(tokenId, notificationContent).then(result => {
console.log("Notification sent!");
//admin.firestore().collection("notifications").doc(userEmail).collection("userNotifications").doc(notificationId).delete();
});
});
});
The following should do the trick.
See the explanations within the code
/*eslint-disable */
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification23 = functions.firestore.document("student/anbu").onWrite((change, context) => {
// Note the syntax has change to Cloud Function v1.+ version (see https://firebase.google.com/docs/functions/beta-v1-diff?0#cloud-firestore)
const promises = [];
let fromUserName = "";
let fromUserId = "";
return admin.firestore().collection("users").doc("iamrajesh#gmail.com").get()
.then(doc => {
if (doc.exists) {
console.log("Document data:", doc.data());
fromUserName = doc.data().userName;
fromUserId = doc.id;
return admin.firestore().collection("users").get();
} else {
throw new Error("No sender document!");
//the error is goinf to be catched by the catch method at the end of the promise chaining
}
})
.then(querySnapshot => {
querySnapshot.forEach(function(doc) {
if (doc.id != fromUserId) { //Here we avoid sending a notification to yourself
const toUserName = doc.data().userName;
const tokenId = doc.data().tokenId;
const notificationContent = {
notification: {
title: fromUserName + " is shopping",
body: toUserName,
icon: "default",
sound : "default"
}
};
promises.push(admin.messaging().sendToDevice(tokenId, notificationContent));
}
});
return Promise.all(promises);
})
.then(results => {
console.log("All notifications sent!");
return true;
})
.catch(error => {
console.log(error);
return false;
});
});

Firebase Cloud functions timeout

The following function works well when tested with shell, and data are created in firestore.
When pushed in prod, it returns Function execution took 60002 ms, finished with status: 'timeout'
Any input?
exports.synchronizeAzavista = functions.auth.user().onCreate(event => {
console.log('New User Created');
const user = event.data;
const email = user.email;
const uid = user.uid;
return admin.database().ref(`/delegates`)
.orderByChild(`email`)
.equalTo(email)
.once("child_added").then(snap => {
const fbUserRef = snap.key;
return admin.firestore().collection(`/users`).doc(`${fbUserRef}`).set({
email: email,
uid: uid
}).then(() => console.log("User Created"));
});
});
Edit
I've update my code with the following, but I still getting Function returned undefined, expected Promise or value but I can't identify where my function return undefined. Why my getUser() function does not return anything?
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.synchronizeAzavista = functions.auth.user().onCreate(event => {
console.log('New User Created');//This log
const user = event.data;
const email = user.email;
const uid = user.uid;
console.log('Const are set');//This log
getUser(email).then(snap => {
console.log("User Key is " + snap.key);//No log
const fbUserRef = snap.key;
return admin.firestore().collection(`/users`).doc(`${fbUserRef}`).set({
email: email,
uid: uid
});
}).then(() => console.log("User Data transferred in Firestore"));
});
function getUser(email) {
console.log("Start GetUser for " + email);//This log
const snapKey = admin.database().ref(`/delegates`).orderByChild(`email`).equalTo(email).once("child_added").then(snap => {
console.log(snap.key);//No Log here
return snap;
});
return snapKey;
}
You're not returning a promise from your write to Firestore.
exports.synchronizeAzavista = functions.auth.user().onCreate(event => {
const user = event.data;
const email = user.email;
const uid = user.uid;
return admin.database().ref(`/delegates`)
.orderByChild(`email`)
.equalTo(email)
.once("child_added").then(snap => {
const fbUserRef = snap.key;
return admin.firestore().collection(`/users`).doc(`${fbUserRef}`).set({
email: email,
uid: uid
});
});
});

Categories

Resources