From d390b0356b8d7666acdde92c6d5df3e1d0f1e10d Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Mon, 1 Jul 2024 12:59:10 +0200 Subject: [PATCH] Add: Available optional features in Capabilities The Capabilities object now has a featureEnabled method that checks if an optional feature is enabled according to the new GET_FEATURES GMP command. This will allow toggling/modifying UI elements for these features without a redundant setting in the GSA config. --- .../capabilities/__tests__/capabilities.js | 13 +++++ src/gmp/capabilities/capabilities.js | 21 ++++++- src/gmp/commands/__tests__/user.js | 55 +++++++++++++++++++ src/gmp/commands/users.js | 3 +- 4 files changed, 88 insertions(+), 4 deletions(-) diff --git a/src/gmp/capabilities/__tests__/capabilities.js b/src/gmp/capabilities/__tests__/capabilities.js index 835994a957..ee6ad31798 100644 --- a/src/gmp/capabilities/__tests__/capabilities.js +++ b/src/gmp/capabilities/__tests__/capabilities.js @@ -215,6 +215,19 @@ describe('Capabilities tests', () => { } expect(i).toEqual(4); }); + + test('should handle features', () => { + const featureList = [ + {name: 'ENABLED_FEATURE_1', _enabled: 1}, + {name: 'DISABLED_FEATURE', _enabled: 0}, + {name: 'ENABLED_FEATURE_2', _enabled: 1}, + ]; + const caps = new Capabilities(['everything'], featureList); + expect(caps.featureEnabled('ENABLED_FEATURE_1')).toBe(true); + expect(caps.featureEnabled('DISABLED_FEATURE')).toBe(false); + expect(caps.featureEnabled('enabled_feature_2')).toBe(true); + expect(caps.featureEnabled('UNDEFINED_FEATURE')).toBe(false); + }); }); // vim: set ts=2 sw=2 tw=80: diff --git a/src/gmp/capabilities/capabilities.js b/src/gmp/capabilities/capabilities.js index e65a1832b2..6b4cf4f760 100644 --- a/src/gmp/capabilities/capabilities.js +++ b/src/gmp/capabilities/capabilities.js @@ -3,10 +3,10 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - import {isDefined} from 'gmp/utils/identity'; -import {map} from 'gmp/utils/array'; +import {forEach, map} from 'gmp/utils/array'; import {pluralizeType} from 'gmp/utils/entitytype'; +import {parseBoolean} from 'gmp/parser'; const types = { audit: 'task', @@ -51,16 +51,27 @@ const convertType = type => { }; class Capabilities { - constructor(cap_names) { + constructor(cap_names, featuresList) { this._has_caps = isDefined(cap_names); + this._has_features = isDefined(featuresList); let caps; + let featuresEnabled = {}; if (this._has_caps) { caps = map(cap_names, name => name.toLowerCase()); } + if (this._has_features) { + forEach(featuresList, feature => { + featuresEnabled[feature.name.toUpperCase()] = parseBoolean( + feature._enabled, + ); + }); + } + this._capabilities = new Set(caps); + this._featuresEnabled = featuresEnabled; } [Symbol.iterator]() { @@ -102,6 +113,10 @@ class Capabilities { get length() { return this._capabilities.size; } + + featureEnabled(feature) { + return this._featuresEnabled[feature.toUpperCase()] == true; + } } export default Capabilities; diff --git a/src/gmp/commands/__tests__/user.js b/src/gmp/commands/__tests__/user.js index 17fe9d1ec9..e86f86df5d 100644 --- a/src/gmp/commands/__tests__/user.js +++ b/src/gmp/commands/__tests__/user.js @@ -121,3 +121,58 @@ describe('UserCommand transformSettingName() function tests', () => { expect(transformSettingName(str4)).toEqual('foobar'); }); }); + +describe('UserCommand capabilities tests', () => { + test('should get capabilities', () => { + const response = createResponse({ + get_capabilities: { + help_response: { + schema: { + command: [ + { + name: 'get_reports', + }, + { + name: 'get_tasks', + }, + ], + }, + }, + get_features_response: { + feature: [ + { + _enabled: 1, + name: 'TEST_FEATURE_1', + }, + { + _enabled: 1, + name: 'TEST_FEATURE_2', + }, + ], + }, + }, + }); + const fakeHttp = createHttp(response); + const cmd = new UserCommand(fakeHttp); + + cmd.currentCapabilities().then(resp => { + const {data: caps} = resp; + + expect(fakeHttp.request).toHaveBeenCalledWith('get', { + args: { + cmd: 'get_capabilities', + }, + }); + + expect(caps._has_caps).toBe(true); + expect(caps.mayAccess('report')).toBe(true); + expect(caps.mayAccess('task')).toBe(true); + expect(caps.mayAccess('user')).toBe(false); + + expect(caps._has_features).toBe(true); + expect(caps.featureEnabled('test_feature_1')).toBe(true); + expect(caps.featureEnabled('TEST_FEATURE_2')).toBe(true); + expect(caps.featureEnabled('TEST_FEATURE_3')).toBe(false); + }); + }); +}); diff --git a/src/gmp/commands/users.js b/src/gmp/commands/users.js index 65dcc9ab98..c94c4077e7 100644 --- a/src/gmp/commands/users.js +++ b/src/gmp/commands/users.js @@ -162,8 +162,9 @@ export class UserCommand extends EntityCommand { ).then(response => { const {data} = response; const {command: commands} = data.get_capabilities.help_response.schema; + const featuresList = data.get_capabilities.get_features_response.feature; const caps = map(commands, command => command.name); - return response.setData(new Capabilities(caps)); + return response.setData(new Capabilities(caps, featuresList)); }); }