When users log into their account I would like to check the users role and direct them to a suitable home page. Roles is set by meteor-roles and I'm using flow-router. Currently this just throws a trigger error:
Exception from Tracker recompute function:
TypeError: Cannot read property 'roles' of undefined
Is it even possible to access roles in the router file?
Path: Routes.js
FlowRouter.route("/", {
name: 'home',
action: function() {
var user = Meteor.user();
var userRole = user.roles;
if (userRole == 'is_student') {
FlowRouter.go('profileNew');
} else if (userRole == 'is_teacher') {
FlowRouter.go('profile');
} else {
FlowRouter.go('profileAdmin');
}
}
});
var user = Meteor.user(); // You are not login because app is just started
var userRole = user.roles; //user is undefined at this moment so how can you get the roles? That why its throwing the error.
So you can manage this situlation like this:-
FlowRouter.route("/", {
name: 'home',
action: function() {
var user = Meteor.user();
if(user){
var userRole = user.roles;
if (userRole == 'is_student') {
FlowRouter.go('profileNew');
} else if (userRole == 'is_teacher') {
FlowRouter.go('profile');
} else {
FlowRouter.go('profileAdmin');
}
}
}
});
Related
I'm trying to implement auth guards in Nuxt with Firebase Auth, but I keep running in to problems. At the moment I'm able to login, but the correct page isn't loaded after login, after login the user should be redirected to the '/profile-overview' page but that doesn't happen. When I navigate away from the 'profile' page to another page and then go back I do automatically go to the 'profile-overview' page. So the login works, there is just something wrong with the navigation / refresh of the page after login. Also when I refresh the page the user is logged out again, I would except the user to still be logged in then?
My code so far:
Page:
loginGoogle () {
this.$store.dispatch('signInWithGoogle').then(() => {
console.log('reload')
location.reload()
//window.location.reload(true)
}).catch((e) => {
this.title = 'Google login failed'
this.message =
"Something went wrong, please try again later. If this problem keeps happening please contact: jonas#co-house.be " + "Error: " + e.message;
this.dialog = true;
})
},
Middleware:
export default function ({ store, redirect, route }) {
console.log('user state' + store.state.user)
console.log('route ' + route.name)
store.state.user != null && route.name == 'profile' ? redirect('/profile-overview') : ''
store.state.user == null && isAdminRoute(route) ? redirect('/profile') : ''
}
function isAdminRoute(route) {
if (route.matched.some(record => record.path == '/profile-overview')) {
return true
}
}
Plugin:
import { auth } from '#/services/fireInit.js'
export default context => {
const { store } = context
return new Promise((resolve, reject) => {
auth.onAuthStateChanged(user => {
if (user) {
return resolve(store.commit('setUser', user))
}
return resolve()
})
})
}
Store (function to login only:
signInWithGoogle ({ commit }) {
return new Promise((resolve, reject) => {
auth.signInWithPopup(GoogleProvider).then((result) => {
// This gives you a Google Access Token. You can use it to access the Google API.
var token = result.credential.accessToken;
// The signed-in user info.
var user = result.user;
return resolve(store.commit(state.user, result.user))
// ...
}).catch((error) => {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// The email of the user's account used.
var email = error.email;
// The firebase.auth.AuthCredential type that was used.
var credential = error.credential;
// ...
})
})
},
Does anyone have any idea what I could be doing wrong, or some documentation / tutorial I could read?
Thanks in advance.
You need to init your user on server in nuxtServerInit. See this repo for example implementation https://github.com/davidroyer/nuxt-ssr-firebase-auth.v2
When a new user account is created I'm using the Accounts.onCreateUser function to insert data into a new collection. I want to check that the insert has successfully worked before progressing. My code appears to work however it seems very messy. I'm wondering if there is a cleaner way to write this code.
Accounts.onCreateUser((options, user) => {
if (user) {
CandidateProfile.insert({
userId: user._id,
firstName: options.profile.name.first,
lastName: options.profile.name.last
});
var checkForNewCandidateProfile = CandidateProfile.findOne(
{ userId: user._id },
{ fields: { userId: 1 } }
);
var userId =
checkForNewCandidateProfile && checkForNewCandidateProfile.userId;
if (userId === user._id) {
return user;
}
}
});
Personally, I don't see any sense in your test. You don't trust insert?
But OK, you need it.
Be sure, that you run your code on the server side. Import it only on server side or just wrap it in if (Meteor.isServer)
Why check if user arg exists? It is, that's how that callback works.
If something's wrong, throw an error to abort user creation.
Possible variant:
if (Meteor.isServer) {
Accounts.onCreateUser((options, user) => {
// You insert sync, so it's up to you to handle errors.
try {
CandidateProfile.insert({
userId: user._id,
firstName: options.profile.name.first,
lastName: options.profile.name.last
});
var checkForNewCandidateProfile = CandidateProfile.findOne(
{ userId: user._id },
{ fields: { userId: 1 } }
);
var userId =
checkForNewCandidateProfile && checkForNewCandidateProfile.userId;
if (userId === user._id) {
return user;
}
} catch (error) {
throw new Error(error);
}
throw new Error("Something's wrong.");
});
}
I'm using Meteor.loginWithGoogle in my app. I'm trying to get the email address of the google user to put it into a Session variable.
Template.login.events({
'click #google-login': function(event){
Meteor.loginWithGoogle({}, function(err){
if ( err ) {
throw new Meteor.Error("Google login failed");
} else {
const emailAddress = ?; // how do I get this from google?
Session.set('email',emailAddress);
Router.go('/profile');
}
});
}
});
I'm not sure whether i understood your question, but i guess what you're trying to ask is: "After a user performed a loginWithGoogle, how can i get his email address, and set it into his Session?"
After a login, Meteor.user() holds the current user document. Having that in mind:
const currentUser = Meteor.user();
const userGoogleServiceMain = currentUser.services.google.email;
With that, you can have:
Template.login.events({
'click #google-login': function(event){
Meteor.loginWithGoogle({}, function(err){
if ( err ) {
throw new Meteor.Error("Google login failed");
} else {
const currentUser = Meteor.user();
const emailAddress = currentUser.services.google.email;
Session.set('email',emailAddress);
Router.go('/profile');
}
});
}
});
You may find more details about that in: Meteor documentation and http://cs.wellesley.edu/~mashups/pages/meteor6.html
This code attempts to add a field to a user which already exist in meteor users.
The error I am getting is
Exception while invoking method 'logMeIn' Error: insert requires an argument
Which I don't understand, how can it be fixed? Thanks
/////////////////////////////////////
// client code
/////////////////////////////////////
Template.login.events({
'click #logMe': function() {
var username = $('#id').val();
var password = $('#pin').val();
Meteor.call('logMeIn', [username,password], function (err, data) { //create new user
if ( err ) {
if (err.message.match(/username already exists/i)) {
Meteor.loginWithPassword(username+password,password)
}
} else {
console.log('new user created');
}
});
}
});
/////////////////////////////////////
// server code
/////////////////////////////////////
Meteor.methods({
logMeIn: function (credentials) {
//do work , if logged in, do next line
var idPin = credentials[0] + credentials[1];
Accounts.createUser({username: idPin, password: credentials[1]});
}
});
Accounts.onCreateUser(function (options, user) {
user.menuGroup = 'a';
});
You need to return the user on the Account.onCreatedUser (documentation here). Also, additional data of the user should be put under the profile branch (check the documentation in here)
Accounts.onCreateUser(function (options, user) {
if (options.profile) {
user.profile = options.profile;
}
if (user['profile'] == null) {
user['profile'] = {};
}
user['profile']['menuGroup'] = 'a';
return user;
});
I have the following code in my Meteor app where I create new users, assign them 'basic' role. Yet I am having a trouble showing on the client side errors returned while processing Accounts.createUser, can someone please tell me how I can return errors returned by Accounts.createUser while having it on the server as my code below. Thanks
/server/users.js
Meteor.methods({
'createMemberAccount': function (data, role) {
var userId;
Meteor.call('createNewAccount', data, function(err, result) {
if (err) {
return err;
}
console.log('New account id: '+ result);
Roles.addUsersToRoles(result, role);
return userId = result;
});
return userId;
},
'createNewAccount': function (adminData) {
return Accounts.createUser({email: adminData.email, password : adminData.password, roles: adminData.roles});
}
});
/client/signup.js
Template.signupForm.events({
'submit #signup-form': function(e, t){
e.preventDefault();
var userData = {};
userData.email = $(e.target).find('[name=email]').val();
userData.password = $(e.target).find('[name=password]').val();
userData.roles = ['basic'];
Meteor.call('createMemberAccount', userData, 'basic', function(err, userId) {
if (!err) {
console.log('All OK');
} else {
console.log('Error: ' + err.message);
}
});
return false;
}
});
Since You are creating an static rol "basic", you don't need to do that pair of methods, and Meteor.calls, instead you can use
So, use the v on the client side, just like this.
Template.register.events({
'submit #register-form' : function(e, t) {
e.preventDefault();
var email = t.find('#account-email').value
, password = t.find('#account-password').value;
// Trim and validate the input
Accounts.createUser({email: email, password : password}, function(err){
if (err) {
// Inform the user that account creation failed
} else {
// Success. Account has been created and the user
// has logged in successfully.
}
});
return false;
}
});
If you see there is not any role yet incude, so now on the server.js use the onCreateUser method.
//Server.js
Accounts.onCreateUser(function(options, user) {
if (options.profile)
user.profile = options.profile;
user.role = "basic"
return user;
});
Now thats is more easy, and with less code, if you are trying to create 2 differents roles like "Admin" and "Basic", just on the client side create a profile field named "profile.roles" and do a if statement on the onCreateUser.
return Accounts.createUser({email: adminData.email, password : adminData.password, roles: adminData.roles});
This part returns the userId once it is created, it doesn't return any errors when it fails.
When it fails, the returned value will be undefined
Also, in the server, we cannot use callbacks with Accounts.createUser
If you want find the errors, you have to use Accounts.createUser in client side.
Coming to this late, but on the server side, you can assign the createUser to a variable and it will return the new user’s _id; then you can check if that exists. For example (server side only):
let email = 'foo#bar.com';
let password = 'bar';
let profile = {firstName: 'foo', lastName: 'bar'};
let newId = Accounts.createUser({
password: password,
email: email,
profile: profile
});
if (!newId) {
// New _id did not get created, reason is likely EMail Already Exists
throw new Meteor.Error(403, "Cannot create user: " + error.reason);
}
else {
// Stuff here to do after creating the user
}
The Meteor.Error line will be passed back as an error in the callback on the client side, so you can reflect that error to the browser.