Undefined in Firebase Functions with Realtime Database - node.js

I have two functions in Firebase. The first one is ok:
exports.sendPush = functions.database.ref('/itemADividir/{itemId}').onCreate((snapshot, context) =>{
const oque = snapshot.val();
const quem = oque.userOrigem;
const itemADV = oque.itemAdividir;
const quanto = oque.itemValor;
return pegaTokenUser(oque.userDestino).then(userTk =>{
let payload ={
notification: {
title: 'Solicitação - Notificação InfSocial',
body: `${quem} quer compartilhar ${itemADV} no valor de ${quanto} com vc`,
sound: 'default',
badge: '1'
}
};
console.log(`${quem} quer compartilhar ${itemADV} no valor de ${quanto} com vc`)
console.log(`token ${userTk}`)
return admin.messaging().sendToDevice(userTk, payload)
})
})
The second is returning undefined in userRecusado:
exports.itemRecusado = functions.database.ref('/ItemDividirNegado/{itemId}').onCreate((snapshot, context) => {
const itemId = context.params.itemId;
const oRecusado = snapshot.val();
const userRecusado = oRecusado.userOrigem;
console.log(`item ${itemId} recusado ${userRecusado}`)
return pegaTokenUser(userRecusado).then(userTk =>{
let payload ={
notification: {
title: 'Solicitação - Notificação InfSocial',
body: `${oRecusado.userDestino} recusou compartilhar ${oRecusado.itemADV} com vc`,
sound: 'default',
badge: '1'
}
};
console.log(`${oRecusado.userDestino} recusou compartilhar ${oRecusado.itemADV} com vc`)
console.log(`token ${userTk}`)
return admin.messaging().sendToDevice(userTk, payload)
})
})
Here is the function to get the token from users:
function pegaTokenUser(userGet){
let userGet2 = userGet.replace ('.','')
let dbRef = admin.database().ref('/UserTokens');
let defer = new Promise((resolve, reject) => {
dbRef.once('value', (snap) => {
let data = snap.val();
let userTk;
for (var user in data) {
if(data[user].user === userGet2){
userTk = (data[user].token);
}
}
resolve (userTk)
},(err) => {
reject(err);
});
});
return defer
}
Does anyone know why this is happening? This two functions do the same thing, but the second one does not get the property of the created record.
The full file:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
exports.sendPush = functions.database.ref('/itemADividir/{itemId}').onCreate((snapshot, context) =>{
const oque = snapshot.val();
const quem = oque.userOrigem;
const itemADV = oque.itemAdividir;
const quanto = oque.itemValor;
return pegaTokenUser(oque.userDestino).then(userTk =>{
let payload ={
notification: {
title: 'Solicitação - Notificação InfSocial',
body: `${quem} quer compartilhar ${itemADV} no valor de ${quanto} com vc`,
sound: 'default',
badge: '1'
}
};
console.log(`${quem} quer compartilhar ${itemADV} no valor de ${quanto} com vc`)
console.log(`token ${userTk}`)
return admin.messaging().sendToDevice(userTk, payload)
})
})
exports.itemRecusado = functions.database.ref('/ItemDividirNegado/{itemId}').onCreate((snapshot, context) => {
const itemId = context.params.itemId;
const oRecusado = snapshot.val();
const userRecusado = oRecusado.userOrigem;
console.log(`item ${itemId} recusado ${userRecusado}`)
// the output
//itemRecusado
//item 1586992687992 recusado **undefined**
return pegaTokenUser(userRecusado).then(userTk =>{
let payload ={
notification: {
title: 'Solicitação - Notificação InfSocial',
body: `${oRecusado.userDestino} recusou compartilhar ${oRecusado.itemADV} com vc`,
sound: 'default',
badge: '1'
}
};
console.log(`${oRecusado.userDestino} recusou compartilhar ${oRecusado.itemADV} com vc`)
console.log(`token ${userTk}`)
return admin.messaging().sendToDevice(userTk, payload)
})
})
function pegaTokenUser(userGet){
let userGet2 = userGet.replace ('.','')
let dbRef = admin.database().ref('/UserTokens');
let defer = new Promise((resolve, reject) => {
dbRef.once('value', (snap) => {
let data = snap.val();
let userTk;
for (var user in data) {
if(data[user].user === userGet2){
userTk = (data[user].token);
}
}
resolve (userTk)
},(err) => {
reject(err);
});
});
return defer
}
exports.helloWorld = functions.https.onRequest((request, response) => {
response.send("Hello from Firebase!");
});
exports.TrocaEmoki = functions.database.ref('/Chat/{pathStr}/{tStamp}').onCreate((snapshot, context) =>{
const pathStr = context.params.pathStr;
const tStamp = context.params.tStamp;
console.log(`Nova mensagem ${tStamp} na mesa ${pathStr}`)
const mensagem = snapshot.val()
const text = addEmoji(mensagem.text)
return snapshot.ref.update({text})
})
function addEmoji(text) {
//return text.replace(/\bpizza\b/g, '🍕')
var regex1 = /pizza/,
regex2 = /hotdog/,
regex3 = /vinho/,
regex4 = /hamburguer/,
regex5 = /taco/,
regex6 = /fritas/,
regex7 = /sushi/,
regex8 = /churrasco/,
regex9 = /pipoca/,
regex10 = /peixe/,
regex11 = /cerveja/,
regex12 = /sorvete/,
alimento = text;
switch(true){
case regex1.test(alimento) :
return text.replace(/\bpizza\b/g, '🍕');
break;
case regex2.test(alimento):
return text.replace(/\bhotdog\b/g, '🌭');
break;
case regex3.test(alimento):
return text.replace(/\bvinho\b/g, '🍷');
break;
case regex4.test(alimento):
return text.replace(/\bhamburguer\b/g, '🍔');
break;
case regex5.test(alimento):
return text.replace(/\btaco\b/g, '🌮');
break;
case regex6.test(alimento):
return text.replace(/\bfritas\b/g, '🍟');
break;
case regex7.test(alimento):
return text.replace(/\bsushi\b/g, '🍣');
break;
case regex8.test(alimento):
return text.replace(/\bchurrasco\b/g, '🍖');
break;
case regex9.test(alimento):
return text.replace(/\bpipoca\b/g, '🍿');
break;
case regex10.test(alimento):
return text.replace(/\bpeixe\b/g, '🐟');
break;
case regex11.test(alimento):
return text.replace(/\bcerveja\b/g, '🍺');
break;
case regex12.test(alimento):
return text.replace(/\bsorvete\b/g, '🍨');
break;
default:
return text;
}
}

