How to add an additional field to Meteor.users collection (not within the Profile field) - facebook

I'm currently building a mini app that takes in a user login into Facebook for an event. There is no determining how many people will login, hence, mongoDB will be updated as users (clients) log in. However, I'm trying to insert an additional boolean field in Meteor's users collection and I'm not sure how to go about doing that. Here is my accounts.js code (server-side) that add's in users
Accounts.onCreateUser(function (options, user) {
if (options.profile) {
//want the users facebook pic and it is not provided by the facebook.service
options.profile.picture = "http://graph.facebook.com/" + user.services.facebook.id + "/picture/?type=large";
data = user.services.facebook;
user.profile = options.profile;
user.profile.voted = false;
}
return user;
});
Currently, I'm assigning the boolean field ("voted") to the profile field. But I can't seem to update this boolean value from the client-side js. The code I've got over here is shown below
Template.skills.events({
'click input.inc': function () {
Skills.update(Session.get("selected_skill"), {$inc: {mana: 1}});
//Meteor.users.update({_id:Meteor.default_connection.userId()},{$set:{profile.name:true}});
alert(Meteor.user().profile.name);
}
});
FYI:skills.events is merely a handlebar (Handlebars.js) that is triggered when a button is clicked. The attempt here is to update MongoDB when the button is clicked.
I'm pretty new to Meteor and hope the information provided is sufficient.

You just add one.
user.voted = false;
If you want to access the field on the client side, make sure to create additional subscription channel for it. Meteor does not publish custom user properties by default.

Related

Is it possible to add a role to a user with alanning:roles in meteor from an template event?

I am fairly new to Meteor and have been having real trouble with this issue.
I would like to have a select element which updates the users role (once logged in) depending on the option selected. I'm storing the value of the option as a variable when the select is changed and trying to take this value as the name of the role to add to the user.
When I run my app and change the select, the role seems to pop up for a second (viewed in Mongol) before disappearing again. I created a small test to display an alert of the role for the user, which shows up containing the name of the role but once you OK it, the role has disappeared. Am I missing something here?
Here is my template containing the select element...
<template name="select">
<select id="select">
<option value="working">Looking for work</option>
<option value="hiring">Hiring</option>
</select>
</template>
And here is the client side code for the change event
Template.select.events({
'change #select': function (event) {
//remove any current roles added to the user as it will be either
//one or the other
Roles.removeUsersFromRoles( Meteor.userId(), 'working', 'hiring' );
//add a role to the current user with the value from select box
var value = $(event.target).val();
Roles.addUsersToRoles( Meteor.user(), value );
//each of these alerts displays correctly depending on the select
//value
var test = Roles.userIsInRole( Meteor.user(), 'hiring' ); // true
if (test===true){
alert('in hiring role');
}
var test2 = Roles.userIsInRole( Meteor.user(), 'working' ); // true
if (test2===true){
alert('in working role');
}
// either working or hiring
alert(Roles.getRolesForUser(Meteor.userId()));
// alert displays count of 1 when you select 'hiring'
alert(Roles.getUsersInRole('hiring').count());
}
});
Any help would be much appreciated, have been searching through the documentation and online for several days to no avail. Many thanks :)
You try to add roles in your client. However, the client reflects only the data from the server's Roles collection.
You need therefore to change your code to a server side method, that
a) checks wether the current user is permitted to change roles (warning here, potential security threats when not checking permissions)
b) checks, wether the targeted user exists
c) sets the roles for the given userId
There is a good example in the documentation on how to do that. This is a slightly modified version of it:
Meteor.methods({
'updateRoles'({userId, roles, group}) {
check(userId, String);
check(roles, [String]);
check(group, String);
// a) check permission
if (!this.userId || !Meteor.users.findOne(this.userId) || !Roles.userIsInRole(this.userId, 'update-roles', 'lifted-users'))
throw new Meteor.Error('403', 'forbidden', 'you have no permission to change roles');
// b) check target user
if (!Meteor.users.findOne(userId))
throw new Meteor.Error('404', 'user not found');
// c) update user's roles
Roles.setUserRoles(userId, roles, group);
return true;
}
});
This method assumes, that there is a special role/group combination for users, that are allowed to change roles. This should be only a very few people, like admins.
Also note, that this method sets the user roles by using Roles.setUserRoles. If you want to extend the roles you need to use Roles.addUserToRoles.
You can then call this method from your client like every Meteor method:
Template.select.events({
'change #select': function (event) {
// get value from select box
var roles = [$(event.target).val()];
// TODO create a second select for the group
var group = 'defaultUsers'
var userId = Meteor.userId();
Meteor.call('updateRoles', { userId, roles, group }, (err, res) => {
// handle err / res
console.log(Roles.userIsInRole(userId, roles, group)); // should return true
});
}
});
Note, that Roles on the client is a collection which is immediately subscribed to. Changes are reflected reactively. If you do not see the changes immediately

Meteor, ReactJS, MongoDB: Do something when user leaves page

I am trying to build a match-making algorithm that connects two random users, but I can't find a way to delete the connection (which is generated in a MongoDB collection, so I need to remove the query) when user leaves the page.
Maybe window.onbeforeunload will be helpful here. It executes Javascript when the user leaves the page.
Meteor:
Meteor.startup(function(){
$(window).bind('beforeunload', function() {
closingWindow();
});
});
closingWindow = function(){
...
}
React:
componentDidMount() {
window.addEventListener('beforeunload', this.handleLeavePage);
}
componentWillUnmount() {
window.removeEventListener('beforeunload', this.handleLeavePage);
}
handleLeavePage() {
...
}
How Does the user trigger the leaving of page , is it via a button click? after a time interval? MongoDB is realtime , and if the connection between the two users is based from the database , setting the database connection to null or deleting its instance + the usage of publish and subscribe will do the trick. Here is an example:
const CheckIfConnection = Meteor.subscribe('collectionsubscription',userId1,userId2)
if(CheckIfConnection.ready()){
const connection = Collection.'ConnectionCollectionName'.findOne();
//Pass it on the component
}
on the Component side , you can have a 'ComponentWillReceiveProps' that will be triggered when a prop ( Coming from the container ) has changed and that is if the connection is Gone. That would do the trick at your matching algorithm via database approach :)

How to get logged off users email address in meteor?

In my routing file I have the following down.
Router.route('/user/:createdBy', {
name: 'user',
/*onBeforeAction: function () {
AccountsEntry.signInRequired(this);
},*/
fastRender: true,
data: function () {
paramId = this.params.createdBy;
// Still have to find a way how to get data
// Function below is only for signed in users
return Meteor.users.findOne(paramId);
}
});
In my user template I want to display the email. I have it like this {{emails.[0].address}} and as {{users.emails.[0].address}} but the email doesn't show up. It only shows up if the user is logged in. I however have the users Id as my param. (This is for testing purposes guys!).
If you want to use the logged off user information, you could try this:
// in your router.js
// callback would be called when login is successful
Meteor.onLogin(function(){
Session.set('login user', Meteor.user());
})
// in your template, or other functions
// the Session would be update only if a user login successfully
var userId = Session.get('login user')._id;
Click here for more details.
I wish it could help :-)

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"})

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!