meteor-roles package, adding roles - meteor

Meteor.publish(null, function (){
var users = [ Meteor.users.find({})];
email="Osoba5#qwe.qwe";
if(users == email ){
users = Meteor.this.userId;
Roles.createRole('admin');
Roles.setUserRoles(users, 'admin');
}else{
users = Meteor.this.userId;
Roles.createRole(['']);
Roles.setUserRoles(users,['']);
}
return Meteor.users.find({});
});}
The goal is when creating user there are two user acc one should have admin and the other is normal user without role. But when I sign in with acc who should get admin role I can't do the things I specified for acc with admin role. I'm missing something and I can't figure what, Thank you in advance for any help you can give.

There are multiple mistakes in this code:
Firstly, you are setting users to be equal to an array and then checking if it is equal to a string. This will always return false.
Secondly, Meteor.this.userId, should be this.userId instead.
Thirdly, change this line:
var users = [ Meteor.users.find({})];
to either:
var users = Meteor.users.find({}); // users is a cursor
or:
var users = Meteor.users.find({}).fetch(); // users is an array

Related

Reactive subscription on user collection

I am trying to subscribe to profdle information of a different user than the logged in user, but I am facing issues as mentioned below
I am using angular-material and my code looks like below:
//publish user info upon following user
Meteor.publish("getUserInfo", function (userId) {
return (Meteor.users.find({_id: userId}, {fields: {profile: 1}}));
});
//subscribe
$scope.$meteorSubscribe("getUserInfo", askLikeController.$root.askLike[0].userId).then(function (subscriptionHandle) {
//Second element in the userProfile array will have the profile of required user
askLikeController.$root.usersProfile = $meteor.collection(Meteor.users, false);
});
Issues:
1. In the variable askLikeController.$root.usersProfile, I am getting both the loggedIn user and the desired userinfo having userId, I was expecting userinfo of only desired userId, why is this?
2. The subscription "getUserInfo" is not reactive, and even the subscription is lost after processing few blocks of code and then in the askLikeController.$root.usersProfile I am left with only user profile of logged in user, my guess is that my subscription is being replaced by inbuilt Meteor subscription for user.
How do I solve the issues?
Regards,
Chidan
First, make sure you have removed autopublish:
> meteor remove autopublish
To get reactivity in angular-meteor you need $meteor.autorun and $scope.getReactively. Here's an example:
// we need the requested id in a scope variable
// anytime the scope var changes, $scope.getReactively will
// ... react!
$scope.reqId = askLikeController.$root.askLike[0].userId;
$meteor.autorun($scope, function() {
$scope.$meteorSubscribe('getUserInfo', $scope.getReactively('reqId')));
}).then(function(){
askLikeController.$root.usersProfile = $meteor.collection(Meteor.users, false);
})
Getting only the user you selected: NOTICE- the logged in users is always published. So you need to specify which user you want to look at on the client side, just like you did on the publish method. So, in the subscribe method:
askLikeController.$root.usersProfile = $meteor.collection(function() {
return Meteor.Users.find({_id: $scope.getReactively('reqId')})
}, false);
At this point you might be better off changing it to an object rather than a collection:
askLikeController.$root.usersProfile = $scope.$meteorObject(Meteor.Users, {_id: $scope.getReactively('reqId')});

Accounts.onCreateUser adding extra attributes while creating new users, good practices?

I'm creating new user with Accounts.createUser() and it works normally if you are not doing anything fancy. But I want to add some other fields to new user that are not listed on documentation. Here is my code:
var options = {
username: "funnyUserNameHere",
email: "username#liamg.com",
password: "drowssap",
profile: {
name: "Real Name"
},
secretAttribute: "secretString"
};
var userId = Accounts.createUser(options);
In this example I have added secretAttribute to my options object. Because this is not documented it's just fair it's not adding my attribute under user object.
So I googled and figured out that something like this might work:
Accounts.onCreateUser(function(options, user) {
if (options.secretAttribute)
user.secretAttribute = options.secretAttribute;
return user;
});
And yes! This works, but there is always BUTT.. *BUT.. After this one it's not saving profile anymore under the user object. However this makes it work:
Accounts.onCreateUser(function(options, user) {
if (options.secretAttribute)
user.secretAttribute = options.secretAttribute;
if (options.profile)
user.profile = options.profile;
return user;
});
So what I want from you guys?
I want to know why onCreateUser loses profile (before the fix above) in my case?
Is my approach good practice?
Is there better solution adding extra attributes for user object while creating them?
ps: I thinks it's obvious why I don't want to save all extra fields under profile ;)
Well it wasn't so hard.. Here it stands in documentation: "The default create user function simply copies options.profile into the new user document. Calling onCreateUser overrides the default hook." - Accounts.onCreateUser
Try this:
Accounts.onCreateUser((options, user) => (Object.assign({}, user, options)));
The best thing I found to this issue is:
Accounts.onCreateUser(function(options, user) {
// Use provided profile in options, or create an empty object
user.profile = options.profile || {};
// Assigns first and last names to the newly created user object
user.profile.firstName = options.firstName;
user.profile.lastName = options.lastName;
// Returns the user object
return user;`enter code here`
});
https://medium.com/all-about-meteorjs/extending-meteor-users-300a6cb8e17f

Publication of items where User is in group (Alanning Roles and Publications)