I found the problem. My code was inserting values one by one in Realtime database (name, than id, than item, than value...).
I did the same that was doing in the first case (make an object with values and than update the database with this object) and than update the database. That's it.

Related

Is there any way to make this node js look more compact?

I am new to node js, and am wondering if there is any way to make this more compact. I am talking specifically about the nested then catch statements. Is there anyway to try to put this into one big then catch, or just return {res:false} once rather than a bunch of repeated time for every then catch?
const uId = data.uId;
const id = data.id;
const updates = {};
updates["/shared/" + id + "/users/" + uId] = null;
updates["/users/" + uId + "/shared/" + id] = null;
return admin.database().ref().update(updates).then(() => {
let ref = "/shared/" + id
// Check if any members are left
return admin.database().ref(ref).once("value").then((snapshot) => {
var users = snapshot.val().users;
if (users == null) {
admin.database().ref(ref).remove().then(() => {
return {res: true};
}).catch(() => {
return {res: false};
});
} else {
return {res: true};
}
}).catch(() => {
return {res: false};
});
}).catch(() => {
return {res: false};
});
Return the next Promise in the chain instead of nesting them, then have a single .catch at the end:
const ref = "/shared/" + id
return admin.database().ref().update(updates)
.then(() => {
// Check if any members are left
return Promise.all([ref, admin.database().ref(ref).once("value")]);
})
.then(([ref, snapshot]) => {
var users = snapshot.val().users;
if (users == null) {
return admin.database().ref(ref).remove();
}
})
.then(() => ({ res: true }))
.then(() => ({ res: false }));
The Promise.all is needed to pass the value from one .then to another.
Using async/await would make things cleaner:
const ref = "/shared/" + id
try {
await admin.database().ref().update(updates);
const snapshot = await admin.database().ref(ref).once("value");
const { users } = snapshot.val();
if (users == null) {
await admin.database().ref(ref).remove();
}
return { res: true };
} catch (e) {
return { res: false };
}

