I tried to write my own custom auth form in meteor. for the email validation part, the system send out an email with the route and token appended on it. However, I want to get the token in the validation page, so I tired the following
Accounts.onEmailVerificationLink(function(token, done) {
console.log("hello");
Session.set(verifyEmailToken, token);
doneCallback = done;
});
Template.emailVerified.onCreated(function(){
console.log(Session.get(verifyEmailToken));
Accounts.verifyEmail(Session.get(verifyEmailToken),function(err){
if(err){
Session.set(ERROR_KEY,err.reason);
}else{
Session.set(SUCESS_KEY,"Your email has been verified, thank you!");
if (doneCallback) {
doneCallback();
}
}
});
});
But the Accounts.onEmailVerificationLink method doesn't seem like have been invoked. Did I miss something there? Any help is appreciated.
Try this:
Server code:
Accounts.urls.verifyEmail = function(token) {
return Meteor.absoluteUrl('verify/' + token);
};
Common/Both Router:
AccountController = RouteController.extend({
verifyEmail: function() {
Accounts.verifyEmail(this.params.token, function(err) {
if (err) {
// error
} else {
//
}
});
}
});
Router.map(function() {
return this.route('verifyEmail', {
controller: 'AccountController',
path: '/verify/:token',
action: 'verifyEmail'
});
});
Related
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);
}
});
I created a collection for adminuser's enter the system.I mean I dont want to use account packet for admin side but I dont know How to make Route setting after admin to be login.I made something but it doesnt work correct,
login.html
Template.login.events({
'click #entre': function (e, template) {
var Username = template.$('#username').val();
var Password = template.$('#password').val();
var getinfo= admin.findOne({});
if (Username == " " || Password == "") {
swal("Error", "All fields must be Completed.", "error");
} else if (getinfo.username== Username && getinfo.password== Password) {
swal("Success", "Welcome admin.", "success");
Session.set("hi", true);
} else {
swal("error", "Login Informations wrong.", "error");
}
}
});
router.js
Router.onBeforeAction(function () {
if (!Session.get("hi")) {
this.render('login');
} else {
this.render('dashboard');
}
});
Router.route('userList', function () {
this.render('userList');
});
Router.route('addnewuser', function () {
this.render('addnewuser');
});
Note:I want to make that when admin to be login,it can reach to all pages userlist,addnewuser etc.
If I understood it properly you want to give admin rights to certain routes of yours. There are several ways to achieve this using iron:router, either by building a Controller or using Filters. I would create an Iron Router Controller to tackle that and attach it to any route that needs that kind of checks. Both Controllers and Filters are actually reusable bits of code which is what we are looking for.
Make sure you add alanning:roles to your packages list (if you haven't already) and add some admin roles to at least one of your Meteor.users() like it's shown here
Building the actual Controllers is easy.
lib/router.js
AdminController = RouteController.extend({
onBeforeAction: function () {
var loggedInUser = Meteor.userId();
if (!!loggedInUser) {
if (!Roles.userIsInRole(loggedInUser, 'admin')) {
// Basic redirect to the homepage
Router.go('homepage');
this.stop();
}
} else {
// Log them in when they are not
Router.go('login');
this.stop();
}
this.next();
}
});
Router.route('/admin', {
name: 'admin',
controller: AdminController,
waitOn: function () {
// return subscriptions here
}
});
Continue to add that to any other routes you like.
I am trying to make email verification that with the accounts-password package work however I have come across a weird problem.
It seems the # in the email verification URL is causing an issue. The verification email URL usually looks like : http://localhost:3000/#/verify-email/cnaTqQSCgYAksIsFo5FgmV94NHwrfaM2g5GvdZDUMlN
When I click on this, nothing seems to happen; it just re-directs to localhost:3000/#
However when I remove the # (http://localhost:3000/verify-email/cnaTqQSCgYAksIsFo5FgmV94NHwrfaM2g5GvdZDUMlN) this seems to work perfectly.
The URL (http://localhost:3000/#/verify-email/cnaTqQSCgYAksIsFo5FgmV94NHwrfaM2g5GvdZDUMlN) comes from Meteor so it's not something I create.
Here are my routes and controllers (using iron-router)
Router.route('/verify-email/:_token', {
controller : 'AccountController',
action : 'verifyEmail'
});
AccountController = RouteController.extend({
fastRender: true,
data: function () {},
onBeforeAction: function () {
this.render('Loading');
this.next();
},
verifyEmail: function() {
var verificationToken = this.params._token;
console.log(verificationToken);
Accounts.verifyEmail(verificationToken, function(error) {
if (error) {
console.log(error);
} else {
Router.go('/');
}
});
}
});
Any help is appreciated.
The conflict might be connected to the accounts-password package together with iron:router as outlined here:
...add a server file that overrides the urls with # paths that Meteor creates, so that the Iron-Router can work:
(function () {
"use strict";
Accounts.urls.resetPassword = function (token) {
return Meteor.absoluteUrl('reset-password/' + token);
};
Accounts.urls.verifyEmail = function (token) {
return Meteor.absoluteUrl('verify-email/' + token);
};
Accounts.urls.enrollAccount = function (token) {
return Meteor.absoluteUrl('enroll-account/' + token);
};
})();
Hope it will guide you in the right direction.
could anybody please tell me how to make clients wait until the called function on the server is executed?
My code:
Meteor.methods({
markLettersAsRead: function(userId) {
if(serverVar) {
Users.update({_id: userId}, {$set: {letters: []}}); // removing all references
}
}
});
Template.letter.events({
'click a': function() {
Meteor.call('markLettersAsRead', Meteor.userId(), this._id, function(err) {
if (err) {
console.log(err);
}
});
var usersExistsWithThisLetter = Users.find({letters: {_id: this._id}}).count();
console.log(usersExistsWithThisLetter);
}
});
In my example usersExistsWithThisLetter is always 1 because the Users.find() doesn't wait until the Meteor.call is done. I verified this by checking the database and no users exists with entries in the letters array.
Any help would be greatly appreciated.
You need to query the collection inside the callback, because then you can be certain that your server method has already been executed. I would do something like this (note the self variable declaration):
var self = this;
Meteor.call('markLettersAsRead', Meteor.userId(), this._id, function(err) {
if (!err) {
var usersExistsWithThisLetter = Users.find({letters: {_id: self._id}}).count();
console.log(usersExistsWithThisLetter);
} else {
console.log(err);
}
});
I hope it helps!
My service looks like
//this mthod under myService
this.checkCookie = this.getAuthorization = function() {
return $http({
method: 'GET',
url: '/api/auth'
});
}
And in my route configuration I am doing like
MyAPP.config(function($routeProvider) {
$routeProvider.
when('/', {
controller: check
}).
when('/login', {
templateUrl: '/partials/login.html',
controller: check
}).
when('/products', {
templateUrl: '/partials/products.html'
})
});
var check = function($location, myService, $q) {
if (myService.checkCookie()) {
$location.path("/products");
} else {
$location.path("/login");
}
};
with get request I want to check session data generated by the server is valid or not. And browser will send the cookie information while sending 'GET' in '/api/auth'.
The problem is when I am calling this.checkCookie I am not getting the response syncronoulsy as angular returns response in asnyc fashion. Depending on the checkCookie response I am suppose to redirect to '/products' but I cant do that now.
How can I do that? What I need to change to get this.checkCookie and check whether the response status is 200 or 500?
You can't do synchronous requests with $http. To handle the promise return by the request, you can do this:
var check = function($location, myService, $q) {
myService.checkCookie()
.success(function() {
$location.path("/products");
})
.error(function() {
$location.path("/login");
})
};
You have to call then on the promise that's returned from $http:
myService.checkCookie().then(function () {
$location.path("/products");
}, function () {
$location.path("/login");
});
The first function is the success handler, and the second one is the error (reject) handler.