Firebase cloud messaging function returning undefined - javascript

I'm simply sending a notification when someone new has followed you, but when I try to return the users username in the notification it just says "undefined has decided to follow you" instead of the username.
exports.observeFollowing = functions.database.ref('/following/{uid}/{followingId}').onCreate((snapshot,context) => {
var uid = context.params.uid;
var followingId = context.params.followingId;
console.log('User: ' + uid + 'is following: ' + followingId);
return admin.database().ref('/users/' + followingId).once('value', snapshot => {
var userWeAreFollowing = snapshot.val();
return admin.database().ref('/users/' + uid).once('value', snapshot => {
var userDoingTheFollowing = snapshot.val();
var payload = {
notification: {
title: "Someone new has followed you",
body: userWeAreFollowing.username + " has decided to follow you...",
sound: 'default'
}
}
admin.messaging().sendToDevice(userWeAreFollowing.fcmToken, payload)
.then((response) => {
console.log('Successfully sent message:', response);
return response
})
.catch((error) => {
console.log('Error sending message:', error);
});
})
})

Instead of
body: userWeAreFollowing.username + " has decided to follow you...",
should't be the following user name
body: userDoingTheFollowing.usernames + " has decided to follow you...",
and notice in your realtime database you saved the username as usernameS, that might be the problem

Related

How To make a post request from react to node/express api

All i need to do is to send my state of invoice details to database through post request but im having troubles doing it is this the right way to do it or am i missing something
post function works fine if the query is only a string so the only problem is reading the body params
const postInvoices = () => {
const URL = "http://localhost:8000/api/InvSave";
axios
.post(URL,InvDet)
.then((response) => {
console.log("DATA : ",response);
})
.catch((error) => {
console.log(error);
});
};
im sending the state on click
in my api i wrote :
router.route('/InvSave').post((request,response)=>{
try{
const invoices = request.body
dboperations.PostInvoices(invoices).then(result => {
response.status(201).json("api results :",result);
})
}catch(err){
console.error(err)
}
})
const PostInvoices = async (invoices) => {
try {
let pool = await sql.connect(configInsert);
console.log("invoices code",CODE_ART)
const q =
"insert into Packingdetails values('1','"+
invoices.CODE_ART +
"','" +
invoices.a_code +
"','" +
invoices.DESC_ART +
"','" +
invoices.TotalPc +
"','" +
invoices.date+
"')";
console.log("query : "+q)
let invs = await pool.query(q);
console.log("saved");
return invs.recordsets;
} catch (err) {
console.log("POSTINV : ", err.message);
}
};
make sure you are using some kind of body-parser to parse your request
console.log(invoices) to check if you are getting the correct invoices in request body

How do you trigger cloud functions when someone follows someone else using Firebase? I'm using Atom and Xcode

I'm using Firebase and I want to trigger a notification when 'person A' follows 'person B'.
This is my code:
exports.observeFollowing = functions.database.ref('/added/{followerID}/{followingID}').onCreate((snapshot, context) => {
var followerID = context.params.followerID;
var followingID = context.params.followingID;
console.log('User: ' + followerID + ' is following: ' + followingID);
//trying to figure out fcmtoken to send a notification
return admin.database().ref('/users/' + followingID).once('value', snapshot => {
var userWeAreFollowing = snapshot.val();
return admin.database().ref('/users/' + followerID).once('value', snapshot => {
var userDoingTheFollowing = snapshot.val();
var payload = {
notification: {
title: "Someone added you as a friend",
body: userDoingTheFollowing.username + ' is now following you'
}
}
return admin.messaging().sendToDevice(userWeAreFollowing.fcmToken, payload)
.then(response => {
console.log("Successfully sent message:", response);
return response
}).catch(function(error) {
console.log("Error sending message:", error);
});
})
})
});
The console prints the ('User: ' + followerID + ' is following: ' + followingID) part but doesn't show the notification. I've tested cloud notifications before and they worked but this doesn't work for some reason. In the logs, it says:
Successfully sent message: { results: [ { error:
[FirebaseMessagingError] } ]," "failureCount: 1," "successCount: 0,"
So I know that everything up until the console.log('User: ' + followerID + ' is following: ' + followingID); works. But I'm not sure if the notification function is even being called. Am I missing a semicolon or something else? I really can't figure it out. Also, what does failureCount mean? Is it talking about the notifications function?
As explained in the Cloud Functions doc, you need to manage the asynchronous Firebase operations by using promises. You are using the callback version of the once() method: you need to use the promise version, as follows:
exports.observeFollowing = functions.database.ref('/added/{followerID}/{followingID}').onCreate((snapshot, context) => {
const followerID = context.params.followerID;
const followingID = context.params.followingID;
let userWeAreFollowing;
console.log('User: ' + followerID + ' is following: ' + followingID);
return admin.database().ref('/users/' + followingID).once('value')
.then(snapshot => {
userWeAreFollowing = snapshot.val();
return admin.database().ref('/users/' + followerID).once('value')
})
.then(snapshot => {
const userDoingTheFollowing = snapshot.val();
const payload = {
notification: {
title: "Someone added you as a friend",
body: userDoingTheFollowing.username + ' is now following you'
}
}
return admin.messaging().sendToDevice(userWeAreFollowing.fcmToken, payload)
}).catch(function (error) {
console.log("Error sending message:", error);
return null;
});
});
If you want to log a message in the console upon success do as follows:
// ...
.then(snapshot => {
const userDoingTheFollowing = snapshot.val();
const payload = {
notification: {
title: "Someone added you as a friend",
body: userDoingTheFollowing.username + ' is now following you'
}
}
return admin.messaging().sendToDevice(userWeAreFollowing.fcmToken, payload)
})
.then(response => {
console.log("Successfully sent message:", response);
return null;
}).catch(function (error) {
console.log("Error sending message:", error);
return null;
});

Sending notifications when button clicked errors

I'm trying to notify my users when someone clicks the going button but I keep getting a couple of errors in my firebase functions logs.
Uncaught Exception &
Registration token(s) provided to sendToDevice() must be a non-empty string or a non-empty array
exports.observeGoing = functions.database.ref('/going/{postId}/{uid}').onCreate((snapshot,context) => {
var postId = context.params.postId;
var uid = context.params.uid;
console.log('User: ' + uid + ' is going to your activity');
return admin.database().ref('/users/' + uid).once('value', snapshot => {
var creatorOfPost = snapshot.val();
admin.database().ref('/users/' + uid).once('value', snapshot => {
var userGoing = snapshot.val();
var payload = {
notification: {
body: userGoing.usernames + " is going",
sound: "default"
}
}
admin.messaging().sendToDevice(creatorOfPost.fcmToken, payload)
.then((response) => {
console.log('Successfully send message:', response);
return response
})
.catch((error) =>{
console.log('Error sending message:', error);
});
})
})
})
You reveive that error because creatorOfPost.fcmToken can be null
According to the firebase document, the first parameter of admin.messaging.Messaging.sendToDevice() cannot be null.
But in your code, there are 2 possibility to violate this precondition.
creatorOfPost.fcmToken can be null
just do null check before calling admin.messaging.Messaging.sendToDevice()
creatorOfPost can be null
firebase.database.Reference.once() returns DataSnapshot, but it doesnt mean there always be corresponding document.
so, var creatorOfPost = snapshot.val(); can be null.
maybe you can check like this:
return admin.database().ref('/users/' + uid).once('value', snapshot => {
if (!snapshot.exists()) {
return; // or do what you would like
}
var creatorOfPost = snapshot.val();
// ...
// ...
})

Inconsistent results from Firestore Cloud Functions

I have a Cloud Function setup on Firebase that involved checking different parts of the Firestore Database and then sending a message via Cloud Messaging
Below is the JavaScript for the function in question:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().Firebase);
var db = admin.firestore();
exports.newMemberNotification = functions.firestore
.document('Teams/{teamId}/Waitlist/{userId}').onDelete((snap, context) => {
// get the user we want to send the message to
const newValue = snap.data();
const teamidno = context.params.teamId;
const useridno = newValue.userID;
//start retrieving Waitlist user's messaging token to send them a message
var tokenRef = db.collection('Users').doc(useridno);
tokenRef.get()
.then(doc => {
if (!doc.exists) {
console.log('No such document!');
} else {
const data = doc.data();
//get the messaging token
var token = data.messaging_token;
console.log("token: ", token);
//reference for the members collection
var memberRef = db.collection('Teams/'+teamidno+' /Members').doc(useridno);
memberRef.get()
.then(doc => {
if (!doc.exists){
console.log('user was not added to team. Informing them');
const negPayload = {
data: {
data_type:"team_rejection",
title:"Request denied",
message: "Your request to join the team has been denied",
}
};
return admin.messaging().sendToDevice(token, negPayload)
.then(function(response){
console.log("Successfully sent rejection message:", response);
return 0;
})
.catch(function(error){
console.log("Error sending rejection message: ", error);
});
} else {
console.log('user was added to the team. Informing them')
const payload = {
data: {
data_type: "team_accept",
title: "Request approved",
message: "You have been added to the team",
}
};
return admin.messaging().sendToDevice(token, payload)
.then(function(response){
console.log("Successfully sent accept message:", response);
return 0;
})
.catch(function(error){
console.log("Error sending accept message: ", error);
});
}
})
.catch(err => {
console.log('Error getting member', err);
});
}
return 0;
})
.catch(err => {
console.log('Error getting token', err);
});
return 0;
});
The issues I have with this are:
The code runs and only sometimes actually checks for the token or sends a message.
the logs show this error when the function runs: "Function returned undefined, expected Promise or value " but as per another Stack Oveflow posts, I have added return 0; everywhere a .then ends.
I am VERY new to node.js, javascript and Cloud Functions so I am unsure what is going wrong or if this is an issue on Firebase's end. Any help you can give will be greatly appreciated
As Doug said, you have to return a promise at each "step" and chain the steps:
the following code should work:
exports.newMemberNotification = functions.firestore
.document('Teams/{teamId}/Waitlist/{userId}').onDelete((snap, context) => {
// get the user we want to send the message to
const newValue = snap.data();
const teamidno = context.params.teamId;
const useridno = newValue.userID;
//start retrieving Waitlist user's messaging token to send them a message
var tokenRef = db.collection('Users').doc(useridno);
tokenRef.get()
.then(doc => {
if (!doc.exists) {
console.log('No such document!');
throw 'No such document!';
} else {
const data = doc.data();
//get the messaging token
var token = data.messaging_token;
console.log("token: ", token);
//reference for the members collection
var memberRef = db.collection('Teams/' + teamidno + '/Members').doc(useridno);
return memberRef.get()
}
})
.then(doc => {
let payload;
if (!doc.exists) {
console.log('user was not added to team. Informing them');
payload = {
data: {
data_type: "team_rejection",
title: "Request denied",
message: "Your request to join the team has been denied",
}
};
} else {
console.log('user was added to the team. Informing them')
payload = {
data: {
data_type: "team_accept",
title: "Request approved",
message: "You have been added to the team",
}
};
}
return admin.messaging().sendToDevice(token, payload);
})
.catch(err => {
console.log(err);
});
});

Firebase function to fetch data from Firebase DB to make Push notification

I have chat app with firebase database and Firebase cloud messaging. I can send firebase notification via console but in real scenario it should be automatic. To make automatic notification,My friend wrote Index.js (Added in cloud functions) file for me but its not sending notifications.
As per our logic function should trigger whenever there is any new entries (in any node or in any room) and fetch these values by firebase function and make post request to FCM server to make notification to receiver device (get value of receiver device from token_To).
Message
Message_From
Time
Type
token_To
Index.js
var functions = require('firebase-functions');
var admin = require('firebase-admin');
var serviceAccount = require('./demofcm-78aad-firebase-adminsdk-4v1ot-2764e7b580.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://demofcm-78aad.firebaseio.com/"
})
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
// response.send("Hello from Firebase!");
// });
exports.setUserNode = functions.auth.user().onCreate(event => {
// ...
});
exports.notifyMsg = functions.database.ref('/{chatroom}/{mid}/')
.onWrite(event => {
if (!event.data.val()) {
return console.log('Message Deleted');
}
const getDeviceTokensPromise = admin.database().ref('/{chatroom}/{mid}/token_to').once('value');
return Promise.all([getDeviceTokensPromise]).then(results => {
const tokensSnapshot = results[0];
if (!tokensSnapshot.hasChildren()) {
return console.log('There are no notification tokens to send to.');
}
const payload = {
notification: {
title: 'You have a new Message!',
body: event.data.val().Message
}
};
const tokens = Object.keys(tokensSnapshot.val());
return admin.messaging().sendToDevice(tokens, payload).then(response => {
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
console.error('Failure sending notification to', tokens[index], error);
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
});
});
});
Firebase function Log
How can i fetch above mentioned values of any newly added node in same room(9810012321-9810012347) or any other room(9810012321-9810012325) from database and send it to FCM to make notification
Thanks in Advance.
What i did is created a Message node and I believe doing this by users key. ie, having the receiver(toId) and sender (fromId) key to send the notification.
Hope it helps.
exports.sendMessageNotification = functions.database.ref('/messages/{pushId}')
.onWrite(event => {
let message = event.data.current.val();
console.log('Fetched message', event.data.current.val());
let senderUid = message.fromId;
let receiverUid = message.toId;
let promises = [];
console.log('message fromId', receiverUid);
console.log('catch me', admin.database().ref(`/users/${receiverUid}`).once('value'));
if (senderUid == receiverUid) {
//if sender is receiver, don't send notification
//promises.push(event.data.current.ref.remove());
return Promise.all(promises);
}
let messageStats = message.messageStatus;
console.log('message Status', messageStats);
if (messageStats == "read") {
return Promise.all(promises);
}
let getInstanceIdPromise = admin.database().ref(`/users/${receiverUid}/pushToken`).once('value');
let getSenderUidPromise = admin.auth().getUser(senderUid);
return Promise.all([getInstanceIdPromise, getSenderUidPromise]).then(results => {
let instanceId = results[0].val();
let sender = results[1];
console.log('notifying ' + receiverUid + ' about ' + message.text + ' from ' + senderUid);
console.log('Sender ', sender);
var badgeCount = 1;
let payload = {
notification: {
uid: sender.uid,
title: 'New message from' + ' ' + sender.displayName,
body: message.text,
sound: 'default',
badge: badgeCount.toString()
},
'data': {
'notificationType': "messaging",
'uid': sender.uid
}
};
badgeCount++;
admin.messaging().sendToDevice(instanceId, payload)
.then(function (response) {
console.log("Successfully sent message:", response);
})
.catch(function (error) {
console.log("Error sending message:", error);
});
});
});
const getDeviceTokensPromise = event.data.child('token_To');
should be there instated of getting data from database reference.
or
with fixed path without wildcard like below
const getDeviceTokensPromise = admin.database().ref('/${chatroom}/${mid}/token_to').once('value');
where chatroom and mid is variable which contain value
Second thing:
if (!tokensSnapshot.exists()) {
should in replace of
if (!tokensSnapshot.hasChildren()) {
third thing:
I am not sure about push notification tokenId but
is it required to do?
const tokens = Object.keys(tokensSnapshot.val());
may be we can use directly like below to send push notification
const tokens = tokensSnapshot.val();
You could store all device tokens in a node called tokens like in my example. Tokens could be an array if you would like one user to be able to get notifications on multiple devices. Anyway, store them by their UID.
This works for both Andriod and iOS.
Here is my code:
function loadUsers() {
let dbRef = admin.database().ref('/tokens/' + recieveId);
console.log(recieveId)
let defer = new Promise((resolve, reject) => {
dbRef.once('value', (snap) => {
let data = snap.val();
console.log("token: " + data.token)
//userToken = data.token
resolve(data.token);
}, (err) => {
reject(err);
});
});
return defer;
}
Next we create the notification. I created a lastMessage node to capture just the last message sent in the chat. It is just updated every time a new message is sent in a chat between two users. Makes it easy to get the value. Also makes it easy to show the message on the Conversations screen where there is a list of users who are in a conversation with the current user.
exports.newMessagePush =
functions.database.ref('/lastMessages/{rcId}/{sendId}').onWrite(event => {
if (!event.data.exists()) {
console.log("deleted message")
return;
}
recieveId = event.params.rcId
//let path = event.data.adminRef.toString();
// let recieveId = path.slice(53, 81);
return loadUsers().then(user => {
console.log("Event " + event.data.child("text").val());
let payload = {
notification: {
title: event.data.child("name").val(),
body: event.data.child("text").val(),
sound: 'default',
priority: "10",
}
};
return admin.messaging().sendToDevice(user , payload);
});
});
To implement this logic on your current data structure, just change this line:
let dbRef = admin.database().ref('/tokens/' + recieveId);
and this line:
exports.newMessagePush =
functions.database.ref('/lastMessages/{rcId}/{sendId}').onWrite(event
=> {
to your token location:
let dbRef =
admin.database().ref('/${chatroom}/${mid}/token_to');
and your conversation location:
exports.notifyMsg = functions.database.ref('/{chatroom}/{mid}/')
.onWrite(event => {
Then just change the notification payload be the message you want to display and throw in your error handling on the end of the sendToDevice function, as you did in your code.
Hopefully you figured all this out already but if not maybe this will help you or others trying to use Cloud Functions for notifications.
let payload = {
notification: {
uid: sender.uid,
title: 'New message from' + ' ' + sender.displayName,
body: message.text,
sound: 'default',
badge: badgeCount.toString()
},
'data': {
'notificationType': "messaging",
'uid': sender.uid
}
};
There are two types of FCMs.
1) Data
2) Notification
For detailed overview : FCM Reference
You have to fix your payload for both FCMS. And for Data FCM you have to extract Data in your FCM Service (Client) and generate a push notification according to your need.

Categories

Resources