get firebase data through cloud functions without any trigger - firebase

can I use cloud function to get data from a specific firebase database node?
if there is a node (Car) with child (price) having value ($1000). how can I get this car value by cloud function? I have searched a lot but only able to find functions which work on triggers like onCreate, onUpdate, etc. But how to just simply fetch data without any trigger?

Define an an HTTP trigger.
Code that trigger to query Realtime Database using the Admin SDK.
Gather the fetched data into some variable, in the format you would like to serialize back to the client.
Send the database back to the client using the provided Response object passed to the trigger.
In the client, invoke that HTTP trigger using the URL it was assigned, and parse the data returned from step 4.

You need initial the firebase first
// Set the configuration for your app
// TODO: Replace with your project's config object
var config = {
apiKey: "apiKey",
authDomain: "projectId.firebaseapp.com",
databaseURL: "https://databaseName.firebaseio.com",
storageBucket: "bucket.appspot.com"
};
firebase.initializeApp(config);
// Get a reference to the database service
var database = firebase.database();
and then read the data:
var carRef = database().ref('Car/);
carRef.on('price', function(snapshot) {
console.log(snapshot.val());
});
more information, please check the firebase official document.

Related

How do I authenticate for cloud functions when using the Firebase Local Emulator?

I'm trying to set up the firebase local emulator to be able to test cloud functions. But I'm either getting "Error: Unauthenticated" responses outside the main function or auth errors within it, depending on whether or not I've tried to authenticate using the client SDK. The cloud function looks like this:
export default functions.https.onCall(async (data, context) => {
console.log(context.auth)
// Custom function code and authentication checks that rely on context.auth existing
}
And the attempts to call it look like this:
await firebase.initializeApp({
apiKey: FIREBASE_API_KEY,
authDomain: FIREBASE_AUTH_DOMAIN,
databaseURL: FIREBASE_DATABASE_URL,
projectId: FIREBASE_PROJECT_ID,
storageBucket: FIREBASE_STORAGE_BUCKET,
messagingSenderId: FIREBASE_MESSAGING_SENDER_ID
})
await firebase.functions().useFunctionsEmulator('http://localhost:5001')
//await firebase.auth().createUserWithEmailAndPassword(email, password)
//let res = await firebase.auth().signInWithEmailAndPassword(email, password)
const result = await firebase.functions().httpsCallable('myFunction')(data)
If I run it like this, I can see logging within the cloud function that shows the context argument has no auth values. If I uncomment the user sign-in stuff, I get an Error: Unauthenticated response and the function itself never gets run.
Is there some configuration stuff I'm missing for this? I haven't been able to find much documentation around using the emulator.
After digging deep into the actual SDK, I managed to figure it out. I was using a bad API key, meaning the generated token was bad. The correct way is to create the user and log in as the user before making the call.

How to import firebase into google apps script, in order to create users with google provider?

I'm trying to create a new user in firebase via the google auth provider either automatically or by the click of a button in a sidebar addon in google sheets. The reason being is I need to get a registered uid for the user so the data that I send from sheets can be attributed to this user.
The closest thing I've found to a tutorial is this, but I get stuck when trying to import firebase.
One method I'm seeing a lot is importing it via a script tag in the html for the sheets side bar.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<script>
// Initialize Firebase
var config = {
apiKey: '...,
authDomain: '...',
databaseURL: '...',
projectId: '...',
storageBucket: '...',
messagingSenderId: '...'
};
firebase.initializeApp(config);
</script>
</body>
</html>
However when I try to use the firebase variable in my .gs script it is undefined. How would I make it available to the script?
The other method I've seen is using eval and URLFetchApp in the gs script.
eval(UrlFetchApp.fetch("https://www.gstatic.com/firebasejs/5.9.2/firebase.js").getContentText());
This results in SyntaxError: Missing name after . operator.
I think this is because this library isn't intended to run on node js.
I realize that the admin sdk for firebase is intended for node js but you can't create a user with a specific provider with this method (afaik). Also I'm not sure how I would import it to Google apps script anyways. Additionally I want the user to interact with the google account selector after initiating the create user process.
Does anyone have any suggestions as to how to get this done?
It is actually quite easy to create new users in Firebase from a Google Sheet by using the Firebase Auth REST API.
You have to issue an HTTP POST request to the Auth signupNewUser endpoint, see the detailed doc here: https://firebase.google.com/docs/reference/rest/auth/#section-create-email-password
For that you will use the fetch() method of the URLFetchApp() Class in your gs script, as follows:
function createUser() {
const userName = "john.doe#gmail.com";
const pwd = "xyz987";
const createUserUrl = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=[API_KEY]" //Replace with your Web API Key
const payload = JSON.stringify({"email": userName, "password": pwd, "returnSecureToken": true});
const createUserResponse = UrlFetchApp.fetch(createUserUrl, {
method: 'post',
contentType: 'application/json',
muteHttpExceptions: true,
payload : payload
});
Logger.log(JSON.parse(createUserResponse));
}
You will obtain the Web API Key for your Firebase project through the project settings page in your Firebase admin console.

Firebase cloud function to use sendgrid for sending emails when a contact form gets submitted to firestore

I want my firebase backend to send an email to me when a document is created in a firestore collection based on a form submission in my vue app..
I found sendgrid to be the easiest to get the job done, the example mentioned in the package page suggests that I store the API key in an Environment variable.
Since this will run from a cloud function, I used the following command firebase functions:config:set sendGrid.key="THE API GOES HERE" as mentioned in Firebase docs here
cloud function
I initialized the firebase cloud functions locally, then I called the admin module so i can listen to onCreate() when a document is created in firestore,
I used sendGrid inside the callback function of onCreate()..
I tested the code and checked the functions logs in my firebase project and it gets invoked and finished successfully with a status ok, which means that everything should be working fine.
here is my index.js code inside the /functions folder in my project root
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
// sendGrid
const sgMail = require('#sendgrid/mail');
// the cloud function
exports.formSubmitted = functions.firestore.document('message/{messageId}').onCreate(doc => {
// referencing the form data
const formData = doc.data();
// the following should be logged in the function logs in my firebase project
console.log(formData);
// retrieving the environment variable
sgMail.setApiKey(functions.config().sendgrid.key);
// the message to be sent
const msg = {
to: 'MY-EMAIL#gmail.com',
from: formData.email,
subject: 'new user submitted our contact form',
text: formData.message,
html: '<h3> test email from sendGrid </h3>'
}
return sgMail.send(msg);
})
result:
everything worked fine except I didn't receive the email.
If further code/explanation is needed, please leave a comment below.
any help or hints is highly appreciated, thanks in advance.

Firebase cloud functions -#google-cloud/storage initialization

First question here.
I am trying to write a firebase cloud function to compress a file. I went through a lot of examples on the web but my code keeps getting stuck at two points.
1.const {gcs} =require('#google-cloud/storage')();
When I use this construct in require , I get the following error
TypeError: require(...) is not a function
If I change this to
const {gcs} =require('#google-cloud/storage'); the error goes away but apparently the object isn't initialized because I get this error when I try to access it like so
TypeError: Cannot read property 'bucket' of undefined
at exports.onfilechangecompressor.functions.storage.object.onFinalize.object
(/user_code/index.js:21:27)
at cloudFunctionNewSignature (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:105:23)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:135:20)
at /var/tmp/worker/worker.js:733:24
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
This is the line where I use gcs like so
const destBucket = gcs.bucket(bucket); where bucket is the object.bucket returned ( object is returned by onFinalize ).
Can someone please tell me how to initialize the storage so it works and returns a valid object.
My node.js version is 8.12.0
firebase version is 5.1.1
The documentation for 2.x shows this:
const {Storage} = require('#google-cloud/storage');
You're adding () after the require, which you're discovered is not correct.
You then go on to initialize it like this:
// Your Google Cloud Platform project ID
const projectId = 'YOUR_PROJECT_ID';
// Creates a client
const storage = new Storage({
projectId: projectId,
});
You may not need to specify the project id if you're running in Cloud Functions or other Google environments.
After that, you can get a reference to your default bucket:
storage.bucket()
You can also use the Admin SDK to invoke the same cloud storage APIs:
const admin = require('firebase-admin');
admin.initializeApp();
const storage = admin.storage();
storage.bucket();

Firebase Cloud Messaging for web: how to send to multiple tokens?

i hope i don't get downvotes on this one, i've been trying to set up web notifications for my CMS using Firebase, and i noticed that Google's Firebase documentations on the topic are huge, i mean very huge you get confused.
So far i managed to add the functionality of letting people subscribe to the notification by letting the browser asking their permission to send them notifications, then i get the unique tokens after they accept and store those tokens in my database, i also managed to change the location of the service worker and everything looks good and dandy.
Now, i want to send a notification to all my users (tokens) that are stored in my database, i think looping through them and send a notification using CURL to each one individually is a nasty solution. I can't find a documentation on how to send a notification to all my tokens in one CURL call.
This is my code so far:
<!-- Firebase Technologies -->
<!-- Firebase App is always required and must be first -->
<script src="https://www.gstatic.com/firebasejs/5.1.0/firebase-app.js">
</script>
<script src="https://www.gstatic.com/firebasejs/5.1.0/firebase-
messaging.js"></script>
<script>
// Initialize Firebase
var config = {
apiKey: "AIzaSyAR84lF2vbnfUWPZ2899dnqiTthgvfv7Ms",
authDomain: "lazemnicms.firebaseapp.com",
databaseURL: "https://lazemnicms.firebaseio.com",
projectId: "lazemnicms",
storageBucket: "lazemnicms.appspot.com",
messagingSenderId: "268754114869"
};
firebase.initializeApp(config);
messaging = firebase.messaging();
//Registering the service worker
navigator.serviceWorker.register("firebase-messaging-sw.js", {scope: "firebase-cloud-messaging-push-scope"}).then(function (registration) {
messaging.useServiceWorker(registration);
}).catch(function (err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
permissionGranted = false;
messaging.getToken().then(function(currentToken) {
if (currentToken) {
console.log(currentToken);
permissionGranted = true;
//sendTokenToServer(currentToken);
//updateUIForPushEnabled(currentToken);
} else {
permissionGranted = false;
}
}).catch(function(err) {
permissionGranted = false;
});
And also if a user got a refreshedToken, how can i know this user's old token so i can remove it from my database after i store his/her new token?
Those questions are really troubling me.
Thanks in advance.
The v1 API currently only allows sending to a single token at a time. Multicast is planned to be added (it was present in the previous API), but I don't have a timeline for when it will be available. So right now that means that you'll need to do a call to the FCM API for each token.
There is nothing built-in to know the previous token for a user. The typical way to do this is to keep the "last known token" in local storage, and unregister that when you get a new token. Alternatively, you can instead catch the errors that indicate an invalid token when sending messages, and remove them from the database that way (see an example of that here). A combination of these two approaches is probably best.

Resources