Node Js value not showing in notification when testing - node.js

I am making a notification using firebase cloud functions with node js and my app made on swift
this is my payload
var payload = {
notification: {
title: (goOfflineTimePeriod,"Inactive for minutes you are now offline"),
body: "Time period for inactive log off can be changed in your settings"
though my notification my notification only shows as; "Inactive for minutes you are now offline", "Time period for inactive log off can be changed in your settings"
so the variable; goOfflineTimePeriod does not show in the notification
I am only new to node js is there a reason why "goOfflineTimePeriod" does not show in the notification?
here is my full node js function code;
exports.goOfflineAlert = functions.firestore
.document('/goneOffline/{uid}')
.onCreate((snap, context) => {
var db = admin.firestore();
var uid = context.params.uid;
const newValue = snap.data();
const goOfflineTimePeriod = newValue.goneOffline;
console.log('uid is',uid)
var cityRef = db.collection('Users').doc(uid);
var getDoc = cityRef.get()
.then(doc => {
if (!doc.exists) {
return console.log('No such document!');
} else {
const newValue = doc.data();
const age = newValue.Age;
const name = newValue['Display Name'];
const fcmToken = newValue.fcmToken;
const goOfflineTimePeriod = newValue.goOfflineTimePeriod;
console.log('Document data:', doc.data(),age,fcmToken,name,goOfflineTimePeriod);
var payload = {
notification: {
title: (goOfflineTimePeriod,"Inactive for minutes you are now offline"),
body: "Time period for inactive log off can be changed in your settings"
}
}

A , operator does not concatenate strings in JavaScript, but it returns the second operand. Instead you should use + or template string. For example:
title: goOfflineTimePeriod+" Inactive for minutes you are now offline",

Related

WA business api nodejs

I have a problem with my nodejs code and the connection to the official whatsapp business api.
The bot connects the webhook correctly, the messages arrive to the server correctly but the code I have implemented to make it respond is not being effective, I checked the code from top to bottom but I can't find the fault.
I leave you the codes so you have more context:
whatsappController.js:
const fs = require("fs");
const myConsole = new console.Console(fs.createWriteStream("./logs.txt"));
const whatsappService = require("../services/whatsappService")
const VerifyToken = (req, res) => {
try {
var accessToken = "456E7GR****************************";
var token = req.query["hub.verify_token"];
var challenge = req.query["hub.challenge"];
if(challenge != null && token != null && token == accessToken){
res.send(challenge);
}
else{
res.status(400).send();
}
} catch(e) {
res.status(400).send();
}
}
const ReceivedMessage = (req, res) => {
try {
var entry = (req.body["entry"])[0];
var changes = (entry["changes"])[0];
var value = changes["value"];
var messageObject = value["messages"];
if(typeof messageObject != "undefined"){
var messages = messageObject[0];
var text = GetTextUser(messages);
var number = messages["from"];
myConsole.log("Message: " + text + " from: " + number);
whatsappService.SendMessageWhatsApp("The user say: " + text, number);
myConsole.log(messages);
myConsole.log(messageObject);
}
res.send("EVENT_RECEIVED");
}catch(e) {
myConsole.log(e);
res.send("EVENT_RECEIVED");
}
}
function GetTextUser(messages){
var text = "";
var typeMessage = messages["type"];
if(typeMessage == "text"){
text = (messages["text"])["body"];
}
else if(typeMessage == "interactive"){
var interactiveObject = messages["interactive"];
var typeInteractive = interactiveObject["type"];
if(typeInteractive == "button_reply"){
text = (interactiveObject["button_reply"])["title"];
}
else if(typeInteractive == "list_reply"){
text = (interactiveObject["list_reply"])["title"];
}else{
myConsole.log("sin mensaje");
}
}else{
myConsole.log("sin mensaje");
}
return text;
}
module.exports = {
VerifyToken,
ReceivedMessage
}
The second file is whatsappService which I make the connection with the api using the token and I also send the format of the message I want to send when I receive a hello for example...
const https = require("https");
function SendMessageWhatsApp(textResponse, number){
const data = JSON.stringify({
"messaging_product": "whatsapp",
"recipient_type": "individual",
"to": number,
"type": "text",
"text": {
"preview_url": false,
"body": textResponse
}
});
const options = {
host:"graph.facebook.com",
path:"/v15.0/1119744*************/messages",
method:"POST",
body:data,
headers: {
"Content-Type":"application/json",
Authorization:"Bearer EAAWNbICfuWEBAK5ObPbD******************************************************"
}
};
const req = https.request(options, res => {
res.on("data", d=> {
process.stdout.write(d);
});
});
req.on("error", error => {
console.error(error);
});
req.write(data);
req.end();
}
module.exports = {
SendMessageWhatsApp
};
Then I declare the routes for the get (to check token) and post (to receive and reply to messages) methods:
const expres = require("express");
const router = expres.Router();
const whatsappController = require("../controllers/whatsappControllers");
router
.get("/", whatsappController.VerifyToken)
.post("/", whatsappController.ReceivedMessage)
module.exports = router;
Last but not least the index file for the code to run correctly:
const express = require("express");
const apiRoute = require("./routes/routes");
const app = express();
const PORT = process.env.PORT || 3000
app.use(express.json());
app.use("/whatsapp", apiRoute);
app.listen(PORT, () => (console.log("El puerto es: " + PORT)));
I should clarify that I did the tests with Postman and they were all successful, it responds and receives messages correctly, finally I did the tests by uploading the bot to the Azure service and it works without problem until it has to answer/replicate the user's message.
The bot is not responding to the user when he talks to it but everything arrives correctly to the server and it processes it with a 200 response. I attach the evidence that there is no problem in the reception.
Finally I must say that in the meta platform I have everything configured as specified by the same platform, I have already configured the api to answer the messages through the webhooks and everything is correct, I just can't get the bot to answer correctly.
The bot is hosted in the Azure service.
Solved: some numbers have a problema with the api of WAB in my country (Argentina) the phone numbers start in +54 9 11. The problem is the 9 in the phone number, and this have a conflict in the servers of meta, Solution quit number 9 to numbers of this country and the message will send to user.

Unable to use 'array-contains' where clause in cloud function

I am working on a job bidding app.
Each user has a field "User job notifications preferences".
The array field stores the data to which type of job they would like to receive notifications for.
for example:
Person A has the setting to receive a notification when a job of type 'plumming' is created.
Person B has the setting to receive a notification when a job of type 'electrical' is created.
Person C creates a plumming job,
Peron A should receive a notification to let them know a new job of type 'plumming' has been created.
here is the code snip
// when a job is updated from new to open
// send notifications to the users that signed up for that jobtype notification
exports.onJobUpdateFromNewToOpen= functions.firestore
.document('job/{docId}')
.onUpdate(async (change, eventContext) => {
const beforeSnapData = change.before.data();
const afterSnapData = change.after.data();
const jobType = afterSnapData['Job type'];
const afterJobState = afterSnapData["Job state"];
const beforeJobState = beforeSnapData["Job state"];
console.log('job updated');
// only consider jobs switching from new to open
if (beforeJobState=="New" && afterJobState == "Open") {
console.log('job updated from new to open');
console.log('jobType: '+jobType);
console.log('job id: '+change.after.id )
// get users that contain the matching job type
const usersWithJobTypePreferenceList = await admin.firestore().collection("user").where("User job notifications preferences", "array-contains-any", jobType).get();
// get their userIds
const userIdsList = [];
usersWithJobTypePreferenceList.forEach((doc) => {
const userId = doc.data()["User id"];
userIdsList.push(userId);
})
// get their user tokens
const userTokenList = [];
for (var user in userIdsList) {
const userId = userIdsList[user];
const userToken = await (await admin.firestore().collection("user token").doc(userId).get()).data()["token"];
userTokenList.push(userToken);
};
// send message
const messageTitle = "new " + jobType + " has been created";
for (var token in userTokenList) {
var userToken = userTokenList[token];
const payload = {
notification: {
title: messageTitle,
body: messageTitle,
sound: "default",
},
data: {
click_action: "FLUTTER_NOTIFICATION_CLICK",
message: "Sample Push Message",
},
};
return await admin.messaging().sendToDevice(receiverToken, payload);
}
}
});
I think the issue is at the following line because I am getting the error 'Error: 3 INVALID_ARGUMENT: 'ARRAY_CONTAINS_ANY' requires an ArrayValue' (see image)
const usersWithJobTypePreferenceList = await admin.firestore().collection("user").where("User job notifications preferences", "array-contains-any", jobType).get();
below is the full error:
Error: 3 INVALID_ARGUMENT: 'ARRAY_CONTAINS_ANY' requires an ArrayValue.
at Object.callErrorFromStatus (/workspace/node_modules/#grpc/grpc-js/build/src/call.js:31:19)
at Object.onReceiveStatus (/workspace/node_modules/#grpc/grpc-js/build/src/client.js:352:49)
at Object.onReceiveStatus (/workspace/node_modules/#grpc/grpc-js/build/src/client-interceptors.js:328:181)
at /workspace/node_modules/#grpc/grpc-js/build/src/call-stream.js:188:78
at processTicksAndRejections (node:internal/process/task_queues:78:11)
I interpret the error as the following: there is no value being passed to 'jobType'.but that cant be right because I am printing the value ( see screenshot )
I found the following related questions but I dont think I am having the same issue:
Getting firestore data from a Google Cloud Function with array-contains-any
Firestore: Multiple 'array-contains'
So I am not sure what the issue is here, any ideas?
here is how the data looks in firebase:
I looked at similar questions and I printed the values being passed to the function that was creating the error
I updated the line that was giving me an issue now everything works :) ::
'''
const usersWithJobTypePreferenceList = await admin.firestore().collection("user").where("User job notifications preferences", "array-contains", jobType).get();
'''

NodeJs Application to send alerts to users email ID

I'm creating a NodeJs application that sends alerts to a user's email ID when the price of the bitcoin goes above the price specified by the user. For scheduling tasks, I'm using cron. Also, I've used the bull as a message broker. When I'm running this program, It isn't working and it isn't sending emails when the price is above the specified price. Please help me to find out what is the problem.
require('dotenv').config({path: require("find-config")(".env")});
const CronJob = require("cron").CronJob;
let Queue = require("bull");
const Alert = require("../models/alert");
const { currentPrice } = require("../utilities/currentPrice");
const { sendEmail } = require("../utilities/sendEmailNotification");
//Creating a Queue
let alertQueue = new Queue("alerts", process.env.RedisURL);
//Consumer Process
alertQueue.process(async function(job, done) {
const {mailTo, title, text} = job.data;
const mailObj = {
from: process.env.SendGridForm,
recipients: mailTo,
subject: title,
message: text
}
const response = sendEmail(mailObj);
if(response.error) {
done(new Error("Error Sending Alert!!!"));
}
done();
})
let sendAlert = new CronJob("*/25 * * * * *", async function () {
let priceObj = await currentPrice();
if (priceObj.error)
return;
let price = priceObj.data;
const alerts = await Alert.find({status: "Created"});
alerts.forEach((alert) => {
if(alert.price <= price) {
mailTo = alert.email;
title = `Bitcoint is UP!`;
text = `Price of Bitcoin has just exceeded your alert price of ${alert.price} USD. Current price is ${price} USD.`;
alertQueue.add(
{mailTo, title, text},
{
attempts: 3,
backoff: 3000
}
)
alert.status = "Triggered";
alert.save();
}
})
});
sendAlert.start();

firebase function returns 403 when doing an http request

I started working on this node.js app using express to send sensor data via http request to my database (from an arduino to be specific). The main purpose of the app is to get the sensors' values from the url and create a new document in my cloud firestore.
var admin = require('firebase-admin');
const functions = require('firebase-functions');
const cors = require('cors')({origin: true});
const express = require('express');
var serviceAccount = require("./minicapcollar-firebase-adminsdk-ovdpm-cda3767493.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://minicapcollar.firebaseio.com"
});
let db = admin.firestore();
const app = express();
app.use(cors);
//Declare the field view for the timestamp
let FieldValue = require('firebase-admin').firestore.FieldValue;
app.get('/send/sensorData', (req, res) => {
var id = 'HpwWiJSGHNbOgJtYi2jM'; //variable to store the id of the collar, TODO: req.query.id
var lat = req.query.lat/1000000;
var lon = req.query.lon/1000000;
var hr = req.query.hr;
var et = req.query.et;
var it = req.query.it;
//Rest of the values
//Declare the index of the collar id
let indexRef = db.collection('dogs').doc(id);
//Declare the index of the position
let posRef = indexRef.collection('position').doc();
//Declare the index of the heartrate
let hrRef = indexRef.collection('heartrate').doc();
//Declare the index of the external temperature
let etRef = indexRef.collection('external_temperature').doc();
//Declare the index of the internal temperature
let itRef = indexRef.collection('temperature').doc();
//Save the current time
var time = FieldValue.serverTimestamp();
//Set position
let setPos = posRef.set({
timestamp: time,
value: new admin.firestore.GeoPoint(lat,lon)
}).then(function() {
console.log("Position data saved to Firestore");
return null;
}).catch(function(error) {
console.log("Got an error: ", error);
});
//Set heartrate
let setHr = hrRef.set({
timestamp: time,
value: hr
}).then(function() {
console.log("Heartrate data saved to Firestore");
return null;
}).catch(function(error) {
console.log("Got an error: ", error);
});
//Set external temperature
let setET = etRef.set({
timestamp: time,
value: et
}).then(function() {
console.log("External temperature data saved to Firestore");
return null;
}).catch(function(error) {
console.log("Got an error: ", error);
});
//Set internal temperature
let setIT = itRef.set({
timestamp: time,
value: it
}).then(function() {
console.log("Data saved to Firestore");
return null;
}).catch(function(error) {
console.log("Got an error: ", error);
});
res.send(`All sensor data sent`);
});
app.get('/send/pos', (req, res) => {
var id = 'HpwWiJSGHNbOgJtYi2jM'; //variable to store the id of the collar, TODO: req.query.id
var lat = req.query.lat/1000000;
var lon = req.query.lon/1000000;
//Rest of the values
//Declare the index of the collar id
let indexRef = db.collection('dogs').doc(id);
//Declare the index of the position
let posRef = indexRef.collection('position').doc();
//Save the current time
var time = FieldValue.serverTimestamp();
//Set position
let setPos = posRef.set({
timestamp: time,
value: new admin.firestore.GeoPoint(lat,lon)
}).then(function() {
console.log("Position data saved to Firestore");
return null;
}).catch(function(error) {
console.log("Got an error: ", error);
});
res.send(`Position sent`);
});
app.get('/send/hr', (req, res) => {
var id = 'HpwWiJSGHNbOgJtYi2jM'; //variable to store the id of the collar, TODO: req.query.id
var hr = req.query.hr;
//Declare the index of the collar id
let indexRef = db.collection('dogs').doc(id);
//Declare the index of the heartrate
let hrRef = indexRef.collection('heartrate').doc();
//Save the current time
var time = FieldValue.serverTimestamp();
//Set heartrate
let setHr = hrRef.set({
timestamp: time,
value: hr
}).then(function() {
console.log("Heartrate data saved to Firestore");
return null;
}).catch(function(error) {
console.log("Got an error: ", error);
});
res.send(setHr & `Heartrate value sent`);
});
app.get('/send/temp', (req, res) => {
var id = 'HpwWiJSGHNbOgJtYi2jM'; //variable to store the id of the collar, TODO: req.query.id
var et = req.query.et;
var it = req.query.it;
//Declare the index of the collar id
let indexRef = db.collection('dogs').doc(id);
//Declare the index of the external temperature
let etRef = indexRef.collection('external_temperature').doc();
//Declare the index of the internal temperature
let itRef = indexRef.collection('temperature').doc();
//Save the current time
var time = FieldValue.serverTimestamp();
//Set external temperature
let setET = etRef.set({
timestamp: time,
value: et
}).then(function() {
console.log("External temperature data saved to Firestore");
return null;
}).catch(function(error) {
console.log("Got an error: ", error);
});
//Set internal temperature
let setIT = itRef.set({
timestamp: time,
value: it
}).then(function() {
console.log("Data saved to Firestore");
return null;
}).catch(function(error) {
console.log("Got an error: ", error);
});
res.send(`Temperature values sent`);
});
exports.app = functions.https.onRequest(app);
Once I finished the app, I tested it on my localhost, and it worked perfectly. I was able to write new data to the cloud firestore without any problems. Once I deployed my app, when sending the request, I get a 403 (Error: Forbidden Your client does not have permission to get URL /app/send/pos/?lat=11111111&lon=22222222 from this server.)
On the firestore rules, I specified that anyone can read and write to see if that was the problem, but it persists.
I also tried to follow along this tutorial: https://www.youtube.com/watch?v=LOeioOKUKI8, but I had the same problem when trying to access "http://baseURL.firebaseapp.com/timestamp", I got a 403 error when deployed (on the localhost it worked perfectly too)
NOTE: This is my first experience with node.js, please forgive any bad practices. I am an electrical eng student, so programming is not my main strength. THANKS IN ADVANCE FOR YOUR HELP!
Thank you samthecodingman! The answer you provided did the trick! The problem was in the IAM configuration of my function.
For those of you who don't want to jump yet to another link, I quote the answer provided by Mike Karp in the link above.
It seems to me that additional IAM functionality was added to Google Cloud Functions, and >as a result, you may have not turned on allUser access to the function (FYI this give >acess to the whole web).
On the Cloud Functions homepage, highlight the Cloud Function you want to add all >>access to.
Click "Show Info Panel" on the top right.
Click "Add Members" and type "allUsers" then select "Cloud Function Invokers" under >>"Cloud Function" in the Role box.
Click "Save"
Deploying a function failed (for some strange reason, which happens time to time), and I guess it didn't update permissions.
Re-deploying succeeded but didn't update its permissions.
I had to delete the function and redeploy to fix this issue.

Firebase Functions check if the user id in the database is the current user id

Im working on sending notifications between android devices using Firebase functions. When A-Device sends a message to B-Device, the message will be stored in the firebasedatabase under A-Device Id und B-Device Id like this the problem is the function which i wrote checks always A-Device id therefore it sends the notification always to A-Device. it means when A-Device sends to B-Device the notification will be sent to A-Device
this is my Node.js code. please help me ;(
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
//const mId = firebase.auth().currentUser.getToken();
exports.sendNotification = functions.database.ref('/Messages/{mId}/{uId}/{messageId}').onWrite(event =>{
const mId = event.params.mId; //getting mId
const uId = event.params.uId; //getting uId
const val = event.data.val(); //getting the values from event
const from = val.from; //from value
const type = val.type; //type value
const message = val.message;
console.log("user_name ",user_name);
console.log("user_email ",user_email);
const getDeviceToken = admin.database().ref(`/Users/${uId}/`).once('value');//getting device token function
return getDeviceToken.then(snapshot =>{ //executing the function
const DeviceToken = snapshot.val().DeviceToken;
console.log ("Device Token is ",DeviceToken);
if (from == mId) {
delete DeviceToken;
}
const getName = admin.database().ref(`/Users/${from}/`).once('value');//getting device token function
return getName.then(snapshot =>{ //executing the function
const Name = snapshot.val().Name;
console.log ("Sender is ",Name);
const payload = {
data: {
title: `${Name} sent you a message.`,
body: `${message}`
}
};
return admin.messaging().sendToDevice(DeviceToken,payload).then(response => {
console.log (`Notification has been sent to ${Name}`);
});});
});
});

Resources