Meteor & account-base - how to get data for different users - meteor

I have basic project in Meteor created from Meteor-admin stub: (https://github.com/yogiben/meteor-admin)
I need to display avatars for all users, not only current one.
For displaying user's avatar I need his email address. (I am using utilities:avatar https://atmospherejs.com/utilities/avatar)
Question: what adjustments to project should I make to be able to access other users' data?
It probably has something to do with publishing users.
At the moment I have:
{{> avatar user=getAuthor shape="circle" size="small"}}
getAuthor: ->
console.log 'Owner:'
console.log #owner
user = Meteor.users.findOne(#owner)
console.log user
user
This correctly prints Owner: #owner (id) for all users, but user object is only populated for current user.
I also have this code in server-side:
Meteor.publishComposite 'user', ->
find: ->
Meteor.users.find _id: #userId
children: [
find: (user) ->
_id = user.profile?.picture or null
ProfilePictures.find _id: _id
]
(children / ProfilePicture are irrelevent)
I think account-base library turns publishing off or something? Thanks for help!
Bonus question: I would like to access only some info about an user (email address).

If you remove the package autopublish, you need to specify explicitly what the server sends to the client. You can do this via Meteor.publish and Meteor.subscribe.
For instance, to publish the email addresses of all users you could do:
if (Meteor.isServer) {
Meteor.publish('emailAddresses', function() {
return Meteor.users.find({}, {
fields: {
'email': 1
}
});
});
}
After that, you need to subscribe to the publication on the client:
if (Meteor.isClient) {
Meteor.subscribe("emailAddresses");
}
Read more about Meteor's publish and subscribe functionality.

Having collection: Meteor.users
To access other users data just publish it on the server-side:
Meteor.publish 'userData', ->
Meteor.users.find()
On client side you don't have to use any userData reference. Just access it:
Meteor.users.findOne(someId)
To allow access to only specific information, publish it with fields parameter:
Meteor.publish 'userData', ->
Meteor.users.find({},{fields: {'_id', 'emails', 'username'}})

Related

How to check Item exists in Firebase Database? - react-native-firebase

Currently, I am using https://github.com/invertase/react-native-firebase for my project. I have a custom database for users and I want to check if the user exists or not by email.
Here is a screenshot of the database:
Here's a generic firebase method but you may need to reconfigure the method to suit your data structure. Please refer to the official docs if you wish to know more.
firebase.database()
.ref(`/users`)
.orderByChild("email")
.equalTo(email)
.once("value")
.then(snapshot => {
if (snapshot.val()) {
// data exist, do something else
}
})
You can also query the registration status with hasChild method. Refer to your root path and query with .once and check the result returned.
export function checkUserExist(email) {
return(dispatch) => {
firebase.database().ref(`/ExistingUser/`)
.once('value', snapshot => {
if(snapshot.hasChild(email)) {
dispatch({
type: FIREBASE_USER_EXISTED
});
} else {
dispatch({
type: FIREBASE_USER_NOT_EXISTED,
});
}
});
}
}
Another preferred method would be using the fetchProvidersForEmail method provided by Firebase. It takes an email and returns a promise that resolves with the list of providers linked to that email if it is already registered, refer here.
Is there a good reason to store users credential in your database? In my daily practice, I would use the createUserWithEmailAndPassword provided by Firebase for security purposes, refer here. Just make sure rules are defined properly to prevent unauthorized access.

Meteor: publish some user data

I want to publish some limited user information about my users, the idea is that the admin role of my web app can view the emailaddress and username (last one is in the profile data).
Meteor.publish("usersSpecificDataforAdmin", function () {
return Meteor.users.find({}, {fields: {
'profile': 1,
'emails': 1,
'roles': 1
}});
});
I'm then subscribing to this in my router:
adminRoutes.route('/users', {
name: 'adminUsersList',
subscriptions: function (params, queryParams) {
this.register('adminUsersList', Meteor.subscribe('usersSpecificDataforAdmin'));
},
action: function (params, queryParams) {
BlazeLayout.render('layout_frontend', {
top: 'menu',
main: 'adminUsersList',
footer: 'footer'
});
}
});
In the template, I'm using the following to display the email address of the user: '{{emails.address}}', but that doesn't work. I can display all other info.
I have following questions:
how can I display the email address of the user in the template
even when I don't add the password or services fields in the publishing, it is send to the client (doing Meteor.user()) is revealing all the info, including passwords etc, which is a security issue in my opinion. How can I disable the publication of this?
Several things:
You don't need to include _id in the list of fields to be published, it is always included
You're publishing allUserData but your router code is subscribing to usersAllforAdmin which you're not showing code for. I suspect that publication is including services
Passwords are not stored anywhere in Meteor, only the bcrypt hash of the password is stored in services
emails is an array, you can't access it with {{emails.address}} in spacebars, instead use {{emails.[0].address}} (reference)

Publishing different data for different users

I'm trying to publish all users to admins only but ommitting certain data (In this case an API key which is supposed to be "private" to each user, I realize that the admin can most likely check the database but let's ignore the security implications for now).
So the basic idea is that a user can see his own profile completely and no one else. An admin can see his own complete profile and a censored version of all other user's profiles. For this I have the following publish code:
Meteor.publish('currentUser', function() {
return Meteor.users.find({_id: this.userId}, {fields: {'profile.apiKey': true}});
});
Meteor.publish('allUsers', function() {
var currentUser = Meteor.users.findOne(this.userId);
return currentUser && currentUser.profile.admin ?
Meteor.users.find({}, {sort: ['username', 'asc'], fields: {'profile.apiKey': false}}) : null;
});
The problem is that the apiKey field doesn't get published after logging in. Ie. if I simply login as an admin the admin's apiKey won't be available until the page is reloaded. Removing the restriction from the 'allUsers' publish function solves the issue so it must have something to do with this. Is there any way to force Meteor to reload the subscriptions after a login?

How do you delete user accounts in Meteor?

The only way I have found to delete user accounts in meteor (other than emptying the database with mrt reset), is by actually logging into that specific user account, and deleting the account from the console, using:
Meteor.users.remove('the user id');
But like I said, I need to be logged in as that specific user, and have not been able to find a solution which enables me to delete any user from the db. I'm sure it has something to do with permissions or roles, but I am not sure how to proceed / what is the best solution / how to set an administrative role for a particular user, so that I can delete different user accounts.
You could do
meteor mongo
or
meteor mongo myapp.meteor.com for a deployed app
Then
db.users.remove({_id:<user id>});
I wouldn't recommend it but if you want to delete any user without being logged in from meteor you would need to modify the allow rules. But deleting a user is a very unlikely event hence the above might be the best way to do it.
Anyway if you do want, modify the Meteor.users.allow({remove:function() { return true }); property. See http://docs.meteor.com/#allow. You could add in some custom logic there so it'll only let you do so if you're the admin
I was having trouble doing this on nitrous.io because I couldn't open both Meteor and Mongo. I put:
Meteor.users.remove(' the _id of the user ');
in the isServer section to remove the user.
If anyone is still looking for an answer to this question, I have outlined my solution below.
When I create a new user, I add a field called role in my user document. If I want a user to be able to remove other users from the Meteor.users collection, I give him a role of administrator. If not, I give him a role of member. So, my user document looks something like this -
{
"_id" : ...,
"createdAt" : ...,
"services" : {...},
"username" : "test",
"profile" : {
"name" : "Test Name",
"role" : "administrator"
}
}
On the client, I have a list of users (added using a #each template tag) with a remove button next to each user. A user has to login to see this list. I defined an event handler for the remove button -
'click #remove-user-btn': function () {
Meteor.users.remove({ _id: this._id }, function (error, result) {
if (error) {
console.log("Error removing user: ", error);
} else {
console.log("Number of users removed: " + result);
}
})
}
However, Meteor.users does not allow remove operations from the client by default. So, you have to edit the Meteor.users.allow callback in the server as shown below to allow the users to be removed from the client side. But we need to make sure that only a user with an administrator role is allowed this privilege.
Meteor.users.allow({
remove: function (userId, doc) {
var currentUser, userRole;
currentUser = Meteor.users.findOne({ _id: userId }, { fields: { 'profile.role': 1 } });
userRole = currentUser.profile && currentUser.profile.role;
if (userRole === "administrator" && userId !== doc._id) {
console.log("Access granted. You are an administrator and you are not trying to delete your own document.");
return true;
} else {
console.log("Access denied. You are not an administrator or you are trying to delete your own document.");
return false;
}
},
fetch: []
});
This is the general idea. You can build upon this to suit your needs.
Here are the steps to delete user from mongo through console:
step 1: open new console
step 2: change diretory to your app such as (cd myapp)
step 3 : enter command meteor mongo
step 4: make sure there exists a table called users, db.users.find({});
step 5: find the userid of the user you wish to delete and type :
db.users.remove({_id:"nRXJCC9wTx5x6wSP2"}); // id should be within quotes

How can I create users server side in Meteor?

In the new Meteor auth branch how can I create users server side?
I see how to create them client side with the call to
[Client] Meteor.createUser(options, extra, callback)
But suppose I want to create a Meteor user collection record on startup?
For example, the Administrator account during startup/bootstrapping for an application?
Thanks
Steeve
On newer versions of meteor use
Accounts.createUser({
username: username,
email : email,
password : password,
profile : {
//publicly visible fields like firstname goes here
}
});
note: the password hash is generated automatically
On older versions of meteor use:
1 - NB: DO YOU HAVE THE REQUIRED PACKAGES INSTALLED ?
mrt add accounts-base
mrt add accounts-password
On some versions of meteor you cannot call SRP password salt generator as Steeve suggested, so try this:
2 - do Meteor.users.insert( )
e.g.
var newUserId =
Meteor.users.insert({
emails: ['peter#jones.com'],
profile : { fullname : 'peter' }
});
note: a user must have EITHER a username or an email address. I used email in this example.
3 - Finally set the password for the newly created account.
Accounts.setPassword(newUserId, 'newPassword');
Probably it's a well known fact now, but for the sake of completing this - there's a new server API for doing this on the auth branch. From the docs on auth:
" [Server] Meteor.createUser(options, extra) - Creates a user and
sends that user an email with a link to choose their initial password
and complete their account enrollment
options a hash containing: email (mandatory), username (optional)
extra: extra fields for the user object (eg name, etc). "
Please note the API is subject to change as it's not on the master branch yet.
For now this has been suggested in the meteor-core google group.
Meteor.users.insert({username: 'foo', emails: ['bar#example.com'], name: 'baz', services: {password: {srp: Meteor._srp.generateVerifier('password')}}});
It works. I tested it in during startup/boot strap.
I would not consider this the permanent or long term answer because I believe the auth branch is still in a great degree of change and I imagine the team behind Meteor will provide some kind of functionality for it.
So, do not depend on this as a long term answer.
Steeve
At the moment, I believe you cannot. Running
Meteor.call('createUser', {username: "foo", password: "bar"});
comes close, but the implementation of createUser in passwords_server.js calls this.setUserId on success, and setUserId cannot be called on the server unless we're in a client-initiated method invocation (search for "Can't call setUserId on a server initiated method call" in livedata_server.js.
This does seem like something worth supporting. Perhaps the last three lines of createUser, which log the user in, should be controlled by a new boolean login option to the method? Then you could use
Meteor.call('createUser', {username: "foo", password: "bar", login: false});
in server bootstrap code.
I've confirmed that the following code in my server/seeds.js file works with the most recent version of Meteor (Release 0.8.1.1)
if (Meteor.users.find().count() === 0) {
seedUserId = Accounts.createUser({
email: 'f#oo.com',
password: '123456'
});
}
Directory (or folder) of server means I'm running the code on the server. The filename seeds.js is completely arbitrary.
The official documentation now describes both the behavior for Accounts.createUser() when run on the client and when run on the server.
Working coffeescript example for Meteor version 1.1.0.2 (server side):
userId = Accounts.createUser
username: 'user'
email: 'user#company.com'
password: 'password'
profile:
name: 'user name'
user = Meteor.users.findOne userId
I struggled for some time with this API getting 'User already exists' exception in working code before adding profiles.name to the options and exception disappeared.
reference: Accounts.createUser(options,[callback])
Create user from server side
// Server method
Meteor.methods({
register: function(data) {
try {
console.log("Register User");
console.log(data);
user = Accounts.createUser({
username: data.email,
email: data.email,
password: data.password,
profile: {
name: data.email,
createdOn: new Date(),
IsInternal: 0
}
});
return {
"userId": user
};
} catch (e) {
// IF ALREADY EXSIST THROW EXPECTION 403
throw e;
}
}
});
// Client call method
Meteor.call('register',{email: "vxxxxx#xxxx.com",password: "123456"}, function(error, result){
if(result){
console.log(result)
}
if(error){
console.log(result)
}
});

Resources