Meteor.js accounts package [duplicate] - meteor

I want to have client-side access for a certain set of fields for ALL users while I would like to have access to even more fields for the current user only. How do I go about writing publish code to accomplish this?

Right from Meteor documentation:
Meteor.publish("userData", function () {
return Meteor.users.find({_id: this.userId},
{fields: {'other': 1, 'things': 1}});
});
And also:
Meteor.publish("allUserData", function () {
return Meteor.users.find({}, {fields: {'nested.things': 1}});
});
Hope this helps.

As mentioned above, the
Meteor.publish("userData", function () {
return Meteor.users.find({_id: this.userId},
{fields: {'other': 1, 'things': 1}});
});
and
Meteor.publish("allUserData", function () {
return Meteor.users.find({}, {fields: {'nested.things': 1}});
});
publish functions will push the data from the Users collection.
Subscribe with
Tracker.autorun(function () {
Meteor.subscribe("userData");
Meteor.subscribe("allUserData");
});
And the additional data will automatically go into the Users collection and be available in the Meteor.user() object.

My story with that:
I proceeded as documentation says, but encountered with weird behavior.
I had publish function, where I published whole profile and email object for current user (lets say userData) and just some subset for the other users (allUserData).
When I had -
Meteor.subscribe("allUserData");
Meteor.subscribe("userData");
On client side right after user logged in, I've received just allUserData data. Thats mean even for my logged in user (That user couldn't see his own email address). When I refresh browser, bug was fixed and I got properly allUserData for all users except one logged in, which has his proper userData (with mentioned email address).
What is interesting, if I changed the sequence of that subscriptions, bug was fixed.:
Meteor.subscribe("userData");
Meteor.subscribe("allUserData");
Putting into Meteor.autosubscribe(function () { }) doesn't changed anything.
Finally I tried put that subscription into Deps.autorun(function() { }) and explicitly add reactivity and the problem with sequence was resolved..:
Deps.autorun(function() {
Meteor.subscribe("allUserData", Meteor.userId());
Meteor.subscribe("userData", Meteor.userId());
// or
// Meteor.subscribe("userData", Meteor.userId());
// Meteor.subscribe("allUserData", Meteor.userId());
});
In publish function I just replace this.userId with userId from parameter.
With next bug which I encountered was, that I've got secret systemData object in profile user's object and that can see just admins, not regular logged in users. But although correct set publish function with 'profile.systemData': 0 that secret object could see all logged in users which looked into his profile object.
Probably it was because my publish function(s) somehow interfered with publish function in Meteor Account package:
// Publish the current user's record to the client.
Meteor.publish(null, function() {
if (this.userId) {
return Meteor.users.find(
{_id: this.userId},
{fields: {profile: 1, username: 1, emails: 1}});
} else {
return null;
}
}, /*suppress autopublish warning*/{is_auto: true});
Anyway I resolved it with help of method Account.onCreateUser() and adding systemData next to profile object, not into profile.
There starts my other problems :) see Meteor.loginWithPassword callback doesn't provide custom object in User accounts doc
PS: If I knew it at begin, I've put systemData object into special collection.

Related

meteorjs meteor-user-status mizzao package: cannot get other users

