i try to send notification to specific device using firebase cloud function - javascript

i am building chat app with flutter and I try to send notification to specific device using the cloud function so when a user send message to his friend then his friend get notification with the message but I get that error
note : I don not have any knowledge with javascript or node js
Unhandled error Error: Value for argument "documentPath" is not a valid resource path. Path must be a non-empty string.
at Object.validateResourcePath (/workspace/node_modules/#google-cloud/firestore/build/src/path.js:446:15)
at CollectionReference.doc (/workspace/node_modules/#google-cloud/firestore/build/src/reference.js:2061:20)
at /workspace/index.js:14:12
at fixedLen (/workspace/node_modules/firebase-functions/lib/providers/https.js:72:41)
at /workspace/node_modules/firebase-functions/lib/common/providers/https.js:407:32
at processTicksAndRejections (node:internal/process/task_queues:96:5)
first I try to get the device token and save it to firebase
void getToken() async {
await fcm.getToken().then((value) {
tokens = value;
print('my token22 is $tokens');
saveToken(tokens: tokens);
});
}
void saveToken({String? tokens}) async {
FirebaseFirestore.instance.collection('userToken').doc(userphone).set({
'token': tokens,
});
}
then I try to call this token at index.js file at function function
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.addMessage = functions.https.onCall(
(data, context) => {
const friendPhone = data.text;
const userDoc = admin
.firestore()
.collection("userToken")
.doc(friendPhone)
.get();
const deviceTokens = userDoc.data();
console.log(deviceTokens);
const title = data.title;
const body = data.body;
try {
if (deviceTokens) {
exports.myFunction = functions.firestore
.document("chats/{chatId}/messegeId/{messageId}")
.onWrite((snap, context) => {
console.log(snap.data());
admin.messaging().sendToDevice(deviceTokens,
{
notification: {title: title,
body: body,
clickAction: "FLUTTER_NOTIFICATION_CLICK",
},
});
});
}
} catch (error) {
console.log(error);
throw new functions.https.
HttpsError("invalid-argument", "some message");
}
}
);
after that I call the function at sendMessege button so that when the user send messgege it work
Future<void> writeMessage({
String? message,
String? title,
String? friendPhone,
}) async {
HttpsCallable callable =
FirebaseFunctions.instance.httpsCallable("addMessage");
final resp = await callable.call(<String, dynamic>{
"text": friendPhone,
"title": title,
"body": message,
});
print("result: ${resp.data}");
}

oare you sure that the path for the friendPhone is a valid path in firebase?
Is there maybe a spelling mistake in messageId?
document("chats/{chatId}/messegeId/{messageId}")
You wrote messegeId instead of messageId
Hope that helps.

Related

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?

Unable to connect to Room: Invalid Access Token issuer/subject twilio

I do want to create an access token in the backend and need to pass to the front end to connect to the video chat room.
This is my back-end code
const twilioAccountSid = process.env.twilioAccountSid;
const twilioApiKey = process.env.twilioApiKey;
const twilioApiSecret = process.env.twilioApiSecret;
const room = "cool room";
app.post("/access-token", (req, res) => {
try {
console.log(
"sid",
twilioAccountSid,
"key",
twilioApiKey,
"secret",
twilioApiSecret
);
const identity = "user";
// Create Video Grant
const videoGrant = new VideoGrant({
room,
});
// Create an access token which we will sign and return to the client,
// containing the grant we just created
const token = new AccessToken(
twilioAccountSid,
twilioApiKey,
twilioApiSecret,
{ identity: identity }
);
token.addGrant(videoGrant);
// Serialize the token to a JWT string
console.log(token.toJwt());
res.status(200).json(token.toJwt());
} catch (error) {
console.warn(error);
res.sendStatus(500);
}
});
For the Twilio account SID I used my dashboard's SID which is starting from AC
For the API key I added the friendly name I gave to the API key when I created it.
API secret is that API key's secret id.
A token is crearted succefully and passed to the front-end.
This is my front-end code
const connectRoom = async () => {
try {
const token = await axios.post("http://localhost:5000/access-token");
connect(token.data, { name: roomName, video: { width: 640 } }).then(
(room) => {
console.log(`Successfully joined a Room: ${room}`);
room.on("participantConnected", (participant) => {
console.log(`A remote Participant connected: ${participant}`);
participant.tracks.forEach((publication) => {
console.log("for each");
if (publication.isSubscribed) {
const track = publication.track;
document
.getElementById("remote-media-div")
.appendChild(track.attach());
}
});
participant.on("trackSubscribed", (track) => {
document
.getElementById("remote-media-div")
.appendChild(track.attach());
});
});
},
(error) => {
console.error(`Unable to connect to Room: ${error.message}`);
}
);
} catch (error) {
console.log(error);
}
Then I get this error
Unable to connect to Room: Invalid Access Token issuer/subject
How do I solve this problem?
Any help!
Thanks in advance
You can create an API Key here (or via the Console). Note, the API Key starts with SK....
REST API: API Keys

How to send notification using FCM?

I wrote a cloud function, to listen for document creation in a collection, in my database
here is the function,
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().functions);
var newData;
exports.myTrigger = functions.firestore.document('FCM/{id}').onCreate(async (snapshot, context) => {
//
if (snapshot.empty) {
console.log('No Devices');
return;
}
newData = 'hello';
const deviceIdTokens = await admin
.firestore()
.collection('FCM')
.get();
var tokens = [];
var i=0;
for (var token of deviceIdTokens.docs) {
tokens.push(token.data().ar1[i]);
i++;
}
var payload = {
notification: {
title: 'push title',
body: 'push body',
sound: 'default',
},
data: {
push_key: 'Push Key Value',
key1: newData,
},
};
try {
const response = await admin.messaging().sendToDevice(tokens, payload);
console.log('Notification sent successfully');
} catch (err) {
console.log(err);
}
});
This function works weirdly,
For example, sometimes it sends notification, and sometimes it does not.
It throws errors like " TypeError: Cannot read property '0' of undefined".
I don't know how to resolve this issue,
In my arr1 field, i have an array of device tokens, to whom i want to send notifications to,
i want the function to send notifications only to the devices(using tokens) which are just created(in the newly created document ),then delete the document.
I think it's sending notifications to all the documents at once.
I'm pretty new at node..
please help me out.
UPDATE:-
Here is my document structure
Type error coming from this line:
tokens.push(token.data().arr1[i]);
So all I can say is that sometimes token.data() doesn't have an arr1 attribute.

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.

Firebase Error: Registration token(s) provided to sendToDevice() must be a non-empty string or a non-empty array

i want to send users notification when they are being sent friend request using firebase cloud messaging, but when the request is sent it returns this error in firebase function log
Error: Registration token(s) provided to sendToDevice() must be a non-empty string or a non-empty array.
at FirebaseMessagingError.Error (native)
at FirebaseMessagingError.FirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:39:28)
this is the java-script code i am using
'use strict'
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 for :', user_id);
if (!change.after.val()){
return console.log("A Notification Has Been Deleted From The Database: ", notification_id)
}
const deviceToken = admin.database().ref(`/Notifications/${user_id}/${notification_id}`).once('value');
return deviceToken.then(result => {
const token_id = result.val();
const payload = {
notification: {
title: "Friend Request",
body: "You just got a new friend request",
icon: "default"
}
};
return admin.messaging().sendToDevice(token_id, payload ).then(Response =>{
console.log('this is the notification')
});
});
});
It sounds like token_id is null or an empty string. Most likely that's because /Notifications/${user_id}/${notification_id} doesn't exist in your database, for example when there is no token for the targeted user.
To prevent the error message, simply check if the snapshot exists before using its value:
const deviceToken = admin.database().ref(`/Notifications/${user_id}/${notification_id}`).once('value');
return deviceToken.then(result => {
if (!result.exists() || result.val() === "") return false;
const token_id = result.val();
const payload = {
notification: {
title: "Friend Request",
body: "You just got a new friend request",
icon: "default"
}
};
return admin.messaging().sendToDevice(token_id, payload ).then(Response =>{
console.log('this is the notification')
});
});
after many wasted hours i got to discover what was wrong. now the issue was that i was pointing to the wrong path. this line of code was the issue
const deviceToken = admin.database().ref(`/Notifications/${user_id}/${notification_id}`).once('value');
it was supposed to be this
const deviceToken = admin.database().ref(`/Users/${user_id}/device_token`).once('value');

Categories