Return Promise<String> from Cloud Function - javascript

I want to return the myref as the promise as the reponse from this function to the calling end.Please help i am new at this.
const functions = require("firebase-functions");
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
exports.createService = functions.https.onRequest((req, res) => {
// Grab the text parameter.
const serviceName = req.query.serviceName;
const ttlHour = req.query.ttlHour;
const promise = [];
const myref = admin.database().ref("/root/events");
promise.push(myref);
// Push the new message into the Realtime Database using the Firebase
Admin SDK.
myref.set({ name: serviceName, ttl: ttlHour, startTs: 0 }).then(snapshot => {
res.send("Write succeeded!");
});
});

Related

how to mirror data from real time database to firestore with cloud function?

I am trying to deploy a cloud function that copies the information that is in my realtime database to firestore whenever it gets updated. I set the cloud function and called it in my function that saves to my realtime database but it's not performing the cloud function. I'm not getting any errors in the console either. What's the error and how can i fix this? I have provided my code below:
Realtime database setup:
studiopick
studio
users
Gcsh31DCGAS2u2XXLuh8AbwBeap1
email : "Test#gmail.com"
firstName : "Test"
lastName : "one"
phoneNumber : "2223334567"
prices
| roomA
| serviceOne
| numberInput : "300"
| serviceType : "mix n master"
studioName : "Studio One"
uid : "Gcsh31DCGAS2u2XXLuh8AbwBeap1"
Cloud Function JS:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
exports.updateFirestore = functions.database
.ref("studiopick/studio/users/{uid}")
.onWrite((change, context) => {
const uid = context.params.uid;
if (!change.after.exists()) {
return null;
}
// Grab the current value of the Realtime Database.
const data = change.after.val();
const firestoreDb = admin.firestore();
const docReference = firestoreDb.collection(uid);
return docReference.set(
{
TransmitterError: data.TransmitterError,
},
{merge: true},
);
});
const updateFirestore = firebase
.functions()
.httpsCallable("updateFirestore");
function updatePrice() {
//Get data
numberInput = document.getElementById("numberInput").value;
const user = firebase.auth().currentUser;
//Enter database location
firebase
.database()
.ref("/studiopick/studio/users/" + user.uid + "/prices/roomA/serviceOne")
.update({
numberInput: numberInput,
});
updateFirestore(); //This is the copy to firestore function
}
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
exports.updateFirestore = functions.database
.ref("studiopick/studio/users/{uid}")
.onWrite((change, context) => {
const uid = context.params.uid;
if (!change.after.exists()) {
return null;
}
// Grab the current value of the Realtime Database.
const data = change.after.val();
const firestoreDb = admin.firestore();
const docReference = firestoreDb.collection("studiopick/studios/" + uid);
return docReference.set(
{
TransmitterError: data.TransmitterError,
},
{merge: true},
);
});

Cloud Function - onWrite is not triggered when a new document is created

I have a 'Users' collection which contains a list of documents, each document has a user object and a sub-collection 'Notifications'. whenever a user get a new notification, a new document is created under it's sub-collection Notifications.
The trigger in the cloud function is not triggered.
Here is my Firestore structure:
And here is my function:
let functions = require('firebase-functions');
let admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.firestore.collection('Users/{userID}/Notifications/{notificationId}')//
.onWrite(async (change,context) => {
// get receiver ID
const receiverId = context.params.userID;
// get notification object
const notificationObject = change.after.val();
// get sender ID
const senderUid = notificationObject.senderId;
console.log('sending notification to: ' + senderUid);
if (senderUid === receiverId) {
// this should never be called
console.log('sender is the receiver.');
}
// receiver's token
const getTokenPromise = await admin.firestore().collection('Users').doc(receiverId).once('value');
const token = getTokenPromise.val().deviceToken;
// sender user object
const sender = await admin.firestore().collection('Users').doc(senderUid).once('value');
const payload = {
data: {
senderName: sender.val().userName,
senderPhoto: sender.val().userPhoto,
object: JSON.stringify(notificationObject)
}
};
try {
const response = await admin.messaging().sendToDevice(token, payload);
console.log("Successfully sent notification:", response);
}
catch (error) {
console.log("Error sending notification:", error);
}
});
What I'm doing wrong ?
You should declare your function with
exports.sendNotification = functions.firestore.document('Users/{userID}/Notifications/{notificationId}')//
.onWrite(async (change,context) => {...});
and not with
exports.sendNotification = functions.firestore.collection('Users/{userID}/Notifications/{notificationId}')//
.onWrite(async (change,context) => {...});
As a matter of fact, Cloud Functions for Firestore are triggered at the level of the document. More details here and here in the doc.

