Autopublish removed but why can I still retrieve data from db? - mongodb

I have a simple Meteor/MongoDB project using the 'roles' package where I optain data from the db to the client. The roles package seems to work fine and the browser shows the right data depending on who is logged in, just like it should do. Then when running 'meteor remove autopublish' in the terminal inside my applications directory I get 'autopublish removed' just like it should. Still I can retrieve data from the server just as before(!?)
I have all of my db calls from the client/client.js.
The server/server.js does nothing (I do have publish/subscribe code but uncomment for now) and same goes for the common js file in main directory.
How can this be? Am I perhaps retrieving data from minimongo somehow? I have also removed insecure even if I don't think that matters in this case(?) Thanks in advance.
EDIT: Here's the code:
client.js:
//when uncomment the subscribe's you should not get access to the server/db, but 'data' that holds all the inlogg info still shows. The 'movies' on the other hand doesn't, just like it shouldn't.
//Meteor.subscribe('data');
//Meteor.subscribe('movies');
/*############# Get User Data ###############*/
Template.userLoggedIn.id = function () {
return Meteor.userId();
};
Template.userLoggedIn.email = function () {
var email = Meteor.users.findOne({_id: Meteor.userId()});
return email.emails[0].address;
};
Template.userLoggedIn.profile = function () {
var profile = Meteor.users.findOne({_id: Meteor.userId()});
return profile.profile.name;
};
Template.userLoggedIn.role = function () {
var role = Meteor.users.findOne({_id: Meteor.userId()});
return role.roles[0];
};
/*############# ###############*/
Template.movies.movies = function() {
var movies = Movies.find().fetch();
return movies;
}
server.js:
Meteor.publish('data', function () {
return Meteor.users.find();
});
Meteor.publish('movies', function() {
return Movies.find();
});

Thanks for providing the code - I see how this could be confusing. The users section of the docs should be written to explicitly say this, but what's happening is the current user is always published. So even if you don't write a publish function for users (or your have your subscribe commented out), you should expect to see the current user on the client. Because your template code only looks for Meteor.userId(), I would expect it to still work.
Assuming you have other users in the database, you can quickly check that they are not being published by running: Meteor.users.find().count() in your browser console. If it returns 1 then you are only publishing the current user (or 0 if you are logged out).

Related

How do I remove a user in mongoDB from the terminal by username?

My question is this: How can I remove a user from the users db by username, or at all even?
I have a meteor application with a custom registration, and when an account is created you can login and manage your account and what have you.. My problem is that, on the local host for testing, I created a few extra user accounts that I want to delete individually (not a complete reset). I am on OS X so I went to terminal, typed in 'show dbs' but users came up empty and when I typed 'show users' nothing came up. If I type 'db.users.findOne()' information appears and I can get a username and _id. I know there is users and this command shows that there is at least one but the rest of the commands indicate that I can't manage them.
Below is some code for the registration page, specifically the Accounts.createUser I'm not sure it will mater for the response but I wanted to be thorough.
Template.SignUp.events({
'submit form': function(event, template){
event.preventDefault();
var UsernameVar = template.find('#username').value;
var emailVar = template.find('#Email').value;
var passwordVar = template.find('#password').value;
var ConfirmPasswordVar = template.find('#Cpassword').value;
if(ConfirmPasswordVar == passwordVar)
{
document.getElementById("NotValid").style.display = 'none';
Accounts.createUser({
username: UsernameVar,
email: emailVar,
password: passwordVar
}, function(err, result){
if(err)
{
document.getElementById("Unavailable").style.display = 'block';
}
else{
document.getElementById("Unavailable").style.display = 'none';
}
});
}
else{
document.getElementById("NotValid").style.display = 'block';
}
}
});
I've done a lot of searching on this issue and all I've found is how to grant users the right to remove profiles but I want to do it from terminal, even when the application launches I will be the only one to be using this feature so I don't want to start giving those rights to users.
If there is anything else I should provide please let me know.
meteor mongo
db.users.find({username: "someusername"}) // ensure that your query returns the correct user that you want to remove
db.users.remove({username: "someusername"})

Meteor - no more callbacks for "findOne" function

