Firebase Database Update Every 1 hour Using AWS lambda function - android

In my scenario i need to update firebase database every 1 hour.so i decided to run this in AWS lamda function because of no schedule trigger in cloud function.
Below is my code unable to add firebase library to AWS Lamda function .
'use strict';
import * as admin from 'firebase-admin';
var Firebase = require('firebase');
exports.handler = (event, context, callback) => {
// TODO implement
context.callbackWaitsForEmptyEventLoop = false; //<---Important
var config = {
apiKey: "AIzaSy########################",
authDomain: "########.firebaseapp.com",
databaseURL: "https://a########.firebaseio.com",
projectId: "aws#####",
storageBucket: "",
messagingSenderId: "83526964121"
};
getting below error:
Cannot find module 'firebase'"
"errorMessage": "Unexpected token import",
"errorType": "SyntaxError",
"stackTrace": [
" ^^^^^^",
"SyntaxError: Unexpected token import",
"createScript (vm.js:56:10)",
Cannot find module 'firebase'"
How to add Firebase module to Aws Lamda function.Please give me a hint..
Thanks in advance

if your admin is imported in your lamda function successfully just initialize it with credentials (json file or required fields). See: https://firebase.google.com/docs/admin/setup .
You don't need firebase dependency to do it since lamda function is not visible to users it can use admin access to your database.
Now when your admin sdk is initialize you just need to get the database reference like this (javascript style) :
let db= admin.database();
Now you have reference to the database and you can easily write to the any location since admin has full access to your database.
db.ref().child('/someNode').set({"key":"value"});

Related

How to perform Firebase scheduled function only if value from realtime database is equal X?

I'm starting my adventure with Firebase cloud functions in my adnroid app in Android Studio and I have no experience with it. What is more I have never used javascript before so everything seems to be new for me. I would like to know if I can make a scheduled function that works like this :
At first function checks if value from realtime databse isn't zero.
If not, function checks if another value from realtime database is not bigger than 7.
If not, the value in database is increased by 1.
And then the notification is send.
I made test function to check if data from database are taken corectly but it execute with error "Firebase is not defined".
exports.scheduledFunction = functions.pubsub.schedule('every 5 minutes').onRun((context) => {
var user = user.uid;
var myRef = firebase.database().ref(user + "/CurrentChallenge/numOfActiveChallenge");
myRef.on('value', (snapshot) => {
const data = snapshot.val();
console.log(data);
});
In a Cloud Function, if you want to interact with the Firebase services, you need to use the Admin SDK.
Also, if you want to read a database node in a Cloud Function, it is more appropriate to read once the node (with get() or once()) instead of setting a listener with on(). As a matter of fact the CF has a short life time and setting a listener is therefore not the correct approach.
It is nor clear how you get the value of the user variable. There is no user in a Scheduled Cloud Function. You need to adapt this line, because, as such it will not work.
Finally, it is important to note that you need to terminate a Cloud Function when all the asynchronous work is completed, see the doc. In the case of a background triggered Cloud Function (e.g. a Pub/Sub schedules Cloud Function) you must return the entire chain of promises returned by the asynchronous method calls. Another possibility is to use async/await, as shown below, and return a value (e.g. null) when all the asynchronous work is completed.
So, the following code skeleton should do the trick:
// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');
// The Firebase Admin SDK to access Firestore.
const admin = require('firebase-admin');
admin.initializeApp();
exports.scheduledFunction = functions.pubsub.schedule('every 5 minutes').onRun(async (context) => {
var user = ... // Set the value of user
const db = admin.database(); // Admin SDK
const snapshot1 = await db.database().ref("...").get();
if (snapshot1.val() !== 0) {
const snapshot2 = await db.database().ref("...").get();
if (snapshot2.val() <= 7) {
await db.ref("...").update({
fieldName: firebase.database.ServerValue.increment(1)
});
//send the notification
// See https://github.com/firebase/functions-samples/blob/main/fcm-notifications/functions/index.js
} else {
return null;
}
} else {
return null;
}
});
Cloud functions are secure environment just like any server. Generally you use the Firebase Admin SDK when using Firebase in Cloud functions or your own servers. To add firebase admin, open terminal and go to the function directory and run the following command:
npm install firebase-admin
The important thing to note is admin sdk doesn't obey any database security rules as the name says. It has privileged access.
You can try the following code.
const admin = require("firebase-admin")
admin.initializeApp()
exports.scheduledFunction = functions.pubsub.schedule('every 5 minutes').onRun(async (context) => {
const myRef1Value = (await admin.database().ref("path/to/resoures").once("value")).val()
if (myRef1Value > 0) {
//make another request
}
}
Similarly make multiple requests as needed (sorry for throwing bunch of JS concepts but feel free to ask any queries)
Another thing I noticed is you are trying to get user ID in it. Scheduled Cloud Functions are not invoked by any user so you can't get any UID in that Cloud function. Can you clarify what is your use case so we can figure out a work around for this?
But what you want to achieve is simple chain if else statements and doing stuff.
You'll need to import and initialize the Firebase Admin SDK as shown here:
// The Firebase Admin SDK to access the database
const admin = require('firebase-admin');
admin.initializeApp();
With that, you can then use it with:
var myRef = admin.database().ref(user + "/CurrentChallenge/numOfActiveChallenge");
myRef.once('value', (snapshot) => {
...

Firebase Cloud Function undefined request query parameters from Android App

I have this Firebase Cloud Function:
exports.verifyToken = functions.https.onRequest(async (req, res) => {
const token = req.query.token;
console.log("token: " + token);
return firebaseAdmin
.auth()
.createCustomToken(token, {provider: 'TEST'})
.then((firebaseToken) => {
console.log("Returning firebase token to user: " + firebaseToken);
return res.json({firebase_token: firebaseToken});
});
});
And this is my android code:
return Single.create<String> { emitter ->
val token = authToken.accessToken
val data = HashMap<String, String>()
data.put("token", token)
FirebaseFunctions.getInstance()
.getHttpsCallable("verifyToken")
.call(data)
.continueWith { task ->
return#continueWith task.result?.data as String
}
.addOnSuccessListener { firebaseToken ->
emitter.onSuccess(firebaseToken)
}
.addOnFailureListener {
emitter.onError(it)
}
}
When I try to run the cloud function via firebase emulator and Postman, it works fine. The function was able to get the value of token. But whenever I do it via Android, I get this from the Firebase Functions Logs:
4:29:40.837 AM
verifyToken
Function execution started
4:29:41.411 AM
verifyToken
token: undefined //<--- this here says that the token is undefined.
4:29:41.554 AM
verifyToken
Unhandled rejection
4:29:41.560 AM
verifyToken
Error: `uid` argument must be a non-empty string uid. at FirebaseAuthError.FirebaseError [as constructor] (/workspace/node_modules/firebase-admin/lib/utils/error.js:43:28) at FirebaseAuthError.PrefixedFirebaseError [as constructor] (/workspace/node_modules/firebase-admin/lib/utils/error.js:89:28) at new FirebaseAuthError (/workspace/node_modules/firebase-admin/lib/utils/error.js:148:16) at FirebaseTokenGenerator.createCustomToken (/workspace/node_modules/firebase-admin/lib/auth/token-generator.js:233:19) at Auth.BaseAuth.createCustomToken (/workspace/node_modules/firebase-admin/lib/auth/auth.js:96:36) at /workspace/index.js:25:6 at cloudFunction (/workspace/node_modules/firebase-functions/lib/providers/https.js:51:16) at /layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/invoker.js:100:17 at processTicksAndRejections (internal/process/task_queues.js:79:11)
4:29:41.562 AM
verifyToken
Function execution took 725 ms, finished with status: 'crash'
If you have noticed, the code is almost similar to what Firebase has in their getting started pages. But then it doesn't fully work on my end.
I have already checked with my google-services.json and it's already updated.
I am currently set as the owner of the project, so no issues with firebase deploy
I also have the service-account.json updated and included with the firebase functions.
I might have missed something in my code or configuration. Any inputs are greatly appreciated!
It's not possible to use the Firebase Functions SDK to invoke onRequest type functions. The Firebase SDK implements the client side of a callable function that you declare with onCall. You're using onRequest here, which means you're writing a standard HTTP type function. For that type of function, you should use a standard HTTP client (not the Firebase SDK). If you actually did want to use the Firebase SDK to invoke your function, you will have to write a callable function instead. Note that callable functions have their own spec, and you won't be able to easily invoke them from postman.

How to use Firestore Database and Datastore in same Android App

I want to use a Firestore database and Datastore in the same Android app. I know that it's not possible to use both in the same GCP project(explained here: Firestore and Datastore in the same GAE project) so I created two different projects, one for the Firestore and one for the Datastore. So now the problem is that I can't create a client Id for my Android app in both projects because of "duplicated fingerprints".
If I had just one project I normally would just login via Firebase AuthUi and then use the token from the FirebaseUser to build my service handler.
//login via FirebaseUI
FirebaseAuth auth = FirebaseAuth.getInstance();
AuthUI.getInstance().createSignInIntentBuilder()
.setTheme(getSelectedTheme())
.setLogo(getSelectedLogo())
.setAvailableProviders(getSelectedProviders())
.setTosAndPrivacyPolicyUrls(getSelectedTosUrl(),getSelectedPrivacyPolicyUrl())
.setIsSmartLockEnabled(true,true)
.build(),
FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
Task<GetTokenResult> tokenResultTask = firebaseUser.getIdToken(false);
tokenResultTask.addOnCompleteListener(task -> {
String result = task.getResult().getToken();
//Creating the service object
GoogleCredential credential = new GoogleCredential();
credential.setAccessToken(result);
EndpointsApi.Builder builder = new EndpointsApi.Builder(
AppConstants.HTTP_TRANSPORT,
AppConstants.JSON_FACTORY, credential);
builder.setApplicationName("endpointsapi-server");
return builder.build();
});
This works very well if I only have one project. But what to do if there are mutliple? The google-services.json is associated with the one project that also has the android client id, but the second project can't create an android client id using the same sha1 and package name(duplicated fingerprints).
If I just use the access token from the first project to build the service object(which belongs to the second project) I just get an error:
401 Unauthorized
{
"code": 401,
"errors": [
{
"domain": "global",
"message": "Authorization required",
"reason": "required"
}
],
"message": "Authorization required"
}
which makes sense, because the second project doesn't know about the first one. Im lost on what to do to somehow use both at the same time.
In my web app I just whitelist the web client of the first project in the second one and then use the credentials of the first, obtained using firebase.AuthUi, to also login the second one. Which works.
this.uiConfig = {
callbacks: {
signInSuccess: (currentUser, credential, redirectUrl) => {
const googleAuthcredential =
firebase.auth.GoogleAuthProvider.credential(credential['idToken']);
firebase.apps[1].auth().signInAndRetrieveDataWithCredential(googleAuthcredential):
}
}
};
this.ui = new firebaseui.auth.AuthUI(firebase.auth());
this.ui.start('#firebaseui-auth-container', this.uiConfig);
How to achieve the same thing in Android?
Thank you very much in advance.

Parse open source server cloud code not working the same as old

I went from using the old parse cloud code to open source parse server on AWS and this part of the main.js does not work.
var Stripe = require('stripe');
Stripe.initialize('sk_live_mylivekey');
var Mailgun = require('mailgun');
Mailgun.initialize("mydomain.mailgun.org");
Native Cloud code modules like Stripe, Mailgun, Sendgrid, Twilio etc. are not available in the open sourced Parse server.
Use official npm modules for the same:
Stripe npm module
Mailgun npm module
Reference: Migrate an existing Parse app - Github
Note:
Because the Parse hosted Cloud Code isn’t running a full node environment, there may be subtle differences in how your Cloud Code runs in Parse Server. We recommend exercising all your critical code paths to ensure full functionality.
I switched from using cloud code for making charges to creating a route in my index.js file for making charges. In index.js create a route as such
var stripe = require('stripe')('sk_test_****');
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended: false
}));
app.post('/charge', function(req, res){
var token = req.body.token;
var amount = req.body.amount;
stripe.charges.create({
amount: amount,
currency: 'usd',
source: token,
}, function(err, charge){
if(err)
// Error check
else
res.send('Payment successful!');
}
});
I call this route using jQuery post however, you could also call it in a form
var handler = StripeCheckout.configure({
key: 'pk_test_****',
locale: 'auto',
token: function(token){
$.post('/charge', {
token: token.id,
amount: total,
}, function(data, status){
alert(data);
});
}
});

Cordova/Phonegap facebook plugin An active access token must be used to query information

I am using https://github.com/Wizcorp/phonegap-facebook-plugin to connect my cordova Android app to Facebook.
I can login with:
facebookConnectPlugin.login(["email"],
fbLoginSuccess,
function (error) { alert("ERROR:" + JSON.stringify(error)); }
);
, logout even call facebookConnectPlugin.getLoginStatus and get:
userID
accessToken
expiresIn
sig
status
but when FB.api('/me', function(response){...}) is called, I receive
{error:
{
message: An active access token must be used to query information about the current user,
type: OAuthException,
code: 2500
}
}
Also this only happens when the app is built, not tested in browser.
Solved issue by manually giving FB.apicall a token with:
FB.api('/me?access_token='+userdata.authResponse.accessToken, function(response) {...
where userdata is the response of facebookConnectPlugin.getLoginStatus
I just don't understand why doesn't it provide token automatically in android app like it does in browser.
Send the access token and the data retrieving fields with the apiString
const fields = ['email', 'first_name', 'last_name', 'gender', 'birthday', 'picture.type(large)'];
const apiString = `me?access_token=${accessToken}&fields=${fields.join(',')}`;

Categories

Resources