Skip to content

Commit

Permalink
- Added parsing function for the groupRole string
Browse files Browse the repository at this point in the history
- Added test coverage for the function.
- Fixed logic for displaying the loading indicator.
  • Loading branch information
brandonandre committed Nov 22, 2023
1 parent 063472a commit a809410
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 44 deletions.
73 changes: 53 additions & 20 deletions packages/common-ui/lib/account/AccountProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export function KeycloakAccountProvider({ children }: { children: ReactNode }) {
}, [devUserConfig]);

// Non-authenticated users should never see the the full website. Display a loading indicator.
if (!authenticated || !initialized || (!keycloak || !devUserConfig?.enabled)) {
if (!authenticated || !initialized) {
return (
<div
className="d-flex align-items-center justify-content-center"
Expand All @@ -134,10 +134,10 @@ export function KeycloakAccountProvider({ children }: { children: ReactNode }) {
const token = "dev-user-token";

//const keycloakGroups = process.env['dev-user.enabled.groupRole'] ? processDevUserGroups() : [];
const groupNames = ["aafc"];
const rolesPerGroup = {
aafc: ["dina-admin"]
}
const { groupNames, rolesPerGroup } = parseGroupRoleDevUser(devUserConfig?.groupRole);

console.log(groupNames);
console.log(rolesPerGroup);

return (
<AccountProvider
Expand All @@ -159,7 +159,7 @@ export function KeycloakAccountProvider({ children }: { children: ReactNode }) {
{children}
</AccountProvider>
);
} else {
} else if (keycloak !== null) {
const tokenParsed = keycloak?.tokenParsed;

const subject = keycloak?.subject;
Expand Down Expand Up @@ -270,17 +270,50 @@ export function generateKeycloakRolesPerGroup(
}, {} as Record<string, string[] | undefined>);
}

// Work in progress...
//function processDevUserGroups() {
// const groupRoles = [];
// for (const key in process.env) {
// if (key.startsWith("dev-user.groupRole.")) {
// const groupName = key.split('.').slice(-2).join('/'); // Extract the group name
// const roles = JSON.parse(process.env[key]);
// roles.forEach((role) => {
// groupRoles.push(`/${groupName}/${role}`);
// });
// }
// }
// return groupRoles;
//}
interface ParseGroupRoleDevUserOutput {
groupNames: string[];
rolesPerGroup: any;
}

/**
* Parses the "groupRole" string to extract group names and roles.
*
* Example: "/aafc/user, /bicoe/read-only, /aafc/super-user" will return:
* groupNames: ["aafc", "bicoe"]
* rolesPerGroup: {
* aafc: ["user", "super-user"],
* bicoe: ["read-only"]
* }
*
* @param groupRole - The input string containing group and role information.
* @returns Object An object containing group names and roles per group.
*/
export function parseGroupRoleDevUser(groupRole: string | null): ParseGroupRoleDevUserOutput {
if (!groupRole || groupRole === "") {
return {
groupNames: [],
rolesPerGroup: {}
};
}

const groups = groupRole.split(',').map(group => group.trim().substring(1));
const groupNames = [...new Set(groups.map(group => group.split('/')[0]))];
const rolesPerGroup = {};

groups.forEach(group => {
const [groupName, role] = group.split('/');

if (!rolesPerGroup[groupName]) {
rolesPerGroup[groupName] = new Set(); // Use a Set to store roles
}

rolesPerGroup[groupName].add(role); // Add role to the Set
});

// Convert Sets back to arrays
for (const groupName in rolesPerGroup) {
rolesPerGroup[groupName] = [...rolesPerGroup[groupName]];
}

return { groupNames, rolesPerGroup };
}
107 changes: 83 additions & 24 deletions packages/common-ui/lib/account/__tests__/AccountProvider.test.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,95 @@
import { DINA_ADMIN, USER } from "../../../types/DinaRoles";
import {
keycloakGroupNamesToBareGroupNames,
generateKeycloakRolesPerGroup
generateKeycloakRolesPerGroup,
parseGroupRoleDevUser
} from "../AccountProvider";

describe("AccountProvider", () => {
// Keycloak test data
const keycloakGroups = [
"/cnc/" + DINA_ADMIN,
"/cnc/" + USER,
"/aafc/" + USER,
"/othergroup",
"no-leading-slash"
];

it("Converts Keycloak's group names to bare group names.", () => {
const bareGroupNames = keycloakGroupNamesToBareGroupNames(keycloakGroups);

expect(bareGroupNames).toEqual([
"cnc",
"aafc",
"othergroup",
describe("AccountProvider component", () => {
describe("keycloakGroupNamesToBareGroupNames function", () => {
// Keycloak test data
const keycloakGroups = [
"/cnc/" + DINA_ADMIN,
"/cnc/" + USER,
"/aafc/" + USER,
"/othergroup",
"no-leading-slash"
]);
];

it("Converts Keycloak's group names to bare group names.", () => {
const bareGroupNames = keycloakGroupNamesToBareGroupNames(keycloakGroups);

expect(bareGroupNames).toEqual([
"cnc",
"aafc",
"othergroup",
"no-leading-slash"
]);
});

it("Converts keycloak group + role name string into a unique key and values.", () => {
const rolesPerGroup = generateKeycloakRolesPerGroup(keycloakGroups);

expect(rolesPerGroup).toEqual({
aafc: [USER],
cnc: [DINA_ADMIN, USER]
});
});
});

it("Converts keycloak group + role name string into a unique key and values.", () => {
const rolesPerGroup = generateKeycloakRolesPerGroup(keycloakGroups);
describe("parseGroupRoleDevUser function", () => {
it("should correctly parse groupRole string and return group names and roles", () => {
const groupRoleString = "/aafc/user, /bicoe/read-only, /aafc/admin";
const expectedResult = {
groupNames: ["aafc", "bicoe"],
rolesPerGroup: {
aafc: ["user", "admin"],
bicoe: ["read-only"],
},
};

const result = parseGroupRoleDevUser(groupRoleString);
expect(result).toEqual(expectedResult);
});

it("should remove duplicates from groupNames array", () => {
const groupRoleString = "/aafc/user, /bicoe/read-only, /aafc/user";
const expectedResult = {
groupNames: ["aafc", "bicoe"],
rolesPerGroup: {
aafc: ["user"],
bicoe: ["read-only"],
},
};

const result = parseGroupRoleDevUser(groupRoleString);
expect(result).toEqual(expectedResult);
});

it("if only one group and role is provided it should correctly parse it", () => {
const groupRoleString = "/aafc/user";
const expectedResult = {
groupNames: ["aafc"],
rolesPerGroup: {
aafc: ["user"]
},
};

const result = parseGroupRoleDevUser(groupRoleString);
expect(result).toEqual(expectedResult);
});

it("should handle an empty groupRole string and return empty group names and roles", () => {
const groupRoleString = "";
const expectedResult = {
groupNames: [],
rolesPerGroup: {},
};

expect(rolesPerGroup).toEqual({
aafc: [USER],
cnc: [DINA_ADMIN, USER]
const result1 = parseGroupRoleDevUser(groupRoleString);
const result2 = parseGroupRoleDevUser(null);
expect(result1).toEqual(expectedResult);
expect(result2).toEqual(expectedResult);
});
});
});

0 comments on commit a809410

Please sign in to comment.