Files
threshold-ui/addons/api/addon/models/role.js
T
55e1e68f30 [COMPLIANCE] Update Copyright and License Headers (#3099)
Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
Co-authored-by: Dharini <dharini@hashicorp.com>
2026-01-20 11:35:10 -05:00

227 lines
5.5 KiB
JavaScript

/**
* Copyright IBM Corp. 2021, 2025
* SPDX-License-Identifier: BUSL-1.1
*/
import GeneratedRoleModel from '../generated/models/role';
import { attr } from '@ember-data/model';
import { service } from '@ember/service';
export const GRANT_SCOPE_THIS = 'this';
export const GRANT_SCOPE_CHILDREN = 'children';
export const GRANT_SCOPE_DESCENDANTS = 'descendants';
export const GRANT_SCOPE_KEYWORDS = Object.freeze([
GRANT_SCOPE_THIS,
GRANT_SCOPE_CHILDREN,
GRANT_SCOPE_DESCENDANTS,
]);
// Sort the grant scope IDs by the order in which they should be displayed
// in the UI as the API will return them in an arbitrary order.
const sortOrder = {
[GRANT_SCOPE_THIS]: 0,
[GRANT_SCOPE_CHILDREN]: 1,
[GRANT_SCOPE_DESCENDANTS]: 2,
global: 3,
o: 4,
p: 5,
};
export default class RoleModel extends GeneratedRoleModel {
// =services
@service store;
// =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('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 scopes, if loaded.
*/
get grantScopes() {
const grantScopes = [];
if (this.grant_scope_ids) {
const sortedScopeIDs = [...this.grant_scope_ids].sort((a, b) => {
const aSplit = a.split('_')[0];
const bSplit = b.split('_')[0];
return sortOrder[aSplit] - sortOrder[bSplit];
});
sortedScopeIDs.forEach((id) => {
if (GRANT_SCOPE_KEYWORDS.includes(id)) {
grantScopes.push({ id });
} else {
const scope = this.store.peekRecord('scope', id);
if (scope) {
grantScopes.push(scope);
}
}
});
}
return grantScopes;
}
/**
* Helper for retrieving grant scope ids that are keywords.
* @type {string[]}
*/
get grantScopeKeywords() {
return this.grant_scope_ids.filter((id) =>
GRANT_SCOPE_KEYWORDS.includes(id),
);
}
/**
* Helper for retrieving grant_scope_ids that are orgs.
* @type {string[]}
*/
get grantScopeOrgIDs() {
return this.grant_scope_ids.filter((id) => id.startsWith('o_'));
}
/**
* Helper for retrieving grant_scope_ids that are projects.
* @type {string[]}
*/
get grantScopeProjectIDs() {
return this.grant_scope_ids.filter((id) => id.startsWith('p_'));
}
/**
* A list of IDs for principals of type `user`.
* @type {string[]}
*/
get userIDs() {
return this.principals
.filter(({ type }) => type === 'user')
.map(({ id }) => id);
}
/**
* A list of IDs for principals of type `group`.
* @type {string[]}
*/
get groupIDs() {
return this.principals
.filter(({ type }) => type === 'group')
.map(({ id }) => id);
}
/**
* A list of IDs for principals of type `managed group`.
* @type {string[]}
*/
get managedGroupIDs() {
return this.principals
.filter(({ type }) => type === 'managed group')
.map(({ id }) => id);
}
// =methods
/**
* Saves grant scope ids on the role via the `set-grant-scopes` method.
* @param {[string]} grantScopeIDs
* @return {Promise}
*/
setGrantScopes(grantScopeIDs) {
return this.save({
adapterOptions: {
method: 'set-grant-scopes',
grantScopeIDs,
},
});
}
/**
* 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);
}
}