/
githubmirror
/
meteor
Обзор
Документация
Войти
/
githubmirror
/
meteor
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
devel
packages/roles/tests/serverAsync.js
3 086 строк
90 KB
Nacho Codoñer
Merge branch 'release-3.4.1' into devel
30 мар 2026, 19:04
Не верифицирован
30 мар 2026, 19:04
52185c6
Код
Авторство
О чём код?
import { Meteor } from "meteor/meteor"; import { Tinytest } from "meteor/tinytest"; // To ensure that the files are loaded for coverage import "../roles_common_async"; // Publication for the client tests Meteor.publish("client_assignments", async () => { return Meteor.roleAssignment.find(); }); // To allow inserting on the client, needed for testing. Meteor.roleAssignment.allow({ insert() { return true; }, insertAsync() { return true; }, update() { return true; }, updateAsync() { return true; }, remove() { return true; }, removeAsync() { return true; }, }); const hasAnyKeys = (test, obj, keys) => { if (typeof keys === "string") { keys = [keys]; } const hasKey = keys.some((key) => Object.prototype.hasOwnProperty.call(obj, key) ); test.equal( hasKey, true, `Object should have at least one of these keys: ${keys.join(", ")}` ); }; const sameMembers = (test, value, expected) => { // Sort arrays to ensure consistent order const sortedValue = [...value].sort(); const sortedExpected = [...expected].sort(); test.equal( JSON.stringify(sortedValue), JSON.stringify(sortedExpected), "Arrays should have the same members" ); }; // Helper to sort object keys recursively const sortObjectKeys = (obj) => { if (Array.isArray(obj)) { return obj.map(sortObjectKeys); } if (obj && typeof obj === "object") { return Object.keys(obj) .sort() .reduce((sorted, key) => { sorted[key] = sortObjectKeys(obj[key]); return sorted; }, {}); } return obj; }; const sameDeepMembers = (test, value, expected) => { const sortedValue = sortObjectKeys(value); const sortedExpected = sortObjectKeys(expected); test.equal( JSON.stringify(sortedValue), JSON.stringify(sortedExpected), "Role assignments should match expected structure" ); }; const sameDeepUnorderedMembers = (test, value, expected) => { const sortAndStringify = (arr) => { return JSON.stringify(arr.map(item => JSON.stringify(sortObjectKeys(item))).sort()); }; const sortedValue = sortAndStringify(value); const sortedExpected = sortAndStringify(expected); test.equal(sortedValue, sortedExpected, 'Arrays should have the same elements, regardless of order'); }; const hasProp = (target, prop) => Object.hasOwnProperty.call(target, prop); let users = {}; const roles = ["admin", "editor", "user"]; Meteor.publish("_roleAssignments", function () { const loggedInUserId = this.userId; if (!loggedInUserId) { this.ready(); return; } return Meteor.roleAssignment.find({ _id: loggedInUserId }); }); async function addUser(name) { return await Meteor.users.insertAsync({ username: name }); } async function testUser(test, username, expectedRoles, scope) { const userId = users[username]; const userObj = await Meteor.users.findOneAsync({ _id: userId }); // check using user ids (makes db calls) await _innerTest(test, userId, username, expectedRoles, scope); // check using passed-in user object await _innerTest(test, userObj, username, expectedRoles, scope); } async function _innerTest(test, userParam, username, expectedRoles, scope) { // test that user has only the roles expected and no others for (const role of roles) { const expected = expectedRoles.includes(role); const msg = username + " expected to have '" + role + "' role but does not"; const nmsg = username + " had the following un-expected role: " + role; const result = await Roles.userIsInRoleAsync(userParam, role, scope); if (expected) { test.equal(result, true, msg); } else { test.equal(result, false, nmsg); } } } async function clearData() { await Meteor.roles.removeAsync({}); await Meteor.roleAssignment.removeAsync({}); await Meteor.users.removeAsync({}); users = { eve: await addUser("eve"), bob: await addUser("bob"), joe: await addUser("joe"), }; } Tinytest.addAsync("roles -can create and delete roles", async function (test) { await clearData(); const role1Id = await Roles.createRoleAsync("test1"); const test1a = await Meteor.roles.findOneAsync(); const test1b = await Meteor.roles.findOneAsync(role1Id); test.equal(test1a._id, "test1"); test.equal(test1b._id, "test1"); const role2Id = await Roles.createRoleAsync("test2"); const test2a = await Meteor.roles.findOneAsync({ _id: "test2" }); const test2b = await Meteor.roles.findOneAsync(role2Id); test.equal(test2a._id, "test2"); test.equal(test2b._id, "test2"); test.equal(await Meteor.roles.countDocuments(), 2); await Roles.deleteRoleAsync("test1"); const undefinedTest = await Meteor.roles.findOneAsync({ _id: "test1" }); test.equal(typeof undefinedTest, "undefined"); await Roles.deleteRoleAsync("test2"); const undefinedTest2 = await Meteor.roles.findOneAsync(); test.equal(typeof undefinedTest2, "undefined"); }); Tinytest.addAsync( "roles -can try to remove non-existing roles without crashing", async function (test) { await clearData(); try { await Roles.deleteRoleAsync("non-existing-role"); } catch (e) { test.notExists(e); } // Roles.deleteRoleAsync('non-existing-role').should.be.fulfilled } ); Tinytest.addAsync("roles -can't create duplicate roles", async function (test) { await clearData(); try { await Roles.createRoleAsync("test1"); } catch (e) { test.notExists(e); } try { await Roles.createRoleAsync("test1"); } catch (e) { test.exists(e); } test.isNull(await Roles.createRoleAsync("test1", { unlessExists: true })); }); Tinytest.addAsync( "roles - can't create role with empty names", async (test) => { await clearData(); try { await Roles.createRoleAsync(""); test.fail("Should throw error for empty name"); } catch (e) { test.matches(e.message, /Invalid role name/); } try { await Roles.createRoleAsync(null); test.fail("Should throw error for null name"); } catch (e) { test.matches(e.message, /Invalid role name/); } try { await Roles.createRoleAsync(" "); test.fail("Should throw error for space name"); } catch (e) { test.matches(e.message, /Invalid role name/); } try { await Roles.createRoleAsync(" foobar"); test.fail("Should throw error for leading space"); } catch (e) { test.matches(e.message, /Invalid role name/); } try { await Roles.createRoleAsync(" foobar "); test.fail("Should throw error for trailing space"); } catch (e) { test.matches(e.message, /Invalid role name/); } } ); Tinytest.addAsync("roles - can't use invalid scope names", async (test) => { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"], "scope1"); await Roles.addUsersToRolesAsync(users.eve, ["editor"], "scope2"); try { await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"], ""); test.fail("Should throw error for empty scope"); } catch (e) { test.matches(e.message, /Invalid scope name/); } try { await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"], " "); test.fail("Should throw error for space scope"); } catch (e) { test.matches(e.message, /Invalid scope name/); } try { await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"], " foobar"); test.fail("Should throw error for leading space in scope"); } catch (e) { test.matches(e.message, /Invalid scope name/); } }); Tinytest.addAsync("roles -can check if user is in role", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"]); await testUser(test, "eve", ["admin", "user"]); }); Tinytest.addAsync( "roles -can check if user is in role by scope", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"], "scope1"); await Roles.addUsersToRolesAsync(users.eve, ["editor"], "scope2"); await testUser(test, "eve", ["admin", "user"], "scope1"); await testUser(test, "eve", ["editor"], "scope2"); test.isFalse( await Roles.userIsInRoleAsync(users.eve, ["admin", "user"], "scope2") ); test.isFalse( await Roles.userIsInRoleAsync(users.eve, ["editor"], "scope1") ); test.isTrue( await Roles.userIsInRoleAsync(users.eve, ["admin", "user"], { anyScope: true, }) ); test.isTrue( await Roles.userIsInRoleAsync(users.eve, ["editor"], { anyScope: true }) ); } ); Tinytest.addAsync( "roles -can check if user is in role by scope through options", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"], { scope: "scope1", }); await Roles.addUsersToRolesAsync(users.eve, ["editor"], { scope: "scope2", }); await testUser(test, "eve", ["admin", "user"], { scope: "scope1" }); await testUser(test, "eve", ["editor"], { scope: "scope2" }); } ); Tinytest.addAsync( "roles -can check if user is in role by scope with global role", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"], "scope1"); await Roles.addUsersToRolesAsync(users.eve, ["editor"], "scope2"); await Roles.addUsersToRolesAsync(users.eve, ["admin"]); test.isTrue(await Roles.userIsInRoleAsync(users.eve, ["user"], "scope1")); test.isTrue(await Roles.userIsInRoleAsync(users.eve, ["editor"], "scope2")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, ["user"])); test.isFalse(await Roles.userIsInRoleAsync(users.eve, ["editor"])); test.isFalse(await Roles.userIsInRoleAsync(users.eve, ["user"], null)); test.isFalse(await Roles.userIsInRoleAsync(users.eve, ["editor"], null)); test.isFalse(await Roles.userIsInRoleAsync(users.eve, ["user"], "scope2")); test.isFalse( await Roles.userIsInRoleAsync(users.eve, ["editor"], "scope1") ); test.isTrue(await Roles.userIsInRoleAsync(users.eve, ["admin"], "scope2")); test.isTrue(await Roles.userIsInRoleAsync(users.eve, ["admin"], "scope1")); test.isTrue(await Roles.userIsInRoleAsync(users.eve, ["admin"])); test.isTrue(await Roles.userIsInRoleAsync(users.eve, ["admin"], null)); } ); Tinytest.addAsync("roles -renaming scopes", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"], "scope1"); await Roles.addUsersToRolesAsync(users.eve, ["editor"], "scope2"); await testUser(test, "eve", ["admin", "user"], "scope1"); await testUser(test, "eve", ["editor"], "scope2"); await Roles.renameScopeAsync("scope1", "scope3"); await testUser(test, "eve", ["admin", "user"], "scope3"); await testUser(test, "eve", ["editor"], "scope2"); test.isFalse( await Roles.userIsInRoleAsync(users.eve, ["admin", "user"], "scope1") ); test.isFalse( await Roles.userIsInRoleAsync(users.eve, ["admin", "user"], "scope2") ); try { await Roles.renameScopeAsync("scope3"); test.fail("Should throw error for invalid scope name"); } catch (e) { test.matches(e.message, /Invalid scope name/); } await Roles.renameScopeAsync("scope3", null); await testUser(test, "eve", ["admin", "user", "editor"], "scope2"); test.isFalse(await Roles.userIsInRoleAsync(users.eve, ["editor"])); test.isTrue(await Roles.userIsInRoleAsync(users.eve, ["admin"])); test.isTrue(await Roles.userIsInRoleAsync(users.eve, ["user"])); test.isFalse(await Roles.userIsInRoleAsync(users.eve, ["editor"], null)); test.isTrue(await Roles.userIsInRoleAsync(users.eve, ["admin"], null)); test.isTrue(await Roles.userIsInRoleAsync(users.eve, ["user"], null)); await Roles.renameScopeAsync(null, "scope2"); await testUser(test, "eve", ["admin", "user", "editor"], "scope2"); test.isFalse(await Roles.userIsInRoleAsync(users.eve, ["editor"])); test.isFalse(await Roles.userIsInRoleAsync(users.eve, ["admin"])); test.isFalse(await Roles.userIsInRoleAsync(users.eve, ["user"])); test.isFalse(await Roles.userIsInRoleAsync(users.eve, ["editor"], null)); test.isFalse(await Roles.userIsInRoleAsync(users.eve, ["admin"], null)); test.isFalse(await Roles.userIsInRoleAsync(users.eve, ["user"], null)); }); Tinytest.addAsync("roles -removing scopes", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"], "scope1"); await Roles.addUsersToRolesAsync(users.eve, ["editor"], "scope2"); await testUser(test, "eve", ["admin", "user"], "scope1"); await testUser(test, "eve", ["editor"], "scope2"); await Roles.removeScopeAsync("scope1"); await testUser(test, "eve", ["editor"], "scope2"); test.isFalse( await Roles.userIsInRoleAsync(users.eve, ["admin", "user"], "scope1") ); test.isFalse( await Roles.userIsInRoleAsync(users.eve, ["admin", "user"], "scope2") ); }); Tinytest.addAsync( "roles -can check if non-existant user is in role", async function (test) { await clearData(); test.isFalse(await Roles.userIsInRoleAsync("1", "admin")); } ); Tinytest.addAsync( "roles -can check if null user is in role", async function (test) { await clearData(); test.isFalse(await Roles.userIsInRoleAsync(null, "admin")); } ); Tinytest.addAsync( "roles -can check user against several roles at once", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"]); const user = await Meteor.users.findOneAsync({ _id: users.eve }); // we can check the non-existing role test.isTrue(await Roles.userIsInRoleAsync(user, ["editor", "admin"])); } ); Tinytest.addAsync( "roles -can't add non-existent user to role", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.addUsersToRolesAsync(["1"], ["admin"]); test.equal(await Meteor.users.findOneAsync({ _id: "1" }), undefined); } ); Tinytest.addAsync( "roles -can't add user to non-existent role", async function (test) { await clearData(); try { await Roles.addUsersToRolesAsync(users.eve, ["admin"]); test.fail("Role shouldn't exist"); } catch (e) { test.matches(e.message, /Role 'admin' does not exist/); } await Roles.addUsersToRolesAsync(users.eve, ["admin"], { ifExists: true }); } ); Tinytest.addAsync( "roles -can't set non-existent user to role", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.setUserRolesAsync(["1"], ["admin"]); test.equal(await Meteor.users.findOneAsync({ _id: "1" }), undefined); } ); Tinytest.addAsync( "roles -can't set user to non-existent role", async function (test) { await clearData(); try { await Roles.addUsersToRolesAsync(users.eve, ["admin"]); test.fail("Role shouldn't exist"); } catch (e) { test.matches(e.message, /Role 'admin' does not exist/); } await Roles.setUserRolesAsync(users.eve, ["admin"], { ifExists: true }); } ); Tinytest.addAsync( "roles -can add individual users to roles", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"]); await testUser(test, "eve", ["admin", "user"]); await testUser(test, "bob", []); await testUser(test, "joe", []); await Roles.addUsersToRolesAsync(users.joe, ["editor", "user"]); await testUser(test, "eve", ["admin", "user"]); await testUser(test, "bob", []); await testUser(test, "joe", ["editor", "user"]); } ); Tinytest.addAsync( "roles -can add individual users to roles by scope", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"], "scope1"); await testUser(test, "eve", ["admin", "user"], "scope1"); await testUser(test, "bob", [], "scope1"); await testUser(test, "joe", [], "scope1"); await testUser(test, "eve", [], "scope2"); await testUser(test, "bob", [], "scope2"); await testUser(test, "joe", [], "scope2"); await Roles.addUsersToRolesAsync(users.joe, ["editor", "user"], "scope1"); await Roles.addUsersToRolesAsync(users.bob, ["editor", "user"], "scope2"); await testUser(test, "eve", ["admin", "user"], "scope1"); await testUser(test, "bob", [], "scope1"); await testUser(test, "joe", ["editor", "user"], "scope1"); await testUser(test, "eve", [], "scope2"); await testUser(test, "bob", ["editor", "user"], "scope2"); await testUser(test, "joe", [], "scope2"); } ); Tinytest.addAsync( "roles -can add user to roles via user object", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); const eve = await Meteor.users.findOneAsync({ _id: users.eve }); const bob = await Meteor.users.findOneAsync({ _id: users.bob }); await Roles.addUsersToRolesAsync(eve, ["admin", "user"]); await testUser(test, "eve", ["admin", "user"]); await testUser(test, "bob", []); await testUser(test, "joe", []); await Roles.addUsersToRolesAsync(bob, ["editor"]); await testUser(test, "eve", ["admin", "user"]); await testUser(test, "bob", ["editor"]); await testUser(test, "joe", []); } ); Tinytest.addAsync( "roles -can add user to roles multiple times", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"]); await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"]); await testUser(test, "eve", ["admin", "user"]); await testUser(test, "bob", []); await testUser(test, "joe", []); await Roles.addUsersToRolesAsync(users.bob, ["admin"]); await Roles.addUsersToRolesAsync(users.bob, ["editor"]); await testUser(test, "eve", ["admin", "user"]); await testUser(test, "bob", ["admin", "editor"]); await testUser(test, "joe", []); } ); Tinytest.addAsync( "roles -can add user to roles multiple times by scope", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"], "scope1"); await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"], "scope1"); await testUser(test, "eve", ["admin", "user"], "scope1"); await testUser(test, "bob", [], "scope1"); await testUser(test, "joe", [], "scope1"); await Roles.addUsersToRolesAsync(users.bob, ["admin"], "scope1"); await Roles.addUsersToRolesAsync(users.bob, ["editor"], "scope1"); await testUser(test, "eve", ["admin", "user"], "scope1"); await testUser(test, "bob", ["admin", "editor"], "scope1"); await testUser(test, "joe", [], "scope1"); } ); Tinytest.addAsync( "roles -can add multiple users to roles", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); await Roles.addUsersToRolesAsync([users.eve, users.bob], ["admin", "user"]); await testUser(test, "eve", ["admin", "user"]); await testUser(test, "bob", ["admin", "user"]); await testUser(test, "joe", []); await Roles.addUsersToRolesAsync( [users.bob, users.joe], ["editor", "user"] ); await testUser(test, "eve", ["admin", "user"]); await testUser(test, "bob", ["admin", "editor", "user"]); await testUser(test, "joe", ["editor", "user"]); } ); Tinytest.addAsync( "roles -can add multiple users to roles by scope", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); await Roles.addUsersToRolesAsync( [users.eve, users.bob], ["admin", "user"], "scope1" ); await testUser(test, "eve", ["admin", "user"], "scope1"); await testUser(test, "bob", ["admin", "user"], "scope1"); await testUser(test, "joe", [], "scope1"); await testUser(test, "eve", [], "scope2"); await testUser(test, "bob", [], "scope2"); await testUser(test, "joe", [], "scope2"); await Roles.addUsersToRolesAsync( [users.bob, users.joe], ["editor", "user"], "scope1" ); await Roles.addUsersToRolesAsync( [users.bob, users.joe], ["editor", "user"], "scope2" ); await testUser(test, "eve", ["admin", "user"], "scope1"); await testUser(test, "bob", ["admin", "editor", "user"], "scope1"); await testUser(test, "joe", ["editor", "user"], "scope1"); await testUser(test, "eve", [], "scope2"); await testUser(test, "bob", ["editor", "user"], "scope2"); await testUser(test, "joe", ["editor", "user"], "scope2"); } ); Tinytest.addAsync( "roles -can remove individual users from roles", async function (test) { await clearData(); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); // remove user role - one user await Roles.addUsersToRolesAsync( [users.eve, users.bob], ["editor", "user"] ); await testUser(test, "eve", ["editor", "user"]); await testUser(test, "bob", ["editor", "user"]); await Roles.removeUsersFromRolesAsync(users.eve, ["user"]); await testUser(test, "eve", ["editor"]); await testUser(test, "bob", ["editor", "user"]); } ); Tinytest.addAsync( "roles -can remove user from roles multiple times", async function (test) { await clearData(); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); // remove user role - one user await Roles.addUsersToRolesAsync( [users.eve, users.bob], ["editor", "user"] ); await testUser(test, "eve", ["editor", "user"]); await testUser(test, "bob", ["editor", "user"]); await Roles.removeUsersFromRolesAsync(users.eve, ["user"]); await testUser(test, "eve", ["editor"]); await testUser(test, "bob", ["editor", "user"]); // try remove again await Roles.removeUsersFromRolesAsync(users.eve, ["user"]); await testUser(test, "eve", ["editor"]); } ); Tinytest.addAsync( "roles -can remove users from roles via user object", async function (test) { await clearData(); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); const eve = await Meteor.users.findOneAsync({ _id: users.eve }); const bob = await Meteor.users.findOneAsync({ _id: users.bob }); // remove user role - one user await Roles.addUsersToRolesAsync([eve, bob], ["editor", "user"]); await testUser(test, "eve", ["editor", "user"]); await testUser(test, "bob", ["editor", "user"]); await Roles.removeUsersFromRolesAsync(eve, ["user"]); await testUser(test, "eve", ["editor"]); await testUser(test, "bob", ["editor", "user"]); } ); Tinytest.addAsync( "roles -can remove individual users from roles by scope", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); // remove user role - one user await Roles.addUsersToRolesAsync( [users.eve, users.bob], ["editor", "user"], "scope1" ); await Roles.addUsersToRolesAsync( [users.joe, users.bob], ["admin"], "scope2" ); await testUser(test, "eve", ["editor", "user"], "scope1"); await testUser(test, "bob", ["editor", "user"], "scope1"); await testUser(test, "joe", [], "scope1"); await testUser(test, "eve", [], "scope2"); await testUser(test, "bob", ["admin"], "scope2"); await testUser(test, "joe", ["admin"], "scope2"); await Roles.removeUsersFromRolesAsync(users.eve, ["user"], "scope1"); await testUser(test, "eve", ["editor"], "scope1"); await testUser(test, "bob", ["editor", "user"], "scope1"); await testUser(test, "joe", [], "scope1"); await testUser(test, "eve", [], "scope2"); await testUser(test, "bob", ["admin"], "scope2"); await testUser(test, "joe", ["admin"], "scope2"); } ); Tinytest.addAsync( "roles -can remove individual users from roles by scope through options", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); // remove user role - one user await Roles.addUsersToRolesAsync( [users.eve, users.bob], ["editor", "user"], { scope: "scope1" } ); await Roles.addUsersToRolesAsync([users.joe, users.bob], ["admin"], { scope: "scope2", }); await testUser(test, "eve", ["editor", "user"], "scope1"); await testUser(test, "bob", ["editor", "user"], "scope1"); await testUser(test, "joe", [], "scope1"); await testUser(test, "eve", [], "scope2"); await testUser(test, "bob", ["admin"], "scope2"); await testUser(test, "joe", ["admin"], "scope2"); await Roles.removeUsersFromRolesAsync(users.eve, ["user"], { scope: "scope1", }); await testUser(test, "eve", ["editor"], "scope1"); await testUser(test, "bob", ["editor", "user"], "scope1"); await testUser(test, "joe", [], "scope1"); await testUser(test, "eve", [], "scope2"); await testUser(test, "bob", ["admin"], "scope2"); await testUser(test, "joe", ["admin"], "scope2"); } ); Tinytest.addAsync( "roles -can remove multiple users from roles", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); // remove user role - two users await Roles.addUsersToRolesAsync( [users.eve, users.bob], ["editor", "user"] ); await testUser(test, "eve", ["editor", "user"]); await testUser(test, "bob", ["editor", "user"]); test.isFalse(await Roles.userIsInRoleAsync(users.joe, "admin")); await Roles.addUsersToRolesAsync([users.bob, users.joe], ["admin", "user"]); await testUser(test, "bob", ["admin", "user", "editor"]); await testUser(test, "joe", ["admin", "user"]); await Roles.removeUsersFromRolesAsync([users.bob, users.joe], ["admin"]); await testUser(test, "bob", ["user", "editor"]); await testUser(test, "joe", ["user"]); } ); Tinytest.addAsync( "roles -can remove multiple users from roles by scope", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); // remove user role - one user await Roles.addUsersToRolesAsync( [users.eve, users.bob], ["editor", "user"], "scope1" ); await Roles.addUsersToRolesAsync( [users.joe, users.bob], ["admin"], "scope2" ); await testUser(test, "eve", ["editor", "user"], "scope1"); await testUser(test, "bob", ["editor", "user"], "scope1"); await testUser(test, "joe", [], "scope1"); await testUser(test, "eve", [], "scope2"); await testUser(test, "bob", ["admin"], "scope2"); await testUser(test, "joe", ["admin"], "scope2"); await Roles.removeUsersFromRolesAsync( [users.eve, users.bob], ["user"], "scope1" ); await testUser(test, "eve", ["editor"], "scope1"); await testUser(test, "bob", ["editor"], "scope1"); await testUser(test, "joe", [], "scope1"); await testUser(test, "eve", [], "scope2"); await testUser(test, "bob", ["admin"], "scope2"); await testUser(test, "joe", ["admin"], "scope2"); await Roles.removeUsersFromRolesAsync( [users.joe, users.bob], ["admin"], "scope2" ); await testUser(test, "eve", [], "scope2"); await testUser(test, "bob", [], "scope2"); await testUser(test, "joe", [], "scope2"); } ); Tinytest.addAsync( "roles -can remove multiple users from roles of any scope", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); // remove user role - one user await Roles.addUsersToRolesAsync( [users.eve, users.bob], ["editor", "user"], "scope1" ); await Roles.addUsersToRolesAsync( [users.joe, users.bob], ["user"], "scope2" ); await testUser(test, "eve", ["editor", "user"], "scope1"); await testUser(test, "bob", ["editor", "user"], "scope1"); await testUser(test, "joe", [], "scope1"); await testUser(test, "eve", [], "scope2"); await testUser(test, "bob", ["user"], "scope2"); await testUser(test, "joe", ["user"], "scope2"); await Roles.removeUsersFromRolesAsync([users.eve, users.bob], ["user"], { anyScope: true, }); await testUser(test, "eve", ["editor"], "scope1"); await testUser(test, "bob", ["editor"], "scope1"); await testUser(test, "joe", [], "scope1"); await testUser(test, "eve", [], "scope2"); await testUser(test, "bob", [], "scope2"); await testUser(test, "joe", ["user"], "scope2"); } ); Tinytest.addAsync("roles -can set user roles", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); const eve = await Meteor.users.findOneAsync({ _id: users.eve }); const bob = await Meteor.users.findOneAsync({ _id: users.bob }); await Roles.setUserRolesAsync([users.eve, bob], ["editor", "user"]); await testUser(test, "eve", ["editor", "user"]); await testUser(test, "bob", ["editor", "user"]); await testUser(test, "joe", []); // use addUsersToRoles add some roles await Roles.addUsersToRolesAsync([bob, users.joe], ["admin"]); await testUser(test, "eve", ["editor", "user"]); await testUser(test, "bob", ["admin", "editor", "user"]); await testUser(test, "joe", ["admin"]); await Roles.setUserRolesAsync([eve, bob], ["user"]); await testUser(test, "eve", ["user"]); await testUser(test, "bob", ["user"]); await testUser(test, "joe", ["admin"]); await Roles.setUserRolesAsync(bob, "editor"); await testUser(test, "eve", ["user"]); await testUser(test, "bob", ["editor"]); await testUser(test, "joe", ["admin"]); await Roles.setUserRolesAsync([users.joe, users.bob], []); await testUser(test, "eve", ["user"]); await testUser(test, "bob", []); await testUser(test, "joe", []); }); Tinytest.addAsync("roles -can set user roles by scope", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); const eve = await Meteor.users.findOneAsync({ _id: users.eve }); const bob = await Meteor.users.findOneAsync({ _id: users.bob }); const joe = await Meteor.users.findOneAsync({ _id: users.joe }); await Roles.setUserRolesAsync( [users.eve, users.bob], ["editor", "user"], "scope1" ); await Roles.setUserRolesAsync([users.bob, users.joe], ["admin"], "scope2"); await testUser(test, "eve", ["editor", "user"], "scope1"); await testUser(test, "bob", ["editor", "user"], "scope1"); await testUser(test, "joe", [], "scope1"); await testUser(test, "eve", [], "scope2"); await testUser(test, "bob", ["admin"], "scope2"); await testUser(test, "joe", ["admin"], "scope2"); // use addUsersToRoles add some roles await Roles.addUsersToRolesAsync([users.eve, users.bob], ["admin"], "scope1"); await Roles.addUsersToRolesAsync( [users.bob, users.joe], ["editor"], "scope2" ); await testUser(test, "eve", ["admin", "editor", "user"], "scope1"); await testUser(test, "bob", ["admin", "editor", "user"], "scope1"); await testUser(test, "joe", [], "scope1"); await testUser(test, "eve", [], "scope2"); await testUser(test, "bob", ["admin", "editor"], "scope2"); await testUser(test, "joe", ["admin", "editor"], "scope2"); await Roles.setUserRolesAsync([eve, bob], ["user"], "scope1"); await Roles.setUserRolesAsync([eve, joe], ["editor"], "scope2"); await testUser(test, "eve", ["user"], "scope1"); await testUser(test, "bob", ["user"], "scope1"); await testUser(test, "joe", [], "scope1"); await testUser(test, "eve", ["editor"], "scope2"); await testUser(test, "bob", ["admin", "editor"], "scope2"); await testUser(test, "joe", ["editor"], "scope2"); await Roles.setUserRolesAsync(bob, "editor", "scope1"); await testUser(test, "eve", ["user"], "scope1"); await testUser(test, "bob", ["editor"], "scope1"); await testUser(test, "joe", [], "scope1"); await testUser(test, "eve", ["editor"], "scope2"); await testUser(test, "bob", ["admin", "editor"], "scope2"); await testUser(test, "joe", ["editor"], "scope2"); const bobRoles1 = await Roles.getRolesForUserAsync(users.bob, { anyScope: true, fullObjects: true, }); const joeRoles1 = await Roles.getRolesForUserAsync(users.joe, { anyScope: true, fullObjects: true, }); test.isTrue(bobRoles1.map((r) => r.scope).includes("scope1")); test.isFalse(joeRoles1.map((r) => r.scope).includes("scope1")); await Roles.setUserRolesAsync([bob, users.joe], [], "scope1"); await testUser(test, "eve", ["user"], "scope1"); await testUser(test, "bob", [], "scope1"); await testUser(test, "joe", [], "scope1"); await testUser(test, "eve", ["editor"], "scope2"); await testUser(test, "bob", ["admin", "editor"], "scope2"); await testUser(test, "joe", ["editor"], "scope2"); // When roles in a given scope are removed, we do not want any dangling database content for that scope. const bobRoles2 = await Roles.getRolesForUserAsync(users.bob, { anyScope: true, fullObjects: true, }); const joeRoles2 = await Roles.getRolesForUserAsync(users.joe, { anyScope: true, fullObjects: true, }); test.isFalse(bobRoles2.map((r) => r.scope).includes("scope1")); test.isFalse(joeRoles2.map((r) => r.scope).includes("scope1")); }); Tinytest.addAsync( "roles -can set user roles by scope including GLOBAL_SCOPE", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("editor"); const eve = await Meteor.users.findOneAsync({ _id: users.eve }); await Roles.addUsersToRolesAsync(eve, "admin", Roles.GLOBAL_SCOPE); await testUser(test, "eve", ["admin"], "scope1"); await testUser(test, "eve", ["admin"]); await Roles.setUserRolesAsync(eve, "editor", Roles.GLOBAL_SCOPE); await testUser(test, "eve", ["editor"], "scope2"); await testUser(test, "eve", ["editor"]); } ); Tinytest.addAsync( "roles -can set user roles by scope and anyScope", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("editor"); const eve = await Meteor.users.findOneAsync({ _id: users.eve }); const eveRoles = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, eveRoles.map((obj) => { delete obj._id; return obj; }), [] ); await Roles.addUsersToRolesAsync(eve, "admin"); const eveRoles2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, eveRoles2.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "admin" }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: "admin" }], }, ] ); await Roles.setUserRolesAsync(eve, "editor", { anyScope: true, scope: "scope2", }); const eveRoles3 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, eveRoles3.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "editor" }, scope: "scope2", user: { _id: users.eve }, inheritedRoles: [{ _id: "editor" }], }, ] ); } ); Tinytest.addAsync("roles -can get all roles", async function (test) { await clearData(); for (const role of roles) { await Roles.createRoleAsync(role); } // compare roles, sorted alphabetically const expected = roles; const fetchAll = await Roles.getAllRoles().fetchAsync(); const actual = fetchAll.map((r) => r._id); sameMembers(test, actual, expected); const fetchSorted = await Roles.getAllRoles({ sort: { _id: -1 }, }).fetchAsync(); sameMembers( test, fetchSorted.map((r) => r._id), expected.reverse() ); }); Tinytest.addAsync( "roles -get an empty list of roles for an empty user", async function (test) { await clearData(); sameMembers(test, await Roles.getRolesForUserAsync(undefined), []); sameMembers(test, await Roles.getRolesForUserAsync(null), []); sameMembers(test, await Roles.getRolesForUserAsync({}), []); } ); Tinytest.addAsync( "roles -get an empty list of roles for non-existant user", async function (test) { await clearData(); sameMembers(test, await Roles.getRolesForUserAsync("1"), []); sameMembers(test, await Roles.getRolesForUserAsync("1", "scope1"), []); } ); Tinytest.addAsync("roles -can get all roles for user", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); const userId = users.eve; let userObj; // by userId sameMembers(test, await Roles.getRolesForUserAsync(userId), []); // by user object userObj = await Meteor.users.findOneAsync({ _id: userId }); sameMembers(test, await Roles.getRolesForUserAsync(userObj), []); await Roles.addUsersToRolesAsync(userId, ["admin", "user"]); // by userId sameMembers(test, await Roles.getRolesForUserAsync(userId), [ "admin", "user", ]); // by user object userObj = await Meteor.users.findOneAsync({ _id: userId }); sameMembers(test, await Roles.getRolesForUserAsync(userObj), [ "admin", "user", ]); const userRoles = await Roles.getRolesForUserAsync(userId, { fullObjects: true, }); sameDeepMembers( test, userRoles.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "admin" }, scope: null, user: { _id: userId }, inheritedRoles: [{ _id: "admin" }], }, { role: { _id: "user" }, scope: null, user: { _id: userId }, inheritedRoles: [{ _id: "user" }], }, ] ); }); Tinytest.addAsync( "roles -can get all roles for user by scope", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); const userId = users.eve; await Roles.addUsersToRolesAsync([users.eve], ["editor"], "scope1"); await Roles.addUsersToRolesAsync([users.eve], ["editor", "user"], "scope2"); // by userId sameMembers(test, await Roles.getScopesForUserAsync(userId, "user"), [ "scope2", ]); sameMembers(test, await Roles.getScopesForUserAsync(userId, "editor"), [ "scope1", "scope2", ]); sameMembers(test, await Roles.getScopesForUserAsync(userId, "admin"), []); // by user object const userObj = await Meteor.users.findOneAsync({ _id: userId }); sameMembers(test, await Roles.getScopesForUserAsync(userObj, "user"), [ "scope2", ]); sameMembers(test, await Roles.getScopesForUserAsync(userObj, "editor"), [ "scope1", "scope2", ]); sameMembers(test, await Roles.getScopesForUserAsync(userObj, "admin"), []); } ); Tinytest.addAsync( "roles -getScopesForUser returns [] when not using scopes", async function (test) { await clearData(); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); const userId = users.eve; await Roles.addUsersToRolesAsync([users.eve], ["editor", "user"]); // by userId sameMembers(test, await Roles.getScopesForUserAsync(userId), []); sameMembers(test, await Roles.getScopesForUserAsync(userId, "editor"), []); sameMembers( test, await Roles.getScopesForUserAsync(userId, ["editor"]), [] ); sameMembers( test, await Roles.getScopesForUserAsync(userId, ["editor", "user"]), [] ); // by user object const userObj = await Meteor.users.findOneAsync({ _id: userId }); sameMembers(test, await Roles.getScopesForUserAsync(userObj), []); sameMembers(test, await Roles.getScopesForUserAsync(userObj, "editor"), []); sameMembers( test, await Roles.getScopesForUserAsync(userObj, ["editor"]), [] ); sameMembers( test, await Roles.getScopesForUserAsync(userObj, ["editor", "user"]), [] ); } ); Tinytest.addAsync( "roles -can get all groups for user by role array", async function (test) { await clearData(); const userId = users.eve; await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); await Roles.createRoleAsync("moderator"); await Roles.createRoleAsync("admin"); await Roles.addUsersToRolesAsync([users.eve], ["editor"], "group1"); await Roles.addUsersToRolesAsync([users.eve], ["editor", "user"], "group2"); await Roles.addUsersToRolesAsync([users.eve], ["moderator"], "group3"); // by userId, one role sameMembers(test, await Roles.getScopesForUserAsync(userId, ["user"]), [ "group2", ]); sameMembers(test, await Roles.getScopesForUserAsync(userId, ["editor"]), [ "group1", "group2", ]); sameMembers(test, await Roles.getScopesForUserAsync(userId, ["admin"]), []); // by userId, multiple roles sameMembers( test, await Roles.getScopesForUserAsync(userId, ["editor", "user"]), ["group1", "group2"] ); sameMembers( test, await Roles.getScopesForUserAsync(userId, ["editor", "moderator"]), ["group1", "group2", "group3"] ); sameMembers( test, await Roles.getScopesForUserAsync(userId, ["user", "moderator"]), ["group2", "group3"] ); // by user object, one role const userObj = await Meteor.users.findOneAsync({ _id: userId }); sameMembers(test, await Roles.getScopesForUserAsync(userObj, ["user"]), [ "group2", ]); sameMembers(test, await Roles.getScopesForUserAsync(userObj, ["editor"]), [ "group1", "group2", ]); sameMembers( test, await Roles.getScopesForUserAsync(userObj, ["admin"]), [] ); // by user object, multiple roles sameMembers( test, await Roles.getScopesForUserAsync(userObj, ["editor", "user"]), ["group1", "group2"] ); sameMembers( test, await Roles.getScopesForUserAsync(userObj, ["editor", "moderator"]), ["group1", "group2", "group3"] ); sameMembers( test, await Roles.getScopesForUserAsync(userObj, ["user", "moderator"]), ["group2", "group3"] ); } ); Tinytest.addAsync( "roles -getting all scopes for user does not include GLOBAL_SCOPE", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); const userId = users.eve; await Roles.addUsersToRolesAsync([users.eve], ["editor"], "scope1"); await Roles.addUsersToRolesAsync([users.eve], ["editor", "user"], "scope2"); await Roles.addUsersToRolesAsync( [users.eve], ["editor", "user", "admin"], Roles.GLOBAL_SCOPE ); // by userId sameMembers(test, await Roles.getScopesForUserAsync(userId, "user"), [ "scope2", ]); sameMembers(test, await Roles.getScopesForUserAsync(userId, "editor"), [ "scope1", "scope2", ]); sameMembers(test, await Roles.getScopesForUserAsync(userId, "admin"), []); sameMembers(test, await Roles.getScopesForUserAsync(userId, ["user"]), [ "scope2", ]); sameMembers(test, await Roles.getScopesForUserAsync(userId, ["editor"]), [ "scope1", "scope2", ]); sameMembers(test, await Roles.getScopesForUserAsync(userId, ["admin"]), []); sameMembers( test, await Roles.getScopesForUserAsync(userId, ["user", "editor", "admin"]), ["scope1", "scope2"] ); // by user object const userObj = await Meteor.users.findOneAsync({ _id: userId }); sameMembers(test, await Roles.getScopesForUserAsync(userObj, "user"), [ "scope2", ]); sameMembers(test, await Roles.getScopesForUserAsync(userObj, "editor"), [ "scope1", "scope2", ]); sameMembers(test, await Roles.getScopesForUserAsync(userObj, "admin"), []); sameMembers(test, await Roles.getScopesForUserAsync(userObj, ["user"]), [ "scope2", ]); sameMembers(test, await Roles.getScopesForUserAsync(userObj, ["editor"]), [ "scope1", "scope2", ]); sameMembers( test, await Roles.getScopesForUserAsync(userObj, ["admin"]), [] ); sameMembers( test, await Roles.getScopesForUserAsync(userObj, ["user", "editor", "admin"]), ["scope1", "scope2"] ); } ); Tinytest.addAsync("roles -can get all users in role", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); await Roles.addUsersToRolesAsync([users.eve, users.joe], ["admin", "user"]); await Roles.addUsersToRolesAsync([users.bob, users.joe], ["editor"]); const expected = [users.eve, users.joe]; const cursor = await Roles.getUsersInRoleAsync("admin"); const fetched = await cursor.fetchAsync(); const actual = fetched.map((r) => r._id); sameMembers(test, actual, expected); }); Tinytest.addAsync("roles - can get all userIds in role", async function (test) { await clearData(); await Roles.createRoleAsync('admin'); await Roles.createRoleAsync('user'); await Roles.createRoleAsync('editor'); const ids = ['foo', 'bar', 'baz']; await Roles.addUsersToRolesAsync([ids[0], ids[1]], ['admin', 'user']); await Roles.addUsersToRolesAsync([ids[1], ids[2]], ['editor']); const expected = [ids[0], ids[1]]; const userIds = await Roles.getUserIdsInRoleAsync('admin'); sameMembers(test, userIds, expected); }); Tinytest.addAsync( "roles -can get all users in role by scope", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.addUsersToRolesAsync( [users.eve, users.joe], ["admin", "user"], "scope1" ); await Roles.addUsersToRolesAsync( [users.bob, users.joe], ["admin"], "scope2" ); let expected = [users.eve, users.joe]; const cursor1 = await Roles.getUsersInRoleAsync("admin", "scope1"); const fetched1 = await cursor1.fetchAsync(); let actual = fetched1.map((r) => r._id); sameMembers(test, actual, expected); expected = [users.eve, users.joe]; const cursor2 = await Roles.getUsersInRoleAsync("admin", { scope: "scope1", }); const fetched2 = await cursor2.fetchAsync(); actual = fetched2.map((r) => r._id); sameMembers(test, actual, expected); expected = [users.eve, users.bob, users.joe]; const cursor3 = await Roles.getUsersInRoleAsync("admin", { anyScope: true, }); const fetched3 = await cursor3.fetchAsync(); actual = fetched3.map((r) => r._id); sameMembers(test, actual, expected); const cursor4 = await Roles.getUsersInRoleAsync("admin"); const fetched4 = await cursor4.fetchAsync(); actual = fetched4.map((r) => r._id); sameMembers(test, actual, []); } ); Tinytest.addAsync( "roles -can get all users in role by scope and passes through mongo query arguments", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.addUsersToRolesAsync( [users.eve, users.joe], ["admin", "user"], "scope1" ); await Roles.addUsersToRolesAsync( [users.bob, users.joe], ["admin"], "scope2" ); const cursor = await Roles.getUsersInRoleAsync("admin", "scope1", { fields: { username: 0 }, limit: 1, }); const results = await cursor.fetchAsync(); test.equal(1, results.length); test.isTrue(hasProp(results[0], "_id")); test.isFalse(hasProp(results[0], "username")); } ); Tinytest.addAsync( "roles -can get all users in role by scope and passes through mongo query arguments only to the users collection when included in the options", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.addUsersToRolesAsync( [users.eve, users.joe], ["admin", "user"], "scope1" ); await Roles.addUsersToRolesAsync( [users.bob, users.joe], ["admin"], "scope2" ); const cursor = await Roles.getUsersInRoleAsync("admin", { scope: "scope1", queryOptions: { fields: { _id: 1, username: 1 }, limit: 1, }}); const results = await cursor.fetchAsync(); test.equal(1, results.length); test.isTrue(hasProp(results[0], "_id")); test.isTrue(hasProp(results[0], "username")); } ); Tinytest.addAsync( "roles -can use Roles.GLOBAL_SCOPE to assign blanket roles", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.addUsersToRolesAsync( [users.joe, users.bob], ["admin"], Roles.GLOBAL_SCOPE ); await testUser(test, "eve", [], "scope1"); await testUser(test, "joe", ["admin"], "scope2"); await testUser(test, "joe", ["admin"], "scope1"); await testUser(test, "bob", ["admin"], "scope2"); await testUser(test, "bob", ["admin"], "scope1"); await Roles.removeUsersFromRolesAsync( users.joe, ["admin"], Roles.GLOBAL_SCOPE ); await testUser(test, "eve", [], "scope1"); await testUser(test, "joe", [], "scope2"); await testUser(test, "joe", [], "scope1"); await testUser(test, "bob", ["admin"], "scope2"); await testUser(test, "bob", ["admin"], "scope1"); } ); Tinytest.addAsync( "roles -Roles.GLOBAL_SCOPE is independent of other scopes", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.addUsersToRolesAsync( [users.joe, users.bob], ["admin"], "scope5" ); await Roles.addUsersToRolesAsync( [users.joe, users.bob], ["admin"], Roles.GLOBAL_SCOPE ); await testUser(test, "eve", [], "scope1"); await testUser(test, "joe", ["admin"], "scope5"); await testUser(test, "joe", ["admin"], "scope2"); await testUser(test, "joe", ["admin"], "scope1"); await testUser(test, "bob", ["admin"], "scope5"); await testUser(test, "bob", ["admin"], "scope2"); await testUser(test, "bob", ["admin"], "scope1"); await Roles.removeUsersFromRolesAsync( users.joe, ["admin"], Roles.GLOBAL_SCOPE ); await testUser(test, "eve", [], "scope1"); await testUser(test, "joe", ["admin"], "scope5"); await testUser(test, "joe", [], "scope2"); await testUser(test, "joe", [], "scope1"); await testUser(test, "bob", ["admin"], "scope5"); await testUser(test, "bob", ["admin"], "scope2"); await testUser(test, "bob", ["admin"], "scope1"); } ); Tinytest.addAsync( "roles -Roles.GLOBAL_SCOPE also checked when scope not specified", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.addUsersToRolesAsync(users.joe, "admin", Roles.GLOBAL_SCOPE); await testUser(test, "joe", ["admin"]); await Roles.removeUsersFromRolesAsync( users.joe, "admin", Roles.GLOBAL_SCOPE ); await testUser(test, "joe", []); } ); Tinytest.addAsync("roles -can use '.' in scope name", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.addUsersToRolesAsync(users.joe, ["admin"], "example.com"); await testUser(test, "joe", ["admin"], "example.com"); }); Tinytest.addAsync( "roles -can use multiple periods in scope name", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.addUsersToRolesAsync(users.joe, ["admin"], "example.k12.va.us"); await testUser(test, "joe", ["admin"], "example.k12.va.us"); } ); Tinytest.addAsync("roles -renaming of roles", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); await Roles.setUserRolesAsync( [users.eve, users.bob], ["editor", "user"], "scope1" ); await Roles.setUserRolesAsync( [users.bob, users.joe], ["user", "admin"], "scope2" ); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "editor", "scope1")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "editor", "scope2")); test.isFalse(await Roles.userIsInRoleAsync(users.joe, "admin", "scope1")); test.isTrue(await Roles.userIsInRoleAsync(users.joe, "admin", "scope2")); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "user", "scope1")); test.isTrue(await Roles.userIsInRoleAsync(users.bob, "user", "scope1")); test.isFalse(await Roles.userIsInRoleAsync(users.joe, "user", "scope1")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "user", "scope2")); test.isTrue(await Roles.userIsInRoleAsync(users.bob, "user", "scope2")); test.isTrue(await Roles.userIsInRoleAsync(users.joe, "user", "scope2")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "user2", "scope1")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "user2", "scope2")); await Roles.renameRoleAsync("user", "user2"); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "editor", "scope1")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "editor", "scope2")); test.isFalse(await Roles.userIsInRoleAsync(users.joe, "admin", "scope1")); test.isTrue(await Roles.userIsInRoleAsync(users.joe, "admin", "scope2")); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "user2", "scope1")); test.isTrue(await Roles.userIsInRoleAsync(users.bob, "user2", "scope1")); test.isFalse(await Roles.userIsInRoleAsync(users.joe, "user2", "scope1")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "user2", "scope2")); test.isTrue(await Roles.userIsInRoleAsync(users.bob, "user2", "scope2")); test.isTrue(await Roles.userIsInRoleAsync(users.joe, "user2", "scope2")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "user", "scope1")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "user", "scope2")); }); Tinytest.addAsync("roles -_addUserToRole", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); const userRoles = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, userRoles.map((obj) => { delete obj._id; return obj; }), [] ); const roles = await Roles._addUserToRoleAsync(users.eve, "admin", { scope: null, ifExists: false, }); hasAnyKeys(test, roles, "insertedId"); const userRoles2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, userRoles2.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "admin" }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: "admin" }], }, ] ); const roles2 = await Roles._addUserToRoleAsync(users.eve, "admin", { scope: null, ifExists: false, }); hasAnyKeys(test, roles2, "insertedId"); const roles3 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, roles3.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "admin" }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: "admin" }], }, ] ); }); Tinytest.addAsync("roles -_removeUserFromRole", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.addUsersToRolesAsync(users.eve, "admin"); const rolesForUser = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, rolesForUser.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "admin" }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: "admin" }], }, ] ); await Roles._removeUserFromRoleAsync(users.eve, "admin", { scope: null }); const rolesForUser2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, rolesForUser2.map((obj) => { delete obj._id; return obj; }), [] ); }); Tinytest.addAsync("roles -keep assigned roles", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("ALL_PERMISSIONS"); await Roles.createRoleAsync("VIEW_PERMISSION"); await Roles.createRoleAsync("EDIT_PERMISSION"); await Roles.createRoleAsync("DELETE_PERMISSION"); await Roles.addRolesToParentAsync("ALL_PERMISSIONS", "user"); await Roles.addRolesToParentAsync("EDIT_PERMISSION", "ALL_PERMISSIONS"); await Roles.addRolesToParentAsync("VIEW_PERMISSION", "ALL_PERMISSIONS"); await Roles.addRolesToParentAsync("DELETE_PERMISSION", "admin"); await Roles.addUsersToRolesAsync(users.eve, ["user"]); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "VIEW_PERMISSION")); const rolesForUser = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepUnorderedMembers( test, rolesForUser.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "user" }, scope: null, user: { _id: users.eve }, inheritedRoles: [ { _id: "user" }, { _id: "ALL_PERMISSIONS" }, { _id: "EDIT_PERMISSION" }, { _id: "VIEW_PERMISSION" }, ], }, ] ); await Roles.addUsersToRolesAsync(users.eve, "VIEW_PERMISSION"); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "VIEW_PERMISSION")); const rolesForUser2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepUnorderedMembers( test, rolesForUser2.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "user" }, scope: null, user: { _id: users.eve }, inheritedRoles: [ { _id: "user" }, { _id: "ALL_PERMISSIONS" }, { _id: "EDIT_PERMISSION" }, { _id: "VIEW_PERMISSION" }, ], }, { role: { _id: "VIEW_PERMISSION" }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: "VIEW_PERMISSION" }], }, ] ); await Roles.removeUsersFromRolesAsync(users.eve, "user"); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "VIEW_PERMISSION")); const rolesForUser3 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepUnorderedMembers( test, rolesForUser3.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "VIEW_PERMISSION" }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: "VIEW_PERMISSION" }], }, ] ); await Roles.removeUsersFromRolesAsync(users.eve, "VIEW_PERMISSION"); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "VIEW_PERMISSION")); const rolesForUser4 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepUnorderedMembers( test, rolesForUser4.map((obj) => { delete obj._id; return obj; }), [] ); }); Tinytest.addAsync( "roles -adds children of the added role to the assignments", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("ALBUM.ADMIN"); await Roles.createRoleAsync("ALBUM.VIEW"); await Roles.createRoleAsync("TRACK.ADMIN"); await Roles.createRoleAsync("TRACK.VIEW"); await Roles.addRolesToParentAsync("ALBUM.VIEW", "ALBUM.ADMIN"); await Roles.addRolesToParentAsync("TRACK.VIEW", "TRACK.ADMIN"); await Roles.addRolesToParentAsync("ALBUM.ADMIN", "admin"); await Roles.addUsersToRolesAsync(users.eve, ["admin"]); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "TRACK.VIEW")); await Roles.addRolesToParentAsync("TRACK.ADMIN", "admin"); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "TRACK.VIEW")); } ); Tinytest.addAsync( "roles -removes children of the removed role from the assignments", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("ALBUM.ADMIN"); await Roles.createRoleAsync("ALBUM.VIEW"); await Roles.createRoleAsync("TRACK.ADMIN"); await Roles.createRoleAsync("TRACK.VIEW"); await Roles.addRolesToParentAsync("ALBUM.VIEW", "ALBUM.ADMIN"); await Roles.addRolesToParentAsync("TRACK.VIEW", "TRACK.ADMIN"); await Roles.addRolesToParentAsync("ALBUM.ADMIN", "admin"); await Roles.addRolesToParentAsync("TRACK.ADMIN", "admin"); await Roles.addUsersToRolesAsync(users.eve, ["admin"]); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "TRACK.VIEW")); await Roles.removeRolesFromParentAsync("TRACK.ADMIN", "admin"); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "TRACK.VIEW")); } ); Tinytest.addAsync( "roles -modify assigned hierarchical roles", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("ALL_PERMISSIONS"); await Roles.createRoleAsync("VIEW_PERMISSION"); await Roles.createRoleAsync("EDIT_PERMISSION"); await Roles.createRoleAsync("DELETE_PERMISSION"); await Roles.addRolesToParentAsync("ALL_PERMISSIONS", "user"); await Roles.addRolesToParentAsync("EDIT_PERMISSION", "ALL_PERMISSIONS"); await Roles.addRolesToParentAsync("VIEW_PERMISSION", "ALL_PERMISSIONS"); await Roles.addRolesToParentAsync("DELETE_PERMISSION", "admin"); await Roles.addUsersToRolesAsync(users.eve, ["user"]); await Roles.addUsersToRolesAsync(users.eve, ["ALL_PERMISSIONS"], "scope"); test.isFalse( await Roles.userIsInRoleAsync(users.eve, "MODERATE_PERMISSION") ); test.isFalse( await Roles.userIsInRoleAsync(users.eve, "MODERATE_PERMISSION", "scope") ); const usersRoles = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepUnorderedMembers( test, usersRoles.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "user" }, scope: null, user: { _id: users.eve }, inheritedRoles: [ { _id: "user" }, { _id: "ALL_PERMISSIONS" }, { _id: "EDIT_PERMISSION" }, { _id: "VIEW_PERMISSION" }, ], }, { role: { _id: "ALL_PERMISSIONS" }, scope: "scope", user: { _id: users.eve }, inheritedRoles: [ { _id: "ALL_PERMISSIONS" }, { _id: "EDIT_PERMISSION" }, { _id: "VIEW_PERMISSION" }, ], }, ] ); await Roles.createRoleAsync("MODERATE_PERMISSION"); await Roles.addRolesToParentAsync("MODERATE_PERMISSION", "ALL_PERMISSIONS"); test.isTrue( await Roles.userIsInRoleAsync(users.eve, "MODERATE_PERMISSION") ); test.isTrue( await Roles.userIsInRoleAsync(users.eve, "MODERATE_PERMISSION", "scope") ); const usersRoles2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepUnorderedMembers( test, usersRoles2.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "user" }, scope: null, user: { _id: users.eve }, inheritedRoles: [ { _id: "user" }, { _id: "ALL_PERMISSIONS" }, { _id: "EDIT_PERMISSION" }, { _id: "VIEW_PERMISSION" }, { _id: "MODERATE_PERMISSION" }, ], }, { role: { _id: "ALL_PERMISSIONS" }, scope: "scope", user: { _id: users.eve }, inheritedRoles: [ { _id: "ALL_PERMISSIONS" }, { _id: "EDIT_PERMISSION" }, { _id: "VIEW_PERMISSION" }, { _id: "MODERATE_PERMISSION" }, ], }, ] ); await Roles.addUsersToRolesAsync(users.eve, ["admin"]); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "DELETE_PERMISSION")); test.isTrue( await Roles.userIsInRoleAsync(users.eve, "DELETE_PERMISSION", "scope") ); const usersRoles3 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepUnorderedMembers( test, usersRoles3.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "user" }, scope: null, user: { _id: users.eve }, inheritedRoles: [ { _id: "user" }, { _id: "ALL_PERMISSIONS" }, { _id: "EDIT_PERMISSION" }, { _id: "VIEW_PERMISSION" }, { _id: "MODERATE_PERMISSION" }, ], }, { role: { _id: "ALL_PERMISSIONS" }, scope: "scope", user: { _id: users.eve }, inheritedRoles: [ { _id: "ALL_PERMISSIONS" }, { _id: "EDIT_PERMISSION" }, { _id: "VIEW_PERMISSION" }, { _id: "MODERATE_PERMISSION" }, ], }, { role: { _id: "admin" }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: "admin" }, { _id: "DELETE_PERMISSION" }], }, ] ); await Roles.addRolesToParentAsync("DELETE_PERMISSION", "ALL_PERMISSIONS"); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "DELETE_PERMISSION")); test.isTrue( await Roles.userIsInRoleAsync(users.eve, "DELETE_PERMISSION", "scope") ); const usersRoles4 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepUnorderedMembers( test, usersRoles4.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "user" }, scope: null, user: { _id: users.eve }, inheritedRoles: [ { _id: "user" }, { _id: "ALL_PERMISSIONS" }, { _id: "EDIT_PERMISSION" }, { _id: "VIEW_PERMISSION" }, { _id: "MODERATE_PERMISSION" }, { _id: "DELETE_PERMISSION" }, ], }, { role: { _id: "ALL_PERMISSIONS" }, scope: "scope", user: { _id: users.eve }, inheritedRoles: [ { _id: "ALL_PERMISSIONS" }, { _id: "EDIT_PERMISSION" }, { _id: "VIEW_PERMISSION" }, { _id: "MODERATE_PERMISSION" }, { _id: "DELETE_PERMISSION" }, ], }, { role: { _id: "admin" }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: "admin" }, { _id: "DELETE_PERMISSION" }], }, ] ); await Roles.removeUsersFromRolesAsync(users.eve, ["admin"]); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "DELETE_PERMISSION")); test.isTrue( await Roles.userIsInRoleAsync(users.eve, "DELETE_PERMISSION", "scope") ); const usersRoles5 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepUnorderedMembers( test, usersRoles5.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "user" }, scope: null, user: { _id: users.eve }, inheritedRoles: [ { _id: "user" }, { _id: "ALL_PERMISSIONS" }, { _id: "EDIT_PERMISSION" }, { _id: "VIEW_PERMISSION" }, { _id: "MODERATE_PERMISSION" }, { _id: "DELETE_PERMISSION" }, ], }, { role: { _id: "ALL_PERMISSIONS" }, scope: "scope", user: { _id: users.eve }, inheritedRoles: [ { _id: "ALL_PERMISSIONS" }, { _id: "EDIT_PERMISSION" }, { _id: "VIEW_PERMISSION" }, { _id: "MODERATE_PERMISSION" }, { _id: "DELETE_PERMISSION" }, ], }, ] ); await await Roles.deleteRoleAsync("ALL_PERMISSIONS"); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "DELETE_PERMISSION")); test.isFalse( await Roles.userIsInRoleAsync(users.eve, "DELETE_PERMISSION", "scope") ); test.isFalse( await Roles.userIsInRoleAsync(users.eve, "MODERATE_PERMISSION") ); test.isFalse( await Roles.userIsInRoleAsync(users.eve, "MODERATE_PERMISSION", "scope") ); const usersRoles6 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepUnorderedMembers( test, usersRoles6.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "user" }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: "user" }], }, ] ); } ); Tinytest.addAsync( "roles -delete role with overlapping hierarchical roles", async function (test) { await clearData(); await Roles.createRoleAsync("role1"); await Roles.createRoleAsync("role2"); await Roles.createRoleAsync("COMMON_PERMISSION_1"); await Roles.createRoleAsync("COMMON_PERMISSION_2"); await Roles.createRoleAsync("COMMON_PERMISSION_3"); await Roles.createRoleAsync("EXTRA_PERMISSION_ROLE_1"); await Roles.createRoleAsync("EXTRA_PERMISSION_ROLE_2"); await Roles.addRolesToParentAsync("COMMON_PERMISSION_1", "role1"); await Roles.addRolesToParentAsync("COMMON_PERMISSION_2", "role1"); await Roles.addRolesToParentAsync("COMMON_PERMISSION_3", "role1"); await Roles.addRolesToParentAsync("EXTRA_PERMISSION_ROLE_1", "role1"); await Roles.addRolesToParentAsync("COMMON_PERMISSION_1", "role2"); await Roles.addRolesToParentAsync("COMMON_PERMISSION_2", "role2"); await Roles.addRolesToParentAsync("COMMON_PERMISSION_3", "role2"); await Roles.addRolesToParentAsync("EXTRA_PERMISSION_ROLE_2", "role2"); await Roles.addUsersToRolesAsync(users.eve, "role1"); await Roles.addUsersToRolesAsync(users.eve, "role2"); test.isTrue( await Roles.userIsInRoleAsync(users.eve, "COMMON_PERMISSION_1") ); test.isTrue( await Roles.userIsInRoleAsync(users.eve, "EXTRA_PERMISSION_ROLE_1") ); test.isTrue( await Roles.userIsInRoleAsync(users.eve, "EXTRA_PERMISSION_ROLE_2") ); const usersRoles = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, usersRoles.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "role1" }, scope: null, user: { _id: users.eve }, inheritedRoles: [ { _id: "role1" }, { _id: "COMMON_PERMISSION_1" }, { _id: "COMMON_PERMISSION_2" }, { _id: "COMMON_PERMISSION_3" }, { _id: "EXTRA_PERMISSION_ROLE_1" }, ], }, { role: { _id: "role2" }, scope: null, user: { _id: users.eve }, inheritedRoles: [ { _id: "role2" }, { _id: "COMMON_PERMISSION_1" }, { _id: "COMMON_PERMISSION_2" }, { _id: "COMMON_PERMISSION_3" }, { _id: "EXTRA_PERMISSION_ROLE_2" }, ], }, ] ); await Roles.removeUsersFromRolesAsync(users.eve, "role2"); test.isTrue( await Roles.userIsInRoleAsync(users.eve, "COMMON_PERMISSION_1") ); test.isTrue( await Roles.userIsInRoleAsync(users.eve, "EXTRA_PERMISSION_ROLE_1") ); test.isFalse( await Roles.userIsInRoleAsync(users.eve, "EXTRA_PERMISSION_ROLE_2") ); const usersRoles2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, usersRoles2.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "role1" }, scope: null, user: { _id: users.eve }, inheritedRoles: [ { _id: "role1" }, { _id: "COMMON_PERMISSION_1" }, { _id: "COMMON_PERMISSION_2" }, { _id: "COMMON_PERMISSION_3" }, { _id: "EXTRA_PERMISSION_ROLE_1" }, ], }, ] ); await Roles.addUsersToRolesAsync(users.eve, "role2"); test.isTrue( await Roles.userIsInRoleAsync(users.eve, "COMMON_PERMISSION_1") ); test.isTrue( await Roles.userIsInRoleAsync(users.eve, "EXTRA_PERMISSION_ROLE_1") ); test.isTrue( await Roles.userIsInRoleAsync(users.eve, "EXTRA_PERMISSION_ROLE_2") ); const usersRoles3 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, usersRoles3.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "role1" }, scope: null, user: { _id: users.eve }, inheritedRoles: [ { _id: "role1" }, { _id: "COMMON_PERMISSION_1" }, { _id: "COMMON_PERMISSION_2" }, { _id: "COMMON_PERMISSION_3" }, { _id: "EXTRA_PERMISSION_ROLE_1" }, ], }, { role: { _id: "role2" }, scope: null, user: { _id: users.eve }, inheritedRoles: [ { _id: "role2" }, { _id: "COMMON_PERMISSION_1" }, { _id: "COMMON_PERMISSION_2" }, { _id: "COMMON_PERMISSION_3" }, { _id: "EXTRA_PERMISSION_ROLE_2" }, ], }, ] ); await Roles.deleteRoleAsync("role2"); test.isTrue( await Roles.userIsInRoleAsync(users.eve, "COMMON_PERMISSION_1") ); test.isTrue( await Roles.userIsInRoleAsync(users.eve, "EXTRA_PERMISSION_ROLE_1") ); test.isFalse( await Roles.userIsInRoleAsync(users.eve, "EXTRA_PERMISSION_ROLE_2") ); const usersRoles4 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, usersRoles4.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "role1" }, scope: null, user: { _id: users.eve }, inheritedRoles: [ { _id: "role1" }, { _id: "COMMON_PERMISSION_1" }, { _id: "COMMON_PERMISSION_2" }, { _id: "COMMON_PERMISSION_3" }, { _id: "EXTRA_PERMISSION_ROLE_1" }, ], }, ] ); } ); Tinytest.addAsync("roles -set parent on assigned role", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("EDIT_PERMISSION"); await Roles.addUsersToRolesAsync(users.eve, "EDIT_PERMISSION"); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "EDIT_PERMISSION")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "admin")); const usersRoles = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, usersRoles.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "EDIT_PERMISSION" }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: "EDIT_PERMISSION" }], }, ] ); await Roles.addRolesToParentAsync("EDIT_PERMISSION", "admin"); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "EDIT_PERMISSION")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "admin")); const usersRoles2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, usersRoles2.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "EDIT_PERMISSION" }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: "EDIT_PERMISSION" }], }, ] ); }); Tinytest.addAsync( "roles -remove parent on assigned role", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("EDIT_PERMISSION"); await Roles.addRolesToParentAsync("EDIT_PERMISSION", "admin"); await Roles.addUsersToRolesAsync(users.eve, "EDIT_PERMISSION"); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "EDIT_PERMISSION")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "admin")); const usersRoles = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, usersRoles.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "EDIT_PERMISSION" }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: "EDIT_PERMISSION" }], }, ] ); await Roles.removeRolesFromParentAsync("EDIT_PERMISSION", "admin"); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "EDIT_PERMISSION")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "admin")); const usersRoles2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, usersRoles2.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "EDIT_PERMISSION" }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: "EDIT_PERMISSION" }], }, ] ); } ); Tinytest.addAsync( "roles -adding and removing extra role parents", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("EDIT_PERMISSION"); await Roles.addRolesToParentAsync("EDIT_PERMISSION", "admin"); await Roles.addUsersToRolesAsync(users.eve, "EDIT_PERMISSION"); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "EDIT_PERMISSION")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "admin")); const usersRoles = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, usersRoles.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "EDIT_PERMISSION" }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: "EDIT_PERMISSION" }], }, ] ); await Roles.addRolesToParentAsync("EDIT_PERMISSION", "user"); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "EDIT_PERMISSION")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "admin")); const usersRoles2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, usersRoles2.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "EDIT_PERMISSION" }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: "EDIT_PERMISSION" }], }, ] ); await Roles.removeRolesFromParentAsync("EDIT_PERMISSION", "user"); test.isTrue(await Roles.userIsInRoleAsync(users.eve, "EDIT_PERMISSION")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "admin")); const usersRoles3 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true, }); sameDeepMembers( test, usersRoles3.map((obj) => { delete obj._id; return obj; }), [ { role: { _id: "EDIT_PERMISSION" }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: "EDIT_PERMISSION" }], }, ] ); } ); Tinytest.addAsync("roles -cyclic roles", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("editor"); await Roles.createRoleAsync("user"); await Roles.addRolesToParentAsync("editor", "admin"); await Roles.addRolesToParentAsync("user", "editor"); try { await Roles.addRolesToParentAsync("admin", "user"); test.fail("Should throw cycle error"); } catch (e) { test.matches(e.message, /form a cycle/); } }); Tinytest.addAsync( "roles -userIsInRole returns false for unknown roles", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); await Roles.addUsersToRolesAsync(users.eve, ["admin", "user"]); await Roles.addUsersToRolesAsync(users.eve, ["editor"]); test.isFalse(await Roles.userIsInRoleAsync(users.eve, "unknown")); test.isFalse(await Roles.userIsInRoleAsync(users.eve, [])); test.isFalse(await Roles.userIsInRoleAsync(users.eve, null)); test.isFalse(await Roles.userIsInRoleAsync(users.eve, undefined)); test.isFalse( await Roles.userIsInRoleAsync(users.eve, "unknown", { anyScope: true }) ); test.isFalse( await Roles.userIsInRoleAsync(users.eve, [], { anyScope: true }) ); test.isFalse( await Roles.userIsInRoleAsync(users.eve, null, { anyScope: true }) ); test.isFalse( await Roles.userIsInRoleAsync(users.eve, undefined, { anyScope: true }) ); test.isFalse( await Roles.userIsInRoleAsync( users.eve, ["Role1", "Role2", undefined], "GroupName" ) ); } ); Tinytest.addAsync( "roles -userIsInRole returns false if user is a function", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.addUsersToRolesAsync(users.eve, ["admin"]); test.isFalse(await Roles.userIsInRoleAsync(() => {}, "admin")); } ); Tinytest.addAsync( "roles -returns false for unknown roles", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); test.isFalse(await Roles.isParentOfAsync("admin", "unknown")); test.isFalse(await Roles.isParentOfAsync("admin", null)); test.isFalse(await Roles.isParentOfAsync("admin", undefined)); test.isFalse(await Roles.isParentOfAsync("unknown", "admin")); test.isFalse(await Roles.isParentOfAsync(null, "admin")); test.isFalse(await Roles.isParentOfAsync(undefined, "admin")); } ); Tinytest.addAsync( "roles -returns false if role is not parent of", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("editor"); await Roles.createRoleAsync("user"); await Roles.addRolesToParentAsync(["editor"], "admin"); await Roles.addRolesToParentAsync(["user"], "editor"); test.isFalse(await Roles.isParentOfAsync("user", "admin")); test.isFalse(await Roles.isParentOfAsync("editor", "admin")); } ); Tinytest.addAsync( "roles -returns true if role is parent of the demanded role", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("editor"); await Roles.createRoleAsync("user"); await Roles.addRolesToParentAsync(["editor"], "admin"); await Roles.addRolesToParentAsync(["user"], "editor"); test.isTrue(await Roles.isParentOfAsync("admin", "user")); test.isTrue(await Roles.isParentOfAsync("editor", "user")); test.isTrue(await Roles.isParentOfAsync("admin", "editor")); test.isTrue(await Roles.isParentOfAsync("admin", "admin")); test.isTrue(await Roles.isParentOfAsync("editor", "editor")); test.isTrue(await Roles.isParentOfAsync("user", "user")); } ); // here Tinytest.addAsync( "should not return null entries if user has no roles for scope", async function (test) { await clearData(); await Roles.createRoleAsync("editor"); const userId = users.eve; let userObj; // by userId sameMembers(test,await Roles.getRolesForUserAsync(userId, "scope1"), []); sameMembers(test,await Roles.getRolesForUserAsync(userId), []); // by user object userObj = await Meteor.users.findOneAsync({ _id: userId }); sameMembers(test,await Roles.getRolesForUserAsync(userObj, "scope1"), []); sameMembers(test,await Roles.getRolesForUserAsync(userObj), []); await Roles.addUsersToRolesAsync( [users.eve], ["editor"], Roles.GLOBAL_SCOPE ); // by userId sameMembers(test,await Roles.getRolesForUserAsync(userId, "scope1"), [ "editor", ]); sameMembers(test,await Roles.getRolesForUserAsync(userId), ["editor"]); // by user object userObj = await Meteor.users.findOneAsync({ _id: userId }); sameMembers(test,await Roles.getRolesForUserAsync(userObj, "scope1"), [ "editor", ]); sameMembers(test,await Roles.getRolesForUserAsync(userObj), ["editor"]); } ); Tinytest.addAsync( "should not fail during a call of addUsersToRoles", async function (test) { await clearData(); await Roles.createRoleAsync("editor"); const userId = users.eve; const promises = []; const interval = setInterval(() => { promises.push( Promise.resolve().then(async () => { await Roles.getRolesForUserAsync(userId); }) ); }, 0); await Roles.addUsersToRolesAsync( [users.eve], ["editor"], Roles.GLOBAL_SCOPE ); clearInterval(interval); return Promise.all(promises); } ); Tinytest.addAsync( "returns an empty list of scopes for null as user-id", async function (test) { await clearData(); sameMembers(test,await Roles.getScopesForUserAsync(undefined), []); sameMembers(test,await Roles.getScopesForUserAsync(null), []); sameMembers(test,await Roles.getScopesForUserAsync("foo"), []); sameMembers(test,await Roles.getScopesForUserAsync({}), []); sameMembers(test,await Roles.getScopesForUserAsync({ _id: "foo" }), []); } ); Tinytest.addAsync("can get all scopes for user", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); const userId = users.eve; await Roles.addUsersToRolesAsync([users.eve], ["editor"], "scope1"); await Roles.addUsersToRolesAsync([users.eve], ["admin", "user"], "scope2"); // by userId sameMembers(test,await Roles.getScopesForUserAsync(userId), [ "scope1", "scope2", ]); // by user object const userObj = await Meteor.users.findOneAsync({ _id: userId }); sameMembers(test,await Roles.getScopesForUserAsync(userObj), [ "scope1", "scope2", ]); }); Tinytest.addAsync("can get all scopes for user by role", async function (test) { await clearData(); await Roles.createRoleAsync("admin"); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); const userId = users.eve; await Roles.addUsersToRolesAsync([users.eve], ["editor"], "scope1"); await Roles.addUsersToRolesAsync([users.eve], ["editor", "user"], "scope2"); // by userId sameMembers(test,await Roles.getScopesForUserAsync(userId, "user"), [ "scope2", ]); sameMembers(test,await Roles.getScopesForUserAsync(userId, "editor"), [ "scope1", "scope2", ]); sameMembers(test,await Roles.getScopesForUserAsync(userId, "admin"), []); // by user object const userObj = await Meteor.users.findOneAsync({ _id: userId }); sameMembers(test,await Roles.getScopesForUserAsync(userObj, "user"), [ "scope2", ]); sameMembers(test,await Roles.getScopesForUserAsync(userObj, "editor"), [ "scope1", "scope2", ]); sameMembers(test,await Roles.getScopesForUserAsync(userObj, "admin"), []); }); Tinytest.addAsync( "getScopesForUser returns [] when not using scopes", async function (test) { await clearData(); await Roles.createRoleAsync("user"); await Roles.createRoleAsync("editor"); const userId = users.eve; await Roles.addUsersToRolesAsync([users.eve], ["editor", "user"]); // by userId sameMembers(test,await Roles.getScopesForUserAsync(userId), []); sameMembers(test,await Roles.getScopesForUserAsync(userId, "editor"), []); sameMembers(test, await Roles.getScopesForUserAsync(userId, ["editor"]), [] ); sameMembers(test, await Roles.getScopesForUserAsync(userId, ["editor", "user"]), [] ); // by user object const userObj = await Meteor.users.findOneAsync({ _id: userId }); sameMembers(test,await Roles.getScopesForUserAsync(userObj), []); sameMembers(test, await Roles.getScopesForUserAsync(userObj, "editor"), [] ); sameMembers(test, await Roles.getScopesForUserAsync(userObj, ["editor"]), [] ); sameMembers(test, await Roles.getScopesForUserAsync(userObj, ["editor", "user"]), [] ); } );