Cannot get Google AI prediction result using JWT credential using node js

I am planning to get AI prediction result using service account and deploy a cloud function to a Firebase project. When trying to get prediction result
https://ml.googleapis.com/v1/projects/projectid/models/category:predict?
using accesstoken JWT and the result is
{ StatusCodeError: 403 - {"error":{"code":403,"message":"Access to model denied.","status":"PERMISSION_DENIED"}}
It is confirmed that the service account I'm using has been added to the ML project.
Any idea how to get the ML result in Firebase function using service account? or other method?
Here is the code (I am still newbie to NodeJS)
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const admin = require('firebase-admin');
const request = require("request");
const requestProm = require("request-promise");
const functions = require('firebase-functions');
const { GoogleAuth } = require('google-auth-library');
admin.initializeApp();
var reportFld, reportNarTr, reportTitTr;
var input, input2, input3;
var result, predictedHaz, predictedSig, predictedRep, setDoc
var getAccessTokenId
getAccessTokenId = async function main() {
const auth = new GoogleAuth({
scopes: 'https://www.googleapis.com/auth/cloud-platform'
});
const client = await auth.getClient();
const projectId = await auth.getProjectId();
const accessTokenId = await auth.getAccessToken();
return accessTokenId
}
exports.newReport = functions.firestore
.document('/users/{usersId}')
.onCreate((change, context) => {
const db = admin.firestore();
const interDoc = db.collection('users').doc(context.params.usersId);
interDoc.get().then(doc => {
if (!doc.exists) {
console.log('No such document!');
} else {
var getPrediction
getPrediction = async function main2() {
reportFld = doc.data();
reportNarTr = JSON.stringify(reportFld.narrative);
reportTitTr = JSON.stringify(reportFld.title);
reportNumTr = context.params.usersId;
input = {
instances: [
[reportNumTr, reportTitTr, reportNarTr]
]
};
var accessToken = await getAccessTokenId();
var endpointhazCat = 'https://ml.googleapis.com/v1/projects/projectid/models/hazcat:predict?access_token=' + accessToken;
var endpointsigCat = 'https://ml.googleapis.com/v1/projects/projectid/models/sig:predict?access_token=' + accessToken;
var endpointrepCat = 'https://ml.googleapis.com/v1/projects/projectid/models/type:predict?access_token=' + accessToken;
var options1 = {
method: 'POST',
uri: endpointhazCat,
body: input,
json: true // Automatically stringifies the body to JSON
};
var options2 = {
method: 'POST',
uri: endpointsigCat,
body: input,
json: true // Automatically stringifies the body to JSON
};
var options3 = {
method: 'POST',
uri: endpointrepCat,
body: input,
json: true // Automatically stringifies the body to JSON
};
requestProm.post(options1)
.then(function (response) {
result = response['predictions'];
switch (parseInt(result)) {
case 0:
predictedHaz = 'A';
break;
case 1:
predictedHaz = 'B';
break;
case 2:
predictedHaz = 'C';
break;
case 3:
predictedHaz = 'D';
break;
case 4:
predictedHaz = 'E';
break;
case 5:
predictedHaz = 'F';
break;
case 6:
predictedHaz = 'G';
break;
default:
predictedHaz = 'error';
}
const predictedHazData = {
HazardCategory: predictedHaz,
};
setDoc = db.collection('users').doc(context.params.usersId).update(predictedHazData);
console.log(response);
return true
})
.catch(function (err) {
console.log('Failed', err)
});
requestProm.post(options2)
.then(function (response) {
result = response['predictions'];
if (parseInt(result) > -4) {
predictedSig = 'Sig';
} else predictedSig = 'Insig'
const predictedSigData = {
SignifanceCategory: predictedSig,
};
setDoc = db.collection('users').doc(context.params.usersId).update(predictedSigData);
console.log(response);
return true
})
.catch(function (err) {
console.log('Failed', err)
});
requestProm.post(options3)
.then(function (response) {
result = response['predictions'];
if (parseInt(result) === 1) {
predictedRep = 'Inc';
} else predictedRep = 'Haz'
const predictedRepData = {
ReportCategory: predictedRep,
};
setDoc = db.collection('users').doc(context.params.usersId).update(predictedRepData);
console.log(response);
return true
})
.catch(function (err) {
console.log('Failed', err)
});
return true
}
getPrediction().catch(console.error);
} return null
})
.catch(err => {
console.log('Error getting document', err);
});
return true;
});
Added some details:
These are the service account permissions:
ml.jobs.cancel
ml.jobs.create
ml.jobs.get
ml.jobs.getIamPolicy
ml.jobs.list
ml.jobs.update
ml.locations.get
ml.locations.list
ml.models.create
ml.models.delete
ml.models.get
ml.models.getIamPolicy
ml.models.list
ml.models.predict
ml.models.update
ml.operations.cancel
ml.operations.get
ml.operations.list
ml.projects.getConfig
ml.studies.create
ml.studies.delete
ml.studies.get
ml.studies.getIamPolicy
ml.studies.list
ml.trials.create
ml.trials.delete
ml.trials.get
ml.trials.list
ml.trials.update
ml.versions.create
ml.versions.delete
ml.versions.get
ml.versions.list
ml.versions.predict
ml.versions.update
resourcemanager.projects.get
I have tried to use other node library 'googleapis' on debug console :
google.auth.getApplicationDefault((err, authClient, projectId) => {
if (err) {
console.log('Authentication failed because of ', err);
res.status(401).send('Authentication failed');
} else {
// create the full model name which includes the project ID
const modelName = 'projects/ml-project-id/models/hazcat';
const mlRequestJson = {
'auth': authClient,
'name': modelName,
'resource': { instances: [['RepNum', 'RepTit', 'RepNar']]
}
}
ml.projects.predict(mlRequestJson, (err, result) => {
if (err) {
console.log(err);
} else {
console.log(result.data.predictions[0]);
}
});
}
});
and the result is:
3
and deployed to firebase:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const admin = require('firebase-admin');
const request = require("request");
const requestProm = require("request-promise");
const functions = require('firebase-functions');
const { GoogleAuth } = require('google-auth-library');
const { google } = require('googleapis');
const ml = google.ml('v1');
admin.initializeApp();
var reportFld, reportNarTr, reportTitTr, reportNumTr, reportTitStr, reportNarStr;
var input, input2, input3;
var result, predictedHaz, predictedSig, predictedRep, setDoc
exports.predictReport = functions.firestore
.document('/users/{usersId}')
.onCreate((change, context) => {
const db = admin.firestore();
const interDoc = db.collection('users').doc(context.params.usersId);
interDoc.get().then(doc => {
if (!doc.exists) {
console.log('No such document!');
} else {
reportFld = doc.data();
reportNarTr = JSON.stringify(reportFld.narrative);
reportTitTr = JSON.stringify(reportFld.title);
reportNumTr = context.params.usersId;
input = {
instances: [
[reportNumTr, reportTitTr, reportNarTr]
]
};
var result1, result2, result3
google.auth.getApplicationDefault((err, authClient, projectId) => {
if (err) {
console.log('Authentication failed because of ', err);
res.status(401).send('Authentication failed');
} else {
const modelName = 'projects/ml-project-id/models/hazcat';
const modelName2 = 'projects/ml-project-id/models/sig';
const modelName3 = 'projects/ml-project-id/models/type';
const mlRequestJson1 = {
'auth': authClient,
'name': modelName,
'resource': input
}
const mlRequestJson2 = {
'auth': authClient,
'name': modelName2,
'resource': input
}
const mlRequestJson3 = {
'auth': authClient,
'name': modelName3,
'resource': input
}
var result1, result2, result3
ml.projects.predict(mlRequestJson1, (err, result) => {
if (err) {
console.log(err);
} else {
console.log(result.data.predictions[0]);
result1 = result.data.predictions[0];
switch (parseInt(result1)) {
case 0:
predictedHaz = 'A';
break;
case 1:
predictedHaz = 'B';
break;
case 2:
predictedHaz = 'C';
break;
case 3:
predictedHaz = 'D';
break;
case 4:
predictedHaz = 'E';
break;
case 5:
predictedHaz = 'F';
break;
case 6:
predictedHaz = 'G';
break;
default:
predictedHaz = 'error';
}
const predictedHazData = {
HazardCategory: predictedHaz,
};
setDoc = db.collection('users').doc(context.params.usersId).update(predictedHazData);
}
}); // endof predict1
ml.projects.predict(mlRequestJson2, (err, result) => {
if (err) {
console.log(err);
} else {
console.log(result.data.predictions[0]);
result2 = result.data.predictions[0];
if (parseInt(result2) > -4) {
predictedSig = 'Sig';
} else predictedSig = 'Insig'
const predictedSigData = {
SignifanceCategory: predictedSig,
};
setDoc = db.collection('users').doc(context.params.usersId).update(predictedSigData);
}
});// endof predict2
ml.projects.predict(mlRequestJson3, (err, result) => {
if (err) {
console.log(err);
} else {
console.log(result.data.predictions[0]);
result3 = result.data.predictions[0];
if (parseInt(result3) === 1) {
predictedRep = 'Inc';
} else predictedRep = 'Haz'
const predictedRepData = {
ReportCategory: predictedRep,
};
setDoc = db.collection('users').doc(context.params.usersId).update(predictedRepData);
}
});// endof predict3
}//endof else getappdefault
});//endof getappdefault
} return true
})//endof getdocument
.catch(err => {
console.log('Error getting document', err);
});
return true;
});//endof onCreate
and the result is
Authentication failed because of Error: Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information.
at AuthPlus.getApplicationDefaultAsync (/srv/node_modules/googleapis-common/node_modules/google-auth-library/build/src/auth/googleauth.js:156:23)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:229:7)
Added details (update 2)
I have used keyfile pointing to service account json file.
getAccessTokenId = async function main() {
const auth = new GoogleAuth({
keyFile: 'projectid.json',
scopes: 'https://www.googleapis.com/auth/cloud-platform'
});
const client = await auth.getClient();
const projectId = await auth.getProjectId();
const accessTokenId = await auth.getAccessToken();
return accessTokenId
}
got access token like this
ya29.c.xxxx
and the permission denied
Failed { StatusCodeError: 403 - {"error":{"code":403,"message":"Access to model denied.","status":"PERMISSION_DENIED"}}
Added details (update 3)
I'm using my personal credentials to enter the ML model works inside cloud function
getAccessTokenId = async function main() {
const auth = new GoogleAuth({
keyFile: 'application_default_credentials.json',
scopes: 'https://www.googleapis.com/auth/cloud-platform'
});
const client = await auth.getClient();
const projectId = await auth.getProjectId();
const accessTokenId = await auth.getAccessToken();
return accessTokenId
}
Get the result
{ predictions: [ 3 ] }
I also have added Service Account Token Creator role on the service account but still not work using service account to access ML Model
iam.serviceAccountKeys.create
iam.serviceAccountKeys.delete
iam.serviceAccountKeys.get
iam.serviceAccountKeys.list
But curious why it doesnt have these
iam.serviceAccounts.getAccessToken
iam.serviceAccounts.signBlob
iam.serviceAccounts.signJwt
iam.serviceAccounts.implicitDelegation
iam.serviceAccounts.getOpenIdToken

Nodejs Await function issue

I've make a translation service in nodejs :
module.exports = {GetcountryFR, GetRegionFR, GetChildrenFR, GetHomeownFR, GetHomestyleFR, GetIncomeFR, GetLstatusFR, GetWdomainFR, GetWtypeFR, GetSexFR}
async function GetcountryFR(country) {
var countrix = country;
switch (countrix) {
case 'createuser.france': countrix = 'FRANCE'; break;
case 'createuser.belgique': countrix = 'BELGIQUE'; break;
default: countrix = 'UNKNOWN'; break;
}
return countrix;
}
And now I make a function which uses translat function
const translate = require('../services/translate');
exports.AllUserToCSV = async function CSV() {
try {
let user = User.find();
var data = [];
len = user.length;
for (i = 0; i < len; i++) {
let sexix = await translate.GetSexFr(user[i].sex);
let regionix = await translate.GetRegionFR(user[i].region);
let countrix = await translate.GetcountryFR(user[i].country);
let wtypix = await translate.GetWtypeFR(user[i].wtype);
let wdomainix = await translate.GetWdomainFR(user[i].wdomain);
temp = {
sex: sexix,
region: regionix,
country: countrix,
wtype: wtypix,
wdomain: wdomainix,
}
data.push(temp);
}
const csvData = csvjson.toCSV(data, { headers: 'key' })
filename2 = '/assets/media/' + 'TEST' + '.csv';
writeFile(filename, csvData, (err) => {
if (err) {
console.log(err); // Do something to handle the error or just throw it
throw new Error(err);
}
console.log('Success!');
});
} catch (e) {
console.error(e);
}
}
In results CSV file is Empty [].
If I put values in temp it's OK.
Why my translate function didn't work ??
Thanks for Help Good Friends :)
Simply await your call to the User model i.e let user = await User.find();
Also for the loop, try
let users = await User.find();
await Promise.all(users.map(async (user) => {
let sexix = await translate.GetSexFr(user.sex);
...
})));
Writing to file, you may want to use await fs.writeFile(...);. This will make sure file is written before processing the next.

