I'm new to React Native and I have an issue with Cloud Functions.
getAuthor(uid){
var getUser = firebase.functions().httpsCallable('getUser');
console.log('success');
getUser({uid: uid}).then(function(result) {
console.log('getUser called')
var user = result.data.uid;
return(
result
)
})
.catch(function(error) {
var code = error.code;
var message = error.message;
var details = error.details;
});
}
When I run this code, 'success' is printed but 'getUser called' is never printed. I take this to mean getUser is never called. But I have followed the Firebase guide 'Call functions from your app' and it seems to be the same. Is it a problem with Cloud Functions never being initialised or something? In the Firebase guide it says to initialise an instance of Cloud Functions by adding
var functions = firebase.functions();
but when I added it to config.js I got an error so I skipped this step. Sorry if this seems obvious, I have never used React Native or Firebase before. Any help would be greatly appreciated!
Edit: the function has been deployed, as can be seen in this screenshot
This is the function, by the way:
exports.getUser = functions.https.onCall((data, context) => {
const uid = data.uid;
auth.getUser(uid)
.then(function(UserRecord) {
console.log('USER RECEIVED:' + UserRecord.email.toJSON());
return {email : UserRecord.email.toJSON()};
})
.catch(function(error){
console.log(error);
});
Turns out I can't access user information with their UID! The solution is to add it into Firebase Database instead.
Related
Hello!
EDIT~
I've eventually managed to do this and wanted to share it just in case anyone else needs it. Most tutorials I've found were outdated and none of them seemed to work for me. But I've finally got everything to work so Here it is!
Sign Up -
(I've created a sign up form with input fields for the username, extra info, password and email)
Make sure you import all firebase scripts you want to use and ABOVE all of them, the firebase app main script. In my case I only needed
Auth & Database - And BELOW all of this you put your Firebase App config and import either an
external .js file where you'll be using firebase functions or write it
all down there. This was a very silly mistake I did myself and I kept getting errors on the console. This is because I've been
trying to call my external .js file BEFORE importing the firebase main
scripts, which makes no sense right?
So here's my .js file for the
sign up function:
//On a different .js file where I make use of most of my functions I've added this part
//(just because I've defined more const for all my functions and I wanted to have them all
//in one place):
//getting all elements -- I've only put in this example the ones that I've used for Sign Up
const signupBtn = document.getElementById("btnsignUp");
const txtEmail = document.getElementById('txtEmail');
const txtPassword = document.getElementById('txtPassword');
const userId = document.getElementById('txtName');
const discord = document.getElementById('txtDiscord');
const bday = document.getElementById('txtBday');
const gender = document.getElementById('txtGender');
const imgURL = document.getElementById('txtimgURL');
//getting references to the apps
const auth = firebase.auth();
const database = firebase.database();
const rootRef = database.ref('users');
//------------------------------------------------//
//firebase SIGN UP.js
signupBtn.addEventListener("click", function(){
var email = txtEmail.value;
var pass = txtPassword.value;
//Signing up
auth.createUserWithEmailAndPassword(email, pass)
.then(() => {
//send verification email
sendVerificationEmail();
})
.catch(function(error) {
// Handle Errors here.
//var errorCode = error.code;
var errorMessage = error.message;
alert("Error :" + errorMessage);
});
});
//verification email function
var sendVerificationEmail = () => {
auth.currentUser.sendEmailVerification()
.then(() => {
alert("Verification Email Sent! Check your mailbox.")
})
.catch(error => {
alert("Error :" + errorMessage);
})
}
//DATABASE
//'set' adds new data to he db
signupBtn.addEventListener('click', (e) => {
e.preventDefault();
rootRef.child(userId.value).set({
Email: txtEmail.value,
Discord: discord.value,
Gender: gender.value,
Birthday: bday.value,
ImgURL: imgURL.value,
CC: 0,//Here I've added some more info that's be stored too along with
RS: 0,//the data that the user has provided
Rupreets: 0,
Bag: 1,//1: small, 2: medium, 3: big
})
});
//And that's all!
In my case, what I did with the database part is something like this:
-App name-
|
+--Users:
|
+--username1
|
+-info1
|
+-info2
|
+-info2
|
+--username2
|
+-info1
|
+-info2
|
+-info2
Well, I hope this will help somebody else too n.n
welcome to Stack Overflow!
A couple of things:
You never actually call writeUserData in your code snippet; you just define it. If you don't call it, nothing will be written.
userId is never defined, so even if you called writeUserData, your database path would be be undefined. You'd need to get the userId from firebase.auth().currentUser.uid. For more on that, see this Firebase doc: https://firebase.google.com/docs/auth/unity/manage-users#get_a_users_profile .
-- Edit --
Here's a code sample. I haven't put in absolutely everything, just the relevant omissions:
//Signing up
firebase.auth().createUserWithEmailAndPassword(email, pass)
.then((data) => {
// createUserWithEmailAndPassWord returns a promise, which, when resolved will contain various user-related properties, so
let id = data.User.uid;
function writeUserData(userId, name, email, imageURL) {
firebase.database().ref('Users/' + userId).set({
Username: name,
Email: email,
Profile_pic: imageURL,
});
}
// call your function, referencing the id above
writeUserData(id, name, email, imageURL)
If the idea of promises and calling functions isn't comfortable, you might look at a Javascript learning resource like javascript.info
Good luck!
I am just trying a simple get command with Firestore, using this code from Google it doesn't work because it's not waiting for the promise?
Earlier I had put only a snippet of code, this is the entirety of index.js -- I'm using Firestore with Dialogflow to build a Google Assistant app and trying to call a function from the welcome intent that gets a field from Firestore, then writes that field to a string (named question1), and then this string should be spoken by the assistant as part of the ssml response. I've been on this for at least 30 hours already, can't seem to comprehend promises in regards to intents, firestore, etc. I've tried about 10 different solutions, this one works, only it says "undefined" in other variations I have tried it would say undefined several times but after 2-3 passes the get command would be complete and then the variable would be read out. I'm just trying to figure out how to get the get command and variable set before moving onto the SSML response. Can anyone point me in the right direction?
'use strict';
const functions = require('firebase-functions'); //don't forget this one
// Import Admin SDK
var admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
var db = admin.firestore();
const collectionRef = db.collection('text');
const Firestore = require('#google-cloud/firestore');
var doc;
var question1;
const url = require('url');
const {
dialogflow,
Image,
Permission,
NewSurface,
} = require('actions-on-google');
const {ssml} = require('./util');
const config = functions.config();
const WELCOME_INTENT = 'Default Welcome Intent';
const app = dialogflow({debug: true});
async function dbaccess(rando) {
console.log("dbaseaccess started")
var currentquestion2 = 'question-' + rando.toString();
var cityRef
try { return cityRef = db.collection('text').doc(currentquestion2).get();
console.log("get command completed")
//do stuff
question1 = cityRef.data().n111
} catch(e) {
//error!
}
console.log("one line above return something");
return rando;
}
app.fallback((conv) => {
// intent contains the name of the intent
// you defined in the Intents area of Dialogflow
const intent = conv.intent;
switch (intent) {
case WELCOME_INTENT:
var rando = Math.floor(Math.random() * 3) + 1;
dbaccess(rando);
const ssml =
'<speak>' +
question1 +
'</speak>';
conv.ask(ssml);
break;
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
You have 2 options: you can use async/await or you can use Promise.then() depending on how you want the code to execute.
Async/await:
async function databasetest {
var cityRef;
try{
cityRef = await db.collection('cities').doc('SF');
// do stuff
} catch(e) {
// error!
}
Promise.then():
db.collection('cities').doc('SF').then((cityRef) => {
cityRef.get()
.then(doc => { /* do stuff */ })
.catch(err => { /* error! */ });
});
maybe a little of work around could help you, I'm not sure yet how you are trying to implement it.
function databasetest () {
var cityRef = db.collection('cities').doc('SF');
return cityRef.get()
}
// so you can implement it like
databasetest().then(doc => {
if (!doc.exists) {
console.log('No such document!');
} else {
console.log('Document data:', doc.data());
}
})
.catch(err => {
console.log('Error getting document', err);
});
More context would help to understand your use case better :)
So I am trying to send a notification via Functions on Firebase.
I am doing the notification programming on JavaScript via Node.js.
Upon clicking Send Friend Request from one account, the other person is suppose to get a notification as specified on the payload of the JavaScript file I have attached below.
I keep getting the following error on my Firebase Functions
ReferenceError: event is not defined.
Here is an image of the exact error.
Here is my JavaScript file:
/*
* Functions SDK : is required to work with firebase functions.
* Admin SDK : is required to send Notification using functions.
*/
//This runs JavaScript in Strict Mode, which prevents the use of things such as undefined variables.
'use strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
/*
* 'OnWrite' works as 'addValueEventListener' for android. It will fire the function
* everytime there is some item added, removed or changed from the provided 'database.ref'
* 'sendNotification' is the name of the function, which can be changed according to
* your requirement
*/
exports.sendNotification = functions.database.ref('/Notifications/{retrieveUserId}/{notificationId}').onWrite((data, context) => {
/*
* You can store values as variables from the 'database.ref'
* Just like here, I've done for 'user_id' and 'notification'
*/
const retrieveUserId = context.params.retrieveUserId;
const notificationId = context.params.notificationId;
console.log('User id is : ', retrieveUserId);
//Prevents notification being sent if there are no logs of notifications in the database.
if (!event.data.val()) {
return console.log('A notification has been deleted from the database : ', notificationId);
}
const deviceToken = admin.database().ref(`/Users/${retrieveUserId}/device_token`).once('value');
return deviceToken.then(result => {
const tokenId = result.val();
const payload = {
notification: {
title: "Friend Request",
body: "You have received a friend request from Slim Shady",
icon: "default"
}
};
return admin.messaging().sendToDevice(tokenId, payload).then(response => {
return console.log('Notification was sent to the user');
});
});
});
This is a picture of parents and children of my Firebase database referred to in the JavaScript file.
As the error states an event not being defined, I'm trying to figure out which event I have not defined.
What is the issue here?
You have not defined event in this code block:
if (!event.data.val()) {
I have used pouchDB in one application and now I want to introduce couchDB to sync the document to remote server. Hence i followed this link http://pouchdb.com/getting-started.html i used the below code to replicate the data to couchDB
var db2 = new PouchDB('todos');
var remoteCouch = 'http://localhost:5984/_utils/database.html?couchdb_sample';
db2.changes({
since: 'now',
live: true
}).on('change', showTodos);
sync();
function sync() {
//alert("sync");
//syncDom.setAttribute('data-sync-state', 'syncing');
//var opts = {live: true};
db2.replicate.to(remoteCouch).on('complete', function () {
console.log("done");
}).on('error', function (err) {
console.log(err);
});
function addTodo(text) {
var todo = {
_id: $("#eid").val()+$("#version").val(),
title: text,
name: $("#nameid").val(),
version: $("#version").val(),
completed: false
};
db2.put(todo, function callback(err, result) {
if (!err) {
console.log('Successfully posted a todo!');
}
else{
console.log(err);
}
});}
here the title has an xml string as value. But i am facing below error
SyntaxError: Unexpected token <
at Object.parse (native)
for this line db2.replicate.to(remoteCouch). I manually created a new document in couchDb database and entered the same data it gave no error but when i try replicating it shows syntax error. Can anyone please hint me where I have gone wrong
http://localhost:5984/_utils/database.html?couchdb_sample
Points to a HTML site (copied over from the browsers address bar, right?). Remove the middle part:
http://localhost:5984/couchdb_sample
It look like you have not defined the remote database in the way PouchDb is expecting. You should use the "new PouchDb" call. The second line of your code is:
var remoteCouch = 'http://localhost:5984/_utils/database.html?couchdb_sample';
but I think it should be like this:
var remoteCouch = new PouchDB('http://localhost:5984/couchdb_sample');
I am not clear from your code what the name of the remote database is, but it would not normally end in ".html" as Ingo Radatz pointed out, so I have assumed it is couchdb_sample above. There is more information about replication on the PouchDb site.
I have the following code in server/statusboard.js;
var require = __meteor_bootstrap__.require,
request = require("request")
function getServices(services) {
services = [];
request('http://some-server/vshell/index.php?type=services&mode=json', function (error, response, body) {
var resJSON = JSON.parse(body);
_.each(resJSON, function(data) {
var host = data["host_name"];
var service = data["service_description"];
var hardState = data["last_hard_state"];
var currState = data["current_state"];
services+={host: host, service: service, hardState: hardState, currState: currState};
Services.insert({host: host, service: service, hardState: hardState, currState: currState});
});
});
}
Meteor.startup(function () {
var services = [];
getServices(services);
console.log(services);
});
Basically, it's pulling some data from a JSON feed and trying to push it into a collection.
When I start up Meteor I get the following exception;
app/packages/livedata/livedata_server.js:781
throw exception;
^
Error: Meteor code must always run within a Fiber
at [object Object].withValue (app/packages/meteor/dynamics_nodejs.js:22:15)
at [object Object].apply (app/packages/livedata/livedata_server.js:767:45)
at [object Object].insert (app/packages/mongo-livedata/collection.js:199:21)
at app/server/statusboard.js:15:16
at Array.forEach (native)
at Function.<anonymous> (app/packages/underscore/underscore.js:76:11)
at Request._callback (app/server/statusboard.js:9:7)
at Request.callback (/usr/local/meteor/lib/node_modules/request/main.js:108:22)
at Request.<anonymous> (/usr/local/meteor/lib/node_modules/request/main.js:468:18)
at Request.emit (events.js:67:17)
Exited with code: 1
I'm not too sure what that error means. Does anyone have any ideas, or can suggest a different approach?
Just wrapping your function in a Fiber might not be enough and can lead to unexpected behavior.
The reason is, along with Fiber, Meteor requires a set of variables attached to a fiber. Meteor uses data attached to a fiber as a dynamic scope and the easiest way to use it with 3rd party api is to use Meteor.bindEnvironment.
T.post('someurl', Meteor.bindEnvironment(function (err, res) {
// do stuff
// can access Meteor.userId
// still have MongoDB write fence
}, function () { console.log('Failed to bind environment'); }));
Watch these videos on evented mind if you want to know more:
https://www.eventedmind.com/posts/meteor-dynamic-scoping-with-environment-variables
https://www.eventedmind.com/posts/meteor-what-is-meteor-bindenvironment
As mentioned above it is because your executing code within a callback.
Any code you're running on the server-side needs to be contained within a Fiber.
Try changing your getServices function to look like this:
function getServices(services) {
Fiber(function() {
services = [];
request('http://some-server/vshell/index.php?type=services&mode=json', function (error, response, body) {
var resJSON = JSON.parse(body);
_.each(resJSON, function(data) {
var host = data["host_name"];
var service = data["service_description"];
var hardState = data["last_hard_state"];
var currState = data["current_state"];
services+={host: host, service: service, hardState: hardState, currState: currState};
Services.insert({host: host, service: service, hardState: hardState, currState: currState});
});
});
}).run();
}
I just ran into a similar problem and this worked for me. What I have to say though is that I am very new to this and I do not know if this is how this should be done.
You probably could get away with only wrapping your insert statement in the Fiber, but I am not positive.
Based on my tests you have to wrap the insert in code I tested that is similar to the above example.
For example, I did this and it still failed with Fibers error.
function insertPost(args) {
if(args) {
Fiber(function() {
post_text = args.text.slice(0,140);
T.post('statuses/update', { status: post_text },
function(err, reply) {
if(reply){
// TODO remove console output
console.log('reply: ' + JSON.stringify(reply,0,4));
console.log('incoming twitter string: ' + reply.id_str);
// TODO insert record
var ts = Date.now();
id = Posts.insert({
post: post_text,
twitter_id_str: reply.id_str,
created: ts
});
}else {
console.log('error: ' + JSON.stringify(err,0,4));
// TODO maybe store locally even though it failed on twitter
// and run service in background to push them later?
}
}
);
}).run();
}
}
I did this and it ran fine with no errors.
function insertPost(args) {
if(args) {
post_text = args.text.slice(0,140);
T.post('statuses/update', { status: post_text },
function(err, reply) {
if(reply){
// TODO remove console output
console.log('reply: ' + JSON.stringify(reply,0,4));
console.log('incoming twitter string: ' + reply.id_str);
// TODO insert record
var ts = Date.now();
Fiber(function() {
id = Posts.insert({
post: post_text,
twitter_id_str: reply.id_str,
created: ts
});
}).run();
}else {
console.log('error: ' + JSON.stringify(err,0,4));
// TODO maybe store locally even though it failed on twitter
// and run service in background to push them later?
}
}
);
}
}
I thought this might help others encountering this issue. I have not yet tested calling the asynchy type of external service after internal code and wrapping that in a Fiber. That might be worth testing as well. In my case I needed to know the remote action happened before I do my local action.
Hope this contributes to this question thread.