I am using Alanning Roles to maintain a set of groups/roles for the users of my application. When a user creates an "Application", I generate a new role for them as the app_name + UUID, then add that as a group with the roles of Admin to the user that created it. I can then use the combination of the generated group name plus either the Admin or Viewer roles to determine which Applications the user has rights to see and/or edit.
The issue that I am having is that I can't figure out a good way to get the publication to only publish the things the user should see. I know that, by default at least, publications are not "reactive" in the way the client is, and they they are only reactive for the cursors they return. But, in my code I create the group/role first, add it to the user, then save the "Application", which I thought would rerun my publication, but it did not:
Meteor.publish('myApplications', function(groups) {
if (this.userId) {
console.log('Running myApplications publication...');
console.log('Found roles for user ' + this.userId + ': ', Roles.getGroupsForUser(this.userId));
return Applications.find({group: {$in: Roles.getGroupsForUser(this.userId)}});
} else {
//console.log("Skipping null user");
return null;
}
});
But, contrary to what I thought would happen (the whole publication method would re-run), I am guessing what really happens is that only the Cursor is updates. So for my next attempt, I added the mrt:reactive-publications package and simply got a cursor to the Meteor.users collection for the user, thinking that would "trigger" the publication to re-run when the user gets updated with the new group/role, but that didn't work.
I have this finally working by simply passing in the groups for the user:
Meteor.publish('myApplications', function(groups) {
if (this.userId) {
if (!groups || groups.length === 0) {
groups = Roles.getGroupsForUser(this.userId);
}
console.log('Running myApplications publication...');
console.log('Found roles for user ' + this.userId + ': ', Roles.getGroupsForUser(this.userId));
return Applications.find({group: {$in: groups}});
} else {
//console.log("Skipping null user");
return null;
}
});
And then I just call the publication like Meteor.subscribe('myApplications', Roles.getGroupsForUser(Meteor.userId())) in my route's waitOn, but this would mean that any client could call the same publication and pass in any groups they like, and potentially see documents they were not intended to see. That seems like a pretty large security flaw.
Is there a better way to implement this such that the client would not be able to coax their way to seeing stuff not theirs? I think the only real way would be to gather the groups on the publication side, but then it breaks the reactivity.
After sifting through a bunch of docs and a few very helpful stack posts, this is the alternative I came up with. Works like a charm!
My objective was to publish 'guest' users' info to the group admins for approval/denial of enhanced permissions.
Meteor.publish('groupAdmin', function(groupId) {
// only publish guest users info to group admins
if(Roles.userIsInRole(this.userId, ['group-admin'], groupId)) {
// I can't explain it but it works!
var obj = {key: {$in: ['guest']}};
var query = {};
var key = ('roles.' + groupId);
query[key] = {$in: ['guest']};
return Meteor.users.find(query, {
fields: {
createdAt: 1,
profile: 1
}
});
} else {
this.stop();
return;
}
});
Reference: How to set mongo field from variable
& How do I use a variable as a field name in a Mongo query in Meteor?

Meteor assign _id when creating user

I want to assign the _id of meteor user when I create them. Meteor.createUser() doesn't seem to allow this.
Is there another way to go about this?
Accounts.onCreateUser exists on the server to allow customisation of the user doc before it is inserted. The code below modifies the doc, the new user appears in the db, and the user on client gets logged in with customised _id.
//in server js code
Accounts.onCreateUser( function( options, user){
user._id = 'myId' + Math.floor( Math.random() * 1000 ) + 1;
if (options.profile)
user.profile = options.profile; //careful not to drop the profile if it exists
return user;
});
Function documentation and a very similar example are here - http://docs.meteor.com/#accounts_oncreateuser

Meteor.js: Get anonymous visitors unique ID/ip/whatever?

Let's say I'm building an app using meteor.js where I just collect some simple form data from users. Maybe an answer to a simple question or something. They don't need to log in to submit data.
How can I protect my app from someone creating a js-loop in their Chrome Console that just inserts crap into my DB?
I can protect removal and updates by doing this:
Formanswers.allow({
insert: function () {
return true;
},
update: function () {
return false;
},
remove: function () {
return false;
},
});
And if the user was logged in (which as you remember is not the case in my app) I could timestamp each insert and check something like:
insert: function (userId, doc) {
if (userId && (Formanswers.findOnd({userid: userId, time: SOMETHING TIME SPECIFIC}).count() < 1)) return true;
},
So my question is: is there any other way of getting a unique userId-thing or IP-address or something for an anonymous (not logged in) user so I can do the above check on him as well?
Thanks!
You can use a meteorite package.
accounts-anonymous
https://github.com/tmeasday/meteor-accounts-anonymous
So you use
Meteor.loginAnonymously();
if the user visits your page for the first time, and use .allow to check what you need
To get the ip address, the observatory (https://github.com/jhoxray/observatory) project uses this:
in coffee:
Meteor.userIP = (uid)->
ret = {}
if uid?
s = ss for k, ss of Meteor.default_server.sessions when ss.userId is uid
if s
ret.forwardedFor = s.socket?.headers?['x-forwarded-for']
ret.remoteAddress = s.socket?.remoteAddress
ret
Which returns an object like { forwardedFor: '192.168.5.4', remoteAddress: '192.168.5.4' }
Use a session or localStorage key. When the visitor submits the form check if the key has been set, and if it has, reject the insert.
You can do something like this:
if (Meteor.isClient) {
Meteor.startup(function () {
Session.set('currentuser', 'something randomly generated by another function');
}
}
and check if the 'currentuser' already has inserted in your database.

Resources