Meteor userId is always null - meteor

This Meteor app has the insecure and autopublish removed and accounts-password added.
meteor:PRIMARY> db.users.find({}); also shows the presence of the only user credentials I used.
Invoking Meteor.call('addTasks1',params); throws the error, further checks show Meteor.userId() being null
Why is that and how to fix it? Thanks
update
As per the suggested fix by Stephen Woods;
When I change the method addTasks1 on the server from Meteor.userId() to this.userId, It still throws the error.
///////////////////////////
// both/both.js //
///////////////////////////
Tasks1 = new Mongo.Collection('tasks1');
///////////////////////////
// client/client.js //
///////////////////////////
Template.login.events({
'click #logMe': function() {
var credentials = [$('#id').val(), $('#pin').val()];
Meteor.call('logMeIn', credentials);
}
});
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);
}
}
}
});
///////////////////////////
// server/server.js //
///////////////////////////
Meteor.methods({
logMeIn: function (credentials) {
Accounts.createUser({username: credentials[0], password: credentials[1]});
}
});
Meteor.publish('tasks1', function(){
return Tasks1.find({userId: this.userId});
});
Meteor.methods({
addTasks1: function (doc) {
if (Meteor.userId()) {
Tasks1.insert(doc);
} else {
throw new Meteor.Error("Not Authorized");
}
}
});

You need to log the user in, use Meteor.loginWithPassword(<USERNAME>, <PASSWORD>) on the client side to log a created user in.
Also, addTasks1, your Meteor method, is executing on the server. You want to use this.userId instead of Meteor.userId() on the server.

Related

Using Meteor.wrapAsync to wrap a callback inside a method

This Meteor code is giving the error:
Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.
I tried Meteor.bindEnvironment for no avail and want to try Meteor.wrapAsync. I could not figure it out from the docs. Could some one please help me with the syntax? thx
Meteor.methods({
'createTransaction':
function (nonceFromTheClient, Payment) {
let user = Meteor.user();
gateway.transaction.sale(
{
arg_object
},
function (err, success) {
if (!err) {
//do stuff here
}
}
);
}
});
Wrap in Meteor.wrapAsync
Meteor.methods({
'createTransaction':
function (nonceFromTheClient, Payment) {
this.unblock();
let user = Meteor.user();
var sale = Meteor.wrapAsync(gateway.transaction.sale);
var res = sale({arg_object});
future.return(res);
return future.wait();
}
});
Or try wrapping it in Fiber
var Fiber = Npm.require('fibers');
Meteor.methods({
'createTransaction': function (nonceFromTheClient, Payment) {
Fiber(function() {
let user = Meteor.user();
gateway.transaction.sale(
{
arg_object
},
function (err, success) {
if (!err) {
//do stuff here
}
}
);
}).run()
}
});
Update: Here's how I handle stripe with Async.runSync and Meteor.bindEnvironment
var stripe = require("stripe")(Meteor.settings.private.StripeKeys.secretKey);
Meteor.methods({
'stripeToken': function() {
this.unblock();
var future = new Future();
var encrypted = CryptoJS.AES.encrypt(Meteor.userId(), userIdEncryptionToken);
future.return(encrypted.toString());
return future.wait();
},
'stripePayment': function(token) {
var userId = Meteor.userId();
var totalPrice = 0;
//calculate total price from collection
totalPrice = Math.ceil(totalPrice * 100) / 100;
userEmail = Meteor.users.findOne({
'_id': userId
}).emails[0].address;
// Create a charge: this will charge the user's card
var now = new Date();
Async.runSync(function(done) {
var charge = stripe.charges.create({
amount: Math.ceil(totalPrice * 100), // Amount in cents // coverting dollars to cents
currency: "usd",
source: token,
receipt_email: userEmail,
description: "Charging"
}, Meteor.bindEnvironment(function(err, charge) {
if (err) {
//handle errors with a switch case for different errors
done();
} else {
//handle res, update order
}
}));
}); // Async.runSync
},
});

Meteor observe changes added callback

#DavidWeldon I tried your code (Meteor observe changes added callback on server fires on all item) and it's very good thank you !
However I would like to have your advise : I use it for desktop notifications : when i get one notification, there is one console log (ok), but when i get another notification (total : 2), there are two console log (I want only one console log because there is only a +1 notification)
Here is my code :
if (Notification.permission !== "granted")
Notification.requestPermission();
var query = Notifications.find({userId: Meteor.userId(), read: false});
(function() {
var initializing = true;
query.observeChanges({
added: function(id, notification) {
if (!initializing) {
console.log(notification);
}
}
});
initializing = false;
})();
Thank you for your help ! :)
You could use another flag in there?
if (Notification.permission !== "granted")
Notification.requestPermission();
var query = Notifications.find({userId: Meteor.userId(), read: false});
(function() {
var initializing = true;
var firstNotif = true;
query.observeChanges({
added: function(id, notification) {
if (!initializing && firstNotif) {
firstNotif = false;
console.log(notification);
}
}
});
initializing = false;
})();
Finally I found an answer, exploring this post in discover meteor : https://www.discovermeteor.com/blog/template-level-subscriptions/
(in my question, I was working in Template.notifications.helpers)
Here's my new code :
Template.notifications.onCreated(function () {
if (Notification.permission !== "granted")
Notification.requestPermission();
var instance = this;
instance.autorun(function () {
var query = Notifications.find({userId: Meteor.userId(), read: false});
query.observeChanges({
added: function(id, notification) {
var notification = new Notification('Notification', {
icon: '',
body: "You got a new notification !"
});
}
});
});
});

