How to retrieve data from Firebase using DialogFlow Inline Editor - javascript

I am pretty new to DialogFlow. I am wondering how can I retrieve data from Firebase through the Inline Editor of DialogFlow. Hope you can help me!

Thats how you can communicate with firebase from dialogflow
const functions = require('firebase-functions');
const firebaseAdmin = require('firebase-admin');
const DialogflowApp = require('actions-on-google').DialogflowApp;
Initialize Firebase Admin SDK.
firebaseAdmin.initializeApp(functions.config().firebase);
Interaction with firebase Collection users in fulfillment function
let userId = app.getUser().userId;
admin.firestore().collection('users').where('userId', '==', userId).limit(1).get()
.then(snapshot => {
let user = snapshot.docs[0]
if (!user) {
// If user is not in DB, its their first time, Welcome them!
app.ask('Welcome to my app for the first time!');
// Add the user to DB
firebaseAdmin.firestore().collection('users').add({
userId: userId
}).then(ref => {
console.log('Added document with ID: ', ref.id);
});
} else {
// User in DB
app.ask('Welcome back!')
}
});
}
// Map function hanlder to Dialogflow's welcome intent action 'input.welcome'
const actionMap = new Map('input.welcome', start)
app.handleRequest(actionMap);

Related

Firebase Funtions push notifications

I'm new to firebase and there is something I can't do. I want to send a notification to the phone with firebase functions. I want to receive notifications on the phone when someone follows me. My Firebase collection is as in the photo. I want to access the Followers array and send its information with notification. The codes I could write are as follows. What do I need to add?
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.sendPushNotification = functions.firestore.document('/users/{uid}').onCreate((snap, context) => {
var values = snap.data();
var token = values.fcmTokens;
var payload = {
notification: {
title: values.title,
body: values.message
}
}
return admin.messaging().sendToDevice(token, payload);
});
First, onCreate() function is triggered when a document is created. I assume followers array will be updated everytime someone follows a user? In that case you should be using onUpdate() that'll trigger the function when the document is updated. You can just check if length of followers array has changed in the update, if yes then send the notification as shown below:
exports.sendPushNotification = functions.firestore
.document('users/{userId}')
.onUpdate((change, context) => {
const newValue = change.after.data();
const previousValue = change.before.data();
if (newValue.followers.length > previousValue.followers.length) {
// followers count increased, send notification
const token = newValue.fcmTokens;
const payload = {
notification: {
title: "New Follower",
body: "Someone followed you"
}
}
await admin.messaging().sendToDevice(token, payload);
}
return null;
});
Here, we send notification only if the followers field has changed since this function will trigger whenever any field in this user document is updated.
If you want to specify who followed the user, then you'll have to find the new UID added in followers array and query that user's data.
Firestore documents have a max size limit of 1 MB so if a user can have many followers then I'll recommend creating a followers sub-collection. Then you'll be able to use onCreate() on the sub-document path /users/{userId}/followers/{followerId}

How do I write a cloud function which creates a user in the Firestore database once a new user gets authenticated?

So far I have written the following code:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
exports.addAccount = functions.auth.user().onCreate((event) => {
const user = event.data; // The firebase user
const id = user.uid;
return admin
.database()
.ref("/users/" + id)
.set("ok");
});
The idea here is to execute a cloud function once a new user gets created. As this happens, I want to create a new node in the Firestore database. Under the 'users' collection I want to add a document with the uid, which contains a bit of information, in this case a String that says 'ok'.
When deploying this function it produces an error. How exactly should I go about creating it?
The admin.database() returns the Realtime Database service. To use Firestore, use firebase.firestore(). Try refactoring the code as shown below:
exports.addAccount = functions.auth.user().onCreate((event) => {
const user = event.data; // The firebase user
const id = user.uid;
return admin
.firestore()
.collection("users")
.doc(id)
.set({ uid: id, ...user });
});

Can't make Firestore to get only docs from logged user id

