From b8fff1278111cba13d77afbc268be17dec797026 Mon Sep 17 00:00:00 2001 From: Simon Schick Date: Mon, 21 Jan 2019 13:13:27 +0400 Subject: [PATCH 01/26] Added a method to check inheritance of roles --- roles/roles_common.js | 41 ++++++++++++++++++++++++++++++++++ roles/tests/server.js | 51 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/roles/roles_common.js b/roles/roles_common.js index f1814ec..45b75ab 100644 --- a/roles/roles_common.js +++ b/roles/roles_common.js @@ -1230,6 +1230,47 @@ _.extend(Roles, { } }, + /** + * Find out if a role is an ancestor of another role. + * + * WARNING: If you check this on the client, please make sure all roles are published. + * + * @method isParentOf + * @param {String} parentRoleName The role you want to research. + * @param {String} childRoleName The role you expect to be among the children of parentRoleName. + * @static + */ + isParentOf: function (parentRoleName, childRoleName) { + if (parentRoleName === childRoleName) { + return true; + } + + if (parentRoleName == null || childRoleName == null) { + return false; + } + + Roles._checkRoleName(parentRoleName); + Roles._checkRoleName(childRoleName); + + var rolesToCheck = [parentRoleName]; + while (rolesToCheck.length !== 0) { + var roleName = rolesToCheck.pop(); + + if (roleName === childRoleName) { + return true; + } + + var role = Meteor.roles.findOne({_id: roleName}); + + // This should not happen, but this is a problem to address at some other time. + if (!role) continue; + + rolesToCheck = rolesToCheck.concat(_.pluck(role.children, '_id')); + } + + return false; + }, + /** * Normalize options. * diff --git a/roles/tests/server.js b/roles/tests/server.js index e6f6f58..cf54e57 100644 --- a/roles/tests/server.js +++ b/roles/tests/server.js @@ -2611,6 +2611,57 @@ test.isFalse(Roles.userIsInRole(users.eve, undefined, {anyScope: true})); }); +Tinytest.add( + 'roles - isParentOf - returns false for unknown roles', + function (test) { + reset(); + + Roles.createRole('admin'); + + test.isFalse(Roles.isParentOf('admin', 'unknown')); + test.isFalse(Roles.isParentOf('admin', null)); + test.isFalse(Roles.isParentOf('admin', undefined)); + + test.isFalse(Roles.isParentOf('unknown', 'admin')); + test.isFalse(Roles.isParentOf(null, 'admin')); + test.isFalse(Roles.isParentOf(undefined, 'admin')); + }); + +Tinytest.add( + 'roles - isParentOf - returns false if role is not parent of', + function (test) { + reset(); + + Roles.createRole('admin'); + Roles.createRole('editor'); + Roles.createRole('user'); + Roles.addRolesToParent(['editor'], 'admin'); + Roles.addRolesToParent(['user'], 'editor'); + + test.isFalse(Roles.isParentOf('user', 'admin')); + test.isFalse(Roles.isParentOf('editor', 'admin')); + }); + +Tinytest.add( + 'roles - isParentOf - returns true if role is parent of the demanded role', + function (test) { + reset(); + + Roles.createRole('admin'); + Roles.createRole('editor'); + Roles.createRole('user'); + Roles.addRolesToParent(['editor'], 'admin'); + Roles.addRolesToParent(['user'], 'editor'); + + test.isTrue(Roles.isParentOf('admin', 'user')); + test.isTrue(Roles.isParentOf('editor', 'user')); + test.isTrue(Roles.isParentOf('admin', 'editor')); + + test.isTrue(Roles.isParentOf('admin', 'admin')); + test.isTrue(Roles.isParentOf('editor', 'editor')); + test.isTrue(Roles.isParentOf('user', 'user')); + }); + function printException (ex) { var tmp = {}; for (var key in ex) { From 2657ce2e2486efd7bf31b47e2292989045b19db0 Mon Sep 17 00:00:00 2001 From: Simon Schick Date: Mon, 21 Jan 2019 13:23:11 +0400 Subject: [PATCH 02/26] Removed underscore from code the base and raised min Meteor version to 1.6.0 --- README.md | 4 +- .../main/client/layouts.js | 4 +- .../main/client/lib/app.js | 2 +- .../main/server/startup/fixtures.js | 8 +- .../secrets/server/fixtures.js | 4 +- examples/flow-router/client/layouts.js | 4 +- examples/flow-router/server/server.js | 12 +- examples/iron-router/client/routing.js | 4 +- examples/iron-router/server/server.js | 12 +- package.js | 9 +- roles/client/uiHelpers.js | 10 +- roles/roles_common.js | 177 +++++++++--------- roles/roles_server.js | 32 ++-- roles/tests/client.js | 14 +- roles/tests/server.js | 140 ++++++++------ 15 files changed, 230 insertions(+), 206 deletions(-) diff --git a/README.md b/README.md index 43af11d..5d9d646 100644 --- a/README.md +++ b/README.md @@ -208,7 +208,7 @@ var users = [ {name:"Admin User",email:"admin@example.com",roles:['admin']} ]; -_.each(users, function (user) { +users.forEach(function (user) { var id; id = Accounts.createUser({ @@ -218,7 +218,7 @@ _.each(users, function (user) { }); if (user.roles.length > 0) { - _.each(user.roles, function (role) { + user.roles.forEach(function (role) { Roles.createRole(role, {unlessExists: true}); }); // Need _id of existing user record so this call must come after `Accounts.createUser`. diff --git a/examples/flow-router-advanced/main/client/layouts.js b/examples/flow-router-advanced/main/client/layouts.js index 6e66fc6..f77746b 100644 --- a/examples/flow-router-advanced/main/client/layouts.js +++ b/examples/flow-router-advanced/main/client/layouts.js @@ -1,5 +1,5 @@ Template.mainLayout.helpers({ - notVerified: function () { + notVerified: function () { var user = Meteor.user() return !emailVerified(user) @@ -7,7 +7,7 @@ Template.mainLayout.helpers({ }) function emailVerified (user) { - return _.some(user.emails, function (email) { + return user.emails.some(function (email) { return email.verified }) } diff --git a/examples/flow-router-advanced/main/client/lib/app.js b/examples/flow-router-advanced/main/client/lib/app.js index d528259..1c5b790 100644 --- a/examples/flow-router-advanced/main/client/lib/app.js +++ b/examples/flow-router-advanced/main/client/lib/app.js @@ -3,7 +3,7 @@ App = {} "use strict" -_.extend(App, { +Object.assign(App, { // Separate routing package details from general app code. navigateTo: function (path) { diff --git a/examples/flow-router-advanced/main/server/startup/fixtures.js b/examples/flow-router-advanced/main/server/startup/fixtures.js index 0c93187..5f78d21 100644 --- a/examples/flow-router-advanced/main/server/startup/fixtures.js +++ b/examples/flow-router-advanced/main/server/startup/fixtures.js @@ -26,9 +26,9 @@ function createUsers () { {name:"Admin User",email:"admin@example.com",roles:['admin']} ]; - _.each(users, function (userData) { + users.forEach(function (userData) { var id - + console.log(userData); id = Accounts.createUser({ @@ -41,12 +41,12 @@ function createUsers () { Meteor.users.update({_id: id}, {$set:{'emails.0.verified': true}}); - _.each(userData.roles, function (role) { + userData.roles.forEach(function (role) { Roles.createRole(role, {unlessExists: true}); }); Roles.addUsersToRoles(id, userData.roles); - + }); } } diff --git a/examples/flow-router-advanced/secrets/server/fixtures.js b/examples/flow-router-advanced/secrets/server/fixtures.js index a12700b..47f163b 100644 --- a/examples/flow-router-advanced/secrets/server/fixtures.js +++ b/examples/flow-router-advanced/secrets/server/fixtures.js @@ -14,7 +14,7 @@ Meteor.startup(function () { function createSecrets () { var secrets - + if (Meteor.secrets.find().fetch().length === 0) { console.log('Creating secrets: '); @@ -23,7 +23,7 @@ function createSecrets () { {secret:"domain registration pw: apple3"} ] - _.each(secrets, function (secret) { + secrets.forEach(function (secret) { console.log(secret) Meteor.secrets.insert(secret); diff --git a/examples/flow-router/client/layouts.js b/examples/flow-router/client/layouts.js index 6e66fc6..f77746b 100644 --- a/examples/flow-router/client/layouts.js +++ b/examples/flow-router/client/layouts.js @@ -1,5 +1,5 @@ Template.mainLayout.helpers({ - notVerified: function () { + notVerified: function () { var user = Meteor.user() return !emailVerified(user) @@ -7,7 +7,7 @@ Template.mainLayout.helpers({ }) function emailVerified (user) { - return _.some(user.emails, function (email) { + return user.emails.some(function (email) { return email.verified }) } diff --git a/examples/flow-router/server/server.js b/examples/flow-router/server/server.js index ae6a845..dd853ac 100644 --- a/examples/flow-router/server/server.js +++ b/examples/flow-router/server/server.js @@ -12,7 +12,7 @@ Meteor.startup(function () { //////////////////////////////////////////////////////////////////// // Create Test Secrets // - + if (Meteor.secrets.find().fetch().length === 0) { Meteor.secrets.insert({secret:"ec2 password: apple2"}); Meteor.secrets.insert({secret:"domain registration pw: apple3"}); @@ -34,10 +34,10 @@ Meteor.startup(function () { {name:"Admin User",email:"admin@example.com",roles:['admin']} ]; - _.each(users, function (userData) { + users.forEach(function (userData) { var id, user; - + console.log(userData); id = Accounts.createUser({ @@ -49,12 +49,12 @@ Meteor.startup(function () { // email verification Meteor.users.update({_id: id}, {$set:{'emails.0.verified': true}}); - _.each(userData.roles, function (role) { + userData.roles.forEach(function (role) { Roles.createRole(role, {unlessExists: true}); }); Roles.addUsersToRoles(id, userData.roles); - + }); } @@ -102,7 +102,7 @@ Meteor.publish("users", function () { if (Roles.userIsInRole(user, ["admin","manage-users"])) { console.log('publishing users', this.userId); return Meteor.users.find({}, {fields: {emails: 1, profile: 1, roles: 1}}); - } + } this.stop(); return; diff --git a/examples/iron-router/client/routing.js b/examples/iron-router/client/routing.js index 71beb41..8b9b72b 100644 --- a/examples/iron-router/client/routing.js +++ b/examples/iron-router/client/routing.js @@ -11,7 +11,7 @@ Meteor.navigateTo = function (path) { } function emailVerified (user) { - return _.some(user.emails, function (email) { + return user.emails.some(function (email) { return email.verified }) } @@ -19,7 +19,7 @@ function emailVerified (user) { var filters = { /** - * ensure user is logged in and + * ensure user is logged in and * email verified */ authenticate: function () { diff --git a/examples/iron-router/server/server.js b/examples/iron-router/server/server.js index ae6a845..8df5daa 100644 --- a/examples/iron-router/server/server.js +++ b/examples/iron-router/server/server.js @@ -12,7 +12,7 @@ Meteor.startup(function () { //////////////////////////////////////////////////////////////////// // Create Test Secrets // - + if (Meteor.secrets.find().fetch().length === 0) { Meteor.secrets.insert({secret:"ec2 password: apple2"}); Meteor.secrets.insert({secret:"domain registration pw: apple3"}); @@ -34,10 +34,10 @@ Meteor.startup(function () { {name:"Admin User",email:"admin@example.com",roles:['admin']} ]; - _.each(users, function (userData) { + users.forEach(function (userData) { var id, user; - + console.log(userData); id = Accounts.createUser({ @@ -49,12 +49,12 @@ Meteor.startup(function () { // email verification Meteor.users.update({_id: id}, {$set:{'emails.0.verified': true}}); - _.each(userData.roles, function (role) { + userData.roles.forEach(function (role) { Roles.createRole(role, {unlessExists: true}); }); Roles.addUsersToRoles(id, userData.roles); - + }); } @@ -102,7 +102,7 @@ Meteor.publish("users", function () { if (Roles.userIsInRole(user, ["admin","manage-users"])) { console.log('publishing users', this.userId); return Meteor.users.find({}, {fields: {emails: 1, profile: 1, roles: 1}}); - } + } this.stop(); return; diff --git a/package.js b/package.js index d34bdc6..5379777 100644 --- a/package.js +++ b/package.js @@ -8,10 +8,9 @@ Package.describe({ Package.onUse(function (api) { var both = ['client', 'server']; - api.versionsFrom("METEOR@1.4.1"); + api.versionsFrom("METEOR@1.6"); - api.use(['underscore', - 'accounts-base', + api.use(['accounts-base', 'tracker', 'mongo', 'check'], both); @@ -28,7 +27,7 @@ Package.onUse(function (api) { }); Package.onTest(function (api) { - api.versionsFrom("METEOR@1.4.1"); + api.versionsFrom("METEOR@1.6"); var both = ['client', 'server']; @@ -36,7 +35,7 @@ Package.onTest(function (api) { api.use(['alanning:roles', 'accounts-password', - 'underscore', + 'mongo', 'tinytest'], both); api.addFiles('roles/tests/client.js', 'client'); diff --git a/roles/client/uiHelpers.js b/roles/client/uiHelpers.js index 523f98a..d9084b0 100644 --- a/roles/client/uiHelpers.js +++ b/roles/client/uiHelpers.js @@ -16,7 +16,7 @@ // // Use a semi-private variable rather than declaring UI // helpers directly so that we can unit test the helpers. -// XXX For some reason, the UI helpers are not registered +// XXX For some reason, the UI helpers are not registered // before the tests run. // Roles._uiHelpers = { @@ -40,7 +40,7 @@ Roles._uiHelpers = { * @param {String} [scope] Optional, name of scope to check. * @return {Boolean} `true` if current user is in at least one of the target roles. * @static - * @for UIHelpers + * @for UIHelpers */ isInRole: function (role, scope) { var user = Meteor.user(), @@ -51,7 +51,7 @@ Roles._uiHelpers = { if (!Match.test(role, String)) return false if (comma !== -1) { - roles = _.reduce(role.split(','), function (memo, r) { + roles = role.split(',').reduce(function (memo, r) { if (!r || !Roles._trim(r)) { return memo } @@ -83,10 +83,10 @@ if (Roles.debug && console.log) { if ('undefined' !== typeof Package.blaze && 'undefined' !== typeof Package.blaze.Blaze && 'function' === typeof Package.blaze.Blaze.registerHelper) { - _.each(Roles._uiHelpers, function (func, name) { + Object.entries(Roles._uiHelpers).forEach(([name, func]) => { if (Roles.debug && console.log) { console.log("[roles] registering Blaze helper '" + name + "'") } - Package.blaze.Blaze.registerHelper(name, func) + Package.blaze.Blaze.registerHelper(name, func) }) } diff --git a/roles/roles_common.js b/roles/roles_common.js index f1814ec..a3e7400 100644 --- a/roles/roles_common.js +++ b/roles/roles_common.js @@ -37,7 +37,7 @@ if ('undefined' === typeof Roles) { var getGroupsForUserDeprecationWarning = false; -_.extend(Roles, { +Object.assign(Roles, { /** * Used as a global group (now scope) name. Not used anymore. @@ -65,9 +65,9 @@ _.extend(Roles, { Roles._checkRoleName(roleName); - options = _.defaults(options, { + options = Object.assign({ unlessExists: false - }); + }, options); var result = Meteor.roles.upsert({_id: roleName}, {$setOnInsert: {children: []}}); @@ -111,11 +111,11 @@ _.extend(Roles, { roles: 1 } } - }).forEach(function (user, index, cursor) { + }).fetch().forEach(function (user, index, cursor) { // role can be assigned multiple times to the user, for multiple scopes // we have to remove the role for each of those scopes - roles = _.filter(user.roles, Roles._roleMatcher(roleName)); - _.each(roles, function (role) { + roles = user.roles.filter(Roles._roleMatcher(roleName)); + roles.forEach(function (role) { Roles._removeUserFromRole(user, roleName, { scope: role.scope, // we want to remove the role in any case @@ -202,9 +202,9 @@ _.extend(Roles, { */ addRolesToParent: function (rolesNames, parentName) { // ensure arrays - if (!_.isArray(rolesNames)) rolesNames = [rolesNames]; + if (!Array.isArray(rolesNames)) rolesNames = [rolesNames]; - _.each(rolesNames, function (roleName) { + rolesNames.forEach(function (roleName) { Roles._addRoleToParent(roleName, parentName); }); }, @@ -236,22 +236,21 @@ _.extend(Roles, { } // detect cycles - alreadyCheckedRoles = []; - rolesToCheck = _.pluck(role.children, '_id'); - while (rolesToCheck.length) { - checkRoleName = rolesToCheck.pop(); + alreadyCheckedRoles = new Set(); + rolesToCheck = new Set(role.children.map(r => r._id)); + rolesToCheck.forEach(checkRoleName => { if (checkRoleName === parentName) { throw new Error("Roles '" + roleName + "' and '" + parentName + "' would form a cycle."); } - alreadyCheckedRoles.push(checkRoleName); - checkRole = Meteor.roles.findOne({_id: checkRoleName}); + alreadyCheckedRoles.add(checkRoleName); - // This should not happen, but this is a problem to address at some other time. - if (!checkRole) continue; + checkRole = Meteor.roles.findOne({_id: checkRoleName}); - rolesToCheck = _.union(rolesToCheck, _.difference(_.pluck(checkRole.children, '_id'), alreadyCheckedRoles)); - } + if (checkRole) { + checkRole.children.map(r => r._id).filter(r => !alreadyCheckedRoles.has(r)).forEach(r => rolesToCheck.add(r)); + } + }) count = Meteor.roles.update({ _id: parentName, @@ -278,11 +277,11 @@ _.extend(Roles, { roles: 1 } } - }).forEach(function (user, index, cursor) { + }).fetch().forEach(function (user, index, cursor) { // parent role can be assigned multiple times to the user, for multiple scopes // we have to assign a new subrole for each of those scopes - parentRoles = _.filter(user.roles, Roles._roleMatcher(parentName)); - _.each(parentRoles, function (parentRole) { + parentRoles = user.roles.filter(Roles._roleMatcher(parentName)); + parentRoles.forEach(function (parentRole) { Roles._addUserToRole(user, roleName, { scope: parentRole.scope, // we are assigning a subrole, so we set it as unassigned, @@ -306,9 +305,9 @@ _.extend(Roles, { */ removeRolesFromParent: function (rolesNames, parentName) { // ensure arrays - if (!_.isArray(rolesNames)) rolesNames = [rolesNames]; + if (!Array.isArray(rolesNames)) rolesNames = [rolesNames]; - _.each(rolesNames, function (roleName) { + rolesNames.forEach(function (roleName) { Roles._removeRoleFromParent(roleName, parentName); }); }, @@ -358,11 +357,11 @@ _.extend(Roles, { roles: 1 } } - }).forEach(function (user, index, cursor) { + }).fetch().forEach(function (user, index, cursor) { // parent role can be assigned multiple times to the user, for multiple scopes // we have to remove the subrole for each of those scopes - parentRoles = _.filter(user.roles, Roles._roleMatcher(parentName)); - _.each(parentRoles, function (parentRole) { + parentRoles = user.roles.filter(Roles._roleMatcher(parentName)); + parentRoles.forEach(function (parentRole) { Roles._removeUserFromRole(user, roleName, { scope: parentRole.scope, // but we want to remove it only if it was not also explicitly assigned @@ -403,22 +402,22 @@ _.extend(Roles, { options = Roles._normalizeOptions(options); // ensure arrays - if (!_.isArray(users)) users = [users]; - if (!_.isArray(roles)) roles = [roles]; + if (!Array.isArray(users)) users = [users]; + if (!Array.isArray(roles)) roles = [roles]; Roles._checkScopeName(options.scope); - options = _.defaults(options, { + options = Object.assign({ ifExists: false, // internal option, should not be used publicly because it will break assumptions // in te code; publicly, you can only add users to an assigned role // should the role be set as assigned, default is `true`; `null` is the same as `false`, // only that it does not force the value to `false` if the role is already assigned _assigned: true - }); + }, options); - _.each(users, function (user) { - _.each(roles, function (role) { + users.forEach(function (user) { + roles.forEach(function (role) { Roles._addUserToRole(user, role, options); }); }); @@ -454,22 +453,22 @@ _.extend(Roles, { options = Roles._normalizeOptions(options); // ensure arrays - if (!_.isArray(users)) users = [users]; - if (!_.isArray(roles)) roles = [roles]; + if (!Array.isArray(users)) users = [users]; + if (!Array.isArray(roles)) roles = [roles]; Roles._checkScopeName(options.scope); - options = _.defaults(options, { + options = Object.assign({ ifExists: false, // internal option, should not be used publicly because it will break assumptions // in te code; publicly, you can only add users to an assigned role // should the role be set as assigned, default is `true`; `null` is the same as `false`, // only that it does not force the value to `false` if the role is already assigned _assigned: true - }); + }, options); - _.each(users, function (user) { - if (_.isObject(user)) { + users.forEach(function (user) { + if (typeof user === 'object') { id = user._id; } else { @@ -479,7 +478,7 @@ _.extend(Roles, { Meteor.users.update(id, {$pull: {roles: {scope: options.scope}}}); // and then add all - _.each(roles, function (role) { + roles.forEach(function (role) { Roles._addUserToRole(user, role, options); }); }); @@ -511,7 +510,7 @@ _.extend(Roles, { Roles._checkRoleName(roleName); Roles._checkScopeName(options.scope); - if (_.isObject(user)) { + if (typeof user === 'object') { id = user._id; } else { @@ -597,9 +596,9 @@ _.extend(Roles, { scope: options.scope }]; - _.each(role.children, function (child) { + role.children.forEach(function (child) { // subroles are set as unassigned, but only if they do not already exist - setRoles = setRoles.concat(Roles._addUserToRole(user, child._id, _.extend({}, options, {_assigned: null}))); + setRoles = setRoles.concat(Roles._addUserToRole(user, child._id, Object.assign({}, options, {_assigned: null}))); }); return setRoles; @@ -629,21 +628,23 @@ _.extend(Roles, { options = Roles._normalizeOptions(options); // ensure arrays - if (!_.isArray(users)) users = [users]; - if (!_.isArray(roles)) roles = [roles]; + if (!Array.isArray(users)) users = [users]; + if (!Array.isArray(roles)) roles = [roles]; Roles._checkScopeName(options.scope); - options = _.defaults(options, { + options = Object.assign({ // internal option, should not be used publicly because it will break assumptions // in te code; publicly, you can only remove users from an assigned role // when should the role be removed, default is `true` which means only when it is assigned, // `false` means when it is not assigned, and `null` means always _assigned: true - }); + }, options); + + users.forEach(function (user) { + if (!user) return; - _.each(users, function (user) { - _.each(roles, function (role) { + roles.forEach(function (role) { Roles._removeUserFromRole(user, role, options); }); @@ -681,7 +682,7 @@ _.extend(Roles, { Roles._checkRoleName(roleName); Roles._checkScopeName(options.scope); - if (_.isObject(user)) { + if (typeof user === 'object') { id = user._id; } else { @@ -714,9 +715,9 @@ _.extend(Roles, { // role does not exist, we do not anything more if (!role) return; - _.each(role.children, function (child) { + role.children.forEach(function (child) { // if a child role has been assigned explicitly, we do not remove it - Roles._removeUserFromRole(user, child._id, _.extend({}, options, {_assigned: false})); + Roles._removeUserFromRole(user, child._id, Object.assign({}, options, {_assigned: false})); }); }, @@ -742,10 +743,10 @@ _.extend(Roles, { user = Roles._resolveUser(user, true); // only assigned roles - roles = _.filter(user.roles, Roles._onlyAssignedMatcher()); + roles = user.roles.filter(Roles._onlyAssignedMatcher()); setRoles = []; - _.each(roles, function (role) { + roles.forEach(function (role) { setRoles = setRoles.concat(Roles._addUserToRole(user, role._id, { scope: role.scope, _assigned: role.assigned, // this is true @@ -758,7 +759,7 @@ _.extend(Roles, { Meteor.users.update(user._id, { $pull: { roles: { - $nor: _.map(setRoles, function (role) {return _.pick(role, '_id', 'scope')}) + $nor: setRoles.map(function (role) { return {_id: role._id, scope: role.scope } }) } } }); @@ -804,26 +805,27 @@ _.extend(Roles, { options = Roles._normalizeOptions(options); // ensure array to simplify code - if (!_.isArray(roles)) roles = [roles]; + if (!Array.isArray(roles)) roles = [roles]; if (!roles.length) return false; Roles._checkScopeName(options.scope); - options = _.defaults(options, { + options = Object.assign({ anyScope: false - }); + }, options); if (!user) return false; - if (_.isObject(user)) { - if (_.has(user, 'roles')) { - return _.some(roles, function (role) { + if (typeof user === 'object') { + if ('roles' in user) { + return roles.some(function (role) { + const roles = user.roles || []; if (options.anyScope) { - return _.some(user.roles || [], Roles._roleMatcher(role)); + return roles.some(Roles._roleMatcher(role)); } else { - return _.some(user.roles || [], Roles._roleAndScopeMatcher(role, options.scope)); + return roles.some(Roles._roleAndScopeMatcher(role, options.scope)); } }) } else { @@ -888,32 +890,30 @@ _.extend(Roles, { Roles._checkScopeName(options.scope); - options = _.defaults(options, { + options = Object.assign({ fullObjects: false, onlyAssigned: false, anyScope: false - }); + }, options); user = Roles._resolveUser(user); if (!user) return []; - if (options.anyScope) { - roles = user.roles || []; - } - else { - roles = _.filter(user.roles || [], Roles._scopeMatcher(options.scope)); + roles = user.roles || []; + if (!options.anyScope) { + roles = roles.filter(Roles._scopeMatcher(options.scope)); } if (options.onlyAssigned) { - roles = _.filter(roles, Roles._onlyAssignedMatcher()); + roles = roles.filter(Roles._onlyAssignedMatcher()); } if (options.fullObjects) { return roles; } - return _.uniq(_.pluck(roles, '_id')); + return [...new Set(roles.map(r => r._id))]; }, /** @@ -988,14 +988,14 @@ _.extend(Roles, { options = Roles._normalizeOptions(options); // ensure array to simplify code - if (!_.isArray(roles)) roles = [roles]; + if (!Array.isArray(roles)) roles = [roles]; Roles._checkScopeName(options.scope); - options = _.defaults(options, { + options = Object.assign({ queryOptions: queryOptions || {}, anyScope: false - }); + }, options); if (options.anyScope) { query = { @@ -1058,22 +1058,22 @@ _.extend(Roles, { var scopes; // ensure array to simplify code - if (roles && !_.isArray(roles)) roles = [roles]; + if (roles && !Array.isArray(roles)) roles = [roles]; user = Roles._resolveUser(user); if (!user) return []; scopes = []; - _.each(user.roles || [], function (userRole) { + (user.roles || []).forEach(function (userRole) { // == used on purpose. if (userRole.scope == null) return; - if (roles && !_.contains(roles, userRole._id)) return; + if (roles && !roles.includes(userRole._id)) return; scopes.push(userRole.scope); }); - return _.uniq(scopes); + return [...new Set(scopes)]; }, /** @@ -1143,11 +1143,13 @@ _.extend(Roles, { */ _resolveUser: function (user, force) { // TODO: We could use $elemMatch to limit returned fields here. - if (!_.isObject(user)) { + if (!user) { + return null; + } else if (typeof user !== 'object') { user = Meteor.users.findOne( {_id: user}, {fields: {roles: 1}}); - } else if (force || !_.has(user, 'roles')) { + } else if (force || !('roles' in user)) { user = Meteor.users.findOne( {_id: user._id}, {fields: {roles: 1}}); @@ -1183,7 +1185,7 @@ _.extend(Roles, { return function (userRole) { // == used on purpose in "userRole.scope == null" return (userRole._id === roleName && userRole.scope === scope) || - (userRole._id === roleName && (!_.has(userRole, 'scope') || userRole.scope == null)); + (userRole._id === roleName && (!('scope' in userRole) || userRole.scope == null)); }; }, @@ -1199,7 +1201,7 @@ _.extend(Roles, { return function (userRole) { // == used on purpose in "userRole.scope == null" return (userRole.scope === scope) || - (!_.has(userRole, 'scope') || userRole.scope == null); + (!('scope' in userRole) || userRole.scope == null); }; }, @@ -1225,7 +1227,7 @@ _.extend(Roles, { * @static */ _checkRoleName: function (roleName) { - if (!roleName || !_.isString(roleName) || Roles._trim(roleName) !== roleName) { + if (!roleName || typeof roleName !== 'string' || Roles._trim(roleName) !== roleName) { throw new Error("Invalid role name '" + roleName + "'."); } }, @@ -1240,9 +1242,9 @@ _.extend(Roles, { * @static */ _normalizeOptions: function (options) { - options = _.isUndefined(options) ? {} : options; + options = options === undefined ? {} : options; - if (options === null || _.isString(options)) { + if (options === null || typeof options === 'string') { options = {scope: options}; } @@ -1281,7 +1283,7 @@ _.extend(Roles, { _checkScopeName: function (scopeName) { if (scopeName === null) return; - if (!scopeName || !_.isString(scopeName) || Roles._trim(scopeName) !== scopeName) { + if (!scopeName || typeof scopeName !== 'string' || Roles._trim(scopeName) !== scopeName) { throw new Error("Invalid scope name '" + scopeName + "'."); } }, @@ -1300,7 +1302,6 @@ _.extend(Roles, { return string.replace(/^\s+|\s+$/g, ''); } } - -}); // end _.extend(Roles ...) +}); }()); diff --git a/roles/roles_server.js b/roles/roles_server.js index 72fd941..a4b2e82 100644 --- a/roles/roles_server.js +++ b/roles/roles_server.js @@ -23,7 +23,7 @@ Meteor.publish('_roles', function () { {fields: fields}); }); -_.extend(Roles, { +Object.assign(Roles, { /** * @method _isNewRole * @param {Object} role `Meteor.roles` document. @@ -34,7 +34,7 @@ _.extend(Roles, { * @static */ _isNewRole: function (role) { - return !_.has(role, 'name') && _.has(role, 'children'); + return !('name' in role) && 'children' in role; }, /** @@ -47,7 +47,7 @@ _.extend(Roles, { * @static */ _isOldRole: function (role) { - return _.has(role, 'name') && !_.has(role, 'children'); + return 'name' in role && !('children' in role); }, /** @@ -60,7 +60,7 @@ _.extend(Roles, { * @static */ _isNewField: function (roles) { - return _.isArray(roles) && _.isObject(roles[0]); + return Array.isArray(roles) && (typeof roles[0] === 'object'); }, /** @@ -73,7 +73,7 @@ _.extend(Roles, { * @static */ _isOldField: function (roles) { - return (_.isArray(roles) && _.isString(roles[0])) || (_.isObject(roles) && !_.isArray(roles)); + return (Array.isArray(roles) && (typeof roles[0] === 'string')) || ((typeof roles === 'object') && !Array.isArray(roles)); }, /** @@ -85,7 +85,7 @@ _.extend(Roles, { * @static */ _convertToNewRole: function (oldRole) { - if (!_.isString(oldRole.name)) throw new Error("Role name '" + oldRole.name + "' is not a string."); + if (!(typeof oldRole.name === 'string')) throw new Error("Role name '" + oldRole.name + "' is not a string."); return { _id: oldRole.name, @@ -102,7 +102,7 @@ _.extend(Roles, { * @static */ _convertToOldRole: function (newRole) { - if (!_.isString(newRole._id)) throw new Error("Role name '" + newRole._id + "' is not a string."); + if (!(typeof newRole._id === 'string')) throw new Error("Role name '" + newRole._id + "' is not a string."); return { name: newRole._id @@ -120,9 +120,9 @@ _.extend(Roles, { */ _convertToNewField: function (oldRoles, convertUnderscoresToDots) { var roles = []; - if (_.isArray(oldRoles)) { - _.each(oldRoles, function (role, index) { - if (!_.isString(role)) throw new Error("Role '" + role + "' is not a string."); + if (Array.isArray(oldRoles)) { + oldRoles.forEach(function (role, index) { + if (!(typeof role === 'string')) throw new Error("Role '" + role + "' is not a string."); roles.push({ _id: role, @@ -131,8 +131,8 @@ _.extend(Roles, { }) }); } - else if (_.isObject(oldRoles)) { - _.each(oldRoles, function (rolesArray, group) { + else if (typeof oldRoles === 'object') { + Object.entries(oldRoles).forEach(([group, rolesArray]) => { if (group === '__global_roles__') { group = null; } @@ -141,8 +141,8 @@ _.extend(Roles, { group = group.replace(/_/g, '.'); } - _.each(rolesArray, function (role, index) { - if (!_.isString(role)) throw new Error("Role '" + role + "' is not a string."); + rolesArray.forEach(function (role) { + if (!(typeof role === 'string')) throw new Error("Role '" + role + "' is not a string."); roles.push({ _id: role, @@ -174,8 +174,8 @@ _.extend(Roles, { roles = []; } - _.each(newRoles, function (userRole, index) { - if (!_.isObject(userRole)) throw new Error("Role '" + userRole + "' is not an object."); + newRoles.forEach(function (userRole) { + if (!(typeof userRole === 'object')) throw new Error("Role '" + userRole + "' is not an object."); // We assume that we are converting back a failed migration, so values can only be // what were valid values in 1.0. So no group names starting with $ and no subroles. diff --git a/roles/tests/client.js b/roles/tests/client.js index 34444d0..6c6e802 100644 --- a/roles/tests/client.js +++ b/roles/tests/client.js @@ -48,8 +48,8 @@ var user = users[username]; // test using user object rather than userId to avoid mocking - _.each(roles, function (role) { - var expected = _.contains(expectedRoles, role), + roles.forEach(function (role) { + var expected = expectedRoles.includes(role), msg = username + ' expected to have \'' + role + '\' permission but does not', nmsg = username + ' had un-expected permission ' + role; @@ -68,7 +68,7 @@ }; Tinytest.add( - 'roles - can check current users roles via template helper', + 'roles - can check current users roles via template helper', function (test) { var isInRole, expected, @@ -86,7 +86,7 @@ expected = true; actual = isInRole('admin, editor'); test.equal(actual, expected); - + expected = true; actual = isInRole('admin'); test.equal(actual, expected); @@ -97,20 +97,20 @@ }); Tinytest.add( - 'roles - can check if user is in role', + 'roles - can check if user is in role', function (test) { testUser(test, 'eve', ['admin', 'editor']); }); Tinytest.add( - 'roles - can check if user is in role by group', + 'roles - can check if user is in role by group', function (test) { testUser(test, 'bob', ['user'], 'group1'); testUser(test, 'bob', ['editor'], 'group2'); }); Tinytest.add( - 'roles - can check if user is in role with Roles.GLOBAL_GROUP', + 'roles - can check if user is in role with Roles.GLOBAL_GROUP', function (test) { testUser(test, 'joe', ['admin']); testUser(test, 'joe', ['admin'], Roles.GLOBAL_GROUP); diff --git a/roles/tests/server.js b/roles/tests/server.js index e6f6f58..557667d 100644 --- a/roles/tests/server.js +++ b/roles/tests/server.js @@ -26,7 +26,7 @@ function testUser (test, username, expectedRoles, scope) { var userId = users[username], userObj = Meteor.users.findOne({_id: userId}); - + // check using user ids (makes db calls) _innerTest(test, userId, username, expectedRoles, scope); @@ -36,8 +36,8 @@ function _innerTest (test, userParam, username, expectedRoles, scope) { // test that user has only the roles expected and no others - _.each(roles, function (role) { - var expected = _.contains(expectedRoles, role), + roles.forEach(function (role) { + var expected = expectedRoles.includes(role), msg = username + ' expected to have \'' + role + '\' role but does not', nmsg = username + ' had the following un-expected role: ' + role; @@ -49,18 +49,42 @@ }) } + var deepEqual = function (x, y) { + if (x === y) { + return true; + } + else if ((typeof x == "object" && x != null) && (typeof y == "object" && y != null)) { + if (Object.keys(x).length != Object.keys(y).length) + return false; + + for (var prop in x) { + if (y.hasOwnProperty(prop)) + { + if (! deepEqual(x[prop], y[prop])) + return false; + } + else + return false; + } + + return true; + } + else + return false; + } + function itemsEqual (test, actual, expected) { actual = actual || []; expected = expected || []; - function intersectionObjects(/*args*/) { + function intersectionObjects(...args) { var array, rest; - array = arguments[0]; - rest = 2 <= arguments.length ? _.toArray(arguments).slice(1) : []; - return _.filter(_.uniq(array), function (item) { - return _.every(rest, function (other) { - return _.any(other, function (element) { - return _.isEqual(element, item); + array = args[0]; + rest = 2 <= args.length ? args.slice(1) : []; + return [...new Set(array)].filter(function (item) { + return rest.every(function (other) { + return other.some(function (element) { + return deepEqual(element, item); }); }); }); @@ -79,7 +103,7 @@ } Tinytest.add( - 'roles - can create and delete roles', + 'roles - can create and delete roles', function (test) { reset(); @@ -101,7 +125,7 @@ }); Tinytest.add( - 'roles - can\'t create duplicate roles', + 'roles - can\'t create duplicate roles', function (test) { reset(); @@ -111,7 +135,7 @@ }); Tinytest.add( - 'roles - can\'t create role with empty names', + 'roles - can\'t create role with empty names', function (test) { reset(); @@ -161,7 +185,7 @@ }); Tinytest.add( - 'roles - can check if user is in role', + 'roles - can check if user is in role', function (test) { reset(); @@ -309,7 +333,7 @@ }); Tinytest.add( - 'roles - can check if non-existant user is in role', + 'roles - can check if non-existant user is in role', function (test) { reset(); @@ -317,16 +341,16 @@ }); Tinytest.add( - 'roles - can check if null user is in role', + 'roles - can check if null user is in role', function (test) { var user = null; reset(); - + test.isFalse(Roles.userIsInRole(user, 'admin')); }); Tinytest.add( - 'roles - can check user against several roles at once', + 'roles - can check user against several roles at once', function (test) { var user; reset(); @@ -342,7 +366,7 @@ }); Tinytest.add( - 'roles - can\'t add non-existent user to role', + 'roles - can\'t add non-existent user to role', function (test) { reset(); @@ -386,7 +410,7 @@ }); Tinytest.add( - 'roles - can add individual users to roles', + 'roles - can add individual users to roles', function (test) { reset(); @@ -439,7 +463,7 @@ }); Tinytest.add( - 'roles - can add user to roles via user object', + 'roles - can add user to roles via user object', function (test) { reset(); @@ -464,7 +488,7 @@ }); Tinytest.add( - 'roles - can add user to roles multiple times', + 'roles - can add user to roles multiple times', function (test) { reset(); @@ -512,7 +536,7 @@ }); Tinytest.add( - 'roles - can add multiple users to roles', + 'roles - can add multiple users to roles', function (test) { reset(); @@ -565,7 +589,7 @@ }); Tinytest.add( - 'roles - can remove individual users from roles', + 'roles - can remove individual users from roles', function (test) { reset(); @@ -603,7 +627,7 @@ }); Tinytest.add( - 'roles - can remove users from roles via user object', + 'roles - can remove users from roles via user object', function (test) { reset(); @@ -612,7 +636,7 @@ var eve = Meteor.users.findOne({_id: users.eve}), bob = Meteor.users.findOne({_id: users.bob}); - + // remove user role - one user Roles.addUsersToRoles([eve, bob], ['editor', 'user']); testUser(test, 'eve', ['editor', 'user']); @@ -679,7 +703,7 @@ }); Tinytest.add( - 'roles - can remove multiple users from roles', + 'roles - can remove multiple users from roles', function (test) { reset(); @@ -735,7 +759,7 @@ }); Tinytest.add( - 'roles - can set user roles', + 'roles - can set user roles', function (test) { reset(); @@ -746,7 +770,7 @@ var eve = Meteor.users.findOne({_id: users.eve}), bob = Meteor.users.findOne({_id: users.bob}), joe = Meteor.users.findOne({_id: users.joe}); - + Roles.setUserRoles([users.eve, bob], ['editor', 'user']); testUser(test, 'eve', ['editor', 'user']); testUser(test, 'bob', ['editor', 'user']); @@ -786,7 +810,7 @@ var eve = Meteor.users.findOne({_id: users.eve}), bob = Meteor.users.findOne({_id: users.bob}), joe = Meteor.users.findOne({_id: users.joe}); - + Roles.setUserRoles([users.eve, users.bob], ['editor', 'user'], 'scope1'); Roles.setUserRoles([users.bob, users.joe], ['admin'], 'scope2'); testUser(test, 'eve', ['editor', 'user'], 'scope1'); @@ -823,8 +847,8 @@ testUser(test, 'bob', ['admin', 'editor'], 'scope2'); testUser(test, 'joe', ['editor'], 'scope2'); - test.isTrue(_.contains(_.pluck(Roles.getRolesForUser(users.bob, {anyScope: true, fullObjects: true}), 'scope'), 'scope1')); - test.isFalse(_.contains(_.pluck(Roles.getRolesForUser(users.joe, {anyScope: true, fullObjects: true}), 'scope'), 'scope1')); + test.isTrue(Roles.getRolesForUser(users.bob, {anyScope: true, fullObjects: true}).map(r => r.scope).includes('scope1')); + test.isFalse(Roles.getRolesForUser(users.joe, {anyScope: true, fullObjects: true}).map(r => r.scope).includes('scope1')); Roles.setUserRoles([bob, users.joe], [], 'scope1'); testUser(test, 'eve', ['user'], 'scope1'); @@ -835,8 +859,8 @@ testUser(test, 'joe', ['editor'], 'scope2'); // When roles in a given scope are removed, we do not want any dangling database content for that scope. - test.isFalse(_.contains(_.pluck(Roles.getRolesForUser(users.bob, {anyScope: true, fullObjects: true}), 'scope'), 'scope1')); - test.isFalse(_.contains(_.pluck(Roles.getRolesForUser(users.joe, {anyScope: true, fullObjects: true}), 'scope'), 'scope1')); + test.isFalse(Roles.getRolesForUser(users.bob, {anyScope: true, fullObjects: true}).map(r => r.scope).includes('scope1')); + test.isFalse(Roles.getRolesForUser(users.joe, {anyScope: true, fullObjects: true}).map(r => r.scope).includes('scope1')); }); Tinytest.add( @@ -850,7 +874,7 @@ var eve = Meteor.users.findOne({_id: users.eve}), bob = Meteor.users.findOne({_id: users.bob}), joe = Meteor.users.findOne({_id: users.joe}); - + Roles.addUsersToRoles(eve, 'admin', Roles.GLOBAL_SCOPE); testUser(test, 'eve', ['admin'], 'scope1'); testUser(test, 'eve', ['admin']); @@ -862,25 +886,25 @@ Tinytest.add( - 'roles - can get all roles', + 'roles - can get all roles', function (test) { reset(); - _.each(roles, function (role) { + roles.forEach(function (role) { Roles.createRole(role); }); // compare roles, sorted alphabetically - var expected = _.clone(roles), - actual = _.pluck(Roles.getAllRoles().fetch(), '_id'); + var expected = roles, + actual = Roles.getAllRoles().fetch().map(r => r._id); test.equal(actual, expected); - test.equal(_.pluck(Roles.getAllRoles({sort: {_id: -1}}).fetch(), '_id'), expected.reverse()); + test.equal(Roles.getAllRoles({sort: {_id: -1}}).fetch().map(r => r._id), expected.reverse()); }); Tinytest.add( - 'roles - can\'t get roles for non-existant user', + 'roles - can\'t get roles for non-existant user', function (test) { reset(); test.equal(Roles.getRolesForUser('1'), []); @@ -888,7 +912,7 @@ }); Tinytest.add( - 'roles - can get all roles for user', + 'roles - can get all roles for user', function (test) { reset(); @@ -1133,7 +1157,7 @@ test.equal(Roles.getRolesForUser(userObj, 'scope1'), ['editor']); test.equal(Roles.getRolesForUser(userObj), ['editor']); }); - + Tinytest.add( 'roles - can get all scopes for user', function (test) { @@ -1156,7 +1180,7 @@ userObj = Meteor.users.findOne({_id: userId}); test.equal(Roles.getScopesForUser(userObj), ['scope1', 'scope2']); }); - + Tinytest.add( 'roles - can get all scopes for user by role', function (test) { @@ -1183,7 +1207,7 @@ test.equal(Roles.getScopesForUser(userObj, 'editor'), ['scope1', 'scope2']); test.equal(Roles.getScopesForUser(userObj, 'admin'), []); }); - + Tinytest.add( 'roles - getScopesForUser returns [] when not using scopes', function (test) { @@ -1249,7 +1273,7 @@ test.equal(Roles.getScopesForUser(userObj, ['editor', 'moderator']), ['group1', 'group2', 'group3']); test.equal(Roles.getScopesForUser(userObj, ['user', 'moderator']), ['group2', 'group3']); }); - + Tinytest.add( 'roles - getting all scopes for user does not include GLOBAL_SCOPE', function (test) { @@ -1288,7 +1312,7 @@ Tinytest.add( - 'roles - can get all users in role', + 'roles - can get all users in role', function (test) { reset(); @@ -1300,7 +1324,7 @@ Roles.addUsersToRoles([users.bob, users.joe], ['editor']); var expected = [users.eve, users.joe], - actual = _.pluck(Roles.getUsersInRole('admin').fetch(), '_id'); + actual = Roles.getUsersInRole('admin').fetch().map(r => r._id); itemsEqual(test, actual, expected); }); @@ -1317,22 +1341,22 @@ Roles.addUsersToRoles([users.bob, users.joe], ['admin'], 'scope2'); var expected = [users.eve, users.joe], - actual = _.pluck(Roles.getUsersInRole('admin', 'scope1').fetch(), '_id'); + actual = Roles.getUsersInRole('admin', 'scope1').fetch().map(r => r._id); itemsEqual(test, actual, expected); expected = [users.eve, users.joe]; - actual = _.pluck(Roles.getUsersInRole('admin', {scope: 'scope1'}).fetch(), '_id'); + actual = Roles.getUsersInRole('admin', {scope: 'scope1'}).fetch().map(r => r._id); itemsEqual(test, actual, expected); expected = [users.eve, users.bob, users.joe]; - actual = _.pluck(Roles.getUsersInRole('admin', {anyScope: true}).fetch(), '_id'); + actual = Roles.getUsersInRole('admin', {anyScope: true}).fetch().map(r => r._id); itemsEqual(test, actual, expected); - actual = _.pluck(Roles.getUsersInRole('admin').fetch(), '_id'); + actual = Roles.getUsersInRole('admin').fetch().map(r => r._id); test.equal(actual, []); }); - + Tinytest.add( 'roles - can get all users in role by scope including Roles.GLOBAL_SCOPE', function (test) { @@ -1345,22 +1369,22 @@ Roles.addUsersToRoles([users.bob, users.joe], ['admin'], 'scope2'); var expected = [users.eve], - actual = _.pluck(Roles.getUsersInRole('admin', 'scope1').fetch(), '_id'); + actual = Roles.getUsersInRole('admin', 'scope1').fetch().map(r => r._id); itemsEqual(test, actual, expected); expected = [users.eve, users.bob, users.joe]; - actual = _.pluck(Roles.getUsersInRole('admin', 'scope2').fetch(), '_id'); + actual = Roles.getUsersInRole('admin', 'scope2').fetch().map(r => r._id); itemsEqual(test, actual, expected); expected = [users.eve]; - actual = _.pluck(Roles.getUsersInRole('admin').fetch(), '_id'); + actual = Roles.getUsersInRole('admin').fetch().map(r => r._id); itemsEqual(test, actual, expected); expected = [users.eve, users.bob, users.joe]; - actual = _.pluck(Roles.getUsersInRole('admin', {anyScope: true}).fetch(), '_id'); + actual = Roles.getUsersInRole('admin', {anyScope: true}).fetch().map(r => r._id); itemsEqual(test, actual, expected); }); @@ -1436,7 +1460,7 @@ testUser(test, 'bob', ['admin'], 'scope2'); testUser(test, 'bob', ['admin'], 'scope1'); }); - + Tinytest.add( 'roles - Roles.GLOBAL_SCOPE also checked when scope not specified', function (test) { From 7653119c2cdac387a6b3ab7b9a5d6a83e6c9a95d Mon Sep 17 00:00:00 2001 From: Simon Schick Date: Mon, 21 Jan 2019 14:34:53 +0400 Subject: [PATCH 03/26] Removed docs-folder and added npm dev-dependency on yuidocjs --- .gitignore | 4 +- docs/api.js | 25 - docs/assets/css/external-small.png | Bin 491 -> 0 bytes docs/assets/css/logo.png | Bin 7143 -> 0 bytes docs/assets/css/main.css | 783 ---- docs/assets/favicon.ico | Bin 5430 -> 0 bytes docs/assets/img/spinner.gif | Bin 2685 -> 0 bytes docs/assets/index.html | 10 - docs/assets/js/api-filter.js | 56 - docs/assets/js/api-list.js | 255 -- docs/assets/js/api-search.js | 98 - docs/assets/js/apidocs.js | 376 -- docs/assets/js/yui-prettify.js | 17 - docs/assets/vendor/prettify/CHANGES.html | 130 - docs/assets/vendor/prettify/COPYING | 202 - docs/assets/vendor/prettify/README.html | 203 - docs/assets/vendor/prettify/prettify-min.css | 1 - docs/assets/vendor/prettify/prettify-min.js | 1 - docs/classes/Roles.html | 3779 ----------------- docs/classes/UIHelpers.html | 246 -- docs/classes/index.html | 10 - docs/data.json | 1260 ------ docs/elements/index.html | 10 - docs/files/index.html | 10 - docs/files/roles_client_subscriptions.js.html | 122 - docs/files/roles_client_uiHelpers.js.html | 196 - docs/files/roles_roles_common.js.html | 1410 ------ docs/files/roles_roles_server.js.html | 423 -- docs/index.html | 118 - docs/modules/Roles.html | 150 - docs/modules/UIHelpers.html | 134 - docs/modules/index.html | 10 - package-lock.json | 728 ++++ package.json | 5 + 34 files changed, 736 insertions(+), 10036 deletions(-) delete mode 100644 docs/api.js delete mode 100644 docs/assets/css/external-small.png delete mode 100644 docs/assets/css/logo.png delete mode 100644 docs/assets/css/main.css delete mode 100644 docs/assets/favicon.ico delete mode 100644 docs/assets/img/spinner.gif delete mode 100644 docs/assets/index.html delete mode 100644 docs/assets/js/api-filter.js delete mode 100644 docs/assets/js/api-list.js delete mode 100644 docs/assets/js/api-search.js delete mode 100644 docs/assets/js/apidocs.js delete mode 100644 docs/assets/js/yui-prettify.js delete mode 100644 docs/assets/vendor/prettify/CHANGES.html delete mode 100644 docs/assets/vendor/prettify/COPYING delete mode 100644 docs/assets/vendor/prettify/README.html delete mode 100644 docs/assets/vendor/prettify/prettify-min.css delete mode 100644 docs/assets/vendor/prettify/prettify-min.js delete mode 100644 docs/classes/Roles.html delete mode 100644 docs/classes/UIHelpers.html delete mode 100644 docs/classes/index.html delete mode 100644 docs/data.json delete mode 100644 docs/elements/index.html delete mode 100644 docs/files/index.html delete mode 100644 docs/files/roles_client_subscriptions.js.html delete mode 100644 docs/files/roles_client_uiHelpers.js.html delete mode 100644 docs/files/roles_roles_common.js.html delete mode 100644 docs/files/roles_roles_server.js.html delete mode 100644 docs/index.html delete mode 100644 docs/modules/Roles.html delete mode 100644 docs/modules/UIHelpers.html delete mode 100644 docs/modules/index.html create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.gitignore b/.gitignore index 10aed3d..627a5c1 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,6 @@ results npm-debug.log smart.lock -.idea \ No newline at end of file +.idea +docs/ +node_modules/ \ No newline at end of file diff --git a/docs/api.js b/docs/api.js deleted file mode 100644 index 89f4eb9..0000000 --- a/docs/api.js +++ /dev/null @@ -1,25 +0,0 @@ -YUI.add("yuidoc-meta", function(Y) { - Y.YUIDoc = { meta: { - "classes": [ - "Roles", - "UIHelpers" - ], - "modules": [ - "Roles", - "UIHelpers" - ], - "allModules": [ - { - "displayName": "Roles", - "name": "Roles", - "description": "Provides functions related to user authorization. Compatible with built-in Meteor accounts packages.\n\nIt uses `roles` field to `Meteor.users` documents which is an array of subdocuments with the following\nschema:\n - `_id`: role name\n - `scope`: scope name\n - `assigned`: boolean, if the role was manually assigned (set), or was automatically inferred (eg., subroles)\n\nRoles themselves are accessible throgh `Meteor.roles` collection and documents consist of:\n - `_id`: role name\n - `children`: list of subdocuments:\n - `_id`\n\nChildren list elements are subdocuments so that they can be easier extended in the future or by plugins.\n\nRoles can have multiple parents and can be children (subroles) of multiple roles.\n\nExample: `{_id: \"admin\", children: [{_id: \"editor\"}]}`" - }, - { - "displayName": "UIHelpers", - "name": "UIHelpers", - "description": "Convenience functions for use on client.\n\nNOTE: You must restrict user actions on the server-side; any\nclient-side checks are strictly for convenience and must not be\ntrusted." - } - ], - "elements": [] -} }; -}); \ No newline at end of file diff --git a/docs/assets/css/external-small.png b/docs/assets/css/external-small.png deleted file mode 100644 index 759a1cdcb5b1697e5be290d98b830e279cd71f3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 491 zcmVDs{zR1^XE?tfB*h@ASKHAa7wwn{MEbP z7_^nS7{V*>+A}bS;P%45fB%Ai|Neasi2rl3{=EO;!w318%8Ovl7jArHc=P5Brfr~D z0AYimtss2w$hlYlfd>7*aO3TNzw875LBK0xAD9Np|A(oEVYnB*eE9~V6wP%78SXuL z&#-X)Er#`zY#Ce)^8hM>B_8 diff --git a/docs/assets/css/logo.png b/docs/assets/css/logo.png deleted file mode 100644 index c82444af95895d38bea6fe96cc5354a7419f770c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7143 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