cloud function for sending fcm notifications to a collection of tokens - google-cloud-functions

I am trying to send a notification whenever a new update to my database takes place. I have the onUpdate side working but I am new to FCM and I am stuck at the sending the notification.
The structure of the devices collection is:
+devices/
+tokenId/
-tokenId:njurhvnlkdnvlksnvlñaksnvlkak
-userId:nkjnjfnwjfnwlknlkdwqkwdkqwdd
The function that I have right now that gets stuck with an empty value of token is:
const functions = require('firebase-functions');
const admin = require("firebase-admin");
admin.initializeApp();
const db = admin.firestore();
const settings = { timestampsInSnapshots: true };
db.settings(settings);
.....
exports.fcmSend = functions.firestore
.document(`chats/{chatId}`).onUpdate((change, context) => {
const messageArray = change.after.data().messages;
const message = messageArray[(messageArray.length-1)].content
if (!change.after.data()) {
return console.log('nothing new');
}
const payload = {
notification: {
title: "nuevo co-lab",
body: message,
}
};
return admin.database().ref(`/devices`)
.once('value')
.then(token => token.val())
.then(userFcmToken => {
console.log("Sending...", userFcmToken);
return admin.messaging().sendToDevice(userFcmToken, payload)
})
.then(res => {
console.log("Sent Successfully", res);
})
.catch(err => {
console.log("Error: ", err);
});
});
I am not able to get the token from the database. It is null or undefined. Can anyone help me with this second part of the function?
Thanks a lot in advance!

Thanks Frank for the tip!
I managed to solve the problem with this code in case anybody needs it:
const payload = {
notification: {
title: "nuevo mensaje de co-lab",
body: message,
}
};
// Get the list of device tokens.
const allTokens = await admin.firestore().collection('devices').get();
const tokens = [];
allTokens.forEach((tokenDoc) => {
tokens.push(tokenDoc.id);
});
if (tokens.length > 0) {
// Send notifications to all tokens.
return await admin.messaging().sendToDevice(tokens, payload);
}else {
return null;
}

Related

How to pass updated set State value in axios request as params

I'm a beginner in react native, I'm trying to get user information from mysql database through an axios API get request.
Once logged in, I stored email address in AsyncStorage and later want to use that email address from AsyncStorage as params or parameters to get the user details.
I wrote a code which set initial state of the setState as 'na'. Please help me how I can pass the email address from AsyncStorage as params or parameters.
Here is my code.
// to load email address
const [SessionEmail, setSessionEmail] = useState('na');
// to load users info
const [users, setUsers] = useState([]);
useFocusEffect(
React.useCallback(() => {
getUsername();
getUsersInfoFromAPI();
}, [])
);
// to get the session username from localstorage
const getUsername = async () => {
try {
const username = await AsyncStorage.getItem('Username')
if (username !== null) {
setSessionEmail(username);
}
} catch (e) {
console.log(e);
}
}
// API Calling user details
const getUsersInfoFromAPI = async () => {
await axios.get(`https://myapi.co.in/api/user/?email=${SessionEmail}`)
.then(response => {
setUser(response.data);
})
.catch(error => {
console.log(error);
});
}
After the page is rendered, and I load page from metro, I can see the parameters have been sent to server.
Update your code in this way:
useFocusEffect(
React.useCallback(() => {
getUsername();
}, [])
);
Instead of saving your email to state, sent it to function directly but if you are using it for other reason you can still save it but call function while getting username from AsyncStorage with username parameter like below.
// to get the session username from localstorage
const getUsername = async () => {
try {
const username = await AsyncStorage.getItem('Username')
if (username !== null) {
getUsersInfoFromAPI(username);
}
} catch (e) {
console.log(e);
}
}
// API Calling user details
const getUsersInfoFromAPI = async (email) => {
await axios.get(`https://myapi.co.in/api/user/?email=${email}`)
.then(response => {
setUser(response.data);
})
.catch(error => {
console.log(error);
});
}
const [users, setUsers] = useState([]);
here you can use like this
const [users, setUsers] = useState();
hope this will help you

Cannot map results from API