I am an UX Designer and I'm pretty new to working with Firebase.
I've been trying to develop a system on webflow integrated with Firebase using JavaScript and the Firebase SDK to a personal project and got stuck with this problem.
I have managed to create the authentication system, the signup system and everything is working as it should.
However, when I try to fetch data from Firestore userdata collection, I am not being able to get the current user id and pass it to the WHERE string on my query.
If I run the query without the WHERE, it works perfectly, bringing me all the documents in the userdata collection, but when I try to do it only for a specific user, it fails.
I already tried a lot of things which I think wasn't the right method to do this, the JavaScript below was my last attempt. I think I'm just too new on this and can't understand how to pass the id variable into the query.
Here is the link to the project: https://poupei.webflow.io/. Just click "Criar conta" to create an account, you can use a fake email and 6 digit password and then login.
// Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.4.0/firebase-app.js";
import { getAuth, onAuthStateChanged, signOut } from "https://www.gstatic.com/firebasejs/9.4.0/firebase-auth.js";
import { getFirestore, collection, getDocs, query, where, doc } from "https://www.gstatic.com/firebasejs/9.4.0/firebase-firestore.js"
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
const app = initializeApp({
apiKey: "AIzaSyAZUIyxf4Lsw6D9JOzVuNslsGJ8gXkPBVY",
authDomain: "poupei-app.firebaseapp.com",
projectId: "poupei-app",
storageBucket: "poupei-app.appspot.com",
messagingSenderId: "837432279066",
appId: "1:837432279066:web:119bc86e42fb87ac17d1a3"
});
// Initialize Firebase
const auth = getAuth()
const db = getFirestore();
onAuthStateChanged(auth, (user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
const userID = user.id;
console.log("Logged In");
console.log(userID);
// ...
} else {
// User is signed out
window.location.replace("https://poupei.webflow.io/");
}
});
const q = query(collection(db, "userdata"), where("id", "==", userID));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
const docs = doc.data();
document.getElementById('nome').innerHTML = docs.nome;
document.getElementById('sobrenome').innerHTML = docs.sobrenome;
document.getElementById('email').innerHTML = docs.email;
document.getElementById('saldo').innerHTML = docs.saldo;
});
document.getElementById('logoutBtn').addEventListener('click', function(){
signOut(auth).then(() => {
// Sign-out successful.
window.location.replace("https://poupei.webflow.io/");
}).catch((error) => {
// An error happened.
});
});
</script>
´´´
#Allennick has the cause of the problem correct in their answer, but the solution won't work.
Signing in to Firebase (as well as loading data from Firestore and most other modern cloud APIs) is an asynchronous operation. While the user is being signed in (or the data is being loaded) your main code continues to run. Then when the user is signed in, your callback code is executed.
It's easiest to see this flow by running in a debugger, or adding some logging:
console.log("Attaching auth state listener");
onAuthStateChanged(auth, (user) => {
if (user) {
console.log("Got user state");
}
});
console.log("Starting database query");
const q = query(collection(db, "userdata"), where("id", "==", userID));
const querySnapshot = await getDocs(q);
When you run this code it logs:
Attaching auth state listener
Starting database query
Got user state
This is probably not the order you expected, but it perfectly explains why you're not getting the user data from the database: the query executes before the user is ever loaded.
The solution to this problem is always the same: any code that needs to react to the current user state, needs to be inside the onAuthStateChanged callback, be called from there, or otherwise synchronized.
The simplest fix is to move your database code into the callback, like this:
onAuthStateChanged(auth, async (user) => {
if (user) {
const userID = user.id;
// 👇 Now that the user us know, we can load their data
const q = query(collection(db, "userdata"), where("id", "==", userID));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
const docs = doc.data();
document.getElementById('nome').innerHTML = docs.nome;
document.getElementById('sobrenome').innerHTML = docs.sobrenome;
document.getElementById('email').innerHTML = docs.email;
document.getElementById('saldo').innerHTML = docs.saldo;
});
document.getElementById('logoutBtn').addEventListener('click', function(){
signOut(auth).then(() => {
// Sign-out successful.
window.location.replace("https://poupei.webflow.io/");
}).catch((error) => {
// An error happened.
});
} else {
// User is signed out
window.location.replace("https://poupei.webflow.io/");
}
});
Also see:
firebase.auth().currentUser is null at page load
Is there any way to get Firebase Auth User UID?
firebase.initializeApp callback/promise?
I think that the query doesn't know what userID is because you are declaring that variable inside authStateChange. Try to move the declaration of userID to global scope + add a console.log() before executing the query to see if the userID is set correctly.
Or just put the code that performs the query inside the onAuthStateChanged code so that you can use the userID.
(Posted answer on behalf of the question author to move it to the answer space).
Updating with the code that worked for me with the help of Frank. Thanks Frank!
onAuthStateChanged(auth, async (user) => {
if (user) {
const userID = user.email;
console.log(userID);
const q = query(collection(db, "userdata"), where("email", "==", userID));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
const docs = doc.data();
document.getElementById('nome').innerHTML = docs.nome;
document.getElementById('sobrenome').innerHTML = docs.sobrenome;
document.getElementById('email').innerHTML = docs.email;
document.getElementById('saldo').innerHTML = docs.saldo;
document.getElementById('meta').innerHTML = docs.objetivo;
})
} else {
console.log("nada");
}
});

How to work with firebase realtime database from Firebase Functions? (Telegram Bot)

