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
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
},
});
#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 !"
});
}
});
});
});
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');
}
});
});
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
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! :)