Skip to content

Commit

Permalink
Provide 'Add' button functionality
Browse files Browse the repository at this point in the history
The 'Add' button functionality allows
to associate a user to a given HBAC rule.

Signed-off-by: Carla Martinez <[email protected]>
  • Loading branch information
carma12 committed May 14, 2024
1 parent 4c3bc3d commit 4255a7b
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 8 deletions.
118 changes: 114 additions & 4 deletions src/components/MemberOf/MemberOfHbacRules.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,19 @@ import { User, HBACRule } from "src/utils/datatypes/globalDataTypes";
// Components
import MemberOfToolbar, { MembershipDirection } from "./MemberOfToolbar";
import MemberOfHbacRulesTable from "./MemberOfTableHbacRules";
import MemberOfAddModal, { AvailableItems } from "./MemberOfAddModal";
// Hooks
import useAlerts from "src/hooks/useAlerts";
// RPC
import { useGetHbacRulesInfoByNameQuery } from "src/services/rpc";
import {
ErrorResult,
useAddToHbacRulesMutation,
useGetHbacRulesInfoByNameQuery,
useGettingHbacRulesQuery,
} from "src/services/rpc";
// Utils
import { API_VERSION_BACKUP, paginate } from "src/utils/utils";
import { apiToHBACRule } from "src/utils/hbacRulesUtils";

