Alanning:roles and aldeed:meteor-collection2

I’m having an issue setting up roles in my project that uses meteor-collection2. I assume this is the roles package noted in the collection2 docs.
I’m using accounts-password and ian:accounts-ui-bootstrap-3 as my accounts solution. Here’s my config for it:

Accounts.ui.config({
	requestPermissions: {},
	extraSignupFields: [{
		fieldName: 'first-name',
		fieldLabel: 'First name',
		inputType: 'text',
		visible: true,
		validate: function(value, errorFunction) {
			if (!value) {
				errorFunction("Please write your first name");
				return false;
			} else {
				return true;
			}
		}
	}, {
		fieldName: 'last-name',
		fieldLabel: 'Last name',
		inputType: 'text',
		visible: true,
	}, {
		fieldName: 'terms',
		fieldLabel: 'I accept the terms and conditions',
		inputType: 'checkbox',
		visible: true,
		saveToProfile: false,
		validate: function(value, errorFunction) {
			if (value) {
				return true;
			} else {
				errorFunction('You must accept the terms and conditions.');
				return false;
			}
		}
	}]
});

I added the roles field to my Users Schema:

Schemas.User = new SimpleSchema({
	username: {
		type: String,
		// For accounts-password, either emails or username is required, but not both. It is OK to make this
		// optional here because the accounts-password package does its own validation.
		// Third-party login packages may not require either. Adjust this schema as necessary for your usage.
		optional: true
	},
	emails: {
		type: [Object],
		optional: true
	},
	"emails.$.address": {
		type: String,
		regEx: SimpleSchema.RegEx.Email
	},
	"emails.$.verified": {
		type: Boolean
	},
	createdAt: {
		type: Date
	},
	services: {
		type: Object,
		optional: true,
		blackbox: true
	},
	profile: {
		type: Object,
		optional: true,
		blackbox: true
	},
	"first-name": {
		type: String
	},
	"last-name": {
		type: String
	},
	// Add `roles` to your schema if you use the meteor-roles package.
	// Option 1: Object type
	// If you specify that type as Object, you must also specify the
	// `Roles.GLOBAL_GROUP` group whenever you add a user to a role.
	// Example:
	// Roles.addUsersToRoles(userId, ["admin"], Roles.GLOBAL_GROUP);
	// You can't mix and match adding with and without a group since
	// you will fail validation in some cases.
	roles: {
		type: Object,
		optional: true,
		blackbox: true
	}
});

And now I want to immediately create one user on the first time I run my project with an admin role and stop any others from being created afterwards:

/*----------------------------------------------- #2 Create admin user ----------------------------------------------*/
/*Notes: Create an admin-type user if no users exist yet.*/

if (Meteor.users.find().count() === 0) { /*------------------------------------ If there are no users created yet*/

	var users = [{
		username: "admin",
		name: "admin",
		email: "test@test.com",
		roles: ['admin']
	}];

	_.each(users, function(user) {

		var id = Accounts.createUser({
			username: user.username,
			email: user.email,
			password: "mypassword123",
			profile: {
				name: user.name
			},
                        first-name: Me,
                        last-name: MeName
		});

		if (user.roles.length > 0) {
			// Need _id of existing user record so this call must come
			// after `Accounts.createUser` or `Accounts.onCreate`
			Roles.addUsersToRoles(id, user.roles);
		}

	});
}
/*-------------------------------------------------------------------------------------------------------------------*/

/*Prevent non-authorized users from creating new users*/

Accounts.validateNewUser(function(user) {
	var loggedInUser = Meteor.user();

	if (Roles.userIsInRole(loggedInUser, ['admin'])) {
		return true;
	}

	throw new Meteor.Error(403, "Not authorized to create new users");
});

So far apparently so good: I get the new user.

The problem is when I use spacebars to hide admin features in html the created user isn’t recognized as an admin and they are hidden from me…

    {{#if isInRole 'admin'}}
        <p>Exclusive to admin stuff</p>
    {{/if}}

Found the issue: incorrectly configured schema. Apparently it needs both options presented in the repo, thus they aren’t really “Options” but rather requirements :expressionless: :

roles: {
	type: [Object],
	optional: true,
	blackbox: true
},
// Option 2: [String] type
// If you are sure you will never need to use role groups, then
// you can specify [String] as the type
roles: {
	type: [String],
	optional: true
}

It’s now working and with the

    {{#if isInRole 'admin'}}

So no need to create my own helper.

If using Roles as an Object (Option #1) you must specify a group and permission for all users (I believe with Roles 2.0 which is coming out soon this will no longer be the case), so for something like an admin user you could use Roles.GLOBAL_GROUP which is used to apply blanket permissions across all groups.

For this, you would need to make the follow change:

Roles.addUsersToRoles(id, user.roles);

To this:

Roles.addUsersToRoles(id, user.roles, Roles.GLOBAL_GROUP);

You will also need to specify the group inside of your isInRole helper, here’s an example of how that would look:

Roles.addUsersToRoles(joesUserId, ['manage-team'], 'manchester-united.com')

//manchester-united.com is the group

For your isInRole helper on the client, you would use this:

{{#if isInRole 'manage-team' 'manchester-united.com'}}
    <h3>Manage Team things go here!</h3>
{{/if}}

You are currently using it as a String (Option #2, without groups). If you are planning on using groups for any users then you will need to make the changes I explained above (you can then remove option #2 as well), but if you don’t plan on using groups for any users then you can remove Option #1 and simply use it as a String.

There is a helpful tutorial on the Roles package here, and the package docs are great too.

2 Likes

Doh, I didn’t remember to check Meteor Chef :sweat_smile:
Thank you, that explains it :smile: