Connecting Dialogflow to Firebase question - firebase

I have been reading around but cannot find the answer
I tried my firebase and it's not storing any data.
Here's the related inline editor
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
function angerEmotionCapture(agent) {
let angryTo = agent.parameters.angryDirectedTo;
agent.add(`love your ${angryTo},dude`);
return db.collection('directedTo').add({directedTo: angryTo});
}
Here's my firebase database
Any help will be greatly appreciated, thanks!

Please have a look into the following sample code showing how to connect Firebase's Firestore database to Dialogflow fulfillment hosting on Firebase functions:
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {WebhookClient} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:*'; // enables lib debugging statements
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
function writeToDb (agent) {
// Get parameter from Dialogflow with the string to add to the database
const databaseEntry = agent.parameters.databaseEntry;
// Get the database collection 'dialogflow' and document 'agent' and store
// the document {entry: "<value of database entry>"} in the 'agent' document
const dialogflowAgentRef = db.collection('dialogflow').doc('agent');
return db.runTransaction(t => {
t.set(dialogflowAgentRef, {entry: databaseEntry});
return Promise.resolve('Write complete');
}).then(doc => {
agent.add(`Wrote "${databaseEntry}" to the Firestore database.`);
}).catch(err => {
console.log(`Error writing to Firestore: ${err}`);
agent.add(`Failed to write "${databaseEntry}" to the Firestore database.`);
});
}
// Map from Dialogflow intent names to functions to be run when the intent is matched
let intentMap = new Map();
intentMap.set('WriteToFirestore', writeToDb);
agent.handleRequest(intentMap);
});
Have a look into the Dialogflow's Firestore GitHub example

Related

firebase firestore presence system

I am trying to implement a presence system, I have followed the documentation for it. it works as it updates both my firestore and realtime databases. However, when i close the app, the realtime database is updated, while the firestore is not. below is the sample code I have in my cloud function, which I assume performs the action.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const firestore = admin.firestore();
exports.onUserStatusChanged = functions.database.ref('/status/{uid}').onUpdate(
async (change, context) => {
const eventStatus = change.after.val();
const userStatusFirestoreRef = firestore.doc(`users/${context.params.uid}`);
const statusSnapshot = await change.after.ref.once('value');
const status = statusSnapshot.val();
console.log(status, eventStatus);
if (status.last_changed > eventStatus.last_changed) {
return null;
}
return userStatusFirestoreRef.set({
online: false,
last_changed: firestore.FieldValue.serverTimestamp(),
}, { merge: true });
});

Cloud Function Update Problem in Firestore Database