I want to store and receive data from firebase realtime database by Telegram bot using Telegraf.
I'm using Firebase Functions / Cloud Functions for this.
Right now storing data on database is working, but I can't figure out how to get data from firebase and then send it as telegram message.
Below is response for /database command
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const Telegraf = require('telegraf');
admin.initializeApp();
const bot = new Telegraf(functions.config().telegram_token.key);
bot.hears('hello', (ctx) => ctx.reply('Hi from Firebase Function!'));
bot.command('database', (ctx) => {
// store data on firebase realtime database - it's working
admin.database().ref('users/' + ctx.message.chat.id).set({
username: ctx.message.from.first_name,
email: 'test#test.gmail.com',
});
// HOW TO? get data from firebase realtime database
const userId = ctx.message.chat.id;
const dataFromDb = admin.database().ref('users/' + userId).once('value');
ctx.reply(`Data from firebase: ${dataFromDb}`);
});
bot.launch();
exports.bot = functions.region('europe-west1').https.onRequest((req, res) => {
bot.handleUpdate(req.body, res).then( (rv) => !rv && res.sendStatus(200));
});
Can someone please share useful example? :)
Thank U for your attencion,
Regards!
Reading data from Firebase is an asynchronous operation, so you'll need to wait for it to complete:
const dataFromDb = await admin.database().ref('users/' + userId).once('value');
In addition, you'll need to get the value from the snapshot you get back, instead of sending the entire snapshot back:
ctx.reply(`Data from firebase: ${dataFromDb.val()}`);

Calling a Firebase Cloud Function 'ForEach' child of a Snapshot

I'm trying to deploy a Firebase Cloud Function that sends a text message to its associated recipient for x number of text messages. The function is triggered in my iOS app when an update is made to the 'send' Realtime Database reference, indicating that the user has pressed the 'send' button.
My Firebase structure is
{
"user1uid": {
"send": false
"messagesToSend": {
"messageuid1": {
"messageText": "What's for dinner?",
"recipientNumber": "+18017378888",
}
"messageuid2:
"messageText": "Who won the Cowboys game?",
"recipientNumber": "+18017377787",
}
}
"user2uid": {
"send": false
"messagesToSend": {
"messageuid1": {
"messageText": "What's for dinner?",
"recipientNumber": "+18017378888",
}
"messageuid2:
"messageText": "Who won the Cowboys game?",
"recipientNumber": "+18017377787",
}
}
}
My code currently only sends one message, and I'm not sure how I can properly iterate through the messagesToSend node for each user and send all the messages in it.
I've been trying to follow the tutorial located here. I have looked at the following Stack Overflow responses but am unable to decipher or derive a solution from them:
Firebase cloud function promises
Am I using ForEach correctly?
My index.js code that sends one message is as follows:
const functions = require('firebase-functions');
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();
const twilio = require('twilio')
const accountSid = functions.config().twilio.sid;
const authToken = functions.config().twilio.token;
const client = new twilio(accountSid, authToken);
const twilioNumber = functions.config().twilio.number;
// Start cloud function
exports.sendSecrets = functions.database
.ref('/{uid}/send')
.onUpdate((change,context) => {
const uid = context.params.uid;
return admin.database().ref(uid+'/messagesToSend').once('value').then(snapshot => {
snapshot.forEach(function(childSnapshot) {
var key = childSnapshot.key;
var messageData = childSnapshot.val();
**if (messageData.sanitized) return true;**
var message = messageData.messageText;
var phoneNumber = messageData.recipientNumber;
const textMessage = {
body: `From My App - ${message}`,
from: twilioNumber, // From Twilio number
to: phoneNumber // Text to this number
}
return client.messages.create(textMessage)
})
**return snapshot.ref.toString();**
});
});
Please note that the lines marked with ** at either end indicate that I know I need to return something based on error messages I received indicating that 'Each then() should return a value or throw'.
I make the assumption that you are using the twilio-node library that use promises: https://www.npmjs.com/package/twilio.
Since you want to send several messages in parallel, you have to use Promise.all(), as follows:
const functions = require('firebase-functions');
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();
const twilio = require('twilio')
const accountSid = functions.config().twilio.sid;
const authToken = functions.config().twilio.token;
const client = new twilio(accountSid, authToken);
const twilioNumber = functions.config().twilio.number;
// Start cloud function
exports.sendSecrets = functions.database
.ref('/{uid}/send')
.onUpdate((change,context) => {
const uid = context.params.uid;
return admin.database().ref(uid+'/messagesToSend').once('value')
.then(snapshot => {
const promises = [];
snapshot.forEach(function(childSnapshot) {
var key = childSnapshot.key;
var messageData = childSnapshot.val();
//**if (messageData.sanitized) return true;**
var message = messageData.messageText;
var phoneNumber = messageData.recipientNumber;
const textMessage = {
body: `From My App - ${message}`,
from: twilioNumber, // From Twilio number
to: phoneNumber // Text to this number
}
promises.push(client.messages.create(textMessage));
})
return Promise.all(promises);
})
// Edits made below to parentheses/brackets
.then(results => {
//Do whatever you want !!
// e.g. print the results which will be an array of messages
// (see https://www.twilio.com/docs/libraries/node#testing-your-installation)
})
});
You can also simply return Promise.all() as follows:
....
return Promise.all(promises);
})
});

Categories

Resources