i'm working on a Meteor project, and I must say that isn't easy at all, especially for one thing: callbacks !
Everything is async, so I wonder how do I must do to get results from my mongodb.
var user = Meteor.users.findOne({username: "john"});
return (user); // sometimes returns "undefined"
...
var user = Meteor.users.findOne({username: "john"});
if (user) // so ok, I check if it exists!
return (user); // Cool, I got my user!
return (); // Ok and what should I return here? I want my user!
I don't want to be dirty and put like setTimeout everywhere.
Anybody has a solution for this ?
EDIT :
I noticed in router.js with console.log that my data is returned 4 times. 2 times with an undefined value and 2 other times with the expected value. In the view, it's still undefined.
Why the router passes like 4 times in this route ? Does it display the first result of the return value in the router ?
What should I return if the find() doesn't find anything ?
EDIT 2: Here is some code to understand.
this.route('profilePage', {
path: 'profil/:_id?',
waitOn: function() {
return [
Meteor.subscribe('article', { prop: this.params._id}), // id can be id or username
Meteor.subscribe('article', { userId: this.params._id}), // id can be id or username
Meteor.subscribe('params'),
Meteor.subscribe('profil', (this.params._id ? this.params._id : Meteor.userId()))
];
},
data: function() {
if (this.params._id) {
var user = Meteor.users.findOne(this.params._id);
if (!user)
user = Meteor.users.findOne({username: this.params._id});
console.log(user);
return user;
}
else if (Meteor.userId())
return Meteor.user();
else
Router.go("userCreate");
}
});
I get this on the console:
http://puu.sh/debdJ/69419911f7.png
(text version following)
undefined
undefined
Object_id: "o3mgLcechYTtHPELh"addresses: (....)
Object_id: "o3mgLcechYTtHPELh"addresses: (....)
findOne(yourId) is a sync method which is equivalent to find({ _id: yourId}, callback). The difference is that find() allows you to define a callback. If you don't pass a callback to find() this method will be sync.
check wrapAsync: http://docs.meteor.com/#/full/meteor_wrapasync
It allows you to code in a sync style with a async operations.
Free lesson on EventedMind: https://www.eventedmind.com/feed/meteor-meteor-wrapasync
My experience thus far is that the Meteor Mongodb package is that the functions do not generally provide callbacks (for some reason insert does...), the functions are atomic (thus sync).
There are meteor packages that can make Mongodb async if you want (I havn't tried any).
I guess this sync approach is in line with the simple maintenance goal of Mongodb. Thinking about it, one of my pet peeves using Node is working with async callback waterfalls/nests, they are a pain to create and maintain... and hopefully this will make my code easier to read and understand and change...
var future = new Future();
var _h = Hunts.findOne({huntId});
if(_h) {
future.return(_h)
} else {
return future.wait();
}
on server/startup.js you need:
Future = Npm.require('fibers/future');

Why am I getting this 'undefined' error?

I'm working on a Meteor project, and for some reason this profile template refuses to work.
I'm using the following code, as well as the accounts-password and accounts-entry packages for user management:
this.route('profile', {
path: '/profile/:username',
data: function() {
var userDoc = Meteor.users.findOne({"username": this.params.username});
var bookCursor = Books.find({owner: userDoc._id});
return {
theUser: userDoc,
theBooks: bookCursor
};
}
});
When I try to go to the profile URL for my test accounts ('misutowolf', and 'test2', respectively), I am given the following error in Chrome's dev console: Exception from Deps recompute function: TypeError: Cannot read property '_id' of undefined, pointing to the use of userDoc._id in the call to Books.find().
This makes no sense whatsoever, as I was able to find a user document with the names in question using meteor mongo with both usernames, in the form db.users.find({username: "misutowolf"}) and db.users.find({username: "test2"}).
I am very confused, not sure what is causing this issue at all.
By default Meteor only publish the currently logged in user info via an automatically setup publication.
What you need to do is push to the client the user info (username) you're trying to use, because if you don't do that, the user you're accessing is not published to the client and you get an undefined error when accessing its _id.
First, setup a dedicated publication (on the server) :
Meteor.publish("userByUsername",function(username){
return Meteor.users.find({
username:username
});
});
Then waitOn this publication in your route :
waitOn:function(){
return this.subscribe("userByUsername",this.params.username);
}
Finally, guard against accessing the user document until it is pushed to the client because even if you are waiting on the subscription, the data method might actually get called even if the subscription is not ready yet.
data: function() {
var userDoc = Meteor.users.findOne({"username": this.params.username});
if(!userDoc){
return;
}
// ...
}

Updating MongoDB in Meteor Router Filter Methods

I am currently trying to log user page views in meteor app by storing the userId, Meteor.Router.page() and timestamp when a user clicks on other pages.
//userlog.js
Meteor.methods({
createLog: function(page){
var timeStamp = Meteor.user().lastActionTimestamp;
//Set variable to store validation if user is logging in
var hasLoggedIn = false;
//Checks if lastActionTimestamp of user is more than an hour ago
if(moment(new Date().getTime()).diff(moment(timeStamp), 'hours') >= 1){
hasLoggedIn = true;
}
console.log("this ran");
var log = {
submitted: new Date().getTime(),
userId: Meteor.userId(),
page: page,
login: hasLoggedIn
}
var logId = Userlogs.insert(log);
Meteor.users.update(Meteor.userId(), {$set: {lastActionTimestamp: log.submitted}});
return logId;
}
});
//router.js This method runs on a filter on every page
'checkLoginStatus': function(page) {
if(Meteor.userId()){
//Logs the page that the user has switched to
Meteor.call('createLog', page);
return page;
}else if(Meteor.loggingIn()) {
return 'loading';
}else {
return 'loginPage';
}
}
However this does not work and it ends up with a recursive creation of userlogs. I believe that this is due to the fact that i did a Collection.find in a router filter method. Does anyone have a work around for this issue?
When you're updating Meteor.users and setting lastActionTimestamp, Meteor.user will be updated and send the invalidation signal to all reactive contexts which depend on it. If Meteor.user is used in a filter, then that filter and all consecutive ones, including checkLoginStatus will rerun, causing a loop.
Best practices that I've found:
Avoid using reactive data sources as much as possible within filters.
Use Meteor.userId() where possible instead of Meteor.user()._id because the former will not trigger an invalidation when an attribute of the user object changes.
Order your filters so that they run with the most frequently updated reactive data source first. For example, if you have a trackPage filter that requires a user, let it run after another filter called requireUser so that you are certain you have a user before you track. Otherwise if you'd track first, check user second then when Meteor.logginIn changes from false to true, you'd track the page again.
This is the main reason we switched to meteor-mini-pages instead of Meteor-Router because it handles reactive data sources much easier. A filter can redirect, and it can stop() the router from running, etc.
Lastly, cmather and others are working on a new router which is a merger of mini-pages and Meteor.Router. It will be called Iron Router and I recommend using it once it's out!

titanium - get the facebook user name?

Using titanium, does anybody have some simple instructions to get the user's facebook name, once signed into facebook?
you don't need to do any of this, the username is provided in the data response after the login is done.
Look at the appcelerator documentation
I haven't tested the code but you can try this:
var fbuid = Titanium.Facebook.uid; //this would be the logged user's facebook uid
function fQuery() //this function exec the fql query
{
var myQuery = "SELECT name FROM user WHERE uid = "+fbuid;
var data = [];
Titanium.Facebook.request('fql.query', {query: myQuery}, function(x)
{
var results = JSON.parse(x.result);
var username = results[0].name; //user's fb name
});
};
Ah, here is how you do it:
function getFacebookInfo(){
Titanium.Facebook.requestWithGraphPath('me', {}, 'GET', function(e){
if (e.success){
var jsonObject = JSON.parse(e.result);
//do something here with these values. They cannot be passed out of this
//function call... this is an asynchronous call
//that is, do this:
saveToDb(jsonObject.first_name);
} else {
//some sort of error message here i guess
}
});
};
Finally, along with name and username, check out the facebook page for the other variables you can get -
http://developers.facebook.com/docs/reference/api/
FINALLY: be aware that this is a callback, and titanium won't actually wait for this call to finish. That is, any variable declared to hold the results the returned after the requestWithGraphPAth will immediately return, and as a result almost always be empty.
I guess you could make a nifty loop that just... loops until some variable is set to false. And you'd set the variable to false in the callback... but that seems dodgy.
Just make your call back do everything else, that is, save to the db etc etc
If you do go the route of calling Ti.Facebook.authorise() to log in the user, remember to define
Ti.Facebook.addEventListener('login',function(e){
if (e.success){
...
...
} else if (e.error){ } else if (e.cancel) { }
}
before the call. And then, in the success bit, you can make a requestWithGraphPath call and so on. I just save all the details to the database and retrieve them each time after that, works fine for me!