API sent Firebase notifications not received on device - javascript

I'm trying to send notifications based on business logic that runs (on nodejs) on my server via a cron.
Issue
Notifications aren't appearing on the device.
Description
I'm using the firebase admin node package.
My code looks something like this
import admin from "firebase-admin";
import serviceAccount from "../../firebase-admin.json" assert { type: 'json' };
import { getMessaging } from 'firebase-admin/messaging';
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
...
console.log(message);
await getMessaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
My log output is something like this
{
notification: {
title: 'This is a string',
body: 'This is another string'
},
token: 'aLphaNumeric:reallyLongAlphaNumericWithDashesAndUnderscores'
}
Successfully sent message: projects/<project-name>/messages/<id>
Everything I'm seeing suggests this should be sent!

sendMulticast and the Admin FCM APIs allow you to multicast a message to a list of device registration tokens. You can specify up to 500 device registration tokens per invocation.
sendMulticast take 2 arguments as input, 1st one is notification which contains the title and body of the message.
The other argument is fcmTokens with type array, so you must pass that argument as array even though there is only one fcmToken
//Import the file where you have imported the service file.
const adminApp = require("../firebase/firebaseConfig");
const notificationToAll = (title, body, tokens) => {
var notibody = {
notification: {
title: title,
body: body,
},
tokens: tokens,
};
return new Promise((resolve, reject) => {
adminApp
.messaging()
.sendMulticast(notibody)
.then((response) => {
console.log(response.responses);
if (response.responses[0].error != undefined) {
console.log(JSON.stringify(response.responses[0].error));
}
resolve(response);
})
.catch((error) => {
console.log(JSON.stringify(error));
reject(error);
});
});
};
module.exports = notificationToAll;
app.js
const notificationToAll = require("./helper/notification");
notificationToAll(
"This is a string",
`This is another string`,
["aLphaNumeric:reallyLongAlphaNumericWithDashesAndUnderscores"]
)
This is tested code and working in a live environment.

Related

no push notification after change is detected in realtime database

I’m trying to create a push notification and after a comment is made in my realtime database.
I use this code which I learned from here
import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin';
export const sendenPushNeu = functions.database
.ref ('/placeID/{placeID}')
.onCreate((snapshot, context) => {
var app = admin.initializeApp({
credential: admin.credential.cert('/Users/...Desktop/firebasedesktop/key.json')
});
var registrationToken = 'dplk1...bS7eu';
var message = {
data: {
score: '850',
time: '2:45'
},
token: registrationToken
};
// Send a message to the device corresponding to the provided
// registration token.
admin.messaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
})
But I don't get a notification.
I am new to javascript and cannot see what is wrong here.

NodeJS: Firebase Admin SDK is not initializing

I am trying to run the below cod which initialises the Firebase Admin SDK, and send a notification message.
const admin = require('firebase-admin/app');
const errorCodes = require('source/error-codes');
const PropertiesReader = require('properties-reader');
const prop = PropertiesReader('properties.properties');
exports.sendSingleNotification = async (event, context) => {
const params = event.queryStringParameters;
var serviceAccount = require("xxx-xxx-firebase-adminsdk-xxx-xxx.json");
try {
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
console.log("INITIALIZED");
// This registration token comes from the client FCM SDKs.
const registrationToken = params.fcmtoken;
console.log()
const message = {
notification: {
title: 'FooCorp up 1.43% on the day',
body: 'FooCorp gained 11.80 points to close at 835.67, up 1.43% on the day.'
},
token: registrationToken
};
// Send a message to the device corresponding to the provided
// registration token.
admin.getMessaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
return {"response":response}
})
.catch((error) => {
console.log('Error sending message:', error);
return {"error 1":error}
});
} catch (error) {
console.log(error);
return {"error 2":error}
}
};
Here the serviceAccount means the path of the Firebase private key file which is in the root of this project.
However when I run this code I always end up with the following error.
START RequestId: e66ffdd9-ab9c-4a68-ade2-7cfa97f42c31 Version: $LATEST
at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)] (/var/task/source/fcm/send-single-notification.js:14:42)rt' of undefined
END RequestId: e66ffdd9-ab9c-4a68-ade2-7cfa97f42c31
Something is undefined and I can't figure out what it is or what the error is.
How can I fix this?