Meteor Router with Meteor call

I having trouble to validate a user with a Meteor.call on Router. Only return "undefined" pr
"Exception in delivering result of invoking 'verifyUserRole':
TypeError: undefined is not a function"
Router.route("/admin", function(){
Meteor.call("verifyUserRole", function(error, result){
if(result){
this.render('adminDashboard');
this.layout("adminLayout");
} else {
this.render('adminLogin');
}
})
});
Meteor.methods({
"verifyUserRole" : function(){
if(this.userId){
var user = Meteor.user();
var role = user.profile.role;
if(role == "admin"){
return true;
} else {
Session.set("adminLoginError", "Restrict Area");
return false;
}
}
}});
The value of this is referring to your inner function instead of your outer function. Try the following:
Router.route("/admin", function(){
var self = this;
Meteor.call("verifyUserRole", function(error, result){
if(result){
self.render('adminDashboard');
self.layout("adminLayout");
} else {
self.render('adminLogin');
}
});
});

Weird undefined error on server

I have the following meteor method
hasNoPendingPayments: function() {
var userId = Meteor.userId();
console.log(userId); <---------------------- correctly logs userId
var user = Users.findOne({_id: userId }, { fields: { services: 0 } });
console.log(user); <-------------------------- logs 'undefined'
return hasNoPendingPayments(user);
},
This private helper I call from the above
hasNoPendingPayments = function(user) {
// console.log('hasNoPendingPayments ');
// console.log(user);
var payments = Payments.find({ userId: user._id, status: {
$in: [Payments.States.PENDING, Payments.States.PROCESSING]}
});
return payments.count() === 0;
};
And I call it from the client here
Template.payments.created = function() {
this.hasNoPendingPayments = new ReactiveVar(false);v
};
Template.payments.rendered = function () {
Session.set('showPaymentRequestForm', false);
var self = this;
Meteor.call('hasNoPendingPayments', function(error, result) {
if (result === true) { self.hasNoPendingPayments.set(true); }
});
...
However, I get an undefined error on the server when I load the template initially (I marked where in code). Although, when I try call the same query on the client with the same userId, i correctly gets the user record
Any idea as to why this is?
Try with this.
Template.payments.rendered = function () {
Session.set('showPaymentRequestForm', false);
var self = this;
if(Meteor.userId()){
Meteor.call('hasNoPendingPayments', function(error, result) {
if (result === true) { self.hasNoPendingPayments.set(true); }
});
}else{
console.log("Seems like user its not logged in at the moment")
}
Maybe when you make the Meteor.call, the data its not ready
Also just to be sure, when you run Users.findOne({_id: userId }, { fields: { services: 0 } }); on console.log what you get?
Maybe the find is wrong or have some typo
update
Router.map(function()
{
this.route('payments',
{
action: function()
{
if (Meteor.userId())
this.render();
} else{
this.render('login') // we send the user to login Template
}
}
}
or waitOn
Router.map(function () {
this.route('payments', {
path: '/payments',
waitOn: function(){
return Meteor.subscribe("userData"); //here we render template until the subscribe its ready
}
});
});
Meteor stores all the user records in Meteor.users collection
so try Meteor.users.findOne({_id: userId }....)
Instead of Users.findOne({_id: userId }, { fields: { services: 0 } });
in your server method

Meteor External API calls works but client gets Undefined

Client Side:
Template.storeInfo.events({
'click #btn-user-data': function(e) {
Meteor.call('callApi', function(err, data) {
$('#result').text(JSON.stringify(data, undefined, 4));
console.log(data); //Not working!!
});
}
});
Server Side:
storeApi.prototype.retrieve = function(endpoint) {
try {
var gotiye = HTTP.get(endpoint);
console.log(gotiye); //Works!
return gotiye;
} catch (err) {
throw new Error("Failed to fetch call GET retrieve from store. " + err.message);
}
};
storeApi.prototype.getStoreInfo = function() {
var url = this.rootApiUrl.replace(this.endpointToken,
this.endpoints.store);
this.retrieve(url);
};
Meteor.methods({
callApi: function() {
var stnvy = new storeApi(Meteor.user().services.store.accessToken);
var data = stnvy.getStoreInfo();
return data;
}
});
Why it works on server side but impossible to use in client side? Is collection the only way to use this?
Forgot to return it at getStoreInfo function return this.retrieve(url); and it works! :)

Resources