geko
geko

Reputation: 33

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 :)

Upvotes: 0

Views: 166

Answers (1)

Jankapunkt
Jankapunkt

Reputation: 8413

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

Upvotes: 0

Related Questions