I'm trying to include a list of users (more than 50) through a specific function in Firebase. Here's my code:
Object.keys(newUsers).forEach((key) => {
console.log(newUsers[key]['name']);
admin.auth().createUser({
uid: key,
email: newUsers[key]['email']
password: newUsers[key]['InitialPwd'],
disabled: false,
emailVerified: false,
displayName: newUsers[key]['name'],
}).then((userRecord) => {
return console.log('Success');
}).catch(function(error) {
console.log("Error:", error);
});
});
And the error is (for each record):
{ Error: Error while making request: timeout of 10000ms exceeded.
at FirebaseAppError.FirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:39:28)
at FirebaseAppError.PrefixedFirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:85:28)
at new FirebaseAppError (/srv/node_modules/firebase-admin/lib/utils/error.js:119:28)
at /srv/node_modules/firebase-admin/lib/utils/api-request.js:117:23
at
at process._tickDomainCallback (internal/process/next_tick.js:228:7) errorInfo: { code:
'app/network-timeout',
message: 'Error while making request: timeout of 10000ms exceeded.' }, codePrefix: 'app' }
How can I solve this?
Cloud Functions are set to run for a short period of time. If you are doing lots of work in a Cloud Function, it may time out before it is complete. There are a few solutions to this that I would suggest:
1.Change your Cloud Functions timeout. In the Cloud console, check at the top to make sure your current project is selected, and then in the middle you'll find your list of functions. Click on your function. You should be in function details now. Click "Edit". Right above the "save" button is "more". Select "more" and you'll see an option for upping the timeout. This can modify how long the function stays alive.
2.Change the batch size so you're creating fewer users at a time.
3.Make sure your promises are working as expected. If you don't return the call to createUser, the resulting UserRecord won't be accessible.
Object.keys(newUsers).forEach((key) => {
console.log(newUsers[key]['name']);
return admin.auth().createUser({
uid: key,
email: newUsers[key]['email']
password: newUsers[key]['InitialPwd'],
disabled: false,
emailVerified: false,
displayName: newUsers[key]['name'],
}).then((userRecord) => {
return console.log('Success');
}).catch(function(error) {
console.log("Error:", error);
});
});
4.I may be incorrect about this point, but it appears that the users are created one after another rather than concurrently. This could be a good case to look into using Promise.all so that all of the users can be created simultaneously, rather than waiting for one to complete before starting the next.
Related
Error: "Cloud Fire Error: functions predeploy error: Command terminated with non-zero exit code 1"
I have a view all users screen in my application. On this screen, I have access to both email and uID. I need to build functionality that I can click a delete user button on the users tile. This should then delete the user from firebase authentication and the users collection in firebase. I seen from other posts that the best way for this would be to create a cloud function which I have tried from firestore documentation. I am getting the below error. The code I am trying is from firestore documentation and is as follows:
getAuth()
.deleteUser(uid)
.then(() => {
console.log('Successfully deleted user');
})
.catch((error) => {
console.log('Error deleting user:', error);
});
Attaching documentation link - https://firebase.google.com/docs/auth/admin/manage-users#node.js_7
Any advice is much appreciated.
This may happen because:
You don't have eslint installed. This could happen if at the time you ran firebase init functions you answered no when prompted Do you want to use ESLint to catch probable bugs and enforce style? and/or you answered no when prompted to install dependencies. If that's the case reinitialize the environment to get it installed.
You're missing the eslint package in your package.js file. To check/fix this open it up and look if you have something in the lines of:
"devDependencies": {
"eslint": "^4.12.0",
"eslint-plugin-promise": "^3.6.0"
},
As stated by #Werner7, that is also a possible solution.
Edit upon reading your question again:
This isn't a direct answer to your question but just a few things to note...
You essentially have 2 options here - deleting the user form the front end or firebase functions - each is slightly different.
Front end - You need to pass the user object into deleteUser() not the user's uid, and vice versa passing in the uid.
Firebase function example:
return admin.auth().getUserByEmail(data.email).then(user => {
return admin.auth().deleteUser(user.uid);
}).then(() => {
return {
massage: `Success, ${data.email} has been deleted.`
}
}).catch(err => {
return err;
});
Front end example:
import { getAuth, deleteUser } from "firebase/auth";
const auth = getAuth();
const user = auth.getUser(uid)
deleteUser(user).then(() => {
// User deleted.
}).catch((error) => {
// An error ocurred
// ...
});
https://firebase.google.com/docs/auth/web/manage-users#delete_a_user
I've made firebase cloud function which adds the claim to a user that he or she has paid (set paid to true for user):
const admin = require("firebase-admin");
exports.addPaidClaim = functions.https.onCall(async (data, context) => {
// add custom claim (paid)
return admin.auth().setCustomUserClaims(data.uid, {
paid: true,
}).then(() => {
return {
message: `Succes! ${data.email} has paid for the course`,
};
}).catch((err) => {
return err;
});
});
However, when I'm running this function: I'm receiving the following error: "Unhandled Rejection (RangeError): Maximum call stack size exceeded". I really don't understand why this is happening. Does somebody see what could cause what's getting recalled which in turn causes the function to never end?
Asynchronous operations need to return a promise as stated in the documentation. Therefore, Cloud Functions is trying to serialize the data contained by promise returned by transaction, then send it in JSON format to the client. I believe your setCustomClaims does not send any object to consider it as an answer to the promise to finish the process so it keeps in a waiting loop that throws the Range Error.
To avoid this error I can think of two different options:
Add a paid parameter to be able to send a JSON response (and remove the setCustomUserClaim if it there isn’t any need to change the user access control because they are not designed to store additional data) .
Insert a promise that resolves and sends any needed information to the client. Something like:
return new Promise(function(resolve, reject) {
request({
url: URL,
method: "POST",
json: true,
body: queryJSON //A json variable I've built previously
}, function (error, response, body) {
if (error) {
reject(error);
}
else {
resolve(body)
}
});
});
I'm trying to send push notifications via a Firebase Cloud Function, but getting an internal error.
Error: Internal error encountered.
at FirebaseMessagingError.FirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:42:28)
at FirebaseMessagingError.PrefixedFirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:88:28)
at new FirebaseMessagingError (/srv/node_modules/firebase-admin/lib/utils/error.js:253:16)
at Function.FirebaseMessagingError.fromServerError (/srv/node_modules/firebase-admin/lib/utils/error.js:283:16)
at Object.createFirebaseError (/srv/node_modules/firebase-admin/lib/messaging/messaging-errors.js:34:47)
at FirebaseMessagingRequestHandler.buildSendResponse (/srv/node_modules/firebase-admin/lib/messaging/messaging-api-request.js:119:47)
at /srv/node_modules/firebase-admin/lib/messaging/messaging-api-request.js:94:30
at Array.map (<anonymous>)
at /srv/node_modules/firebase-admin/lib/messaging/messaging-api-request.js:93:30
at <anonymous> errorInfo: [Object], codePrefix: 'messaging'
My function is simple enough:
sendPushNotification.js
const admin = require('firebase-admin');
const messaging = admin.messaging();
module.exports = function(title, deepLink, deviceTokens) {
var message = {
notification: {
title: title
},
data: {
deepLink: deepLink,
},
tokens: deviceTokens
};
console.log(`Sending notification ${title} with Deep Link ${deepLink} to ${deviceTokens.length} devices`);
console.log(deviceTokens);
return messaging.sendMulticast(message).then(response => {
console.log(`Success: ${response.successCount}, failure: ${response.failureCount}`);
if (response.failureCount > 0) {
console.log(response.responses)
}
});
}
The weird thing is that sometimes it does work, but maybe one in 10? The other times I get this less-than-helpful error. The APNs Authentication Key is uploaded in the Firebase Console in the project settings. The App Bundle ID is correct. I'm at a loss for what else could be going on.
(Yes, I am giving the function an array of valid deviceTokens.)
None of the other questions on StackOverflow seem to be related to this internal error, the answers on those questions don't apply here.
Router.route('/settings', {
name: 'settings',
data: function() {
return Settings.findOne({userId: Meteor.user()._id});
}
});
It's showing an error in the browser:
Uncaught TypeError: Cannot read property '_id' of undefined
Any suggestions on how to grab the settings record for a logged in user?
Meteor logging in process usually takes a few ms to get ready, meanwhile Meteor.user() will return undefined and the first execution of your route data method will fail.
You can use Meteor.userId() to avoid this from happening until the user is connected for real.
Router.route('/settings', {
name: 'settings',
data: function() {
return Settings.findOne({
userId: Meteor.userId()
});
}
});
I have the following:
Template.joinTemplate.events({
"submit #Signup-Form": function(event, template) {
event.preventDefault();
var email = template.find('#Email').value;
Accounts.createUser({
username: template.find('#Email').value,
emails: {
address: template.find('#Email').value
},
password: template.find('#Password').value,
profile: {
firstname: template.find("#Firstname").value,
lastname: template.find("#Lastname").value
}
}, function(error) {
if (error) {
// Deal with errors
} else {
Accounts.sendVerificationEmail(this.userId, email);
Router.go('/');
}
});
}
});
But get the following error:
Error logging in with token: Error: You've been logged out by the server. Please login again. [403] debug.js:41
Exception in delivering result of invoking 'createUser': TypeError: Object #<Object> has no method 'sendVerificationEmail'
at http://localhost:3000/client/views/application/authentication/join_template.js?0ca175e5dc0f3b4596ed33e260d5636f8f9cc69b:28:26
at http://localhost:3000/packages/underscore.js?0a80a8623e1b40b5df5a05582f288ddd586eaa18:801:19
at loggedInAndDataReadyCallback (http://localhost:3000/packages/accounts-base.js?efdcc57c69f7e2ccbb61f1e963da216b1729ac72:455:5)
at null._callback (http://localhost:3000/packages/meteor.js?2b578107b8239ff9bc64200e6af2a24001461b30:801:22)
at _.extend._maybeInvokeCallback (http://localhost:3000/packages/livedata.js?418d88f2513ae6bf0ff1447759a5c590923456bd:3502:12)
at _.extend.receiveResult (http://localhost:3000/packages/livedata.js?418d88f2513ae6bf0ff1447759a5c590923456bd:3522:10)
at _.extend._livedata_result (http://localhost:3000/packages/livedata.js?418d88f2513ae6bf0ff1447759a5c590923456bd:4452:9)
at onMessage (http://localhost:3000/packages/livedata.js?418d88f2513ae6bf0ff1447759a5c590923456bd:3376:12)
at http://localhost:3000/packages/livedata.js?418d88f2513ae6bf0ff1447759a5c590923456bd:2705:11
at Array.forEach (native)
I have all accounts-base, accounts-ui, accounts-password installed.
Not sure what I'm doing wrong :(
As you can read in the documentation, Accounts.sendVerificationEmail is only available on the server, and you're trying to use it on the client.
I'm not sure that you can use the Accounts.onCreateUser function to send verification emails: in this function, the user has not been added to the Meteor.users collection yet, and I guess Accounts.sendVerificationEmail requires the user to be in that collection. I don't know the best way to solve this, but you can always use a cursor selecting all users, and then observe users added to the collection (although, this is not a good solution).
It's not enough to use the sendVerificationEmail field in the Accounts.config function?