Session expiring in Dialogflow

I came to know that context expires in 15 minutes but is there any way to solve it manually i.e by storing the previous conversation in dB so can we handle that session expiring issue or else the whole conversation(output context) under that session ID will get clear and need to start from the first.
exports.fulfillmenttext = functions.https.onRequest((req,res) =>{
const answer1 = req.body.Text;
console.log("Text said by the user",answer1);
const uid = answer1.substring(0,28);
console.log("uid1 is",uid);
const answer = answer1.substring(28);
console.log("answer is",answer);
const sessionId = uid;
var count,questvalue;
runSample();
async function runSample(projectId = 'xxxxxxx') {
const languageCode = 'en-US';
const credentials = {
client_email: 'xxxxxxxxxx',
private_key: 'xxxxxxxxx'
};
//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: sessionPath,
queryInput: {
text: {
text: answer,
languageCode,
},
},
};
const responses = await sessionClient.detectIntent(request);
console.log('Detected intent');
const result = responses[0].queryResult;
let action = result.action;
console.log("action is"+action);
console.log(` Query: ${result.queryText}`);
console.log(` Response: ${result.fulfillmentText}`);
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('User').doc(uid).collection("Popop").doc(uid).collection('Answers').doc('Earlyyears').update(data1);
},
'family': () => {
console.log('familyaction1', action);
let mname1 = JSON.stringify(result.parameters.fields.M_Name.stringValue);
let mname_string = mname1.toString().replace(/"/g,"");
var data20 = {
MName: mname_string
};
var setDoc20 = admin.firestore().collection('User').doc(uid).collection("Popop").doc(uid).collection('Answers').doc('Family').update(data20);
}
};
if (action === 'early') {
console.log('1');
actionHandlers[action]();
}
else if (action === 'family') {
console.log('2');
actionHandlers[action]();
}
res.status(200).send({"question":result.fulfillmentText,"action":action});
} else {
console.log(` No intent matched.`);
res.status(400).send({"action":"empty"});
}
}
});
I stumbled upon this problem as well. My solution was to save the userID and save the contexts to Firestore.
UPDATE:
This is how I stored Dialogflow's contexts in Firestore:
function saveContexts(userId, contexts) {
let UID = userId;
//get all contexts + parameters
if (contexts === undefined) {
console.log("contexts are undefined! returning");
return false;
}
db.collection("user-contexts-prod").doc(UID).set({
dateCreated: new Date(),
contexts: JSON.stringify(contexts)
})
.then(function () {
console.log("success!");
return true;
})
.catch(function (error) {
console.log("error writing document..", error);
return false;
});
}
Retrieving user contexts:
async function getContexts(userId) {
let UID = userId;
let docRef = db.collection("user-contexts-prod").doc(UID);
return docRef.get()
.then(res => {
if (res.exists) {
let contexts = JSON.parse(res.data().contexts);
console.log("<><> parsed contexts <><>: ");
console.log(contexts);
return contexts;
} else {
console.log(" UID DOES NOT EXIST!");
return false;
}
})
}
You can set the contexts again by looping over them and using the contextClient to create new contexts. Or use this method to loop through the contexts and find the one you need:
contexts.forEach(function(context) {
if (context.name === 'projects/{DIALOGFLOWPROJECTID}/agent/sessions/' + senderId + '/contexts/{CONTEXTNAME}') {
sessionData = context.parameters;
// all data that you saved in CONTEXTNAME is now available in the sessionData variable
}
});
Original answer:
Whenever a user started talking that didn't have any active contexts I check if I had the userID stored in my Database. If this user existed in my DB I retrieved the user information with all his data like this:
knownUser = await db.isKnownUser(senderId);
if (knownUser) {
//knownUser
console.log("Known user");
let userData = db.getUserDataById(senderId)
//initialize contexts with data you need
payload = returningUser_useSameData();
messenger.send(payload, senderId);
dashbot.logBotMessage(payload.toString, sessionId, intentName);
break;
} else {
//newUser
console.log("new user");
createContext('await_fillInTogether', '', sessionPath, sessionId, 1);
createContext('session', '', sessionPath, sessionId, 500);
payload = fillInTogetherNewUser();
messenger.send(payload, senderId);
dashbot.logBotMessage(payload.toString, sessionId, intentName);
break;
}