Twilio not sending SMS inside firebase cloud function

i am trying to send sms using twilio api for node.js through a firebase cloud function but the sms is not sent. however if the same code i run as an independent java script code, then it works fine.can someone
please help why this is not happening inside the firebase cloud function. the code is attached below:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotfication = functions.database.ref('/kakuh/{pushId}/firstName')
.onCreate((snapshot, context) => {
const original = snapshot.val();
const accountSid = 'ACb6b4820df073e63312382f95b0314d07';
const authTcoken = 'c60923ca097368662b39dfab470f2fd1';
const client = require('twilio')(accountSid, authToken);
client.messages
.create({
from: '+16304263296',
body: original,
to: '+918169813384'
});
console.log('Uppercasing', context.params.pushId, original);
const uppercase = original.toUpperCase();
return snapshot.ref.parent.child('firstName').set(uppercase);
});
You'll need to wait for Twilio to respond, then return to Firebase.
Try this:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotfication = functions.database.ref('/kakuh/{pushId}/firstName')
.onCreate((snapshot, context) => {
const original = snapshot.val();
const accountSid = 'ACb6b4820df073e63312382f95b0314d07';
const authToken = 'c60923ca097368662b39dfab470f2fd1';
const client = require('twilio')(accountSid, authToken);
client.messages
.create({
from: '+16304263296',
body: original,
to: '+918169813384'
})
.then((message) => {
console.log(message.sid);
console.log('Uppercasing', context.params.pushId, original);
const uppercase = original.toUpperCase();
return snapshot.ref.parent.child('firstName').set(uppercase);
})
.catch((err) => {
throw (err);
});
});

Firebase Auth - Set session expiration

