I'd like to be able to mark users as "admin" in the Meteor auth system, and allow that user to do special things, as well as show some gui elements I wouldn't show if they weren't an admin. I've already tried setting an "admin" property on the user object, which would work fine on the server side (for the RPCs for the admin actions), however I need to access it on the client side to change the rendering of the page, and it appears only emails is sent with the Meteor.user() object.
Basic question: How can I assign a user-specific property that both the server and client can see?
To anyone in the future, simply assign the value in the users table in the database. You can publish additional fields to the user using the following:
Meteor.publish("userData", function () {
return Meteor.users.find({_id: this.userId}, {fields: {'admin': 1}});
});
And on the client:
Meteor.subscribe("userData");
Poof. Straight from the documentation.
You can also add properties in "profile" attribute of the user. profile attribute is alrealy populated to client side :
Meteor.users.update({_id: userId}, {$set: {'profile.admin': 1}});
//on client side
Meteor.user().profile.admin
Related
So I'm creating a new user as my template is created. The user is being created successfully, and automatically is logged in however if I sign out and then try to sign in , I get the 'user not found'. Here is my code
Template.hello.onCreated(function helloOnCreated() {
// counter starts at 0
this.counter = new ReactiveVar(0);
var userObject = {
username: "anotherTest",
mail: "anotherTest#me.com",
password: "testingME"
};
Accounts.createUser(userObject, function(error){
console.log('User created');
console.log(error);
});
});
And here is the full project in case it is needed.
https://github.com/hayk94/UbMvp/tree/accountsTEST
Do you know what is the problem?
You're trying to use client side accounts management to perform a task it hasn't been designed for.
Client side accounts package purpose is to specifically allow new users to create their account and expect to be logged in immediately.
You have to remember that certain functions can be run on the client and/or on the server with different behaviors, Accounts.createUser docs specify that : "On the client, this function logs in as the newly created user on successful completion."
On the contrary, "On the server, it returns the newly created user id." (it doesn't mess with the currently logged in user on the client).
In order to solve your problem, you should write a server side method creating a new user and be able to call it from your client side admin panel, after filling correctly a user creation form of your own design.
I'm writing a section of my app which requires the user to have the 'operator' role.
I'm checking for this in FlowRouter's triggersEnter function. I want that the user which doesn't have the operator role to be shown a restricted access page.
I use FlowRouter, Roles and brettle:accounts-deluxe which auto logs in as guest every visitor.
Here is my code, routes.js:
FlowRouter.route('/switchboard', {
name: 'switchboard',
triggersEnter: [function (context, redirect, stop) {
if (!Roles.userIsInRole(Meteor.userId(), ['operator'])) {
BlazeLayout.render('main', {
content: 'restrictedAccess'
});
stop();
}
}],
action: function () {
BlazeLayout.render('main', {
content: 'switchboard'
});
}
});
Everything works as expected on localhost, but when the app is deployed using mup, on a server, at the time triggersEnter is ran, Meteor.user() is undefined (Meteor.userId() returns ok), and the result of Roles.userIsInRole call is false, although looking in the database it's clear the user has the operator role.
I think the users subscription is not available at the time triggersEnter is ran meaning that the users collection is not published on the client. I have this feeling because if i access the route by clicking on a link the userIsInRole result is ok, but if I refresh the page I get the problem described.
I would like to know why is this happening only on the server and how can I fix it.
The reason is that FlowRouter triggersEnter is not blocking templates from rendering and it makes checking roles before Roles collections are subscribed. Solution is to use FlowRouter.wait() on app init and then make the global subscription for Roles (you need it global - not tied to template level) collection and call FlowRouter.initialize() when its ready.
That way FlowRouter will wait for your collection and will be initialized after it's ready to check.
Update
On localhost there is much less latency between local db and app. When your app is deployed is takes more time for client to fetch data from database. In result on localhost your collection is ready when FlowRouter initializes and on deployed app it isn't.
Use the Template.subscriptionsReady flag
<template name="blogPost">
Back
{{#if Template.subscriptionsReady}}
{{#with post}}
<h3>{{title}}</h3>
<p>{{content}}</p>
{{/with}}
{{else}}
<p>Loading...</p>
{{/if}}
</template>
check full doc here:
https://kadira.io/academy/meteor-routing-guide/content/subscriptions-and-data-management/with-blaze
to see how to handle individual subscriptions
I've got facebook, google and regular registration/login turned on on my website. The problem I have is that the email address is stored in different fields depending on how the user first joined.
For regular users, it is in field emails[0].address. For facebook and google authenticated users it is in field services[0].email.
At various places in the client (templates, events) and on the server (method), I just want to call one method that works out which field to use and returns the email address. I also want to do something similar for the verification field.
I'm fairly new to meteor and the only ways I've found to do the above so far is to repeat the same logic in the client and on the server which doesn't sit well with me.
The best thing to do would be to transfer the email address to 'emails' if they log in with facebook, google or another services for the first time. This would also make it more future proof incase you add other services, since meteor will always use emails.address (including in other packages)
Server side code:
Accounts.onCreateUser(function(user) {
user.emails = user.emails || []; //If its null set it to an empty array
if(user.services.facebook) {
user.emails.push({address: user.services.facebook.email, verified: false});
}else if(user.services.google) {
user.emails.push({address: user.services.google.email, verified: false});
}
return user;
});
Then you can just check Meteor.user().emails[0].address every time.
Note: If not published due to the autopublish package you may have to publish the emails field for it to work on the client.
You may also have to run this the first time for users who have already logged in before:
Meteor.startup(function() {
Meteor.users({'emails':{$exists: false}}).fetch().forEach(function(user) {
var email = (user.services.facebook || user.services.google).email;
if(email) Meteor.users.update({_id: user._id},{$push:{emails:{address: email, verified: false}}});
});
});
I'm not sure if facebook and google both use email in the services key, if they do the above should work fine. If they don't you can edit out the key that is used for google or facebook, in case one is emailAddress instead of email for example.
How do you get the _id of the user that logged in. I have tried the following combinations and I get errors, or undefined
Upon user creation, the user is automatically signed into the application. Is the user that is returned by the Accounts.onCreateUser function occurring after the user is logged in?
Accounts.onLogin(function(){
var user = this.userId / Meteor.user() / Meteor.user()._id
console.log(user)
})
http://docs.meteor.com/#/full/accounts_onlogin
The Accounts.onLogin(function(){}), come with 1 parameter user.
When it is known which user was attempting to login, the Meteor user
object. This will always be present for successful logins.
from the docs.
So this should work.
Accounts.onLogin(function(user){
console.log(user.user._id)
});
And you should see, all the user document into the server console,check this meteorpad for an example.
NOTE: this feature is only available on server side check this Hooks Accounts.onLogin/onLoginFailure should be available on client
You can always get the _id of the logged-in user via Meteor.userId(). This also works inside the Accounts.onLogin callback
Accounts.onLogin(function() {
console.log(Meteor.userId());
})
How can I make a variable for the current user's username as they log in to create a database document for them to store their info?
You need to setup a custom function to configure user creation in server side, see Accounts.onCreateUser on docs.meteor.com
In this function you can initialize your user database document, either in user.field or user.profile.field.
The username is automatically stored in user.username, you do not need to create it.
Then to modify the user record client side, simply call a server method that will update the Meteor.users collection, ie
server/users.js
Meteor.methods({
updateUser:function(fields){
if(!this.userId){
// error : no user logged in
}
check(fields,{/* fields verification */});
Meteor.users.update(this.userId,{
$set:fields
});
}
});
client/main.js
Meteor.call("updateUser",{
"username":"foo",
"profile.bar":"bar"
});
Note that Meteor built-in user accounts greatly simplify all this process : it is well documented so I encourage you re-read that particular section in the docs.