I'm trying to build an Android application. In my Firestore database I have Users collection and Counters collection. In Counters collection I have userCounter. What I want to do is whenerever a new user logs in and I push it to firestore, userCounter to increase.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.addNewUser =
functions.firestore.document('Users/{userID}').onCreate((event) => {
var db = admin.firestore();
var counterRef = db.collection("Counters");
var temp = counterRef.doc("0").data().userCounter++;
counterRef.doc("0").update(
{
userCounter: temp
});
});
In this state, this function doesn't work, and I'm a newbie so I'd appreciate any help.
Thx beforehand
EDIT
After implementing Firebaser and Pablo Almécija Rodríguez's answers, my code looks like this.
const Firestore = require('#google-cloud/firestore');
const firestore = new Firestore({
projectId: process.env.GCP_PROJECT,
});
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.addNewUser =
functions.firestore.document('Users/{userId}').onCreate((snapShot) => {
const userCounterRef = db.collection('Counters').doc('Users');
return db.runTransaction(transaction => {
const doc = transaction.get(userCounterRef);
console.log("1");
const count = doc.data();
console.log(`5`);
const updatedCount = count + 1;
console.log(`6`);
return transaction.update(userCounterRef, {counter: updatedCount })
})
});
And this is the firebase console log. The problem is
const count = doc.data();
TypeError: doc.data is not a function
Firebase Console Log
I suggest you to create a collection named counters and inside it a document named users to handle counter for users. Here is the structure:
- counters (collection)
- users (document)
count: 0 (field)
Then, you should use a transaction to perform an update on this counter document to make sure you are working with up-to-date data to deal with concurrency (multiple accounts created at the same time)
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.addNewUser =
functions.firestore.document('users/{userId}').onCreate((snapShot) => {
const userCounterRef = db.doc('counters/users');
return db.runTransaction(async transaction => {
const doc = await transaction.get(userCounterRef)
const { count } = doc.data()
const updatedCount = count + 1
return transaction.update(userCounterRef, {count: updatedCount })
})
});
https://firebase.google.com/docs/firestore/manage-data/transactions
EDIT: If you don't want to deal with async/await syntax, update your transaction like that :
return db.runTransaction(transaction => {
return transaction.get(userCounterRef)
.then(doc => {
const count = doc.data().count
const updatedCount = count + 1
transaction.update(userCounterRef, {count: updatedCount })
})
})
I have reproduced it in Cloud Functions, and this simple solution worked. Edited answer to fit Firebase, and it also uses the Firestore dependency for nodejs.
const Firestore = require('#google-cloud/firestore');
const firestore = new Firestore({
projectId: process.env.GCP_PROJECT,
});
const functions = require('firebase-functions');
//I am not using next two lines right now though
const admin = require('firebase-admin');
admin.initializeApp();
exports.helloFirestore =
functions.firestore.document('users/{userID}').onCreate((event) => {
const doc = firestore.doc('Counters/UserCounter/');
doc.get().then(docSnap => {
//Get the specific field you want to modify
return docSnap.get('userCount');
}).then(field => {
field++;
//Log entry to see the change happened
console.log(`Retrieved field value after +1: ${field}`);
//Update field of doc with the new value
doc.update({
userCount: field,
});
});
});
The wildcard you used should be fine, just be careful with the full path for the collection, mind the upper/lower case. For this case, this is how my package.json looks like:
{
"name": "sample-firestore",
"version": "0.0.1",
"dependencies": {
"#google-cloud/firestore": "^1.1.0",
"firebase-functions": "2.2.0",
"firebase-admin": "7.0.0"
}
}

Firebase Functions ReferenceError with SendGrid function

I'm trying to get started with SendGrid and a Firestore database, using Firebase functions. I've gone through tutorials and set up according to the latest notation, (snap, context) instead of (event). I can't figure out what's wrong with this script:
// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();
//admin.initializeApp(functions.config().firebase);
const SENDGRID_API_KEY = my-api-key-is-here;
const sendgridemail = require('#sendgrid/mail');
sendgridemail.setApiKey(SENDGRID_API_KEY);
exports.confEmail = functions.firestore
.document('clients/{clientId}/projects/{projectId}/form-data/{docId}') //any write to this node will trigger email
.onCreate((snap, context) => {
const clientId = context.params.clientId;
const projectId = context.params.projectId;
const docId = context.params.docId;
const fsdb = admin.firestore();
return fsdb.collection('clients/'+clientId+'/projects/'+projectId+'/form-data').doc(docId)
.get()
.then(doc => {
const docData = doc.data()
const msgbody = {
to: docData.EMAIL,
from: 'xxxxx#gmail.com',
subject: 'Form Submission Confirmation',
templateId: 'd-07bf6a2b89084951a30ceddcd9c8915f',
substitutionWrappers: ['{{', '}}'],
substitutions: {
formdata: "Message Body\n<br>"+docData.CONF_MSG
}
};
return confEmail.send(msgbody)
})
.then(() => console.log('confimration mail sent success') )
.catch(err => console.log(err) )
});
The error message generated in the Firebase console is mysterious, and I'm not even sure how to interpret it.
ReferenceError: confEmail is not defined
at fsdb.collection.doc.get.then.doc (/user_code/index.js:48:13)
at process._tickDomainCallback (internal/process/next_tick.js:135:7
)
My best guess just that my 'confEmail' function is not defined because there's an error in it, but I can't figure out what. Or does it mean something else?
It looks like most of the tutorial scripts are over-complicating things. and a simpler script like this seems to work.
const sendgrid = require('#sendgrid/mail');
sendgrid.setApiKey(SENDGRID_API_KEY);
exports.confEmail = functions.firestore
.document('clients/{clientId}/projects/{projectId}/form-data/{docId}') //any write to this node will trigger email
.onCreate((snap, context) => {
const docData = snap.data();
const msgbody = {
to: docData.EMAIL,
from: 'xxxxxxx#gmail.com',
subject: 'Form Submission Confirmation',
templateId: 'd-07bf6a2b89084951a30ceddcd9c8915f',
substitutionWrappers: ['{{', '}}'],
substitutions: {
formdata: docData.CONF_MSG
}
};
return sendgrid.send(msgbody)
});