I'm trying to dynamically generate routes in my next.js application. I have an api called getUsers that returns something like this:
{"users":[{"_id":"639a87ae8a128118cecae85b","username":"STCollier","image":"https://storage.googleapis.com/replit/images/1641322468533_db666b7453a6efdb886f0625aa9ea987.jpeg","admin":false,"likedPosts":["639e34c5991ecaea52ace9e4","639e34c7991ecaea52ace9e7","639e34c7991ecaea52ace9ea","639e39a216a642f686a28036","639e39a216a642f686a28037","639e3b3d8cdebd89d9691f97","639e3b3d8cdebd89d9691f98","639e3b3e8cdebd89d9691f9d","639e3b5a8cdebd89d9691fa0","639e3b5c8cdebd89d9691fa3","639e3b5c8cdebd89d9691fa6"],"dislikedPosts":[""]},{"_id":"639a88abc4274fba4e775cbe","username":"IcemasterEric","image":"https://storage.googleapis.com/replit/images/1646785533195_169db2a072ad275cfd18a9c2a9cd78a1.jpeg","admin":false,"likedPosts":[],"dislikedPosts":[]}
So I know the API works succesfully, but when trying to get these api results and generate a page for each username, I get an error stating:
TypeError: users.map is not a function
Here's my code for generating the routes:
//pages/user/[username].js
const Get = async (url) => {
return await fetch(url).then(r => r.json());
}
export async function getStaticPaths() {
const users = Get('/api/getUsers')
return {
paths: users.map(u => {
const username = u.users.username
return {
params: {
username
}
}
}),
fallback: false
}
}
What is wrong with my getStaticPaths() code? I know that the API is working, so why can't I map the results?
And if anyone needs the code for api/getUsers, here is that:
import clientPromise from "../../lib/mongodb";
import nc from "next-connect";
const app = nc()
app.get(async function getUsers(req, res) {
const client = await clientPromise;
const db = client.db("the-quotes-place");
let users = []
try {
const dbUsers = await db
.collection("users")
.find({})
.toArray();
users = dbUsers
return res.json({
users: JSON.parse(JSON.stringify(users)),
success: true
})
} catch(e) {
return res.json({
message: new Error(e).message,
success: false,
});
}
})
export default app
Thanks for any help!!
Modify Get method to return an async value instead of Promise.
As Get is an async method, you need the await in getStaticPaths method.
const Get = async (url) => {
let response = await fetch(url);
return await response.json();
}
export async function getStaticPaths() {
const users = await Get('/api/getUsers');
...
}

Dialogflow ES fulfillment did not reply

[Update] with the entire code
// See https://github.com/dialogflow/dialogflow-fulfillment-nodejs
// for Dialogflow fulfillment library docs, samples, and to report issues
'use strict';
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
const admin = require('firebase-admin');
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
const settings = {/* your settings... */ timestampsInSnapshots: true};
db.settings(settings);
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
// console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
function writeToDb (agent) {
const startDate = agent.parameters.startdate;
// Always assume user enter time in the past (for existing time)
console.log("start date:" + startDate);
if (Date.parse(startDate) > Date.now()) {
startDate.setFullYear(startDate.getFullYear() - 1);
// console.log("modify start date to: " + startDate);
}
const dfRef = db.collection('period').doc(request.body.originalDetectIntentRequest.payload.data.sender.id);
agent.add('Got it. That me write it done for ya');
dfRef.get().then(user => {
if(!user.exists) {
dfRef.create({dates: admin.firestore.FieldValue.arrayUnion(startDate)})
.then(() => {
}).catch(err => {
console.log('error create firestore date entry:' + `${err}`);
});
} else {
dfRef.update({dates: admin.firestore.FieldValue.arrayUnion(startDate)})
.then(() => {
}).catch(err => {
console.log('error update firestore date entry:' + `${err}`);
});
}
}).catch(err => {
console.log('error access firestore date:' + `${err}`);
});
}
function readFromDb (agent) {
// Get the database collection 'dialogflow' and document 'agent'
const startDate = agent.parameters.startdate;
const future = agent.parameters.future;
const dialogflowAgentDoc = db.collection('period').doc(request.body.originalDetectIntentRequest.payload.data.sender.id);
// Get the value of 'entry' in the document and send it to the user
return dialogflowAgentDoc.get()
.then(doc => {
if (doc.exists) {
var darray = doc.data().dates;
if (darray.length > 0) {
if (future) {
agent.add('let me calculate for you..');
var next = new Date(darray[darray.length-2]);
const dayDiff = calculateSchedule(darray);
next.setDate(next.getDate() + dayDiff * 1);
agent.add(next.toLocaleDateString('en-us', {month:"short", day: 'numeric', weekday: 'short'}));
} else {
agent.add('let me look up for you..');
agent.add(new Date(darray[darray.length-1]).toLocaleDateString('en-us', {month:"short", day: 'numeric', weekday: 'short'}));
}
} else {
agent.add('I cant find anything :( ');
}
} else {
agent.add('something was wrong, I cant find your record :/');
}
return Promise.resolve('complete!');
}).catch(err => {
agent.add(`Error reading entry from the Firestore database. ${err}`);
});
}
function calculateSchedule(arr) {
// emitted..
}
// Run the proper function handler based on the matched Dialogflow intent name
let intentMap = new Map();
intentMap.set('it start today', writeToDb);
intentMap.set('when did it start', readFromDb);
agent.handleRequest(intentMap);
});
[Original]
Hi my dialogflow ES is connected to fb messenger and the purpose is to reply a message after I recorded what the customer say into DB, I checked if the document exist: here is my code
function writeToDb (agent) {
const startDate = agent.parameters.startdate;
const dfRef = db.collection('start').doc('my_id');
dfRef.get().then(user => {
if(!user.exists) {
dfRef.create({dates: admin.firestore.FieldValue.arrayUnion(startDate)})
.then(() => {
agent.add('Got it. let me write it down for ya');
}).catch(err => {
console.log(`${err}`);
});
} else {
dfRef.update({dates: admin.firestore.FieldValue.arrayUnion(startDate)})
.then(() => {
agent.add('Got it. let me write it down for ya');
}).catch(err => {
console.log(`${err}`);
});
}
});
}
the startDate value is successfully store in the firestore. However, I never get the reply message, is there anything I did wrong? I felt it should be simple enough.
Thanks for your help.
You are missing to set up the IntentMap() see step 5 and 6.
In the intentMap, you will need to add a map from the Intent name to a function that will do the handling when that Intent triggers the webhook. You can have a different handler function for each Intent, use the same function for some, have those functions call other functions, whatever you need. Finally use agent.handleRequest(intentMap);.

