The most advanced roles package for meteor.
This roles package introduces a new way of thinking about roles. It makes you think first about actions and then define the different responses for each role to that action and makes it very easy to add more roles later.
Project sponsored by Orion Hosting - Hosting for Meteor
meteor add nicolaslopezj:roles
You can use roles as a normal roles package
Only on server
To add roles to a user.
Roles.addUserToRoles(userId, roles)
userId
String. The id of the user.roles
Array or String. The name of the roles you want to add to the user.
To set roles.
Roles.setUserRoles(userId, roles)
userId
String. The id of the user.roles
Array or String. The name of the roles you want to set to the user.
To remove roles from a user
Roles.removeUserFromRoles(userId, roles)
userId
String. The id of the user.roles
Array or String. The name of the roles you want to remove from the user.
Roles.userHasRole(userId, role)
userId
String. The id of the user.role
String. The name of the role.
Roles also attach helpers to the Meteor.users
collection.
var user = Meteor.user();
var roles = user.roles;
var user = Meteor.user();
var hasRole = user.hasRole();
Roles allows you to define actions and have different responses for each role on that action.
If you use Roles as the basic way this is not necessary, but if you want to use actions, this is needed.
myRole = new Roles.Role(name)
name
String. The name of the new role.
Now, to set responses of a role on an action
myRole.allow(action, func)
action
String. The name of the action.func
Function. Return true to allow the role to perform this action. You can get the user id usingthis.userId
. To pass arguments to this function pass extra arguments when checking, example: Roles.allow(userId, action, arg1, arg2)
myRole.deny(action, func)
action
String. The name of the action.func
Function. Return true to deny the role to perform this action. You can get the user id usingthis.userId
. To pass arguments to this function pass extra arguments when checking, example: Roles.deny(userId, action, arg1, arg2)
Now that we have our allow/deny rules we want to check if the user has permissions. Note that a user can have more than one role, so Roles will check every action. If a role doesn't have allow/deny rules for an action they won't be considered.
To check if a user is allowed to perform an action. Roles will check all the roles the user has and if at least one role return true
on an action, this function will return true
.
Roles.allow(userId, action, [extra])
userId
String. The id of the user.action
String. The name of the action.[extra]
Each argument that you add to this function will be passed to the allow/deny functions you defined.
To check if a user is denied to perform an action. Roles will check all the roles the user has and if at least one role return true
on an action, this function will return true
.
Roles.deny(userId, action, [extra])
userId
String. The id of the user.action
String. The name of the action.[extra]
Each argument that you add to this function will be passed to the allow/deny functions you defined.
This function will return true
if the user is allowed and not denied to perform an action.
Roles.userHasPermission(userId, action, [extra])
userId
String. The id of the user.action
String. The name of the action.[extra]
Each argument that you add to this function will be passed to the allow/deny functions you defined.
To throw an error if the user doesn't have permission (useful for methods)
Roles.checkPermission(userId, action, [extra])
To check a permission in GraphQL resolvers you can use the @Roles.graphQLAction
decorator
Example:
import {Roles} from 'meteor/nicolaslopezj:roles'
const role = new Roles.Role('role')
role.allow('viewPostStats', function (post, params) {
return post.createdBy === this.userId
})
// Resolvers
{
Post: {
@Roles.action('viewPostStats')
stats (post, params, context) {
return postStats
}
}
}
Set Roles.debug = true;
log details.
We will create a collection and create an action to update it.
// We create the collection
Posts = new Mongo.Collection('posts');
// Use the action
Posts.allow({
update: function (userId, doc, fields, modifier) {
return Roles.allow(userId, 'posts.update', userId, doc, fields, modifier);
},
});
Posts.deny({
update: function (userId, doc, fields, modifier) {
return Roles.deny(userId, 'posts.update', userId, doc, fields, modifier);
},
});
// Create a new role
EditorRole = new Roles.Role('editor');
// Set the allow/deny rules
EditorRole.allow('posts.update', function(userId, doc, fields, modifier) {
return doc.userId === userId; // Will be allowed to edit his own posts
})
EditorRole.deny('posts.update', function(userId, doc, fields, modifier) {
return !_.contains(fields, 'userId') // Can't update userId field.
})
Now, we will create a publication only for editors.
// Register the action
Roles.registerAction('posts.subscribeToMyPosts');
// Create the publication
if (Meteor.isServer) {
Meteor.publish('myPosts', function () {
// Roles.userHasPermission checks allow and deny rules
if (!Roles.userHasPermission(this.userId, 'posts.subscribeToMyPosts')) {
return [];
} else {
return Posts.find({ userId: this.userId })
}
});
}
// Now we will allow editor to subscribe to their posts
EditorRole.allow('posts.subscribeToMyPosts', true)
Instead of registering and implementing the actions for a collection, there is a helper that do that for you.
myCollection.attachRoles('myCollectionRolesPrefix')
That code will register the following actions:
myCollectionRolesPrefix.insert
myCollectionRolesPrefix.update
myCollectionRolesPrefix.remove
And automatically attach the allow/deny rules to the collection.
Check if the logged in has permissions over an action
<template name="myTemplate">
{{# if userHasPermission 'myCollection.insert' }}
<h1>Insert a document</h1>
{{ else }}
<p>You don't have permissions!</p>
{{/ if }}
</template>
Check if roles are ready
<template name="myTemplate">
{{# if rolesIsReady }}
<p>Roles are loaded</p>
{{ else }}
<p>We don't know if you have permissions yet...</p>
{{/ if }}
</template>
Now roles are saved in the users collection. You need to migrate the db to update. The api is the same.
To migrate run:
Meteor.call('nicolaslopezj_roles_migrate');