Dialogflow - Fulfillment Inline Editor(Firebase) is timeout

I am testing with Dialogflow using Firebase project.
The Firebase Project is already used as an android backend. (Firestore)
Now, I am trying to attach chatbot.
This github code is what I want.
I create a new Dialogflow Agent, it refers to the Firebase project.
Enable Fullfillment Inline Editor, and I copy&paste a code from upper github code.
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {WebhookClient} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:*'; // enables lib debugging statements
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
function writeToDb (agent) {
const databaseEntry = agent.parameters.databaseEntry;
const dialogflowAgentRef = db.collection('dialogflow').doc('agent');
return db.runTransaction(t => {
t.set(dialogflowAgentRef, {entry: databaseEntry});
return Promise.resolve('Write complete');
}).then(doc => {
agent.add(`Wrote "${databaseEntry}" to the Firestore database.`);
}).catch(err => {
console.log(`Error writing to Firestore: ${err}`);
agent.add(`Failed to write "${databaseEntry}" to the Firestore database.`);
});
}
let intentMap = new Map();
intentMap.set('WriteToFirestore', writeToDb);
agent.handleRequest(intentMap); // Here is index.js:51
});
This is very simple.
It just writes a text into the Firestore.
That's all.
I deployed this fulfillment and linked to an Intent.
In case of first conversation after deploy, I can find below log in Firebase Cloud Functions.
Error: No handler for requested intent
at WebhookClient.handleRequest (/user_code/node_modules/dialogflow-fulfillment/src/dialogflow-fulfillment.js:317:29)
at exports.dialogflowFirebaseFulfillment.functions.https.onRequest (/user_code/index.js:51:9)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/providers/https.js:57:9)
And after some times, when I retry again, I can find below logs in the Firebase Cloud Functions.
dialogflowFirebaseFulfillment - Function execution took 60002 ms, finished with status: 'timeout'
I don't know what I am missing...
It was my fault.
The key of intentMap should be same with Intent name.
After I fix it, it works fine.

How do I write to Firestore using Angular 5?

I've connected my Stripe checkout to Firebase Real Time Database by using this tutorial https://angularfirebase.com/lessons/angular-stripe-payments-part-2-firebase-cloud-functions-backend/
It is successful. However, I need the checkout process to work using Firestore since we have migrated our database there. Unfortunately, it is not working! The function works BUT the data is still being saved in Real Time Database, not Firestore. Here's my code:
const functions = require('firebase-functions');
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase);
const firebaseConfig = JSON.parse(process.env.FIREBASE_CONFIG);
const db = admin.firestore(); // Firebase
const stripe = require('stripe')(functions.config().stripe.testkey) // Stripe
exports.stripeCharge = functions.firestore
.document('/payments/{userId}')
.onWrite(event => {
const payment = event.data.val();
const userId = event.params.userId;
const paymentId = event.params.paymentId;
// checks if payment exists or if it has already been charged
if (!payment || payment.charge) return;
return admin.firestore()
.collection('payments')
.doc('{userId}')
.once('value')
.then(snapshot => {
return snapshot.val();
})
.then(customer => {
const amount = payment.amount;
const idempotency_key = paymentId; // prevent duplicate charges
const source = payment.testkey.id;
const currency = 'php';
const charge = {amount, currency, source};
return stripe.charges.create(charge, { idempotency_key });
})
.then(charge => {
db
.collection('payments')
.doc('{userId}')
.collection('{paymentId}')
.field('charge')
.set(charge)
})
});
From part 1 of the tutorial, the database structure is like this:
payments
$userId
$paymentId
amount: number
token: object
charge: object
I think you are using firebase-functions >1.0.0
admin.initializeApp();
Check full migration guide here

Resources