Files
threshold-ui/addons/api/addon/models/role.js
T
Zhihe Li bcf004b8a4 Reformat codebase with trailing commas in functions (#2006)
* style: 💄 Update trailing commas in API

* style: 💄 Update trailing commas in core

* style: 💄 Update trailing commas in rose

* style: 💄 Update trailing commas in admin

* style: 💄 Update trailing commas in desktop
2023-11-22 14:07:41 -05:00

239 lines
6.6 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import GeneratedRoleModel from '../generated/models/role';
import { attr } from '@ember-data/model';
import { inject as service } from '@ember/service';
import { all, resolve } from 'rsvp';
import {
TYPE_AUTH_METHOD_OIDC,
TYPE_AUTH_METHOD_LDAP,
} from 'api/models/auth-method';
export default class RoleModel extends GeneratedRoleModel {
// =services
@service store;
@service resourceFilterStore;
// =attributes
/**
* Principals are users and groups assigned to a role. They are represented
* as references to User and Group instances. Since Ember Data relationships
* are wanting, we do not model these as a polymorphic relationship as might
* see obvious. Instead, the application layer is expected to load referenced
* users and groups as needed.
*/
@attr('principal-array', {
readOnly: true,
emptyArrayIfMissing: true,
})
principals;
/**
* Grant strings are read-only. But grants can be persisted via a dedicated
* call to `saveGrantStrings(grants)`.
*/
@attr({ readOnly: true, emptyArrayIfMissing: true }) grant_strings;
/**
* Convenience for looking up the grant scope, if loaded.
*/
get grantScope() {
return this.grant_scope_id
? this.store.peekRecord('scope', this.grant_scope_id)
: 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: [TYPE_AUTH_METHOD_OIDC, TYPE_AUTH_METHOD_LDAP] },
{ 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
/**
* Saves grant strings on the role via the `set-grants` method.
* See serializer and adapter for more information.
* @param {[string]} grantStrings
* @return {Promise}
*/
saveGrantStrings(grantStrings) {
return this.save({
adapterOptions: {
method: 'set-grants',
grantStrings,
},
});
}
/**
* Adds principals via the `add-principals` method.
* See serializer and adapter for more information.
* @param {[string]} principalIDs
* @param {object} options
* @param {object} options.adapterOptions
* @return {Promise}
*/
addPrincipals(principalIDs, options = { adapterOptions: {} }) {
const defaultAdapterOptions = {
method: 'add-principals',
principalIDs,
};
// There is no "deep merge" in ES.
return this.save({
...options,
adapterOptions: {
...defaultAdapterOptions,
...options.adapterOptions,
},
});
}
/**
* Delete principals via the `remove-principals` method.
* See serializer and adapter for more information.
* @param {[string]} principalIDs
* @param {object} options
* @param {object} options.adapterOptions
* @return {Promise}
*/
removePrincipals(principalIDs, options = { adapterOptions: {} }) {
const defaultAdapterOptions = {
method: 'remove-principals',
principalIDs,
};
// There is no "deep merge" in ES.
return this.save({
...options,
adapterOptions: {
...defaultAdapterOptions,
...options.adapterOptions,
},
});
}
/**
* Delete a single principal via the `remove-principals` method.
* @param {number} principalIDs
* @param {object} options
* @return {Promise}
*/
removePrincipal(principalID, options) {
return this.removePrincipals([principalID], options);
}
}