Wikipedia API not working alexa javascript

i am very new to amazon skill and javascript and i am trying to create a skill that returns wikipedia first paragraph. I am trying to use Promise to retrieve content from external api however I can't seem to find my issue. I have tried async and await as well but didn't get anywhere with it.
This is my code
'''
const GetInfoIntentHandler = {
canHandle(handlerInput) {
return (
handlerInput.requestEnvelope.request.type === "IntentRequest" &&
handlerInput.requestEnvelope.request.intent.name === "GetInfoIntent"
);
},
async handle(handlerInput) {
let outputSpeech = 'This is the default message.';
await getRemoteData("https://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=god&origin=*&format=json")
.then((response) => {
const data = JSON.parse(response);
outputSpeech = data;
})
.catch((err) => {
console.log(`ERROR: ${err.message}`);
// set an optional error message here
outputSpeech = "hereeeee";
});
return handlerInput.responseBuilder
.speak(outputSpeech)
.getResponse();
},
};
const getRemoteData = (url) => new Promise((resolve, reject) => {
const client = url.startsWith('https') ? require('https') : require('http');
const request = client.get(url, (response) => {
if (response.statusCode < 200 || response.statusCode > 299) {
reject(new Error(`Failed with status code: ${response.statusCode}`));
}
const body = [];
response.on('data', (chunk) => body.push(chunk));
});
//request.on('error', (err) => reject(err));
});
'''
[My error][1]
This is the API i am using:"https://en.wikipedia.org/w/api.php?format=json&origin=*&action=query&prop=extracts&exlimit=max&explaintext&titles="+query+"&redirects=",
[My BUILD ][2]
Can you please tell me where i am going wrong
[1]: https://i.stack.imgur.com/Gvp2Q.png
[2]: https://i.stack.imgur.com/bAvzR.png

Why am I getting an internal server error when trying to post a new Activity using Design Automation API?

I am creating a simple Node application that posts a new Activity using the Forge Design Automation API. The activity is not supposed to do anything. This is just a test and I plan to delete the Activity right away. When I run this, I get an internal server error. What am I doing wrong?
const config = require(`./utils/Config`);
const CLIENT_ID = config.forge.credentials.client_id;
const CLIENT_SECRET = config.forge.credentials.client_secret;
const autoRefresh = true;
const ForgeSDK = require(`forge-apis`);
const oAuth2TwoLegged = new ForgeSDK.AuthClientTwoLegged(CLIENT_ID, CLIENT_SECRET, [`code:all`], autoRefresh);
const ActivitiesApi = new ForgeSDK.ActivitiesApi();
const activityObject = {
id: `TestActivity`,
instruction: {
CommandLineParameters: null,
Script: ``
},
appPackages: [``],
requiredEngineVersion: `20.1`,
parameters: { InputParameters: [], OutputParameters: [] },
allowedChildProcesses: [],
version: 1,
isPublic: true,
theData: null,
obj: null
};
const activity = new ForgeSDK.Activity(
activityObject.id,
activityObject.instruction,
activityObject.appPackages,
activityObject.requiredEngineVersion,
activityObject.parameters,
activityObject.allowedChildProcesses,
activityObject.version,
activityObject.isPublic,
activityObject.theData,
activityObject.obj
);
const main = async () => {
try {
await oAuth2TwoLegged.authenticate();
createActivity();
} catch (error) {
console.log(error);
}
}
const createActivity = async () => {
try {
await ActivitiesApi.createActivity(activity, oAuth2TwoLegged, oAuth2TwoLegged.getCredentials());
} catch (error) {
console.log(`Creating the activity did not work!`);
console.log(error);
}
};
main();
And here's what I get from logging the error...
Not much there, so I'm at a loss.