How can I set session expiration for a Firebase auth session?
By default the session never expires.
I wish for the session to expire after 8 hours of inactivity.
I have read the documentation but cannot figure out how to set session expiration.
My code for signing in the user and performing tasks on sign in and sign out
firebase.auth().signInWithEmailAndPassword(data.email, data.password)
firebase.auth().onAuthStateChanged((user) => {
if (user) {
//Signed in
}else{
//Signed out
}
}
Thanks for all replies!
I have tried but cannot seem to get Firebase-admin to work.
Firebase-db.js
const admin = require('firebase-admin')
const databaseConnection = {
serviceAccountFile: './serviceAccount.json',
databaseURL: 'https://myProject.firebaseio.com/'
}
const serviceAccount = require(databaseConnection.serviceAccountFile)
const app = admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: databaseConnection.databaseURL
}, 'test')
const database = admin.database(app)
module.exports = database
sessionSignout.js
const functions = require('firebase-functions')
const database = require('../../firebase-db')
const admin = database.admin
exports.sessionSignout = functions
.region('europe-west1')
.pubsub
.schedule('*/15 * * * *')
.timeZone('Europe/Stockholm')
.onRun(async (event) => {
database.ref(`users`)
.once('value', (usersSnapshots) => {
usersSnapshots.forEach((snapshot) => {
const uid = snapshot.key
admin.auth().revokeRefreshTokens(uid)
})
})
}
I get error
Error: function execution failed. Details: Cannot read property 'auth' of undefined
The documentation you linked says that you can use the Firebase Admin SDK to revoke a user's refresh tokens in order to terminate their session. This code must run on a backend you control, which means that you won't be able to do it in the client app. The backend will need to know when the user became "inactive", by whatever definition of that you choose. Wiring this all up is non-trivial, but possible.
Thanks for all the answers!
I just wanted to share my code for others to use.
I already had code in place to accommodate presence awareness.
index.js
import database from './firebase/firebase' //Firebase setup for client
firebase.auth().onAuthStateChanged((user) => {
//Handle login and redirect
if (user) {
//We are logged in
addPresenceAwarenessListener()
}else{
...
}
}
const addPresenceAwarenessListener = () => {
// Create a reference to the special '.info/connected' path in
// Realtime Database. This path returns `true` when connected
// and `false` when disconnected.
database.ref('.info/connected').on('value', (snapshot) => {
// If we're not currently connected, don't do anything.
if (snapshot.val() == false) {
return
}
const uid = firebase.auth().currentUser.uid
//Push last login/logout to user profile
const userLastLoginOutRef = database.ref(`users/${uid}`)
userLastLoginOutRef.onDisconnect().update({lastLoginOut: firebase.database.ServerValue.TIMESTAMP})
.then(() => { userLastLoginOutRef.update({lastLoginOut: firebase.database.ServerValue.TIMESTAMP}) })
})
}
Session handling - expire sessions after n hours (setting "sessExp" in database)
firebase-db.js - Basic Firebase setup for cloud functions
const admin = require('firebase-admin')
const databaseConnection = {
serviceAccountFile: './my-project.json',
databaseURL: 'https://my-project.firebaseio.com/'
}
const serviceAccount = require(databaseConnection.serviceAccountFile)
const app = admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: databaseConnection.databaseURL
}, 'remindMiNotifier')
const database = admin.database(app)
module.exports = database
sessionSignout.js - Signout user after a specific time period - if specified. Default to eternal session.
const functions = require('firebase-functions')
const moment = require('moment')
const database = require('../../firebase-db')
const admin = database.app
//Import enviroment variable config (.env)
require('dotenv').config()
//Export cron job - deploy: firebase deploy --only functions:sessionSignout
exports.sessionSignout = functions
.region('europe-west1')
.pubsub
.schedule('*/15 * * * *')
.timeZone('Europe/Stockholm')
.onRun(async (event) => {
//Start execution
const now = moment()
const defaultSessionTime = 0 //Eternal session
//Get all users and calculate inactive time - time since last login
let logoutUsersArray = []
await database.ref(`users`)
.once('value', (usersSnapshots) => {
usersSnapshots.forEach((snapshot) => {
const userData = snapshot.val()
const lastLoginOut = (userData.lastLoginOut) ? userData.lastLoginOut : 0
//Only process users that has a login/out time stamp
if(lastLoginOut > 0){
const userSessionTime = (userData.sessExp) ? userData.sessExp : defaultSessionTime
const hoursSinceLastLoginOut = now.diff(lastLoginOut, 'hours')
const logoutUser = ( userSessionTime > 0 && (hoursSinceLastLoginOut > userSessionTime) )
if(logoutUser){
const userId = snapshot.key
const userName = (userData.alias) ? userData.alias : userData.displayName
const email = (userData.email) ? userData.email : ''
const userObject = {
userId,
userName,
email,
lastLoginOut,
diffHours: now.diff(lastLoginOut, 'hours')
}
logoutUsersArray.push(userObject)
}
}
})
})
console.log('logoutUsersArray', logoutUsersArray)
//Collect all promises to carry out
let myPromises = []
// Revoke all refresh tokens for each user
logoutUsersArray.forEach((logoutUser) => {
const uid = logoutUser.userId
myPromises.push(
admin.auth().revokeRefreshTokens(uid)
.then(() => {
return admin.auth().getUser(uid)
})
.then((userRecord) => {
return new Date(userRecord.tokensValidAfterTime).getTime() / 1000
})
.then((timestamp) => {
// Retrieve the timestamp of the revocation, in seconds since the epoch.
console.log('Tokens revoked at: ', timestamp)
return Promise.resolve(true)
})
.catch((err) => {
console.error('Error', err)
return Promise.reject(err)
})
)
})
//Execute promises
console.log('Execute promises')
return Promise.all(myPromises)
.then(() => Promise.resolve(true))
.catch((err) => {
console.error('Error', err)
return Promise.reject(err)
})
})//End sessionSignout
Documentation on firebase-admin can be found here.

