Accounts.createUser on server does not return response to client - meteor

I'm attempting to use Meteorjs Accounts on the server to create a new user and then send them an email to set their initial password. The idea is that an admin user can add new users.
I can successfully add the new user (I can see the new user ID in the server console if I log it), but that ID is never returned to the client. This is my server-side
Meteor.methods({
createNewUser: function(email){
return Accounts.createUser({email: email});
}
});
And the relevant client-side JS:
if (isNotEmpty(email) && isEmail(email)) {
Meteor.call("createNewUser", email, function(ret){
if (typeof ret.message !== 'undefined') {
if (ret.message === 'Email already exists. [403]') {
alert("exists");
} else {
alert("not created");
}
} else {
Accounts.sendEnrollmentEmail(ret, function(err){
if (err){
alert("email didn't get sent");
} else {
alert('success');
}
});
}
});
}
I get this in my browser console:
Exception in delivering result of invoking 'createNewUser': TypeError: Cannot read property 'message' of undefined
It's probably worth noting that I also get the "exists" alert if I try to submit the same email address twice in a row, so the error is getting returned to the client just fine.

The first argument in callback is always error object.
error equals null if everything is fine.
Meteor.call('createNewUser', email, function( error, result ){
if( error ){
console.error("ERROR -> ", error )
}else{
console.log("User was created!")
}
})

but that ID is never returned to the client.
Thats because you don't have any console.log on the client. also the meteor call look incorrect.
if (isNotEmpty(email) && isEmail(email)) {
Meteor.call("createNewUser", email, function(err,result){
if (typeof ret.message !== 'undefined') {
if (ret.message === 'Email already exists. [403]') {
alert("exists");
} else {
console.log(result) //here for example you should get the id
}
} else {
Accounts.sendEnrollmentEmail(ret, function(err){
if (err){
alert("email didn't get sent");
} else {
alert('success');
}
});
}
});
}

Related

how to work with callback when calling Meteor methods?

I have noticed the callback functions never get executed all though the server method runs fine. Also from the Meteor documentation, i understand that when Meteor.Error is thrown it will notify the client but i don't see that working as well. Am i doing something fundamentally wrong?
Client
if (Meteor.isCordova) {
getContacts(function (contacts) {
$meteor.call('createContacts', contacts, function(err){
alert("in create contacts callback");
if(err && err.error === "not-logged-in"){
alert("error due to not-logged-in");
$ionicPopup.alert({
title: err.reason || "User not logged in",
template: 'Please try again after logged in',
okType: 'button-positive button-clear'
});
}
else if(err && err.error === "contacts-exists"){
$ionicPopup.alert({
title: err.reason || "Connections already exists",
template: 'Please try again after logged in',
okType: 'button-positive button-clear'
});
}
$meteor.call('createConnections');
});
});
}
function getContacts(success, error) {
function onSuccess(contacts) {
success && success(contacts);
};
var options = {};
options.multiple = true;
var fields = ["displayName", "name"];
navigator.contacts.find(fields, onSuccess, error, options);
}
Server
createContacts: function (contacts, callback) {
if (!this.userId) {
throw new Meteor.Error('not-logged-in',
'Must be logged in to update contacts')
}
var userId = this.userId, exist = Contacts.findOne({userId: userId});
log.debug("Is contacts for userId %s exist in database ? %s", userId, !! exist);
if (!exist) {
Contacts.insert({'userId': userId, 'contacts': contacts}, function () {
callback && callback();
});
} else {
log.debug("Contacts for user exists so throwing exception as contacts-exists");
var meteorErr = new Meteor.Error('contacts-exists', "Contacts are already exist");
callback && callback(meteorErr);
}
},
These callbacks are asynchronous. Your server-side method shouldn't invoke the callback function, nor even expect one as an argument.
You are right to pass the callback as the last argument to Meteor.call('createContacts'), but it is not up to the receiver of createContacts to determine when that callback should be invoked. In simple terms, from the client's point of view, the server's job is simply to return an 'OK' or an 'error' signal.
Remove any reference to the callback in the method definition (on the server), and expect the client to execute that callback when the server responds.
Try this:
Server
createContacts: function (contacts) {
if (!this.userId) {
throw new Meteor.Error('not-logged-in',
'Must be logged in to update contacts');
}
var userId = this.userId;
var exist = Contacts.findOne({userId: userId});
log.debug("Is contacts for userId %s exist in database ? %s", userId, !! exist);
if (!exist) {
Contacts.insert({'userId': userId, 'contacts': contacts});
} else {
log.debug("Contacts for user exists so throwing exception as contacts-exists");
throw new Meteor.Error('contacts-exists', "Contacts are already exist");
}
},
Client
$meteor.call('createContacts', contacts, function(err){
alert("in create contacts callback");
if(err && err.error === "not-logged-in"){
alert("error due to not-logged-in");
$ionicPopup.alert({
title: err.reason || "User not logged in",
template: 'Please try again after logged in',
okType: 'button-positive button-clear'
});
}
else if(err && err.error === "contacts-exists"){
$ionicPopup.alert({
title: err.reason || "Connections already exists",
template: 'Please try again after logged in',
okType: 'button-positive button-clear'
});
}
$meteor.call('createConnections');
});
Seems like i need to use .then() as documented in Angular-Meteor Document
Also changed the code as per amageddian

