Cloud Functions for Firebase Notification - node.js

I am trying to fire a notification using Cloud Functions for Firebase. I can get it to console log stating a message has been fired, but can't actually get the notification to work in the browser. Can anyone see a flaw?
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.newMessageAlert = functions.database.ref('/messages/{message}').onWrite((event) => {
const message = event.data.val();
const getTokens = admin.database().ref('users').once('value').then((snapshot) => {
const tokens = [];
snapshot.forEach((user) => {
const token = user.child('token').val();
if (token) tokens.push(token);
});
return tokens;
});
const getAuthor = admin.auth().getUser(message.uid);
Promise.all([getTokens, getAuthor]).then(([tokens, author]) => {
const payload = {
notification: {
title: `Hot Take from ${author.displayName}`,
body: message.content,
icon: author.photoURL
}
};
admin.messaging().sendToDevice(tokens, payload).then((resp) =>{
console.log("IT WORKED", resp);
});
});
});

Related

How to retrieve FCM Token and userId from database then send Push Notification with Node.js and Cloud Functions

I'm very new to Node.js and I'm having trouble figuring out how to send a push notification.
This is my code so far.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.sendPushOrderOnTheWay = functions.https.onRequest((req, res) => {
const userId = req.body.id;
const registrationToken = ''
db.collection('users').doc(userId).get().then(function (doc) {
registrationToken = doc.data().registrationToken;
});
const payload = {
token: registrationToken,
notification: {
title: 'Din levering er på vej!',
body: 'Vi er der indenfor 30 min.'
},
data: {
body: message,
}
};
admin.messaging().send(payload).then((response) => {
console.log('wuhuu:', response);
return { success: true };
}).catch((error) => {
return { error: error.code };
});
});
I know something is missing to make it work, but I can't seem to figure out what it is.
My problem:
I don't know how to properly get the userId and FCM token.
Or if there are any other mistakes in my code.
This is my firestore structure:
Picture here

How to send data via HTTP request to Firestore database

So, I am trying to make an app with Node.js, Vue, and Firebase. I currently have a very basic function using firebase functions to send data to the realtime database via http request. I cant figure out how to do the same for Firestore database.
My goal is to send data or a file of some JSON data to my Firestore database from outside the app with an HTTP request. I know how to deploy functions I just am not sure how to send files or JSON to the database for further use.
Any help is greatly appreciated!
I have been playing around with different functions but can't seem to figure it out. I have looked at many of the docs/videos for firebase but I am pretty knew to this and can't quite grasp it.
const functions = require('firebase-functions');
const admin = require('firebase-admin')
admin.initializeApp() //need admin sdk
const toUpperCase = (string) => string.toUpperCase();
exports.addMessage = functions.https.onRequest((request, response) => {
const text = request.query.text;
const secretText = toUpperCase(text);
admin
.database()
.ref('/sentMSG')
.push({ text: secretText })
.then(() =>
response.json({
message: 'great!!!!',
text
})
)
.catch(() => {
response.json({
message: 'not great :^('
});
});
});
exports.writeToStore = functions.firestore.https.onRequest((request,
response) => {
let data = request.query.text
let setDoc = db.collection('cities').doc('LA').set(data)
.then(() =>
response.json({
message: 'great!!!!',
text
})
)
.catch(() => {
response.json({
message: 'not great :^('
});
});
});
The addMessage function adds data to realtime database but I need to do it for Firestore
index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const _ = require('lodash');
admin.initializeApp();
const db = admin.firestore();
const express = require('express');
const cors = require('cors');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.get('/', async (req, res) => {
let data = req.query.data;
try {
await db.collection('users').doc().set({ userId: data });
} catch(err) { res.send(JSON.stringify(err)) }
res.send('Success');
})
app.post('/', async (req, res) => {
let payload = req.body;
let keys = Object.keys(payload);
let obj = {};
let i = 0;
try {
_.forEach(payload, async data => {
obj[keys[i]] = data;
i++;
})
await db.collection('users').doc().set(obj);
} catch(err) { res.send(JSON.stringify(err))}
res.send('Success');
})
exports.writeToFirestore = functions.https.onRequest(app);
You can then call this Cloud Function like such: linkToURL/writeToFirestore?data=5 or make a Post request to linkURL/writeToFirestore
From what I understand, whenever the Cloud Function is triggered, you want to write data in both the Firebase Realtime Database and in Firestore. Cloud Function will only execute one function in the exports object. In this case, since the function is being triggered by HTTPS, you can create a single exports.writeToBoth that encapsulates the code to write in Realtime DB and Firestore. Furthermore, I noticed that the writeToFirestore written is invalid, you need to change functions.firestore.https.onRequest to functions.https.onRequest.
In any case, you can refer to this code as a base, should you want:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
let writeToFirestore = data => {
let setDoc = db.collection('users').doc('0').set(data);
}
let writeToRealtimeDB = data => {
// ...
// Your code
// ...
}
exports.writeToBoth = functions.https.onRequest((req, res) => {
let data = req.query.text;
// Write to both DB
try {
writeToFirestore(data);
writeToRealtimeDB(data);
} catch(err) { res.send('Error') }
res.send('Success');
})