Stubbing auth0 in firebase functions

I have the following Firebase Function that makes use of Auth0 to get a user profile.
'use strict';
const {
dialogflow,
Image,
} = require('actions-on-google')
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
// database collection and key names
const DB_BANK_COLLECTION_KEY = 'bank'
// the action name from all Dialogflow intents
const INTENT_WELCOME_USER = 'Default Welcome Intent';
// Initialize the Auth0 client
var AuthenticationClient = require('auth0').AuthenticationClient;
var auth0 = new AuthenticationClient({
domain: functions.config().familybank.auth0.domain,
clientID: functions.config().familybank.auth0.clientid
});
const app = dialogflow();
app.intent(INTENT_WELCOME_USER, async (conv) => {
console.log('Request: ' + JSON.stringify(conv.request));
const userInfo = await auth0.getProfile(conv.user.access.token)
.catch( function(err) {
console.error('Error getting userProfile from Auth0: ' + err);
conv.close("Something went wrong. Please try again in a few minutes. " + err)
});
console.log('userInfo: ' + JSON.stringify(userInfo));
// check for existing bank, if not present, create it
var bankRef = db.collection(DB_BANK_COLLECTION_KEY).doc(userInfo.email);
const bankSnapshot = await bankRef.get()
})
exports.accessAccount = functions.https.onRequest(app);
I tried to mock auth0 in my tests using the following code (and several permutations), but the actual function always gets called instead of the mock.
const chai = require('chai');
const assert = chai.assert;
const sinon = require('sinon');
// Require firebase-admin so we can stub out some of its methods.
const admin = require('firebase-admin');
const test = require('firebase-functions-test')();
var AuthenticationClient = require('auth0').AuthenticationClient;
var auth0 = new AuthenticationClient({
domain: "mock",
clientID: "mock"
});
describe('Cloud Functions', () => {
let myFunctions, adminInitStub;
before(() => {
test.mockConfig({"familybank": {"auth0": {"domain": "mockdomain", "clientid": "mockid"}}});
adminInitStub = sinon.stub(admin, 'initializeApp');
sinon.stub(admin, 'firestore')
.get(function() {
return function() {
return "data";
}
});
sinon.stub(auth0, 'getProfile').callsFake( function fakeGetProfile(accessToken) {
return Promise.resolve({"email": "daniel.watrous#gmail.com", "accessToken": accessToken});
});
myFunctions = require('../index');
});
after(() => {
adminInitStub.restore();
test.cleanup();
});
describe('accessAccount', () => {
it('should return a 200', (done) => {
const req = {REQUESTDATA};
const res = {
redirect: (code, url) => {
assert.equal(code, 200);
done();
}
};
myFunctions.accessAccount(req, res);
});
});
})
Is there some way to mock auth0 for my offline tests?
I discovered that rather than initialize the Auth0 AuthenticationClient, I could first require the UsersManager, where the getProfile (which wraps getInfo) is defined.
var UsersManager = require('auth0/src/auth/UsersManager');
In my before() method, I can then create a stub for getInfo, like this
sinon.stub(UsersManager.prototype, 'getInfo').callsFake( function fakeGetProfile() {
return Promise.resolve({"email": "some.user#company.com"});
});
All the calls to auth0.getProfile then return a Promise that resolves to the document shown in my stub fake function.

Categories