Meteor registering and assigning role error

I have a Meteor application and am trying to register a user and assign a role:
In the client registration file, I have a user with email, password, username, profile (firstname and lastname) and role:
Accounts.createUser(user, user.roles, function(error){
if(!error) {
FlowRouter.go('home');
console.log("Registration successful");
}
else {
FlashMessages.sendError(error.reason);
console.log("Registration not successful: " + error.reason);
}
});
And then in the server file I have:
Accounts.onCreateUser(function(options, user) {
if(options.roles) {
user.roles = options.roles;
Roles.addUsersToRoles(user._id, user.roles);
}
return user;
});
With this code, I always get an error message:
Exception in delivering result of invoking 'createUser': TypeError: options.userCallback.apply is not a function
at http://localhost:3000/packages/accounts-base.js?7dabd814506e384c709f8bf707377955f9814129:612:26
at http://localhost:3000/packages/underscore.js?46eaedbdeb6e71c82af1b16f51c7da4127d6f285:794:19
at loggedInAndDataReadyCallback (http://localhost:3000/packages/accounts-base.js?7dabd814506e384c709f8bf707377955f9814129:708:7)
at null._callback (http://localhost:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:999:22)
The user does get added successfully though!
EDIT: THE FIX
On server side:
Accounts.onCreateUser(function(options, user) {
if (options.profile) {
user.profile = options.profile;
}
if(options.roles) {
user.roles = options.roles;
Roles.addUsersToRoles(user._id, user.roles);
}
return user;
});
On client side:
Accounts.createUser(user, function(error){
if(!error) {
FlowRouter.go('home');
}
else {
FlashMessages.sendError(error.reason);
}
});
You are adding the roles to the user in onCreateUser. The user object has not been inserted in the collection at that point.
Another remark: you pass user.roles as your second parameter to createUser. According to Meteor docs you can only pass options and a callback. See http://docs.meteor.com/#/full/accounts_createuser
Maybe change to something like:
Accounts.createUser(user, function(error){
if(!error) {
Roles.addUsersToRoles(user._id, user.roles);
FlowRouter.go('home');
console.log("Registration successful");
} else {
FlashMessages.sendError(error.reason);
console.log("Registration not successful: " + error.reason);
}
});

Meteor.call not firing on the server, fine in the console

I have a server method:
server/methods.js
Meteor.methods({
removeStructure: function(id) {
this.unblock();
console.log("method removestructure was called on "+ id);
Structure.remove({"overlay_id": id}, function(error, result) {
if (error) {
console.log(error);
} else {
console.log("Deleted " + result + " structures.");
}
});
}
It is invoked in an observer when a document is removed from a collection:
client/x.js
Overlays.find().observe({
removed: function(item) {
console.log('Overlay removed' );
if ( Meteor.isClient ) {
drawnItems.eachLayer(function (layer) {
if (layer.meteor_id == item._id) {
drawnItems.removeLayer(layer);
}
});
}
console.log("attempting to remove meteor id " + item._id);
Meteor.call("removeStructure", item._id);
}
});
Nothing happens. The trace "attempting to remove meteor id jykkcEJuBL4NfJdte" fires, but the meteor method does not get called on the server. No error is returned client or server, it's as if it skips clean over that line.
When I type into the client browser console
Meteor.call("removeStructure", "jykkcEJuBL4NfJdte");
It runs no problem on the server and client.
What could be going wrong here? Am stumped!

How to verify if a Meteor.user username exists?

I'm building a messenger application, and before a conversation is created I want to verify if a user exists. If it does, then it will create the conversation. If not, then it should return an error. I've been working with this code on the server side but for some reason it won't work. I've tried many different tweaks, but this is basically my structure:
Meteor.methods({
createConversation: function(secondPerson) {
function doesUserExist(secondPerson) {
var userx = Meteor.users.findOne({username: secondPerson});
if (userx === secondPerson) {
return false;
} else {
return true;
}
}
if (doesUserExist()) {
Conversations.insert({
person1: Meteor.user().username,
person2: secondPerson
});
} else {
Conversations.insert({
person1: "didn't work"
});
}
}
});
The main point you were missing is that find returns a cursor, whereas findOne returns a document. Here is one way to implement the method:
Meteor.methods({
createConversation: function(username) {
check(username, String);
if (!this.userId) {
throw new Meteor.Error(401, 'you must be logged in!');
}
if (Meteor.users.findOne({username: username})) {
return Conversations.insert({
person1: Meteor.user().username,
person2: username
});
} else {
throw new Meteor.Error(403, username + " does not exist!");
}
}
});
Note the following features:
validates that username is a string
requires that the user be logged in to create a conversation
reduces the user existence check to a single line
returns the id of the new conversation
uses Meteor.Error with explanations which can be seen on the client
To use it just open your browser console and try making calls like:
Meteor.call('createConversation', 'dweldon', function(err, id){console.log(err, id);});

App authentication dialog box for facebook app

I have made an facebook app. Now i need to take user information using a pop-up permission box. If a user has authenticated the app, facebook should not open dialog box for permission but if a user comes to app first time then it must open a dialog box. What I am trying to do here is...and getting error like...
Cannot call method 'showPermissionDialog' of undefined
FB.getLoginStatus(function (response) {
if (response.status === 'connected') {
alert("1");
// the user is logged in and has authenticated your
// app, and response.authResponse supplies
// the user's ID, a valid access token, a signed
// request, and the time the access token
// and signed request each expire
var uid = response.authResponse.userID;
//alert(uid);
var accessToken = response.authResponse.accessToken;
jQuery("#<%= accessToken.ClientID %>").val(accessToken);
// alert(accessToken);
fqlQuerynew();
} else if (response.status === 'not_authorized') {
// the user is logged in to Facebook,
// but has not authenticated your app
alert('not_authorized');
OnRequestPermission();
} else {
alert("3");
//alert('the user isnt logged in to Facebook');
}
});
};
function OnRequestPermission() {
var myPermissions = "publish_stream, manage_pages"; // permissions your app needs
FB.Connect.showPermissionDialog("email,offline_access", function (perms) {
if (!perms) {
alert("hi");
// document.location.href = 'YouNeedToAuthorize.html';
} else {
alert("buy");
document.location.href = 'homePage.html';
}
});
}
If you have just copied and pasted it from your code then I think you have added one extra closing bracket after FB.getLoginStatus '};'.
After removing that try your code. If it doesn't work then can we know when you want to check login status like after clicking some social button or while loading page.
Here's a modified version of your code, I haven't tested it and it's not complete, but should give you an idea of what to do:
FB.getLoginStatus(function (response) {
if (response.status === 'connected') {
var uid = response.authResponse.userID;
var accessToken = response.authResponse.accessToken;
jQuery("#<%= accessToken.ClientID %>").val(accessToken);
fqlQuerynew();
} else if (response.status === 'not_authorized') {
OnRequestPermission();
} else {
...
}
});
function OnRequestPermission() {
var myPermissions = "publish_stream, manage_pages"; // permissions your app needs
FB.login(function(response) {
if (response.status === 'connected') {
FB.api("me/permissions", checkPermissions);
}
else {
....
}
}, { scope: "email,offline_access" });
}
function checkPermissions(response) {
if (response.data && response.data.legth == 1) {
var perms = response.data[0];
// iterate over perms and check if the user has all needed permissions
}
}

Resources