Firebase Push Notification Not Popping Up

I successfully registered firebase service worker with
let messaging = null;
export const registerFirebaseServiceWorker = () => {
if ("serviceWorker" in navigator) {
console.log("serviceWorker in navigator");
navigator.serviceWorker.register(("./firebase-messaging-sw.js"))
.then((registration) => {
console.log("Registration successful, scope is: ", registration.scope);
})
}
}
and try to receive the message with messaging.onMessage callback
if (supportsWebPush) {
messaging.onMessage(payload => {
console.log("There's a message!", payload);
const notificationTitle = "notificationTitle"
const notificationOptions = {
body: payload
};
//self.registration.showNotification(notificationTitle, notificationOptions);
navigator.serviceWorker.getRegistration("./firebase-messaging-sw.js").then(registration => {
console.log("got the registration");
registration.showNotification('Hello world!');
}).catch(error => {
console.log("No service worker registered", error);
});
});
Even though console.log was working and registration.showNotification was executed, there were no push notification on my browser ? Why is this? I've been trying multiple different ways and search for many suspected issues but can't found a proper way to display default web push pop up

Any data passed to a Firebase Function returns Undefined

I've made a firebase function which every time I pass data to it and try to use the data, it returns that the data is undefined. This is the function I made:
const functions = require('firebase-functions');
// The Firebase Admin SDK to access Cloud Firestore.
const admin = require('firebase-admin');
// CORS Express middleware to enable CORS Requests.
const cors = require('cors')({origin: true});
admin.initializeApp();
exports.addUser = functions.https.onRequest((req, res) => {
const handleError = (error) => {
console.log('Error creating new user:', error);
//sends back that we've been unable to add the user with error
return res.status(500).json({
error: err,
});
}
try {
return cors(req, res, async () => {
console.log(req);
const uid = req.uid;
const dob = req.dob;
const postcode = req.postcode;
const sex = req.sex;
const username = req.username;
admin.firestore().collection('users').doc(uid).set({
dob:dob,
postcode:postcode,
sex:sex,
username:username,
})
.then(function(userRecord) {
console.log('Successfully created new user:', userRecord.username);
// Send back a message that we've succesfully added a user
return res.status(201).json({
message: 'User stored',
id: req.body.uid,
});
})
.catch(function(error) {
return handleError(error);
});
});
} catch (error) {
return handleError(error);
}
});
This is how I call it within react:
const addUserFunc = firebase.functions().httpsCallable('addUser');
console.log("Calling user func " + user.uid)
addUserFunc({
uid:user.uid,
dob:dob,
postcode:postcode,
sex:sex,
username:username,
}).then(function(result) {
console.log(result);
}).catch(err => {
console.log(err)
setErrors(prev => ([...prev, err.message]))
});
I've printed the data before sending the request and it definitely exists. I've also tried getting it within the function using req.body and req.query but this just returns the same.
This is the error I get in the firebase function logs:
Error: Value for argument "document path" is not a valid resource path. The path must be a non-empty string.
at Object.validateResourcePath (/srv/node_modules/#google-cloud/firestore/build/src/path.js:406:15)
at CollectionReference.doc (/srv/node_modules/#google-cloud/firestore/build/src/reference.js:1982:20)
at cors (/srv/index.js:44:51)
at cors (/srv/node_modules/cors/lib/index.js:188:7)
at /srv/node_modules/cors/lib/index.js:224:17
at originCallback (/srv/node_modules/cors/lib/index.js:214:15)
at /srv/node_modules/cors/lib/index.js:219:13
at optionsCallback (/srv/node_modules/cors/lib/index.js:199:9)
at corsMiddleware (/srv/node_modules/cors/lib/index.js:204:7)
at exports.addUser.functions.https.onRequest (/srv/index.js:31:16)
This is the error return in the web console for the react app:
Access to fetch at 'https://***/addUser' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I tested the function within using the emulator and passing the values using the link which works there but just not when deployed.
Any help would be great.
Your Cloud Function is defined as a HTTPS Function, which means that you can access it over a URL, but then you're calling it from your code as a Callable Function. The two types are different and not interchangeable.
If you want to use the firebase.functions().httpsCallable('addUser'); in your client code, you'll have to modify your Cloud Function to be a Callable Function too. This mostly means that you get the parameters from data instead of res, and return responses instead of sending them through res.
exports.addUser = functions.https.onCall((data, context) => {
...
const uid = context.auth.uid; // automatically passed to Callable Functions
return admin.firestore().collection('users').doc(uid).set({
dob: data.dob,
postcode: data.postcode,
sex: data.sex,
username: data.username,
})
.then(function(userRecord) {
return {
message: 'User stored',
id: req.body.uid,
};
}).catch(err => {
throw new functions.https.HttpsError('dabase-error', error);
})
});
Alternatively, you can leave your Cloud Function as is and instead modify the calling code to use something like fetch().

How do you receive Whatsapp messages from Twilio using Node.JS?

I am trying to build a Whatsapp chatbot using Node.JS and am running into a bit of trouble in receiving the Whatsapp message from Twilio. On checking the debugger, I get a Bad Gateway error, ie. Error 11200: HTTP Retrieval Failure. The message is getting sent, and ngrok shows the post request, however, dialogflow does not receive the request. On terminal, the error is showing UnhandledPromiseRejectionWarning: Error: 3 INVALID ARGUMENT: Input text not set. I'm not sure if it's because the message is not in JSON format. Please help!
This is the app.post function:
app.post('/api/whatsapp_query', async (req, res) =>{
message = req.body;
chatbot.textQuery(message.body, message.parameters).then(result => {
twilio.sendMessage(message.from, message.to, result.fulfillmentText).then(result => {
console.log(result);
}).catch(error => {
console.error("Error is: ", error);
});
return response.status(200).send("Success");
})
});
And this is the sendMessage function I've imported:
const config = require('./config/keys');
const twilioAccountID = config.twilioAccountID;
const twilioAuthToken = config.twilioAuthToken;
const myPhoneNumber = config.myPhoneNumber;
const client = require('twilio')(twilioAccountID,twilioAuthToken);
module.exports = {
sendMessage: async function(to, from, body) {
return new Promise((resolve, reject) => {
client.messages.create({
to,
from,
body
}).then(message => {
resolve(message.sid);
}).catch(error => {
reject(error);
});
});
}
}
And this is the textQuery function I've imported:
textQuery: async function(text, parameters = {}) {
let self = module.exports;
const request = {
session: sessionPath,
queryInput: {
text: {
text: text,
languageCode: config.dialogFlowSessionLanguageCode
},
},
queryParams: {
payload: {
date: parameters
}
}
};
let responses = await sessionClient.detectIntent(request);
responses = await self.handleAction(responses)
return responses[0].queryResult;
},
Twilio developer evangelist here.
The issue is that you are not passing the correct message body from the incoming WhatsApp message to your textQuery function.
First, you should make sure that you are treating the incoming webhook from Twilio as application/x-www-form-urlencoded. If you are using body-parser, ensure you have urlencoded parsing turned on.
app.use(bodyParser.urlencoded());
Secondly, the parameters that Twilio sends start with a capital letter. So your code currently gets message = req.body and then uses message.body. But it should be message.Body.
Those two points should sort you out.
One final thing though. The Twilio Node.js library will return a Promise if you do not pass a callback function. So you don't need to create a Promise here:
module.exports = {
sendMessage: async function(to, from, body) {
return new Promise((resolve, reject) => {
client.messages.create({
to,
from,
body
}).then(message => {
resolve(message.sid);
}).catch(error => {
reject(error);
});
});
}
}
You can just return the result of the call to client.messages.create
module.exports = {
sendMessage: async function(to, from, body) {
return client.messages.create({ to, from, body });
}
}
Hope this helps.

Categories