Get current user email meteor - meteor

I am having a bit of difficulty getting the email of the current user in Meteor.
publish.js
Meteor.publish('allUsers', function(){
if(Roles.userIsInRole(this.userId, 'admin')) {
return Meteor.users.find({});
}
});
Meteor.publish('myMail', function(){ {
return Meteor.user().emails[0].address;
}
});
profile.html
<template name="Profile">
<h1> My Profile </h1>
{{#if currentUser}}
<p>{{currentUser.profile.firstName}}</p> <p>{{currentUser.roles}}</p>
<p>{{currentUser.userEmail}}</p>
{{/if}}
</template>
profile.js
Template.Profile.helpers({
users: function() {
return Meteor.users.find();
},
userEmail: function() {
return Meteor.user().emails[0].address;
}
});
Firstname and ._id display fine, emailaddress unfortunately does not. Does anyone have a tip? thanks!

Your 'myMail publication is both redundant and incorrect. You should either return a cursor (or an array of cursors), or observe a cursor and send handle the publication lifecycle yourself (a fairly advanced feature, irrelevant to your question). You are using it a-la Meteor.methods, and you should not really user Meteor.user() in a publication anyway.
It's redundant because Meteor's accounts package publishes the current user's emails field automatically.
In your template, you are treating userEmail as an attribute of the current user, instead of calling it as a helper.
I would advise to use a guard and make sure that the user actually has an email address, something in the lines of:
JS:
Template.Profile.helpers({
users: function() {
return Meteor.users.find();
},
userEmail: function(user) {
if (user.emails && user.emails.length > 0) {
return user.emails[0].address;
}
return 'no email';
}
});
HTML:
<template name="Profile">
<h1> My Profile </h1>
{{#if currentUser}}
<p>{{currentUser.profile.firstName}}</p> <p>{{currentUser.roles}}</p>
<p>{{userEmail currentUser}}</p>
{{/if}}
</template>
I would also strongly advise against publishing all of the fields in the 'allUsers' publication, as it will expose sensitive data that should not leave the server under almost any circumstances (e.g, password data).

Related

find a document with the current username in a helper

I'm trying to create a helper like this:
this.helpers({
data() {
return Customers.findOne({ user: Meteor.user().username });
}
});
but an error occurs, It seems that the user is logging in when the helper is executing, How can I execute the helper after the user is logged in ?
Don't know if is the best solution but I created a deferred promise that wait for the user to login and resolve the $state.
resolve: {
currentUser: ($q) => {
var deferred = $q.defer();
Meteor.autorun(function() {
if(!Meteor.loggingIn()) {
if(!Meteor.user()) {
deferred.reject('PERMISSION_REQUIRED');
} else {
deferred.resolve();
}
}
});
I hope that it can be useful for someone else.
Try this:
data() {
if(Meteor.user()){
return Customers.findOne({ user: Meteor.user().username });
}
}
Try builtin currentUser users helper, which check whether the user is logged in. Like that:
{{#if currentUser}}
{{data}}
{{/if}}

Waiting on a subscription in Flow Router

Objective : I want to render one among template A or template B from my flow router function, based upon a document which is retrieved after a subscribe call.
More specifically, I want to render either an admin or a student template based upon the isAdmin field of a user document, retrieved after a completed subscribe call.
My router function is as shown below.
FlowRouter.route('/songs/list', {
name: 'Songs.list',
subscriptions: function(params, queryParams) {
this.register('getUser', Meteor.subscribe('allUsers', Meteor.userId()));
}
action(params, queryParams) {
if(Meteor.user().isAdmin){
BlazeLayout.render("admin_home");
}
else{
BlazeLayout.render("student_home");
}
}
});
The Flow router documentation mentions specifically that
FlowRouter only deals with registration of subscriptions. It does not wait until subscription becomes ready.
So there could be a case where the "if condition" is evaluated before the subscription has updated the local cache.
With iron-router, this is easily handled using a waitOn. However for flow router, I am forced to have 2 separate functions, which further enforces 2 separate url's, for rendering the admin and student templates.
Is this a design choice made by the flow router developers?
Why not carry subscription logic out of routing and use template level subscriptions with builtin Template.subscriptionsReady helper?
FlowRouter.route('/songs/list', {
name: 'Songs.list',
action: function(params) {
BlazeLayout.render('home');
}
});
<template name="home">
{{#if Template.subscriptionsReady}}
{{#if isAdmin}}
{{> admin_home}}
{{else}}
{{> student_home}}
{{/if}}
{{/if}}
</template>
Template.home.onCreated(function() {
this.subscribe('allUsers', Meteor.userId());
});
Template.home.helpers({
isAdmin: function() {
// check if user is admin
}
});
This approach also recommended in FlowRouter docs.
Try:
Meteor.subscribe('allUsers', {
OnReady(){
if(Meteor.user().isAdmin){ BlazeLayout.render("admin_home"); } else{ BlazeLayout.render("student_home"); } }
I think the function you're after is FlowRouter.subsReady, an example of how you might use it within a router (similar to IronRouter) is provided in the docs here.
So in your case, it might look something like:
FlowRouter.route('/songs/list', {
name: 'Songs.list',
subscriptions: function(params, queryParams) {
this.register('getUser', Meteor.subscribe('allUsers', Meteor.userId()));
},
action(params, queryParams) {
Tracker.autorun(function() {
var ready = FlowRouter.subsReady("getUser");
Tracker.nonreactive(function(){
if(ready && Meteor.user().isAdmin){
BlazeLayout.render("admin_home");
}
else if(ready){
BlazeLayout.render("student_home");
}
else {
BlazeLayout.render("loading");
}
});
});
}
});

Meteor not loading data

am calling my template like this {{> list_items}} and for some reason it doesn't work
this is the template code
<template name="list_items">
{{#each items}}
<div class="col-sm-4 col-lg-4 col-md-4">
<div class="thumbnail">
<img src="{{previewImage}}" alt="">
<div class="caption">
<h4 class="pull-right">{{price}}</h4>
<h4>{{title}}</h4>
<p>{{description}}</p>
</div>
</div>
</div>
{{/each}}
</template>
and items is a function in the template helper that returns the documents in my collection, here is its code:
Template.list_items.helpers({
items: function(){
return Items.find({});
}
});
This is my Items collection allow rules
Items.allow({
insert: function (userId, doc) {
// the user must be logged in, and the document must be owned by the user
return true;
},
update: function (userId, doc, fields, modifier) {
// can only change your own documents
return true;
},
remove: function (userId, doc) {
// can only remove your own documents
return true;
}
});
And collection inside "lib" folder so that i can use it from the client side.
When i tried to use Items.find().fetch() i get an empty collection [] Even though i have the collection with one document inside it
Why it doesn't work? are there any required package to be added first?
solved it by making publish and subscribe
in the server
Meteor.publish('items-all', function publishFunction() {
return Items.find({});
})
in the client
Meteor.subscribe('items-all');
This will not allow you to find any data on client side.Items.find({}) will return empty docs.
Items.allow({
insert: function (userId, doc) {
// the user must be logged in, and the document must be owned by the user
return true;
},
update: function (userId, doc, fields, modifier) {
// can only change your own documents
return true;
},
remove: function (userId, doc) {
// can only remove your own documents
return true;
}
});
If you want to allow Items.find({}) allow to all routes/templates. You can publish the data on server side like :
Meteor.publish('all-Items', function(){
return Items.find({});
})
And on the client side you can subscribe the all-Items publish on inside the Meteor.startup like this :
Meteor.startup(function () {
Meteor.subscribe('all-Items');
}
Then you can access Items.find({}) on each and every routes and that will return all the docs reactively.
Don't forget to add fetch function to see on console like : Items.find({}).fetch(), It will return array of your docs.

Meteor publish ALL Users does not seem to work (or even get called?)

I have the following in server/publications.js...
Meteor.publish("users", function(){
return Meteor.users.find({}, {fields: {profile: 1}});
});
... and in my iron router route...
Router.route('/', function() {
this.layout('ConfLayout');
this.render('UserList', {
waitOn: function () {
return Meteor.subscribe("users");
},
data: function () {
return {
users: function () {
return Meteor.users.find();
}
};
}
});
});
...then in my template....
<template name="UserList">
<h1>Users</h1>
<ul>
{{#each users}}
<li>
{{#linkTo route='user.show'}}
<div>
{{profile.lastName}}, {{profile.firstName}}
</div>
{{/linkTo}}
</li>
{{/each}}
</ul>
</template>
...and it sort of works except the only user on the client is the currently logged in user. I am trying to get a list of ALL users for admins (don't worry about the for admins part for now).
What is also odd is that is I add a console.log statement to the publish function it never gets logged. However all the other publications in the same file seem to work fine. Also if I enable autopublish, then all the users show up as expected.
What an I missing here? Based on all I could find it seems like publishing specific fields should work for displaying all users in the client, but it almost seems like Meteor is ignoring any publications on Meteor.users altogether. I am using Meteor 1.1.0.3.
Any thoughts or help appreciated!
TIA
OK... not entirely sure why, but I suspect I may have been missing a "this" somewhere or something, but if I change the route to not use a function as the 2nd param and just pass options and then leave EVERYTHING else EXACTLY the same, it works...
Router.route('/', {
waitOn: function () {
return Meteor.subscribe('users');
},
data: function () {
return {
users: function () {
return Meteor.users.find();
}
};
},
template: 'UserList',
layoutTemplate: 'ConfLayout'
});

User Profiles / Router

I'm trying to figure out how I would be able to view user profiles by traveling to /player/:username. I have the template, now I just need to call Meteor.users to find the user account by the :username that is specified in the URL. I'm using the Router package.
'/player/:username': {
to: 'user_profile',
and: function(){
var user = Meteor.users.findOne({ username: username });
}
},
Thanks in advance,
Nathan
I would set the Session variable in the route function, and then use that to return the user in a template helper. So:
'/player/:username': {
to: 'user_profile',
and: function(username){
Session.set('currentUsername', username);
}
},
And then in the template helper
Template.user_profile.helpers({
currentUser: function() {
return Meteor.users.findOne({username: Session.get('currentUsername')});
}
})
And then in your template
<template name="user_profile">
{{#with currentUser}}
User name is {{username}}
{{/with}}
</template>
You could try var user = Meteor.users.findOne({ username: username }); -- then to look up profile properties of the user, you could do user.profile.foobar.

Resources