Trying to implement mizzao/meteor-user-status user status package, but only getting the status for the currently logged in user (me). Others show undefined.
Code in /server folder:
Meteor.publish('userStatus', function() {
return Meteor.users.find({
"status.online": true
});
});
Code in /client folder:
Meteor.subscribe('userStatus');
Template.member.helpers({
isOnline: function(username) {
console.log(username); //gets each username, not just logged me logged in
var currentUser = Meteor.users.findOne({
username: username
});
console.log(currentUser.status.online); //gets undefined for other users other than me
return currentUser.status.online; //returns undefined for other users
}
});
Maybe this needs to reference "userStatus" somehow instead of Meteor.users.findOne(...), but since global object was not created, e.g. like UsersOnline = new Mongdb.Collection - I don't know how to implement this.
Getting error in Chrome debugging tool: TypeError: Cannot read property 'status' of undefined, obviously, it only gets currently logged in user.
Edit: To clarify: I get other users from a custom "profiles" collection in Mongo that I created specifically to overcome the issue of not being able to read "users" collection, due to security, I guess. So I get the list of profiles and supply the user name to this function that supposed to use mizzao package to see if they are online. Since the package reads from "users" collection, it only returns current user (me).
I would be totally OK if I could modify the package for it to write to my "profiles" collection, if someone suggests how to do that.
Another update:
I ran the count on the server, and it returns only one (me, I guess).
var cursor = Meteor.users.find({
"status.online": true
}, {
fields:{
_id: 1,
status: 1,
username: 1
// Any other fields you may need
}
});
console.log(cursor.count());
If you have a publication like this:
Meteor.publish('userStatus', function() {
return Meteor.users.find({
"status.online": true
});
});
it will return users that are online only. So you get undefined for users other than you, because they are not logged-in.
Try logging in as a different user at the same time (i.e. using different browser), and see whether you can now see the status of that user.
You can always change your publication to:
Meteor.publish('userStatus', function() {
return Meteor.users.find({}, {fields: {username : 1, status : 1}});
});
and you will get statuses for all users. But if you only need to check the "online" flag (i.e. you don't need other features of the package), it is better to only send data about the online users and consider not published user as offline.
I guess you trying to read users before subscription is ready.
Server:
Meteor.publish('userStatus', function() {
return Meteor.users.find({
"status.online": true
}, {
fields:{
_id: 1,
status: 1,
profile: 1,
username: 1
// Any other fields you may need
}
});
});
Client (you should return cursor, which will re-run once subscription is ready):
Meteor.subscribe('userStatus');
Template.member.helpers({
isOnline: function(username) {
console.log(username); //gets each username, not just logged me logged in
var cursor = Meteor.users.find({username: username});
if(cursor.count()){
var currentUser = cursor.fetch()[0];
if(currentUser.status && currentUser.status.online){
console.log(currentUser.status.online); //gets undefined for other users other than me
return currentUser.status.online; //returns undefined for other users
}
}
return {};
}
});

Meteor reactive transform

I have a mobile app in development and I'm transforming one of the collections to get the user last seen time, avatar etc.
PlayerRecord.prototype = {
constructor : PlayerRecord,
getAssociatedUser: function () {
return Meteor.users.findOne( this.user_id );
},
lastSeenFormatted: function () {
var user = this.getAssociatedUser();
return (user && user.last_seen) ? user.last_seen : 'Never';
}
}
My problem is that, if the user last seen returns Never initially but then the user is seen, my string return over there is not updated...obviously.
How would you advise me to handle this situation?
Did you check whether any user had a value for last_seen? This field has to be explicitly published.
According to the Meteor docs (http://docs.meteor.com/#/full/meteor_user):
By default, the current user's username, emails and profile are
published to the client. You can publish additional fields for the
current user with:
// server
Meteor.publish("userData", function () {
if (this.userId) {
return Meteor.users.find({_id: this.userId},
{fields: {'last_seen': 1}});
} else {
this.ready();
}
});
// client
Meteor.subscribe("userData");

Why is current user also getting returned after using the $ne

On the server i got this
Meteor.publish('allusersbutme', function () {
// every except the current use
if (Meteor.userId) {
return Meteor.users.find({_id: {$ne: Meteor.userId}}, {fields: {profile: 1, 'services.facebook': 1}});
}
});
on the client I have
Meteor.subscribe('allusersbutme');
Template.discover.helpers(
{
users: function () {
return Meteor.users.find({}).fetch();
}
});
The users helper is still returning the current user. This works if I do return Meteor.users.find({_id: {$ne: Meteor.userId}}).fetch(). This is abit confusing.
You can't use Meteor.userId() inside a publish function, right? I thought you had to use this.userId. Besides, Meteor.userId is a function, so your query is making sure that _id is $ne to a function... which I imagine is always true.
Meteor.publish docs for this.userId: http://docs.meteor.com/#/full/publish_userId

Add extra user field

In my Meteor app I use the default accounts package, which gives me the default login and registration functionality. Now I want to add an extra field to user, say nickname, and for the logged in user the possibility to edit this information.
For editing the profile I suppose I should be doing something like this:
Template.profileEdit.events({
'submit form': function(e) {
e.preventDefault();
if(!Meteor.user())
throw new Meteor.Error(401, "You need to login first");
var currentUserId = this._id;
var user = {
"profile.nickname": $(e.target).find('[name=nickname]').val()
};
Meteor.users.update(currentUserId, {
$set: user
}, function(error){
if(error){
alert(error.reason);
} else {
Router.go('myProfile', {_id: currentUserId});
}
});
}
});
But I doesn't store the info if I look in Mongo. Also when showing the profile, {{profile.nickname}} returns empty. What is wrong here?
Edit: added collections\users.js to show permissions:
Meteor.users.allow({
update: function (userId, doc) {
if (userId && doc._id === userId) {
return true;
}
}
});
Meteor.users.deny({
update: function(userId, user, fieldNames) {
return (_.without(fieldNames, 'profile.nickname').length > 0);
}
});
Yeah, I believe that should do the job, although I haven't actually run the code. The idea is certainly right.
The main things to be aware of are:
The necessity to allow the user doc to be edited from the client with an appropriate Meteor.users.allow() block on the server, assuming you're going to remove the "insecure" package (which you need to before doing anything in production).
The fact that "by default the server publishes username, emails, and profile", so you'll need to write a Meteor.publish function on the server and subscribe to it if you want to expose any other fields within the user document to the client once you've removed the "autopublish" package (which again, you really should).

Cannot access other users' email addresses in Meteor app

Before I begin, I have followed the steps here: Meteor Querying other users by email
And I have read the Meteor documentation about publishing users and how to add more fields than the id, username, and profile. My situation exists in spite of all of these things.
I'm trying to access other user's email addresses, beyond just the currently logged in user. I have 2 templates that need this access. The first template works and is able to access it. The second template is unable to.
Here is the setup code I have for publishing the emails field, and subscribing (I've also tried not specifying 'address' [e.g. fields: {emails: 1}] but that has the same result)
if (Meteor.isServer) {
Meteor.publish("allUsers", function () {
return Meteor.users.find({});
});
Meteor.publish("allUserData", function () {
return Meteor.users.find({}, {fields: {"emails.address": 1}});
});
};
if (Meteor.isClient) {
Meteor.subscribe("allUsers");
Meteor.subscribe("allUserData");
};
Here is the code from the template that works:
Template.createPartner.events({
'click .setup-partner' : function(event, template) {
var partner = Meteor.users.findOne({"emails.address": 'example#mail.com' }); <-- works
}
});
Here is the code from the template that doesn't work:
Template.infoSelect.partnerEmail = function() {
var partnerId = Meteor.user().profile.partnerId; <-- works
var partner = Meteor.users.findOne({_id: partnerId}); <-- works but only _id and profile are returned
return partner.emails[0].address; <-- throws exception because the 'emails' field doesn't exist
};
I've also tried this, but no difference:
var partner = Meteor.users.find({_id: partnerId}, {fields: {"emails.address": 1}});
Why can I not see the user's email address in the second template, but I can in the first?
I think its because you're subscribing to two sets of the same collection. Meteor uses the first subscription and ignores the second. I'm not sure why it works on one occasion though.
If you remove the first subscription and go with the second It should work, basically remove the line:
Meteor.subscribe("allUsers");
One more tip. You could alter your email function to:
Template.infoSelect.partner = function() {
var partnerId = Meteor.user().profile.partnerId; <-- works
var partner = Meteor.users.findOne({_id: partnerId}); <-- works but only _id and profile are returned
return partner;
};
And your handlebar would be : (it just opens up more options for your partner variable so you could reference him/her by name too)
<template name="infoSelect">
{{partner.email.0.address}}
{{partner.profile.name}} <!--If you have configured profiles -->
</template>

Resources