Giter Site home page Giter Site logo

roles's Introduction

Roles

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

Installing

meteor add nicolaslopezj:roles

Basic use

You can use roles as a normal roles package

Attach roles to users

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.

Check if a user has a role

Roles.userHasRole(userId, role)
  • userId String. The id of the user.
  • role String. The name of the role.

Users collection helpers

Roles also attach helpers to the Meteor.users collection.

Get user roles

var user = Meteor.user();
var roles = user.roles;

Check if a user has a role

var user = Meteor.user();
var hasRole = user.hasRole();

Advanced features

Roles allows you to define actions and have different responses for each role on that action.

Creating a role

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.

Adding rules

Now, to set responses of a role on an action

Allow

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 using this.userId. To pass arguments to this function pass extra arguments when checking, example: Roles.allow(userId, action, arg1, arg2)

Deny

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 using this.userId. To pass arguments to this function pass extra arguments when checking, example: Roles.deny(userId, action, arg1, arg2)

Check permissions

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.

Check allow

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.

Check deny

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.

Check combined

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

GraphQL Integration

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

Debug

Set Roles.debug = true; log details.

Example

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)

Helper for collections

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.

Template Helpers

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>

Version 2.0 Breaking Changes

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');

roles's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

roles's Issues

quick role implementation question

In orion the admin has the ability to add an "admin" role to any user via this interface
image

I would like my custom roles to show up here as well. Is there another library/package I need to integrate in order to make this happen or would there be a better way to do it?

Role 'admin' already defined

Hello,

I am having problems defining roles. I get the following error:

Error: "admin" role is already defined
at new Roles.Role (packages/nicolaslopezj:roles/roles.js:90:11)
at meteorInstall.lib.roles.js (lib/roles.js:3:19)

Here is my /lib/roles.js file

import {Roles} from 'meteor/nicolaslopezj:roles';

const AdminRole = new Roles.Role('admin');
const EditorRole = new Roles.Role('editor');
const AuthorRole = new Roles.Role('author');
const SubscriberRole = new Roles.Role('subscriber');

export {AdminRole, EditorRole, AuthorRole, SubscriberRole};

There is no other file in which I define a role. Not even users added to admin role.

If I change the name to admin2 or something else, no errors are thrown.

Is there already a definition for admin role?

Exception while invoking method collection/update?

Hi @nicolaslopezj,

After updating the roles to version 2.0.3 last night,I get this error on the console when i tried to update any collection.

Exception while invoking method '/products/update' TypeError: Object function (a) {                                                     // 2   // 10
I20151130-04:38:40.607(8)?   return this.filter(function(i) {                                                       // 3   // 11
I20151130-04:38:40.607(8)?     return a.indexOf(i) < 0;                                                             // 4   // 12
I20151130-04:38:40.607(8)?   });                                                                                    // 5   // 13
I20151130-04:38:40.607(8)? } has no method 'indexOf'
I20151130-04:38:40.607(8)?     at packages/nicolaslopezj_roles/helpers.js:7:1
I20151130-04:38:40.607(8)?     at Array.forEach (native)
I20151130-04:38:40.607(8)?     at Function._.each._.forEach (packages/underscore/packages/underscore.js:134:1)
I20151130-04:38:40.607(8)?     at willChangeWithParent (packages/nicolaslopezj_roles/helpers.js:6:1)
I20151130-04:38:40.607(8)?     at deny.update (packages/nicolaslopezj_roles/roles.js:363:1)
I20151130-04:38:40.607(8)?     at packages/mongo/collection.js:1068:1
I20151130-04:38:40.607(8)?     at Array.some (native)
I20151130-04:38:40.608(8)?     at Function._.some._.any (packages/underscore/packages/underscore.js:262:1)
I20151130-04:38:40.608(8)?     at [object Object].Mongo.Collection._validatedUpdate (packages/mongo/collection.js:1066:1)
I20151130-04:38:40.608(8)?     at [object Object].m.(anonymous function) (packages/mongo/collection.js:892:1)

How do i downgrade the version before the upgrade? I forgot the version number before the upgrade.

Thanks,

Package breaks in Meteor 1.7

ReferenceError: _ is not defined
    at new Roles.Role (packages/nicolaslopezj:roles/roles.js:89:3)
    at roles.js (packages/nicolaslopezj:roles/roles.js:321:19)

Meteor 1.3.3

Hi,

its not yet compatible with Meteor 1.3.3
nicolaslopezj:roles 1.5.3* The most advanced roles package for meteor

thanks! Lukas

Can't see documents / no subscriptions

When I create a new role and then create an account with that role I can't see documents in my table.

I run this in client code:

const moderator = new Roles.Role('moderator');

moderator.allow('collections.alumni.index', true);
moderator.allow('collections.alumni.insert', true);
moderator.allow('collections.alumni.update', true);
moderator.allow('collections.alumni.remove', true);
moderator.allow('collections.alumni.showCreate', true);
moderator.allow('collections.alumni.showUpdate', true);
moderator.allow('collections.alumni.showRemove', true);
moderator.helper('collections.alumni.indexFilter', {});

