Publish which depends on user state - meteor

I have publish method that depends on user state:
Meteor.publish('myGroup', function () {
if (this.userId != null) {
var user = Meteor.users.findOne(this.userId);
return Group.find(user.profile.groupId);
} else {
return [];
}
});
When user state changes (user.profile.groupId), I don't get new data. I can fix it by refreshing the browser.
I was trying to fix that, by making subscription reactive:
Tracker.autorun(function () {
var user = Meteor.user(); // depend on user
if (user != null) {
Meteor.subscribe('myGroup');
}
});
But it doesn't seem to work. What is the best way to solve this problem?

Passing unused parameters seems to be the best workaround:
Meteor.subscribe("myGroup", user.profile.groupId);

Related

insert still works after Meteor.logout

This Meteor app has the insecure and autopublish removed and accounts-password added.
It uses Accounts.createUser({username: someName, password: somePwrd});
It avoids using allow/deny and uses instead Meteor.call to insert documents because reading in the docs, it says that
Server code is trusted and isn't subject to allow and deny restrictions. That includes methods that are called with Meteor.call — they are expected to do their own access checking rather than relying on allow and deny.
But when I fire up the Meteor.logout(), I am still able to insert new documents to Tasks1 collection. How can that be? I though logout will stop inserting any new documents. How can I fix it? Thanks
///////////////////////////
//both/both.js
///////////////////////////
Tasks1 = new Mongo.Collection('tasks1');
///////////////////////////
//server/server.js
///////////////////////////
Meteor.publish('tasks1', function(){
return Tasks1.find({userId: this.userId});
});
Meteor.methods({
addTasks1: function (doc) {
Tasks1.insert(doc);
}
});
///////////////////////////
//client/client.js
///////////////////////////
Template.footer.events({
'click button': function () {
if ( this.text === "SUBMIT" ) {
var inputs = document.getElementsByTagName('input');
for (var i = 0; i < inputs.length; i++) {
var params = {};
params[inputs[i].name] = inputs[i].value;
Meteor.call('addTasks1', params);
}
}
}
});
Template.mainMenu.events({
'click #logout': function () {
Meteor.logout();
}
});
In your server addTasks1 method, you should first check if the user is a user like so:
Meteor.methods({
addTasks1: function(doc) {
if (!Meteor.userId()) {
throw new Meteor.Error("Not Authorized");
} else {
Tasks1.insert(doc);
}
}
})
Logout alone doesn't stop users from being able to insert. You must edit your method code to achieve this.
addTasks1: function (doc) {
if (Meteor.userId()) {
Tasks1.insert(doc);
}
}

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");

Getting a username from ID without autopublish

I just got done with the rough draft of my app, and thought it was time to remove autopublish and insecure mode. I started transfering all the stray update and insert methods I had been calling on the client to methods. But now I'm having trouble returning a username from an ID.
My function before: (that worked, until I removed autopublish)
challenger: function() {
var postId = Session.get('activePost');
var post = Posts.findOne(postId);
if (post.challenger !== null) {
var challenger = Meteor.users.findOne(post.challenger);
return challenger.username;
}
return false;
}
Now what I'm trying:
Template.lobby.helpers({
challenger: function() {
var postId = Session.get('activePost');
var post = Posts.findOne(postId);
if (post.challenger !== null) {
var userId = post.challenger;
Meteor.call('getUsername', userId, function (err, result) {
if (err) {
console.log(err);
}
return result;
});
}
return false;
},
Using:
Meteor.methods({
getUsername: function(userId) {
var user = Meteor.users.findOne({_id: userId});
var username = user.username;
return username;
},
...
})
I have tried blocking the code, returning values only once they're defined, and console.logging in the call-callback (which returned the correct username to console, but the view remained unchanged)
Hoping someone can find the obvious mistake I'm making, because I've tried for 3 hours now and I can't figure out why the value would be returned in console but not returned to the template.
Helpers need to run synchronously and should not have any side effects. Instead of calling a method to retrieve the user, you should ensure the user(s) you need for that route/template are published. For example your router could wait on subscriptions for both the active post and the post's challenger. Once the client has the necessary documents, you can revert to your original code.

Meteor never see's me as looged in

I want to detect if a logged in user has no records in the collection and then start them with some default values. So I use this at the beginning of my isClient part;
if (Meteor.isClient) {
if(Meteor.user()){
Meteor.subscribe('collection');
var currentUserId = Meteor.userId();
if (collection.find({"userID": currentUserId}).count() == 0)
{
Meteor.call('initUser', currentUserId);
}
} else {
console.log("You are not logged in");
}
}
Problem is that it never see's me as logged in. Do I need to be calling this from a template or something? In the tutorial that I did they just had it all by itself.
Your code looks good to me but it does not live in a reactive computation, meaning that it's going to run only once at the beginning of your code and never again, just like regular sequential programming.
You need to surround your code with a Tracker.autorun like this :
if (Meteor.isClient) {
Tracker.autorun(function(){
// Meteor.userId() is a reactive data source that will trigger invalidation
// of the reactive computation whenever it is modified (on login/logout)
var currentUserId = Meteor.userId();
if(currentUserId){
Meteor.subscribe('collection',function(){
if (collection.find({
userID: currentUserId
}).count() === 0){
Meteor.call('initUser', currentUserId);
}
});
} else {
console.log("You are not logged in");
}
}
}
I've refactored it to only use Meteor.userId() because you don't use the currentUser properties in this piece of code.

Meteor accounts framework signed/logged in event

I'm using the accounts-ui package and would like to process some javascript as soon as the user is logged in/and or registered.
Is there an event that gets called as soon as the user signs in?
The raw login API (eg loginWithFacebook, loginWithPassword, etc) has a callback that fires when login is complete, but this is not currently exposed through accounts-ui. This may change.
A potential workaround, inspired by Werner's suggestion, but also taking page load into account:
var oldUserId = undefined;
Meteor.autorun(function() {
var newUserId = Meteor.userId();
if (oldUserId === null && newUserId) {
console.log('The user logged in');
} else if (newUserId === null && oldUserId) {
console.log('The user logged out');
}
oldUserId = Meteor.userId();
});
You could check the result of the Meteor.userId() function inside Meteor.autorun():
Meteor.autorun(function() {
if (Meteor.userId()) {
console.log('The user logged in');
}
});
Just to give an alternative; I monkey patched the callback function. It looks a bit more complex because the credentialRequestCompleteHandler requires a function that returns a function but besides that its a plain monkey patch. Stick this in main.js or something that gets processed late and only once. I hope it helps for future reference.
var orgCallback = Accounts.oauth.credentialRequestCompleteHandler;
Accounts.oauth.credentialRequestCompleteHandler = function(callback){
return function (credentialTokenOrError) {
var tmpFunc = orgCallback(callback);
tmpFunc(credentialTokenOrError);
alert("do your own thing here");
}
}

Resources