interface MemberOfHbacRulesProps {
user: Partial<User>;
Expand Down Expand Up @@ -103,10 +110,103 @@ const MemberOfHbacRules = (props: MemberOfHbacRulesProps) => {
const someItemSelected = hbacRulesSelected.length > 0;
const showTableRows = hbacRules.length > 0;

// Dialogs and actions
const [showAddModal, setShowAddModal] = React.useState(false);

// Buttons functionality
// - Refresh
const isRefreshButtonEnabled =
!fullHbacRulesQuery.isFetching && !props.isUserDataLoading;
const isAddButtonEnabled =
membershipDirection !== "indirect" && isRefreshButtonEnabled;

// Add new member to 'HBAC rules'
// API calls
const [addMemberToHbacRules] = useAddToHbacRulesMutation();
const [adderSearchValue, setAdderSearchValue] = React.useState("");
const [availableHbacRules, setAvailableHbacRules] = React.useState<
HBACRule[]
>([]);
const [availableItems, setAvailableItems] = React.useState<AvailableItems[]>(
[]
);

// Load available HBAC rules, delay the search for opening the modal
const hbacRulesQuery = useGettingHbacRulesQuery({
search: adderSearchValue,
apiVersion: API_VERSION_BACKUP,
sizelimit: 100,
startIdx: 0,
stopIdx: 100,
});

// Trigger available HBAC rules search
React.useEffect(() => {
if (showAddModal) {
hbacRulesQuery.refetch();
}
}, [showAddModal, adderSearchValue, props.user]);

// Update available HBAC rules
React.useEffect(() => {
if (hbacRulesQuery.data && !hbacRulesQuery.isFetching) {
// transform data to HBAC rules
const count = hbacRulesQuery.data.result.count;
const results = hbacRulesQuery.data.result.results;
let items: AvailableItems[] = [];
const avalHbacRules: HBACRule[] = [];
for (let i = 0; i < count; i++) {
const hbacRule = apiToHBACRule(results[i].result);
avalHbacRules.push(hbacRule);
items.push({
key: hbacRule.cn,
title: hbacRule.cn,
});
}
items = items.filter((item) => !hbacRulesNamesToLoad.includes(item.key));

setAvailableHbacRules(avalHbacRules);
setAvailableItems(items);
}
}, [hbacRulesQuery.data, hbacRulesQuery.isFetching]);

// - Add
const onAddHbacRule = (items: AvailableItems[]) => {
const uid = props.user.uid;
const newHbacRuleNames = items.map((item) => item.key);
if (uid === undefined || newHbacRuleNames.length == 0) {
return;
}

addMemberToHbacRules([uid, "user", newHbacRuleNames]).then((response) => {
if ("data" in response) {
if (response.data.result) {
// Set alert: success
alerts.addAlert(
"add-member-success",
`Assigned new HBAC rule to user ${uid}`,
"success"
);
// Update displayed HBAC Rules before they are updated via refresh
const newHbacRules = hbacRules.concat(
availableHbacRules.filter((hbacRule) =>
newHbacRuleNames.includes(hbacRule.cn)
)
);
setHbacRules(newHbacRules);

// Refresh data
props.onRefreshUserData();
// Close modal
setShowAddModal(false);
} else if (response.data.error) {
// Set alert: error
const errorMessage = response.data.error as unknown as ErrorResult;
alerts.addAlert("add-member-error", errorMessage.message, "danger");
}
}
});
};

return (
<>
Expand All @@ -121,9 +221,8 @@ const MemberOfHbacRules = (props: MemberOfHbacRulesProps) => {
deleteButtonEnabled={someItemSelected}
// eslint-disable-next-line @typescript-eslint/no-empty-function
onDeleteButtonClick={() => {}}
addButtonEnabled={true}
// eslint-disable-next-line @typescript-eslint/no-empty-function
onAddButtonClick={() => {}}
addButtonEnabled={isAddButtonEnabled}
onAddButtonClick={() => setShowAddModal(true)}
membershipDirectionEnabled={true}
membershipDirection={membershipDirection}
onMembershipDirectionChange={setMembershipDirection}
Expand All @@ -150,6 +249,17 @@ const MemberOfHbacRules = (props: MemberOfHbacRulesProps) => {
onSetPage={(_e, page) => setPage(page)}
onPerPageSelect={(_e, perPage) => setPerPage(perPage)}
/>
{showAddModal && (
<MemberOfAddModal
showModal={showAddModal}
onCloseModal={() => setShowAddModal(false)}
availableItems={availableItems}
onAdd={onAddHbacRule}
onSearchTextChange={setAdderSearchValue}
title={`Assign HBAC rule to user ${props.user.uid}`}
ariaLabel="Add user of HBAC rule modal"
/>
)}
</>
);
};
Expand Down
48 changes: 44 additions & 4 deletions src/services/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export interface GenericPayload {
| "group"
| "netgroups"
| "role"
| "hbacRule";
| "hbacrule";
}

export interface GroupShowPayload {
Expand Down Expand Up @@ -793,7 +793,7 @@ export const api = createApi({
}
}

if (objName === "hbacRule") {
if (objName === "hbacrule") {
if (description) {
params["description"] = description;
}
Expand Down Expand Up @@ -836,7 +836,7 @@ export const api = createApi({
id = idResponseData.result.result[i] as cnType;
} else if (objName === "role") {
id = idResponseData.result.result[i] as roleType;
} else if (objName === "hbacRule") {
} else if (objName === "hbacrule") {
id = idResponseData.result.result[i] as cnType;
} else {
// Unknown, should never happen
Expand Down Expand Up @@ -1645,6 +1645,44 @@ export const api = createApi({
return hbacRulesList;
},
}),
/**
* Add entity to HBAC rules
* @param {string} toId - ID of the entity to add to HBAC rules
* @param {string} type - Type of the entity
* Available types: user | host | service | sourcehost
* @param {string[]} listOfMembers - List of members to add to the HBAC rules
*/
addToHbacRules: build.mutation<
BatchRPCResponse,
[string, string, string[]]
>({
query: (payload) => {
const memberId = payload[0];
const memberType = payload[1];
const roleNames = payload[2];

let methodType = "";
if (memberType === "user") {
methodType = "hbacrule_add_user";
} else if (memberType === "host") {
methodType = "hbacrule_add_host";
} else if (memberType === "service") {
methodType = "hbacrule_add_service";
} else if (memberType === "sourcehost") {
methodType = "hbacrule_add_sourcehost";
}

const membersToAdd: Command[] = [];
roleNames.map((roleName) => {
const payloadItem = {
method: methodType,
params: [[roleName], { [memberType]: memberId }],
} as Command;
membersToAdd.push(payloadItem);
});
return getBatchCommand(membersToAdd, API_VERSION_BACKUP);
},
}),
}),
});

Expand Down Expand Up @@ -1708,8 +1746,9 @@ export const useGettingRolesQuery = (payloadData, options) => {
payloadData["objAttr"] = "cn";
return useGettingGenericQuery(payloadData, options);
};
// HBAC rules
export const useGettingHbacRulesQuery = (payloadData) => {
payloadData["objName"] = "hbacRule";
payloadData["objName"] = "hbacrule";
payloadData["objAttr"] = "cn";
return useGettingGenericQuery(payloadData);
};
Expand Down Expand Up @@ -1796,4 +1835,5 @@ export const {
useRemoveFromRolesMutation,
useGetRolesInfoByNameQuery,
useGetHbacRulesInfoByNameQuery,
useAddToHbacRulesMutation,
} = api;

0 comments on commit 4255a7b

Please sign in to comment.