Skip to content

Commit e8b309a

Browse files
committed
fix: refactor permission handling to use custom hook for team view permissions
1 parent 9e97e1e commit e8b309a

8 files changed

Lines changed: 42 additions & 49 deletions

File tree

src/authz-module/audit-user/index.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import {
1414
import AuthZLayout from '@src/authz-module/components/AuthZLayout';
1515
import { useNavigate, useParams } from 'react-router-dom';
1616
import { useUserAccount, useValidateUserPermissionsNonSuspense } from '@src/data/hooks';
17-
import { CONTENT_COURSE_PERMISSIONS, VIEW_TEAM_PERMISSIONS, libraryRolesMetadata } from '@src/authz-module/roles-permissions';
17+
import { LIBRARY_ROLE_KEYS } from '@src/authz-module/roles-permissions';
18+
import { useViewTeamPermissions } from '@src/authz-module/hooks/useViewTeamPermissions';
1819
import baseMessages from '@src/authz-module/messages';
1920
import AddRoleButton from '@src/authz-module/components/AddRoleButton';
2021
import {
@@ -33,8 +34,6 @@ import messages from './messages';
3334
import ConfirmDeletionModal from '../components/ConfirmDeletionModal';
3435
import { getCellHeader, getScopeManageActionPermission } from '../utils';
3536

36-
const LIBRARY_ROLE_KEYS = libraryRolesMetadata.map((r) => r.role).join(',');
37-
3837
const AuditUserPage = () => {
3938
const { formatMessage } = useIntl();
4039
const [columnsWithFiltersApplied, setColumnsWithFiltersApplied] = useState<string[]>([]);
@@ -46,10 +45,7 @@ const AuditUserPage = () => {
4645
} = useUserAccount(username);
4746
const { querySettings, handleTableFetch } = useQuerySettings();
4847

49-
const { data: permissions } = useValidateUserPermissionsNonSuspense(VIEW_TEAM_PERMISSIONS);
50-
const isCourseViewAllowed = permissions
51-
? permissions.some((p) => p.action === CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM && p.allowed)
52-
: true;
48+
const { isCourseViewAllowed } = useViewTeamPermissions();
5349

5450
const effectiveQuerySettings = useMemo(() => {
5551
if (isCourseViewAllowed || querySettings.roles) { return querySettings; }

src/authz-module/components/TableControlBar/RolesFilter.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ describe('RolesFilter', () => {
9191

9292
it('shows no role options while permissions are still loading', async () => {
9393
const user = userEvent.setup();
94-
mockUsePermissions.mockReturnValue({ data: undefined });
94+
mockUsePermissions.mockReturnValue({ data: undefined, isLoading: true });
9595
renderWrapper(<RolesFilter {...defaultProps} />);
9696
const menu = await openDropdown(user);
9797
expect(menu.queryByText('Courses')).not.toBeInTheDocument();

src/authz-module/components/TableControlBar/RolesFilter.tsx

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import { useMemo } from 'react';
22
import { useIntl } from '@edx/frontend-platform/i18n';
33
import { Person } from '@openedx/paragon/icons';
4-
import { useValidateUserPermissionsNonSuspense } from '@src/data/hooks';
5-
import {
6-
CONTENT_COURSE_PERMISSIONS, CONTENT_LIBRARY_PERMISSIONS, VIEW_TEAM_PERMISSIONS,
7-
} from '@src/authz-module/roles-permissions';
4+
import { useViewTeamPermissions } from '@src/authz-module/hooks/useViewTeamPermissions';
85
import { CONTEXT_TYPES } from '@src/authz-module/constants';
96
import MultipleChoiceFilter from './MultipleChoiceFilter';
107
import { MultipleChoiceFilterProps } from './types';
@@ -16,24 +13,16 @@ const RolesFilter = ({
1613
filterButtonText, filterValue, setFilter, disabled,
1714
}: RolesFilterProps) => {
1815
const intl = useIntl();
19-
const { data: permissions } = useValidateUserPermissionsNonSuspense(VIEW_TEAM_PERMISSIONS);
16+
const { isCourseViewAllowed, isLibraryViewAllowed, isLoading } = useViewTeamPermissions();
2017

21-
// Only show role groups for the domains the user can view. Global roles stay
22-
// hidden until a platform-wide permission is available to gate them on.
23-
const allowedContexts = useMemo(() => {
24-
const contexts = new Set<string>();
25-
permissions?.forEach((p) => {
26-
if (!p.allowed) { return; }
27-
if (p.action === CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM) { contexts.add(CONTEXT_TYPES.LIBRARY); }
28-
if (p.action === CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM) { contexts.add(CONTEXT_TYPES.COURSE); }
18+
const rolesOptions = useMemo(() => {
19+
if (isLoading) { return []; }
20+
return getRolesFiltersOptions(intl).filter((option) => {
21+
if (option.contextType === CONTEXT_TYPES.COURSE) { return isCourseViewAllowed; }
22+
if (option.contextType === CONTEXT_TYPES.LIBRARY) { return isLibraryViewAllowed; }
23+
return false;
2924
});
30-
return contexts;
31-
}, [permissions]);
32-
33-
const rolesOptions = useMemo(
34-
() => getRolesFiltersOptions(intl).filter((option) => allowedContexts.has(option.contextType)),
35-
[intl, allowedContexts],
36-
);
25+
}, [intl, isCourseViewAllowed, isLibraryViewAllowed, isLoading]);
3726
return (
3827
<MultipleChoiceFilter
3928
filterButtonText={filterButtonText}

src/authz-module/components/TableControlBar/ScopesFilter.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { useMemo, useState } from 'react';
22
import { useIntl } from '@edx/frontend-platform/i18n';
33
import { LocationOn } from '@openedx/paragon/icons';
4-
import { useValidateUserPermissionsNonSuspense } from '@src/data/hooks';
5-
import { CONTENT_COURSE_PERMISSIONS, VIEW_TEAM_PERMISSIONS } from '@src/authz-module/roles-permissions';
4+
import { useViewTeamPermissions } from '@src/authz-module/hooks/useViewTeamPermissions';
65
import { useScopes } from '@src/authz-module/data/hooks';
76
import { DEFAULT_FILTER_PAGE_SIZE } from '@src/authz-module/constants';
87
import { MultipleChoiceFilterProps } from './types';
@@ -18,10 +17,7 @@ const ScopesFilter = ({
1817
const { formatMessage } = useIntl();
1918
const [searchValue, setSearchValue] = useState<string | undefined>(undefined);
2019

21-
const { data: permissions } = useValidateUserPermissionsNonSuspense(VIEW_TEAM_PERMISSIONS);
22-
const isCourseViewAllowed = permissions
23-
? permissions.some((p) => p.action === CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM && p.allowed)
24-
: true;
20+
const { isCourseViewAllowed } = useViewTeamPermissions();
2521

2622
const { data: scopesData } = useScopes({
2723
search: searchValue,
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { useValidateUserPermissionsNonSuspense } from '@src/data/hooks';
2+
import {
3+
CONTENT_COURSE_PERMISSIONS, CONTENT_LIBRARY_PERMISSIONS, VIEW_TEAM_PERMISSIONS,
4+
} from '@src/authz-module/roles-permissions';
5+
6+
export const useViewTeamPermissions = () => {
7+
const { data: permissions, isLoading } = useValidateUserPermissionsNonSuspense(VIEW_TEAM_PERMISSIONS);
8+
9+
const isCourseViewAllowed = permissions
10+
? permissions.some((p) => p.action === CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM && p.allowed)
11+
: true;
12+
13+
const isLibraryViewAllowed = permissions
14+
? permissions.some((p) => p.action === CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM && p.allowed)
15+
: true;
16+
17+
return { isCourseViewAllowed, isLibraryViewAllowed, isLoading };
18+
};

src/authz-module/role-assignation-wizard/AssignRoleWizardPage.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import { ROUTES } from '../constants';
77
import messages from './messages';
88
import {
99
CONTENT_COURSE_PERMISSIONS, CONTENT_LIBRARY_PERMISSIONS, courseRolesMetadata, libraryRolesMetadata,
10-
MANAGE_TEAM_PERMISSIONS, VIEW_TEAM_PERMISSIONS,
10+
MANAGE_TEAM_PERMISSIONS,
1111
} from '../roles-permissions';
12+
import { useViewTeamPermissions } from '../hooks/useViewTeamPermissions';
1213

1314
const AssignRoleWizardPage = () => {
1415
const intl = useIntl();
@@ -24,11 +25,7 @@ const AssignRoleWizardPage = () => {
2425
: returnTo;
2526

2627
const { data: managePermissions } = useValidateUserPermissionsNonSuspense(MANAGE_TEAM_PERMISSIONS);
27-
const { data: viewPermissions } = useValidateUserPermissionsNonSuspense(VIEW_TEAM_PERMISSIONS);
28-
29-
const isCourseViewAllowed = viewPermissions
30-
? viewPermissions.some((p) => p.action === CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM && p.allowed)
31-
: true;
28+
const { isCourseViewAllowed } = useViewTeamPermissions();
3229

3330
const rolesAssignable = managePermissions?.flatMap((p) => {
3431
if (!p.allowed) { return []; }

src/authz-module/roles-permissions/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { CONTENT_COURSE_PERMISSIONS } from './course/constants';
2-
import { CONTENT_LIBRARY_PERMISSIONS } from './library/constants';
2+
import { CONTENT_LIBRARY_PERMISSIONS, libraryRolesMetadata as _libraryRolesMetadata } from './library/constants';
33

44
export {
55
CONTENT_LIBRARY_PERMISSIONS,
@@ -9,6 +9,8 @@ export {
99
rolesLibraryObject,
1010
} from './library/constants';
1111

12+
export const LIBRARY_ROLE_KEYS = _libraryRolesMetadata.map((r) => r.role).join(',');
13+
1214
export {
1315
CONTENT_COURSE_PERMISSIONS,
1416
courseResourceTypes,

src/authz-module/team-members/TeamMembersTable.tsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import {
77
} from '@openedx/paragon';
88

99
import { useToastManager } from '@src/components/ToastManager/ToastManagerContext';
10-
import { useValidateUserPermissionsNonSuspense } from '@src/data/hooks';
11-
import { CONTENT_COURSE_PERMISSIONS, VIEW_TEAM_PERMISSIONS, libraryRolesMetadata } from '@src/authz-module/roles-permissions';
10+
import { LIBRARY_ROLE_KEYS } from '@src/authz-module/roles-permissions';
11+
import { useViewTeamPermissions } from '@src/authz-module/hooks/useViewTeamPermissions';
1212
import { useQuerySettings } from '@src/authz-module/hooks/useQuerySettings';
1313
import OrgFilter from '@src/authz-module/components/TableControlBar/OrgFilter';
1414
import RolesFilter from '@src/authz-module/components/TableControlBar/RolesFilter';
@@ -24,8 +24,6 @@ import { UserRole } from '@src/types';
2424
import messages from './messages';
2525
import TableFooter from '../components/TableFooter/TableFooter';
2626

27-
const LIBRARY_ROLE_KEYS = libraryRolesMetadata.map((r) => r.role).join(',');
28-
2927
interface TeamMembersTableProps {
3028
presetScope?: string;
3129
}
@@ -48,10 +46,7 @@ const TeamMembersTable = ({ presetScope }: TeamMembersTableProps) => {
4846

4947
const { querySettings, handleTableFetch } = useQuerySettings(initialQuerySettings);
5048

51-
const { data: permissions } = useValidateUserPermissionsNonSuspense(VIEW_TEAM_PERMISSIONS);
52-
const isCourseViewAllowed = permissions
53-
? permissions.some((p) => p.action === CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM && p.allowed)
54-
: true;
49+
const { isCourseViewAllowed } = useViewTeamPermissions();
5550

5651
const effectiveQuerySettings = useMemo(() => {
5752
if (isCourseViewAllowed || querySettings.roles) { return querySettings; }

0 commit comments

Comments
 (0)