Hiding/showing disallowing stuff works but I can't see any documents in my tables. There are no subscriptions apparently.

Hope someone can help.

Geeting Exception while invoking method '/countries/update' after upgrade into 2.1.2

I'm getting error on edit documents in any collection:

Exception while invoking method '/countries/update' TypeError: Object function () {                                                              // 1
I20160102-19:40:38.699(2)?   var i, key, output, ref, results, value;                                                         // 2
I20160102-19:40:38.699(2)?   output = {};                                                                                     // 2
I20160102-19:40:38.699(2)?   for (key = i = 0, ref = this.length; 0 <= ref ? i < ref : i > ref; key = 0 <= ref ? ++i : --i) {
I20160102-19:40:38.699(2)?     output[this[key]] = this[key];                                                                 // 3
I20160102-19:40:38.700(2)?   }                                                                                                // 3
I20160102-19:40:38.700(2)?   results = [];                                                                                    // 4
I20160102-19:40:38.700(2)?   for (key in output) {                                                                            //
I20160102-19:40:38.700(2)?     value = output[key];                                                                           //
I20160102-19:40:38.700(2)?     results.push(value);                                                                           // 4
I20160102-19:40:38.701(2)?   }                                                                                                // 4
I20160102-19:40:38.701(2)?   return results;                                                                                  //
I20160102-19:40:38.701(2)? } has no method 'indexOf'
I20160102-19:40:38.701(2)?     at helpers.js:7:20
I20160102-19:40:38.701(2)?     at Array.forEach (native)
I20160102-19:40:38.701(2)?     at Function._.each._.forEach (packages/underscore/underscore.js:105:1)
I20160102-19:40:38.701(2)?     at willChangeWithParent (helpers.js:6:5)
I20160102-19:40:38.702(2)?     at deny.update (roles.js:386:15)
I20160102-19:40:38.702(2)?     at packages/mongo/collection.js:1068:1
I20160102-19:40:38.702(2)?     at Array.some (native)
I20160102-19:40:38.702(2)?     at Function._.some._.any (packages/underscore/underscore.js:233:1)
I20160102-19:40:38.702(2)?     at [object Object].Mongo.Collection._validatedUpdate (packages/mongo/collection.js:1066:1)
I20160102-19:40:38.702(2)?     at [object Object].m.(anonymous function) (packages/mongo/collection.js:892:1)

After reverting into 1.5.3 everything works fine.

Deny rule question

I'm returning true for all allow rules and just using deny. The problem with this approach is, that Roles.deny returns false, if the user doesn't have a role or if the role doesn't have any deny rules registered for the action. How could I fix this?

Edit: Some code:

Mongo.Collection.prototype.registerActions = ->
  Roles.registerAction "#{@_name}.insert", true, false
  Roles.registerAction "#{@_name}.update", true, false
  Roles.registerAction "#{@_name}.remove", true, false

Mongo.Collection.prototype.addAllowRules = ->

  @allow
    insert: (args...) => true
    update: (args...) => true
    remove: (args...) => true

Mongo.Collection.prototype.addDenyRules = ->

  isDenied = (collectionName, mode, args...) ->
    userId = args[0]
    Roles.deny(userId, "#{collectionName}.#{mode}", args...)

  @deny
    insert: (args...) => isDenied(@_name, 'insert', args...)
    update: (args...) => isDenied(@_name, 'update', args...)
    remove: (args...) => isDenied(@_name, 'remove', args...)

App.hooks.add 'collections:on:startup', (collection, name) ->
  collection.registerActions()
  collection.addAllowRules()
  collection.addDenyRules()

Multiple allow/ deny rules

Thanks for this package, it's great!

At the moment it seems not possible to have multiple allow/ deny rules for one action.
As an example, if I have multiple deny rules, they will get ignored:

myRole.deny('collection.insert', function () { return true; });
myRole.deny('collection.insert', function () { return true; });
// Insert will pass

So it would be great if we could set multiple allow/ deny rules. Any opinions?

Publish example

Hi Nicolas,

Thanks for beautiful library. We are migrating from alanning:roles. Since we have being heavily use roles, we want to make inplace migration.

One thing I cannot figure out is efficient way to publish roles. You have publishing example in your last part of readme file for publishing [Posts] roles. Our use case is more complex such that we need collection of [Posts] keys, rather then pull out by single [userId]. I would be greatly appreciate if you could show more example in such use case.

Thanks again for great library.

Does checking of roles can be used to limit the subscription?

Hi @nicolaslopezj ,

I have a dashboard with all of the data on my collection and i have a widget which displays the document count, if admin, all documents count, then if non-admin the document count will be based on his profile (company and branch), the guys from publish-count package help me create a publish function.

Here's the publish function:

