Add model support for managed groups (#1544)
* chore: 🤖 streamline managed groups getter on role
This commit is contained in:
1 parent
392da009d0
commit
f2c0458fb5
3 files changed
+134
-40
No files matched your search
@@ -1,11 +1,13 @@
|
||||
import GeneratedRoleModel from '../generated/models/role';
|
||||
import { attr } from '@ember-data/model';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { all, resolve } from 'rsvp';
|
||||
|
||||
export default class RoleModel extends GeneratedRoleModel {
|
||||
// =services
|
||||
|
||||
@service store;
|
||||
@service resourceFilterStore;
|
||||
|
||||
// =attributes
|
||||
|
||||
@@ -37,6 +39,123 @@ export default class RoleModel extends GeneratedRoleModel {
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of IDs for principals of type `user`.
|
||||
* @type {string[]}
|
||||
*/
|
||||
get userIDs() {
|
||||
return this.principals
|
||||
.filter(({ type }) => type === 'user')
|
||||
.map(({ principal_id }) => principal_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of IDs for principals of type `group`.
|
||||
* @type {string[]}
|
||||
*/
|
||||
get groupIDs() {
|
||||
return this.principals
|
||||
.filter(({ type }) => type === 'group')
|
||||
.map(({ principal_id }) => principal_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of IDs for principals of type `managed group`.
|
||||
* @type {string[]}
|
||||
*/
|
||||
get managedGroupIDs() {
|
||||
return this.principals
|
||||
.filter(({ type }) => type === 'managed group')
|
||||
.map(({ principal_id }) => principal_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* A promise that resolves to an array of User instances.
|
||||
* When calling this getter, be sure to await resolution
|
||||
* before interacting with the results.
|
||||
* @type {Promise[UserModel]}
|
||||
*/
|
||||
get users() {
|
||||
const ids = this.userIDs;
|
||||
|
||||
// Role has prinicipal IDs,
|
||||
// return a promise which resolves model instances for those IDs
|
||||
if (ids?.length) {
|
||||
return this.resourceFilterStore
|
||||
.queryBy('user', { id: ids }, { scope_id: 'global', recursive: true })
|
||||
.then((models) => models.map((model) => model));
|
||||
}
|
||||
|
||||
// No principal IDs,
|
||||
// return a promise resolving to an empty array
|
||||
return resolve([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* A promise that resolves to an array of Group instances.
|
||||
* When calling this getter, be sure to await resolution
|
||||
* before interacting with the results.
|
||||
* @type {Promise[GroupModel]}
|
||||
*/
|
||||
get groups() {
|
||||
const ids = this.groupIDs;
|
||||
|
||||
// Role has prinicipal IDs,
|
||||
// return a promise which resolves model instances for those IDs
|
||||
if (ids?.length) {
|
||||
return this.resourceFilterStore
|
||||
.queryBy('group', { id: ids }, { scope_id: 'global', recursive: true })
|
||||
.then((models) => models.map((model) => model));
|
||||
}
|
||||
|
||||
// No principal IDs,
|
||||
// return a promise resolving to an empty array
|
||||
return resolve([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* A promise that resolves to an array of ManagedGroup instances.
|
||||
* When calling this getter, be sure to await resolution
|
||||
* before interacting with the results.
|
||||
* @type {Promise[ManagedGroupModel]}
|
||||
*/
|
||||
get managedGroups() {
|
||||
const ids = this.managedGroupIDs;
|
||||
|
||||
// Role has prinicipal IDs
|
||||
// return a promise which resolves model instances for those IDs
|
||||
if (ids?.length) {
|
||||
// Collect all auth methods.
|
||||
const authMethods = this.resourceFilterStore.queryBy(
|
||||
'auth-method',
|
||||
{ type: 'oidc' },
|
||||
{ scope_id: 'global', recursive: true }
|
||||
);
|
||||
|
||||
// For each auth method, query all managed groups with IDs
|
||||
// that match the role's manage group principal IDs.
|
||||
const managedGroups = authMethods
|
||||
.then((methods) =>
|
||||
all(
|
||||
methods.map(({ id: auth_method_id }) =>
|
||||
this.resourceFilterStore
|
||||
.queryBy('managed-group', { id: ids }, { auth_method_id })
|
||||
.then((models) => models.map((model) => model))
|
||||
)
|
||||
)
|
||||
)
|
||||
// The result is an array of arrays of model instances (grouped by
|
||||
// auth methods), so these must be flattened.
|
||||
.then((grouped) => grouped.flat());
|
||||
|
||||
return managedGroups;
|
||||
}
|
||||
|
||||
// No principal IDs,
|
||||
// return a promise resolving to an empty array
|
||||
return resolve([]);
|
||||
}
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,6 +64,7 @@ module('Unit | Model | role', function (hooks) {
|
||||
principals: [
|
||||
{ id: '1', type: 'user' },
|
||||
{ id: '3', type: 'group' },
|
||||
{ id: '5', type: 'managed group' },
|
||||
],
|
||||
version: 1,
|
||||
scope: {
|
||||
@@ -84,7 +85,7 @@ module('Unit | Model | role', function (hooks) {
|
||||
(schema, request) => {
|
||||
const body = JSON.parse(request.requestBody);
|
||||
assert.deepEqual(body, {
|
||||
principal_ids: ['1', '3'],
|
||||
principal_ids: ['1', '3', '5'],
|
||||
version: 1,
|
||||
});
|
||||
return { id: '123abc' };
|
||||
@@ -101,6 +102,7 @@ module('Unit | Model | role', function (hooks) {
|
||||
principals: [
|
||||
{ id: '1', type: 'user' },
|
||||
{ id: '3', type: 'group' },
|
||||
{ id: '5', type: 'managed group' },
|
||||
],
|
||||
version: 1,
|
||||
scope: {
|
||||
@@ -111,7 +113,7 @@ module('Unit | Model | role', function (hooks) {
|
||||
},
|
||||
});
|
||||
const model = store.peekRecord('role', '123abc');
|
||||
await model.removePrincipals(['1', '3']);
|
||||
await model.removePrincipals(['1', '3', '5']);
|
||||
});
|
||||
|
||||
test('it has a `removePrincipal` method that deletes a single principal using `removePrincipals` method', async function (assert) {
|
||||
@@ -138,6 +140,7 @@ module('Unit | Model | role', function (hooks) {
|
||||
principals: [
|
||||
{ id: '1', type: 'user' },
|
||||
{ id: '3', type: 'group' },
|
||||
{ id: '5', type: 'managed group' },
|
||||
],
|
||||
version: 1,
|
||||
scope: {
|
||||
|
||||
@@ -8,60 +8,32 @@ import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
export default class ScopesScopeRolesRolePrincipalsRoute extends Route {
|
||||
// =services
|
||||
@service intl;
|
||||
|
||||
@service resourceFilterStore;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* Returns users and groups associated with this role.
|
||||
* Returns users, groups and managed-groups associated with this role.
|
||||
* @param {object} params
|
||||
* @return {Promise{RoleModel}}
|
||||
* @return {Promise{role, principals}}
|
||||
*/
|
||||
async model() {
|
||||
const role = this.modelFor('scopes.scope.roles.role');
|
||||
// Fetch user and group principals.
|
||||
const users = await role.users;
|
||||
const groups = await role.groups;
|
||||
const managedGroups = await role.managedGroups;
|
||||
// Merge polymorphic principals.
|
||||
const principals = [...users, ...groups, ...managedGroups];
|
||||
|
||||
// Gather user and group IDs as separate arrays, since these
|
||||
// will be queried in separate API queries.
|
||||
const userIDs = role.principals
|
||||
.filter(({ type }) => type === 'user')
|
||||
.map(({ principal_id }) => principal_id);
|
||||
const groupIDs = role.principals
|
||||
.filter(({ type }) => type === 'group')
|
||||
.map(({ principal_id }) => principal_id);
|
||||
|
||||
// Query for users.
|
||||
const users = userIDs?.length
|
||||
? (
|
||||
await this.resourceFilterStore.queryBy(
|
||||
'user',
|
||||
{ id: userIDs },
|
||||
{ scope_id: 'global', recursive: true }
|
||||
)
|
||||
).map((model) => model)
|
||||
: [];
|
||||
// Query for groups.
|
||||
const groups = groupIDs?.length
|
||||
? (
|
||||
await this.resourceFilterStore.queryBy(
|
||||
'group',
|
||||
{ id: groupIDs },
|
||||
{ scope_id: 'global', recursive: true }
|
||||
)
|
||||
).map((model) => model)
|
||||
: [];
|
||||
|
||||
return {
|
||||
role,
|
||||
principals: users.concat(groups),
|
||||
};
|
||||
return { role, principals };
|
||||
}
|
||||
|
||||
// =actions
|
||||
|
||||
/**
|
||||
* Remove a principal from the current role and redirect to principals index.
|
||||
* @param {UserModel, GroupModel} principal
|
||||
* @param {UserModel, GroupModel, ManagedGroupModel} principal
|
||||
*/
|
||||
@action
|
||||
@loading
|
||||
|
||||
Reference in new issue
Block a user