Getting document not a function

I am attempting to retrieve the boolean child (notificationsOn) of an object stored as a Firestore document to see if the rest of a function should be executed.
The overall function works to completion without this portion, but adding the portion from let threadDoc to the if statement presents a "threadDoc.get is not a function" error. I think my syntax is wrong but I don't know how, as a similar function works in a later part of the function:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendDMNotification =functions.firestore.document('/dm_threads/{thread_id}/messages/{message_id}').onCreate((snapshot, context) => {
const newMessage = snapshot.data();
const senderName = newMessage.authorName;
const senderID = newMessage.authorUID;
const messageText = newMessage.message;
const recipientID = newMessage.recipientUID;
var notificationsOn = null;
let deviceTokenQuery = admin.firestore().collection(`/users/${recipientID}/device_tokens/`);
var idsToBeSorted = [senderID, recipientID];
idsToBeSorted.sort();
var threadID = idsToBeSorted[0] + idsToBeSorted[1];
console.log(recipientID);
console.log(threadID);
let threadDoc = admin.firestore().document(`users/${recipientID}/threads/${threadID}/`);
return threadDoc.get().then(doc => {
let notificationsOn = doc.data.notificationsOn;
console.log(notificationsOn);
if (notificationsOn !== false){
return deviceTokenQuery.get().then(querySnapshot => {
let tokenShapshot = querySnapshot.docs;
const notificationPromises = tokenShapshot.map(doc => {
let token_id = doc.data().tokenID;
const payload = {
data: {
title: senderName,
body: messageText,
senderID: senderID,
senderName: senderName
}
};
return admin.messaging().sendToDevice(token_id, payload).then(response => {
console.log("Notification sent: ", response);
})
.catch(error => {
console.log("Error sending message: ", error);
});
});
return Promise.all(notificationPromises);
});
}
return;
});
});
admin.firestore().document() was supposed to be admin.firestore().collection(...).doc(...)
This fixed my problem
I think you meant to say admin.firestore() instead of functions.firestore.

Resources