How to deal with the different type of errors that returns from the cloud function?

I have written the cloud functions which sends the response either with the statuscode 200 or 400 but sometimes I am getting this error
Function execution took 219 ms, finished with status: 'connection error'
Error: function crashed out of request scope Function invocation was interrupted.
So the problem is I need to know send this error message with some statuscode as the response of the cloud function.
const functions = require('firebase-functions');
const dialogflow = require('dialogflow');
const admin = require('firebase-admin');
const Firestore = require('#google-cloud/firestore');
const firestore = new Firestore();
admin.initializeApp();
var db = admin.firestore();
const {WebhookClient} = require('dialogflow-fulfillment');
var UID = new Object();
exports.fulfillmenttext = functions.https.onRequest((req,res) =>{
const answer1 = req.body.Text;
const uid = answer1.substring(0,28);
const answer = answer1.substring(28);
const sessionId = uid;
var count,questvalue;
const promise = db.collection("***").doc('***').collection("**").doc("uid").get();
promise.then(doc => {
snapshot.forEach(function(doc) {
if (doc.exists) {
count = doc.data().count;
if(count == 1){
var updatequest = title[questvalue];
res.status(200).send({"question":updatequest,"question_number":questvalue});
return;
}
else{
runSample();
}
}
else {
console.log("No such document!");
}
});
}).catch(function(error) {
console.log("Error getting document:", error);
});
async function runSample() {
const languageCode = 'en-US';
const projectId = 'xxxxxxx';
const credentials = {
client_email: 'xxxxxxx',
private_key:
'xxxxxxx',
};
//Instantiate a DialogFlow client.
const dialogflow = require('dialogflow');
const sessionClient = new dialogflow.SessionsClient({
projectId,
credentials,
});
// Define session path
const sessionPath = sessionClient.sessionPath(projectId, sessionId);
// The text query request.
const request = {
//session: context1,
session: sessionPath,
queryInput: {
text: {
text: answer,
languageCode,
},
},
};
const responses = await sessionClient.detectIntent(request);
const result = responses[0].queryResult;
let action = result.action;
if (result.intent) {
const question = result.fulfillmentText;
console.log("question is",question);
const actionHandlers = {
'early': () => {
console.log('earlyaction1', action);
let name1 = JSON.stringify(result.parameters.fields.Name.stringValue);
name1 = name1.toString().replace(/"/g,"");
var data1 = {
Name: name1
};
var setDoc1 = admin.firestore().collection('**').doc('uid').collection("***").doc('uid').collection('**').doc('**').update(data1);
},
};
if (action === 'early') {
console.log('1');
actionHandlers[action]();
}
res.status(200).send({"question":result.fulfillmentText,"action":action,"question_number":title.indexOf(question)});
} else {
console.log(` No intent matched.`);
res.status(400).send({"action":"empty"});
}
}
});
That message is telling you that you have some async code that was still running after the function terminated normally by sending a response to the client. That bit of async code crashed. Since the function already terminated by sending a response, there's nothing you can do to send another response. There can only be one response per function invocation.
What you'll have to do is review your code and make sure you're 1) handling promises correctly and 2) not intentionally trying to leave any work going after sending the response, since Cloud Functions does not support that.

Function returned undefined, expected Promise or value Firebase log error

Im trying to add a push notification on my app using firebase-function and node.js and all its all working fine, like I got notification from the sender. but my only concern is that the log gave me this error
Function returned undefined, expected Promise or value
and this is my code:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotification = functions.database.ref('/notifications/{user_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 console.log('A notification has been deleted from the database', notification_id);
}
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');
});
});
});
});
what should I return here and where it will be place? I am currently using the latest firebase CFM version 1.0
This line could be causing the error message:
return console.log('A notification has been deleted from the database', notification_id);
When this line is hit, you're effectively returning undefined from the function, because that's what console.log() returns. Instead, you should just return null after the log.

How to get push notification in FCM when child is added in Firebase?

Notification is to be sent when a child is added to /ADMIN/Orders
The notification has to be sent to each user who have the same Token ID
My node.js code is
'use strict'
var topic = "Users";
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.updateOrder =
functions.database.ref('/ADMIN/Orders/{order_id}').onWrite(event =>{
const order_id = event.params.order_id;
console.log("Today's order is updated!",order_id);
const deviceToken = admin.database().ref(`/USERS/{user_id}/TokenId`).once('value');
return deviceToken.then(result => {
const TokenId = result.val();
const payload = {
notification: {
title: "Order is updated!",
body: "Click to enter Yes/No",
icon: "default"
}
};
// return admin.messaging().sendToDevice(TokenId,payload).then(response =>{
return admin.messaging().sendToTopic(topic, payload).then(response =>{
console.log('This was the notification feature');
});
});
});
My cloud function(.js file) is showing successful execution, but still the push notificaiton is not appearing on my phone.

Resources