Cannot get Google AI prediction result using JWT credential using node js - 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

Related

Error received on token expiration despite of not being outdated in node js app

Good day developers, recently as been working in this node js app, and when implementing jwt library i got an error related to tghe verify() method in this jwt repo.
Kind of :
return secretCallback(null, secretOrPublicKey);
^
TokenExpiredError: jwt expired
The repo is structured in several folders:
controllers
middlewares
helpers
socket controllers
On my middleware folder, sepecifically in a file related to jwt validation i settled this:
file middleware jwt-validation
export {};
const { request, response } = require("express");
const User = require("../models/user-model");
const jwt = require("jsonwebtoken");
const jwtValidator = async (req = request, res = response, next) => {
const token_response = req.header("token-response");
if (!token_response) {
return res.status(401).json({
message: "Not valid token .You don't have authorization",
});
}
try {
const payload = await jwt.verify(token_response, process.env.SECRETKEYJWT)
const userAuth = await User.findById(payload.id);
if (userAuth.userState != true) {
return res.status(401).json({
message: "User inhabilitated",
});
}
if (!userAuth) {
return res.status(404).json({
message: "User not found",
});
}
req.user = userAuth;
next();
} catch (error) {
return res.status(500).json({
message: "Not valid token.Error 500",
});
}
};
module.exports = { jwtValidator };
file middleware jwt-validation-sockets
import { UserSchema } from "../interfaces";
const jwt = require("jsonwebtoken");
const User = require("../models/user-model");
const jwtValidatorRenew = async (
token: string = ""
): Promise<UserSchema | null> => {
if (token == "" || token.length < 10 || token == undefined) {
return null;
}
const payloadToken = await jwt.verify(token, process.env.SECRETKEYJWT)
const userTokenDecoded: UserSchema = User.findById(payloadToken.id);
if (userTokenDecoded?.userState) {
return userTokenDecoded;
} else {
return null;
}
};
module.exports = { jwtValidatorRenew };
file helper jwt-generator
const { request, response } = require("express");
const jwt = require("jsonwebtoken");
const createJWT = async (id = "", nickname = "") =>
return new Promise((resolve, reject) => {
const payloadInJWT = { id, nickname };
jwt.sign(
payloadInJWT,
process.env.SECRETKEYJWT,
{
expiresIn: 3600,
},
//calback
(error:any, token:string) => {
if (error) {
alert(error)
reject("Error creating token ");
} else {
resolve(token);
}
}
);
});
};
module.exports = { createJWT };
file socket-controller
const { jwtValidatorRenew } = require("../middlewares/jwt-validation-socket");
const { userData } = require("../helpers/helper-user-schema-data");
const { Socket } = require("socket.io");
const User = require("../models/user-model");
const {
ChatMessage,
Message,
MessagePrivate,
GroupChat,
} = require("../models/chat-model");
const chatMessage = new ChatMessage()
const socketController = async (socket = new Socket(), io) => {
const user = await jwtValidatorRenew(
socket.handshake.headers["token-response"]
);
try {
...some sockets flags
} catch (error) {
socket.disconnect();
}
};
module.exports = { socketController };

RefreshToken not present in tokenSET

I am trying to connect with the api hubstaff to which I have set up my authentication using auth0 and express as my backend. To know about the info about the logged in user I need to send the token object via the API.
By some research I have gotten to this point:
const {
Issuer,
TokenSet
} = require('openid-client');
const fs = require('fs');
const jose = require('jose');
// constants
const ISSUER_EXPIRE_DURATION = 7 * 24 * 60 * 60; // 1 week
const ACCESS_TOKEN_EXPIRATION_FUZZ = 30; // 30 seconds
const ISSUER_DISCOVERY_URL = 'https://account.hubstaff.com';
// API URl with trailing slash
const API_BASE_URL = 'https://api.hubstaff.com/';
let state = {
api_base_url: API_BASE_URL,
issuer_url: ISSUER_DISCOVERY_URL,
issuer: {}, // The issuer discovered configuration
issuer_expires_at: 0,
token: {},
};
let client;
function loadState() {
return fs.readFileSync('./configState.json', 'utf8');
}
function saveState() {
fs.writeFileSync('./configState.json', JSON.stringify(state, null, 2), 'utf8');
console.log('State saved');
}
function unixTimeNow() {
return Date.now() / 1000;
}
async function checkToken() {
//console.log('state.token.access_token', state.token.access_token);
if (!state.token.access_token || state.token.expires_at < (unixTimeNow() + ACCESS_TOKEN_EXPIRATION_FUZZ)) {
// console.log('Refresh token');
state.token = await client ? .refresh(state.token);
// console.log('Token refreshed');
saveState();
}
}
async function initialize() {
console.log('API Hubstaff API');
let data = loadState();
data = JSON.parse(data);
if (data.issuer) {
state.issuer = new Issuer(data.issuer);
state.issuer_expires_at = data.issuer_expires_at;
}
if (data.token) {
state.token = new TokenSet(data.token);
}
if (data.issuer_url) {
state.issuer_url = data.issuer_url;
}
if (data.api_base_url) {
state.api_base_url = data.api_base_url;
}
if (!state.issuer_expires_at || state.issuer_expires_at < unixTimeNow()) {
console.log('Discovering');
state.issuer = await Issuer.discover(state.issuer_url);
state.issuer_expires_at = unixTimeNow() + ISSUER_EXPIRE_DURATION;
console.log(state.issuer);
}
client = new state.issuer.Client({
// For personal access token we can use PAT/PAT.
// This is only needed because the library requires a client_id where as the API endpoint does not require it
client_id: 'Z',
client_secret: 'J',
});
saveState();
console.log('API Hubstaff initialized');
}
async function request(url, options) {
await checkToken();
let fullUrl = state.api_base_url + url;
return client ? .requestResource(fullUrl, state.token, options);
}
function tokenDetails() {
let ret = {};
if (state.token.access_token) {
ret.access_token = jose.JWT.decode(state.token.access_token);
}
if (state.token.refresh_token) {
ret.refresh_token = jose.JWT.decode(state.token.refresh_token);
}
return ret;
}
module.exports = {
initialize,
checkToken,
request,
tokenDetails
};
// COntroller
const { response } = require('express')
const api = require('../util/hubstaffConnect.util');
const testConnected = require('../util/testhubstaff.util');
const usersGet = async (req, res = response) => {
await api.initialize();
const response = await api.request('v2/organizations',{
method: 'GET',
json: true,
});
console.log('response', response);
if(response != null){
const body = JSON.parse(response);
res.json({
organizations: body.organizations || []
});
}
};
Although when I go to the address localhost:8080/oauth/api/organizations I ran into an error:
I do realise this is regarding missing tokens which won't let me get the user's information.