Meteor.publish("enrollments", function (limit) {
    Counts.publish(this, 'enrollmentsCount', Enrollments.find({}), {noReady: true});
    if (limit) {
        return Enrollments.find({});
    } else {
        return Enrollments.find({}, {limit: limit}) ;
    }
});

Meteor.publish("enrollmentsByCompany", function(company, limit) {
    Counts.publish(this, 'enrollmentCompany', Enrollments.find({company: company}), {noReady: true});
    if (limit) {
        return Enrollments.find({company: company});
    } else {
        return Enrollments.find({company: company}, {limit: limit}) ;
    }
});

Meteor.publish("enrollmentsByBranch", function(branch, limit) {
    Counts.publish(this, 'enrollmentBranch', Enrollments.find({branch: branch}), {noReady: true});
    if (limit) {
        return Enrollments.find({branch: branch});
    } else {
        return Enrollments.find({branch: branch}, {limit: limit}) ;
    }
});

My question is does checking of roles will run on client or only on server?
Because when i tried to subscribed by checking the user roles, it seems that it didn't run the subscription.
I have this subscription on the client:

var user = Meteor.users.findOne({"_id": this.userId},{fields:{profile: 1}});
  var adminRole = Roles.userHasRole(this.userId, "admin");
  var hqRole = Roles.userHasRole(this.userId, "HQ");
  var branchRole = Roles.userHasRole(this.userId, "Branch");
  if (adminRole)
    Meteor.subscribe("enrollments", 5);
  else if (hqRole)
    Meteor.subscribe("enrollmentsByCompany", user.profile.company, 5);
  else if (branchRole)
    Meteor.subscribe("enrollmentsByBranch", user.profile.branch, 5);

I've console log the count output and gives 0 count.

Is this is something on how do i check the roles or am I missing something or misused?

Error: When the modifier option is true, validation object must have at least one operator

when calling Roles.addUserToRoles got this error, I think it caused by the schema that I declare with collection2? is it possible to call operation of Roles with out any schema validate?

There are the complete error message with meteor shell

Roles.addUserToRoles('sDpAmDEAPQZQv2T4T', 'admin')
Error: When the modifier option is true, validation object must have at least one operator
at checkModifier (packages/aldeed_simple-schema/packages/aldeed_simple-schema.js:2293:1)
at doValidation1 (packages/aldeed_simple-schema/packages/aldeed_simple-schema.js:2343:1)
at doValidation (packages/aldeed_simple-schema/packages/aldeed_simple-schema.js:2758:1)
at SimpleSchemaValidationContext.simpleSchemaValidationContextValidate as validate
at [object Object].doValidate (packages/aldeed_collection2/packages/aldeed_collection2.js:372:1)
at [object Object].Mongo.Collection.(anonymous function) as update
at Object.Roles.addUserToRoles (packages/nicolaslopezj:roles/roles_server.js:34:23)
at [object Object]:1:-55
at Script.(anonymous function) as runInThisContext
at /Users/shingo0620/Documents/Work/project-core/.meteor/local/build/programs/server/shell-server.js:366:27

"Group" feature

I was just wondering if the concept of groups could be integrated in this library, or maybe it's already in the roadmap. It could be a nice evolution, but might cost much time to revert/update existing code.

Uploading files issue

Hi Nicolas,

I'm working with orionjs with the microscope boilerplate, after upgrading to meteor 1.3.3 I am unable to upload files unless admin, here is the error:

Uncaught Error: The user has no permission to perform this action [unauthorized] - roles.js:292

I have configured 2 users: user and admin. It was working well before the upgrade
What can I do to solve this. Any help is appreciated.

Thanks.

Implementing Groups

I've a lot of subprojects in which users may have different authorizations.
As far as I've understood the package will allow me to define
proj1_role1, proj1_role2, proj1_role3,
proj2_role1, proj2_role2, proj2_role3... and so on...

Is there a way to implement "groups" (in the sense of alanning:roles) rather than adding tons of roles to each single user?

'undefined' list of users after applying filter to roles

After updating
nicolaslopezj:roles 2.0.4
orionjs:relationships 1.7.0
and others

below code is also returns list of user (as 'undefined') having 'default' user role.

assignedTo: orion.attribute('users', {
            label: 'Assigned To',
            optional: true,
            autoform: {
                afFormGroup: {
                    'formgroup-class': 'col-md-12'
                }
            }
        }, {
                publicationName: 'Activity assgined to',
                additionalFields: ['roles'],
                filter: function () {
                    return { roles: { $ne: 'default' } } // // or { roles: 'contributors' }; 
                }
            })```

React client

Hi, Is it possible to use the client helpers of this package on a React client?

Uncaught Helper "collections.projects.forbiddenFields" is not defined.

How do I use this forbidden fields feature? I have tried googling around a bit but don't see any documentation. I've just removed insecure and now my orion admin panel cannot even insert new documents into my collection without throwing Uncaught Helper "collections.projects.forbiddenFields" is not defined.

I am using orion, but not explicitly using attachRoles (any more than what the blog example comes with).

As discussed in: e98ce1e

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.