AWS Lambda (NodeJS) does not log to cloudwatch

I'm trying to log my lambda app after following serverless-next.js because of the issue where I can't go to the root of my file. So basically I'm deploying nextJS app in AWS through lambda#edge, s3, and cloudfront.
I'm new to AWS so I'm not really sure how to debug this thing at all. I assume traditional console.log in my lambda where every request comes in would log it in the cloudwatch. I also made sure that I deployed my lambda to my cloud front
Here's the code:
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.handler = void 0;
const prerender_manifest_json_1 = __importDefault(require("./prerender-manifest.json"));
const manifest_json_1 = __importDefault(require("./manifest.json"));
const next_aws_cloudfront_1 = __importDefault(require("#sls-next/next-aws-cloudfront"));
const addS3HostHeader = (req, s3DomainName) => {
req.headers["host"] = [{ key: "host", value: s3DomainName }];
};
const isDataRequest = (uri) => uri.startsWith("/_next/data");
const normaliseUri = (uri) => (uri === "/" ? "/index" : uri);
const normaliseS3OriginDomain = (s3Origin) => {
if (s3Origin.region === "us-east-1") {
return s3Origin.domainName;
}
if (!s3Origin.domainName.includes(s3Origin.region)) {
const regionalEndpoint = s3Origin.domainName.replace("s3.amazonaws.com", `s3.${s3Origin.region}.amazonaws.com`);
return regionalEndpoint;
}
return s3Origin.domainName;
};
const router = (manifest) => {
const { pages: { ssr, html } } = manifest;
const allDynamicRoutes = Object.assign(Object.assign({}, ssr.dynamic), html.dynamic);
return (uri) => {
let normalisedUri = uri;
if (isDataRequest(uri)) {
normalisedUri = uri
.replace(`/_next/data/${manifest.buildId}`, "")
.replace(".json", "");
}
if (ssr.nonDynamic[normalisedUri]) {
return ssr.nonDynamic[normalisedUri];
}
console.log(uri);
for (const route in allDynamicRoutes) {
const { file, regex } = allDynamicRoutes[route];
const re = new RegExp(regex, "i");
const pathMatchesRoute = re.test(normalisedUri);
if (pathMatchesRoute) {
return file;
}
}
if (html.nonDynamic["/404"] !== undefined) {
return "pages/404.html";
}
return "pages/_error.js";
};
};
exports.handler = (event) => __awaiter(void 0, void 0, void 0, function* () {
const request = event.Records[0].cf.request;
const uri = normaliseUri(request.uri);
const manifest = manifest_json_1.default;
const prerenderManifest = prerender_manifest_json_1.default;
const { pages, publicFiles } = manifest;
const isStaticPage = pages.html.nonDynamic[uri];
const isPublicFile = publicFiles[uri];
const isPrerenderedPage = prerenderManifest.routes[request.uri];
const origin = request.origin;
const s3Origin = origin.s3;
const isHTMLPage = isStaticPage || isPrerenderedPage;
const normalisedS3DomainName = normaliseS3OriginDomain(s3Origin);
s3Origin.domainName = normalisedS3DomainName;
if (isHTMLPage || isPublicFile) {
s3Origin.path = isHTMLPage ? "/static-pages" : "/public";
addS3HostHeader(request, normalisedS3DomainName);
if (isHTMLPage) {
request.uri = `${uri}.html`;
}
return request;
}
const pagePath = router(manifest)(uri);
if (pagePath.endsWith(".html")) {
s3Origin.path = "/static-pages";
request.uri = pagePath.replace("pages", "");
addS3HostHeader(request, normalisedS3DomainName);
return request;
}
const page = require(`./${pagePath}`);
const { req, res, responsePromise } = next_aws_cloudfront_1.default(event.Records[0].cf);
if (isDataRequest(uri)) {
const { renderOpts } = yield page.renderReqToHTML(req, res, "passthrough");
res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify(renderOpts.pageData));
}
else {
page.render(req, res);
}
return responsePromise;
});
Permission:
Allow: logs:CreateLogGroup
Allow: logs:CreateLogStream
Allow: logs:PutLogEvents
What else should I do? Should I create a new stream or is it automatically created? I can see a log group in my cloudwatch named aws/lambda but i'm not sure how to connect them
Really appreciate any help
Cheers

Undefined in Firebase Functions with Realtime Database

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.

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;
}

Resources