From 28c6f59b00ec41fd8eda6b62f6982350fdb5d16d Mon Sep 17 00:00:00 2001 From: Diana Olarte Date: Wed, 24 Jun 2026 19:55:39 +1000 Subject: [PATCH 1/5] fix(authz): correct library permission labels and relocate permission-matrix utils --- .../components/UserPermissions.test.tsx | 25 +++ .../components/UserPermissions.tsx | 16 +- .../RolesPermissions.test.tsx | 2 +- .../roles-permissions/RolesPermissions.tsx | 20 +-- src/authz-module/roles-permissions/index.ts | 1 + .../roles-permissions/library/constants.ts | 148 ++++++++---------- .../{library => }/messages.ts | 48 +++--- .../{library => }/utils.test.ts | 9 +- .../roles-permissions/{library => }/utils.ts | 2 +- 9 files changed, 138 insertions(+), 133 deletions(-) rename src/authz-module/roles-permissions/{library => }/messages.ts (55%) rename src/authz-module/roles-permissions/{library => }/utils.test.ts (89%) rename src/authz-module/roles-permissions/{library => }/utils.ts (98%) diff --git a/src/authz-module/components/UserPermissions.test.tsx b/src/authz-module/components/UserPermissions.test.tsx index fac0fa65..c81bd4f8 100644 --- a/src/authz-module/components/UserPermissions.test.tsx +++ b/src/authz-module/components/UserPermissions.test.tsx @@ -1,3 +1,4 @@ +import { screen } from '@testing-library/react'; import { initializeMockApp } from '@edx/frontend-platform/testing'; import { renderWrapper } from '@src/setupTest'; import * as coursesConstants from '@src/authz-module/roles-permissions'; @@ -52,6 +53,30 @@ describe('UserPermissions', () => { expect(container.querySelector('.d-flex')).toBeInTheDocument(); }); + it('renders library role permissions with their metadata labels', () => { + const props = { + row: { + original: { + role: 'library_admin', + }, + }, + }; + + const { container } = renderWrapper(); + + // Resource group headers from libraryResourceTypes + expect(screen.getByText('Library')).toBeInTheDocument(); + expect(screen.getByText('Team')).toBeInTheDocument(); + // Explicit labels from the permission metadata + expect(screen.getAllByText('Manage tags').length).toBeGreaterThan(0); + expect(screen.getAllByText('Publish').length).toBeGreaterThan(0); + expect(screen.getAllByText('Reuse').length).toBeGreaterThan(0); + // No permission renders with an empty label + const labels = Array.from(container.querySelectorAll('li span.font-weight-light')); + expect(labels.length).toBeGreaterThan(0); + labels.forEach((label) => expect(label.textContent?.trim()).not.toBe('')); + }); + it('returns null when role is empty', () => { const props = { row: { diff --git a/src/authz-module/components/UserPermissions.tsx b/src/authz-module/components/UserPermissions.tsx index 468b5a5e..38c2fce1 100644 --- a/src/authz-module/components/UserPermissions.tsx +++ b/src/authz-module/components/UserPermissions.tsx @@ -1,3 +1,4 @@ +import { useIntl } from '@edx/frontend-platform/i18n'; import { DJANGO_MANAGED_ROLES } from '@src/authz-module/constants'; import { courseResourceTypes, @@ -6,8 +7,8 @@ import { libraryResourceTypes, libraryPermissions, rolesLibraryObject, + getPermissionMetadata, } from '@src/authz-module/roles-permissions'; -import { PermissionItem } from '@src/types'; import RenderPermissionColumn from './RenderPermissionColumn'; import RenderPermissionInLine from './RenderPermissionInLine'; import RenderAdminRole from './RenderAdminRole'; @@ -21,6 +22,7 @@ interface UserPermissionsProps { } const UserPermissions = ({ row }: UserPermissionsProps) => { + const intl = useIntl(); let roleKey = row?.original?.role; if (!roleKey) { return null; } @@ -51,15 +53,17 @@ const UserPermissions = ({ row }: UserPermissionsProps) => { if (!roleObj) { return null; } const rolePerms = new Set(roleObj.permissions.map(String)); - // Build resource list with permissions (only once) + // Build resource list with permissions (only once). Permissions without an + // explicit label (most library ones) get a localized label derived from + // their action key, the same enrichment the permissions matrix uses. const resources = config.resourceTypes .map(resource => { - const perms = config.permissions.filter( - p => p.resource === resource.key && rolePerms.has(String(p.key)), - ); + const perms = config.permissions + .filter(p => p.resource === resource.key && rolePerms.has(String(p.key))) + .map(p => getPermissionMetadata(p, intl)); return perms.length ? { ...resource, perms } : null; }) - .filter((r): r is PermissionItem => r !== null); + .filter((r): r is NonNullable => r !== null); const isSingleRow = resources.length <= 3; const mid = Math.ceil(resources.length / 2); diff --git a/src/authz-module/roles-permissions/RolesPermissions.test.tsx b/src/authz-module/roles-permissions/RolesPermissions.test.tsx index db7bdd26..1558f7d1 100644 --- a/src/authz-module/roles-permissions/RolesPermissions.test.tsx +++ b/src/authz-module/roles-permissions/RolesPermissions.test.tsx @@ -5,7 +5,7 @@ import { renderWrapper } from '@src/setupTest'; import RolesPermissions from './RolesPermissions'; // Mock utils -jest.mock('./library/utils', () => ({ +jest.mock('./utils', () => ({ buildPermissionMatrixByResource: jest.fn(() => [ { key: 'test-resource', diff --git a/src/authz-module/roles-permissions/RolesPermissions.tsx b/src/authz-module/roles-permissions/RolesPermissions.tsx index eff45521..287934ab 100644 --- a/src/authz-module/roles-permissions/RolesPermissions.tsx +++ b/src/authz-module/roles-permissions/RolesPermissions.tsx @@ -18,9 +18,9 @@ import { import AnchorButton from '../components/AnchorButton'; import PermissionTable from '../components/PermissionTable'; -import { buildPermissionMatrixByResource } from './library/utils'; +import { buildPermissionMatrixByResource } from './utils'; -import messages from './library/messages'; +import messages from './messages'; const RolesPermissions = () => { const intl = useIntl(); @@ -56,13 +56,13 @@ const RolesPermissions = () => { onClick={() => setActive('courses')} variant={`${active === 'courses' ? 'primary' : 'outline-primary'}`} > - {intl.formatMessage(messages['library.authz.tabs.permissionsRoles.courses.tab']) } + {intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.tab']) } @@ -72,7 +72,7 @@ const RolesPermissions = () => { { >
-

{intl.formatMessage(messages['library.authz.tabs.permissionsRoles.courses.alert.title'])}

+

{intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.alert.title'])}

- {intl.formatMessage(messages['library.authz.tabs.permissionsRoles.courses.alert.note'])} - {intl.formatMessage(messages['library.authz.tabs.permissionsRoles.courses.alert.description'])} + {intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.alert.note'])} + {intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.alert.description'])}
- {intl.formatMessage(messages['library.authz.tabs.permissionsRoles.courses.alert.link'])} + {intl.formatMessage(messages['authz.tabs.permissionsRoles.courses.alert.link'])}
@@ -100,7 +100,7 @@ const RolesPermissions = () => { )} diff --git a/src/authz-module/roles-permissions/index.ts b/src/authz-module/roles-permissions/index.ts index 982a59e3..ea81797e 100644 --- a/src/authz-module/roles-permissions/index.ts +++ b/src/authz-module/roles-permissions/index.ts @@ -28,3 +28,4 @@ export const VIEW_TEAM_PERMISSIONS: { action: string }[] = [ { action: CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM }, { action: CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM }, ]; +export { buildPermissionMatrixByResource, getPermissionMetadata } from './utils'; diff --git a/src/authz-module/roles-permissions/library/constants.ts b/src/authz-module/roles-permissions/library/constants.ts index c03e53d7..27320ede 100644 --- a/src/authz-module/roles-permissions/library/constants.ts +++ b/src/authz-module/roles-permissions/library/constants.ts @@ -70,10 +70,10 @@ export const libraryPermissions: PermissionMetadata[] = [ key: CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY, resource: 'library', label: 'View', description: 'See the library in Studio and access its content in read-only mode.', icon: RemoveRedEye, }, { - key: CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TAGS, resource: 'library', label: 'Manage tag', description: 'Create, edit, and delete tags on this library.', icon: Settings, + key: CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TAGS, resource: 'library', label: 'Manage tags', description: 'Create, edit, and delete tags on this library.', icon: Settings, }, { - key: CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY, resource: 'library', label: 'Publish', description: 'Publish the library to make it available for use in courses.', icon: DownloadDone, + key: CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY, resource: 'library', label: 'Delete', description: 'Allows users to delete the entire content library.', icon: Delete, }, { key: CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_CONTENT, resource: 'library_content', label: 'Create', description: 'Create new content items in the library.', icon: Plus, @@ -100,96 +100,70 @@ export const libraryPermissions: PermissionMetadata[] = [ key: CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TEAM, resource: 'library_team', label: 'Manage', description: 'Add, change, or remove role assignments for this library from the Roles and Permissions console.', icon: Settings, }, { - key: CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_COLLECTION, resource: 'library_collection', label: 'View', description: 'Create new collections to organize content within the library.', icon: RemoveRedEye, + key: CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_COLLECTION, resource: 'library_collection', label: 'Create', description: 'Create new collections to organize content within the library.', icon: Plus, }, { - key: CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_COLLECTION, resource: 'library_collection', label: 'Publish', description: 'Update the name and contents of existing collections.', icon: EditOutline, + key: CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_COLLECTION, resource: 'library_collection', label: 'Edit', description: 'Update the name and contents of existing collections.', icon: EditOutline, }, { - key: CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_COLLECTION, resource: 'library_collection', label: 'Edit', description: 'Permanently remove collections from the library.', icon: EditOutline, + key: CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_COLLECTION, resource: 'library_collection', label: 'Delete', description: 'Permanently remove collections from the library.', icon: Delete, }, ]; -export const rolesLibraryObject: Role[] = [ - { - role: 'library_admin', - contextType: 'library', - scope: '', - permissions: [ - CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY, - CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TAGS, - CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY, - CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.PUBLISH_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM, - CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TEAM, - CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_COLLECTION, - CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_COLLECTION, - CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_COLLECTION, - CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.REUSE_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.IMPORT_LIBRARY_CONTENT, - ], - userCount: 1, - name: 'Library Admin', - description: 'The Library Admin has full control over the library, including managing users, modifying content, and handling publishing workflows. They ensure content is properly maintained and accessible as needed.', - }, - { - role: 'library_author', - contextType: 'library', - scope: '', - permissions: [ - CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY, - CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TAGS, - CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.PUBLISH_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.REUSE_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM, - CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_COLLECTION, - CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_COLLECTION, - CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_COLLECTION, - CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.IMPORT_LIBRARY_CONTENT, - ], - userCount: 1, - name: 'Library Author', - description: 'The Library Author is responsible for creating, editing, and publishing content within a library. They can manage tags and collections but cannot delete libraries or manage users.', - }, - { - role: 'library_contributor', - contextType: 'library', - scope: '', - permissions: [ - CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY, - CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TAGS, - CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.REUSE_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM, - CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_COLLECTION, - CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_COLLECTION, - CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_COLLECTION, - CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.IMPORT_LIBRARY_CONTENT, +const LIBRARY_ROLE_PERMISSIONS: Record = { + library_admin: [ + CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY, + CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TAGS, + CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY, + CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_CONTENT, + CONTENT_LIBRARY_PERMISSIONS.PUBLISH_LIBRARY_CONTENT, + CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM, + CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TEAM, + CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_COLLECTION, + CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_COLLECTION, + CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_COLLECTION, + CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_CONTENT, + CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_CONTENT, + CONTENT_LIBRARY_PERMISSIONS.REUSE_LIBRARY_CONTENT, + CONTENT_LIBRARY_PERMISSIONS.IMPORT_LIBRARY_CONTENT, + ], + library_author: [ + CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY, + CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TAGS, + CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_CONTENT, + CONTENT_LIBRARY_PERMISSIONS.PUBLISH_LIBRARY_CONTENT, + CONTENT_LIBRARY_PERMISSIONS.REUSE_LIBRARY_CONTENT, + CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM, + CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_COLLECTION, + CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_COLLECTION, + CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_COLLECTION, + CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_CONTENT, + CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_CONTENT, + CONTENT_LIBRARY_PERMISSIONS.IMPORT_LIBRARY_CONTENT, + ], + library_contributor: [ + CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY, + CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TAGS, + CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_CONTENT, + CONTENT_LIBRARY_PERMISSIONS.REUSE_LIBRARY_CONTENT, + CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM, + CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_COLLECTION, + CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_COLLECTION, + CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_COLLECTION, + CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_CONTENT, + CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_CONTENT, + CONTENT_LIBRARY_PERMISSIONS.IMPORT_LIBRARY_CONTENT, + ], + library_user: [ + CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY, + CONTENT_LIBRARY_PERMISSIONS.REUSE_LIBRARY_CONTENT, + CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM, + ], +}; - ], - userCount: 1, - name: 'Library Contributor', - description: 'The Library Contributor can create and edit content within a library but cannot publish it. They support the authoring process while leaving final publishing to Authors or Admins.', - }, - { - role: 'library_user', - contextType: 'library', - scope: '', - permissions: [ - CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY, - CONTENT_LIBRARY_PERMISSIONS.REUSE_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM, - ], - userCount: 1, - name: 'Library User', - description: 'The Library User can view and reuse content but cannot edit or delete anything.', - }, -]; +export const rolesLibraryObject: Role[] = libraryRolesMetadata.map((meta) => ({ + ...meta, + scope: '', + userCount: 1, + permissions: LIBRARY_ROLE_PERMISSIONS[meta.role] ?? [], +})); diff --git a/src/authz-module/roles-permissions/library/messages.ts b/src/authz-module/roles-permissions/messages.ts similarity index 55% rename from src/authz-module/roles-permissions/library/messages.ts rename to src/authz-module/roles-permissions/messages.ts index 13e102f4..c23f8f21 100644 --- a/src/authz-module/roles-permissions/library/messages.ts +++ b/src/authz-module/roles-permissions/messages.ts @@ -1,63 +1,63 @@ import { defineMessages } from '@edx/frontend-platform/i18n'; const messages = defineMessages({ - 'library.authz.tabs.permissions': { - id: 'library.authz.tabs.permissions', + 'authz.tabs.permissions': { + id: 'authz.tabs.permissions', defaultMessage: 'Permissions', description: 'Libraries AuthZ title for the permissions tab', }, - 'library.authz.tabs.permissionsRoles': { - id: 'library.authz.tabs.permissionsRoles', + 'authz.tabs.permissionsRoles': { + id: 'authz.tabs.permissionsRoles', defaultMessage: 'Roles and Permissions', description: 'Libraries AuthZ title for the permissions and roles tab', }, - 'library.authz.tabs.permissionsRoles.courses.alert.title': { - id: 'library.authz.tabs.permissionsRoles.courses.alert.title', + 'authz.tabs.permissionsRoles.courses.alert.title': { + id: 'authz.tabs.permissionsRoles.courses.alert.title', defaultMessage: 'Course Roles', description: 'Libraries AuthZ title for the course roles alert', }, - 'library.authz.tabs.permissionsRoles.courses.tab': { - id: 'library.authz.tabs.permissionsRoles.courses.tab', + 'authz.tabs.permissionsRoles.courses.tab': { + id: 'authz.tabs.permissionsRoles.courses.tab', defaultMessage: 'Courses', description: 'Libraries AuthZ title for the course roles tab', }, - 'library.authz.tabs.permissionsRoles.libraries.tab': { - id: 'library.authz.tabs.permissionsRoles.libraries.tab', + 'authz.tabs.permissionsRoles.libraries.tab': { + id: 'authz.tabs.permissionsRoles.libraries.tab', defaultMessage: 'Libraries', description: 'Libraries AuthZ title for the libraries roles tab', }, - 'library.authz.tabs.permissionsRoles.libraries.tab.title': { - id: 'library.authz.tabs.permissionsRoles.libraries.tab.title', + 'authz.tabs.permissionsRoles.libraries.tab.title': { + id: 'authz.tabs.permissionsRoles.libraries.tab.title', defaultMessage: 'Library Roles', description: 'Libraries AuthZ title for the library roles table', }, - 'library.authz.tabs.permissionsRoles.courses.tab.title': { - id: 'library.authz.tabs.permissionsRoles.courses.tab.title', + 'authz.tabs.permissionsRoles.courses.tab.title': { + id: 'authz.tabs.permissionsRoles.courses.tab.title', defaultMessage: 'Course Roles', description: 'Libraries AuthZ title for the course roles table', }, - 'library.authz.tabs.permissionsRoles.courses.alert.note': { - id: 'library.authz.tabs.permissionsRoles.courses.alert.note', + 'authz.tabs.permissionsRoles.courses.alert.note': { + id: 'authz.tabs.permissionsRoles.courses.alert.note', defaultMessage: 'Note:', description: 'Libraries AuthZ note for the course roles alert', }, - 'library.authz.tabs.permissionsRoles.courses.alert.description': { - id: 'library.authz.tabs.permissionsRoles.courses.alert.description', + 'authz.tabs.permissionsRoles.courses.alert.description': { + id: 'authz.tabs.permissionsRoles.courses.alert.description', defaultMessage: 'This list shows the permissions currently available in Authoring Studio. Some roles may grant additional permissions managed outside this interface.', description: 'Libraries AuthZ description for the course roles alert', }, - 'library.authz.tabs.permissionsRoles.courses.alert.link': { - id: 'library.authz.tabs.permissionsRoles.courses.alert.link', + 'authz.tabs.permissionsRoles.courses.alert.link': { + id: 'authz.tabs.permissionsRoles.courses.alert.link', defaultMessage: 'See full documentation', description: 'Libraries AuthZ link for the course roles alert', }, - 'library.authz.team.remove.user.toast.success.description': { - id: 'library.authz.team.remove.user.toast.success.description', + 'authz.team.remove.user.toast.success.description': { + id: 'authz.team.remove.user.toast.success.description', defaultMessage: 'The {role} role has been successfully removed.{rolesCount, plural, =0 { The user no longer has access to this library and has been removed from the member list.} other {}}', description: 'Libraries team management remove user toast success', }, - 'library.authz.team.toast.default.error.message': { - id: 'library.authz.team.toast.default.error.message', + 'authz.team.toast.default.error.message': { + id: 'authz.team.toast.default.error.message', defaultMessage: 'Something went wrong on our end.

Please try again later.', description: 'Libraries default error message', }, diff --git a/src/authz-module/roles-permissions/library/utils.test.ts b/src/authz-module/roles-permissions/utils.test.ts similarity index 89% rename from src/authz-module/roles-permissions/library/utils.test.ts rename to src/authz-module/roles-permissions/utils.test.ts index 0d4f0ff5..f5c9b2bb 100644 --- a/src/authz-module/roles-permissions/library/utils.test.ts +++ b/src/authz-module/roles-permissions/utils.test.ts @@ -1,4 +1,5 @@ import { createIntl } from '@edx/frontend-platform/i18n'; +import type { Role } from '@src/types'; import { buildPermissionMatrixByResource } from './utils'; const intl = createIntl({ locale: 'en', messages: {} }); @@ -14,15 +15,15 @@ const permissions = [ const resources = [ { key: 'library', label: 'Library', description: '' }, ]; -const roles = [ +const roles: Role[] = [ { - name: 'admin', permissions: ['create_library', 'edit_library'], userCount: 2, role: 'admin', description: '', contextType: '', scope: '', + name: 'admin', permissions: ['create_library', 'edit_library'], userCount: 2, role: 'admin', description: '', contextType: 'library', scope: '', }, { - name: 'editor', permissions: ['edit_library'], userCount: 2, role: 'editor', description: '', contextType: '', scope: '', + name: 'editor', permissions: ['edit_library'], userCount: 2, role: 'editor', description: '', contextType: 'library', scope: '', }, { - name: 'guest', permissions: [], userCount: 2, role: 'guest', description: '', contextType: '', scope: '', + name: 'guest', permissions: [], userCount: 2, role: 'guest', description: '', contextType: 'library', scope: '', }, ]; diff --git a/src/authz-module/roles-permissions/library/utils.ts b/src/authz-module/roles-permissions/utils.ts similarity index 98% rename from src/authz-module/roles-permissions/library/utils.ts rename to src/authz-module/roles-permissions/utils.ts index affcaec2..e805b253 100644 --- a/src/authz-module/roles-permissions/library/utils.ts +++ b/src/authz-module/roles-permissions/utils.ts @@ -96,4 +96,4 @@ const buildPermissionMatrixByResource = ({ }); }; -export { buildPermissionMatrixByResource }; +export { buildPermissionMatrixByResource, getPermissionMetadata }; From 1de66aa90a019058072f7f615d371979786056f3 Mon Sep 17 00:00:00 2001 From: Diana Olarte Date: Thu, 23 Jul 2026 10:38:25 +1000 Subject: [PATCH 2/5] style: display multiline role-metadata to improve reditability --- .../components/UserPermissions.test.tsx | 8 +- .../components/UserPermissions.tsx | 8 +- .../RolesPermissions.test.tsx | 23 ++ .../roles-permissions/RolesPermissions.tsx | 16 +- .../roles-permissions/course/constants.ts | 303 ++++++++++-------- src/authz-module/roles-permissions/index.ts | 4 +- .../roles-permissions/library/constants.ts | 126 ++++++-- 7 files changed, 307 insertions(+), 181 deletions(-) diff --git a/src/authz-module/components/UserPermissions.test.tsx b/src/authz-module/components/UserPermissions.test.tsx index c81bd4f8..c8fb5598 100644 --- a/src/authz-module/components/UserPermissions.test.tsx +++ b/src/authz-module/components/UserPermissions.test.tsx @@ -112,8 +112,8 @@ describe('UserPermissions', () => { }, ]; - const originalRolesObject = coursesConstants.rolesObject; - const rolesObjectSpy = jest.spyOn(coursesConstants, 'rolesObject', 'get') + const originalRolesObject = coursesConstants.courseRolesWithPermissions; + const courseRolesWithPermissionsSpy = jest.spyOn(coursesConstants, 'courseRolesWithPermissions', 'get') .mockReturnValue([...originalRolesObject, ...mockRoleObject] as typeof originalRolesObject); const props = { @@ -126,10 +126,10 @@ describe('UserPermissions', () => { const { getByTestId } = renderWrapper(); expect(getByTestId('render-permission-inline')).toBeInTheDocument(); - rolesObjectSpy.mockRestore(); + courseRolesWithPermissionsSpy.mockRestore(); }); - it('returns null when role is not found in rolesObject (line 52 coverage)', () => { + it('returns null when role is not found in courseRolesWithPermissions (line 52 coverage)', () => { const props = { row: { original: { diff --git a/src/authz-module/components/UserPermissions.tsx b/src/authz-module/components/UserPermissions.tsx index 38c2fce1..efa56be4 100644 --- a/src/authz-module/components/UserPermissions.tsx +++ b/src/authz-module/components/UserPermissions.tsx @@ -3,10 +3,10 @@ import { DJANGO_MANAGED_ROLES } from '@src/authz-module/constants'; import { courseResourceTypes, coursePermissions, - rolesObject, + courseRolesWithPermissions, libraryResourceTypes, libraryPermissions, - rolesLibraryObject, + libraryRolesWithPermissions, getPermissionMetadata, } from '@src/authz-module/roles-permissions'; import RenderPermissionColumn from './RenderPermissionColumn'; @@ -41,12 +41,12 @@ const UserPermissions = ({ row }: UserPermissionsProps) => { ? { resourceTypes: libraryResourceTypes, permissions: libraryPermissions, - roles: rolesLibraryObject, + roles: libraryRolesWithPermissions, } : { resourceTypes: courseResourceTypes, permissions: coursePermissions, - roles: rolesObject, + roles: courseRolesWithPermissions, }; const roleObj = config.roles.find(r => r.role === roleKey); diff --git a/src/authz-module/roles-permissions/RolesPermissions.test.tsx b/src/authz-module/roles-permissions/RolesPermissions.test.tsx index 1558f7d1..760c791a 100644 --- a/src/authz-module/roles-permissions/RolesPermissions.test.tsx +++ b/src/authz-module/roles-permissions/RolesPermissions.test.tsx @@ -16,6 +16,29 @@ jest.mock('./utils', () => ({ ]), })); +// Mock constants +jest.mock('./course/constants', () => ({ + courseRolesWithPermissions: [ + { + name: 'Course Admin', role: 'admin', permissions: [], userCount: 1, + }, + ], + coursePermissions: [], + courseResourceTypes: [], + courseRolesMetadata: [], +})); + +jest.mock('./library/constants', () => ({ + libraryRolesWithPermissions: [ + { + name: 'Library Admin', role: 'admin', permissions: [], userCount: 1, + }, + ], + libraryPermissions: [], + libraryResourceTypes: [], + libraryRolesMetadata: [], +})); + jest.mock('@openedx/paragon', () => ({ ...jest.requireActual('@openedx/paragon'), Hyperlink: ({ children, ...props }: diff --git a/src/authz-module/roles-permissions/RolesPermissions.tsx b/src/authz-module/roles-permissions/RolesPermissions.tsx index 287934ab..2a160674 100644 --- a/src/authz-module/roles-permissions/RolesPermissions.tsx +++ b/src/authz-module/roles-permissions/RolesPermissions.tsx @@ -10,11 +10,13 @@ import { import { coursePermissions, courseResourceTypes, - rolesObject, - rolesLibraryObject, + courseRolesWithPermissions, +} from './course/constants'; +import { + libraryRolesWithPermissions, libraryPermissions, libraryResourceTypes, -} from '@src/authz-module/roles-permissions'; +} from './library/constants'; import AnchorButton from '../components/AnchorButton'; import PermissionTable from '../components/PermissionTable'; @@ -28,7 +30,7 @@ const RolesPermissions = () => { const libraryPermissionsByResource = useMemo(() => { const permissionsByResource = buildPermissionMatrixByResource({ - roles: rolesLibraryObject, + roles: libraryRolesWithPermissions, permissions: libraryPermissions, resources: libraryResourceTypes, intl, @@ -39,7 +41,7 @@ const RolesPermissions = () => { const coursePermissionsByResource = useMemo(() => { const permissionsByResource = buildPermissionMatrixByResource({ - roles: rolesObject, + roles: courseRolesWithPermissions, permissions: coursePermissions, resources: courseResourceTypes, intl, @@ -71,7 +73,7 @@ const RolesPermissions = () => {
{ { active === 'libraries' && ( )} diff --git a/src/authz-module/roles-permissions/course/constants.ts b/src/authz-module/roles-permissions/course/constants.ts index 964fe391..219a95e5 100644 --- a/src/authz-module/roles-permissions/course/constants.ts +++ b/src/authz-module/roles-permissions/course/constants.ts @@ -67,42 +67,77 @@ export const CONTENT_COURSE_PERMISSIONS = { export const courseResourceTypes: ResourceMetadata[] = [ { - key: 'course_access_content', label: 'Course Access & content', description: 'Permissions related to accessing the course and managing core course content, including creating, editing, and publishing materials.', icon: BookOpen, + key: 'course_access_content', + label: 'Course Access & content', + description: 'Permissions related to accessing the course and managing core course content, including creating, editing, and publishing materials.', + icon: BookOpen, }, { - key: 'course_library_updates', label: 'Library updates', description: 'Permissions for reviewing and managing updates made to content libraries connected to the course.', icon: LibraryBooks, + key: 'course_library_updates', + label: 'Library updates', + description: 'Permissions for reviewing and managing updates made to content libraries connected to the course.', + icon: LibraryBooks, }, { - key: 'course_updates_handouts', label: 'Course updates & handouts', description: 'Permissions for viewing and managing course updates and handouts that are visible to learners.', icon: Sync, + key: 'course_updates_handouts', + label: 'Course updates & handouts', + description: 'Permissions for viewing and managing course updates and handouts that are visible to learners.', + icon: Sync, }, { - key: 'course_pages_resources', label: 'Pages & resources', description: 'Permissions for viewing and managing course pages and additional learning resources.', icon: Article, + key: 'course_pages_resources', + label: 'Pages & resources', + description: 'Permissions for viewing and managing course pages and additional learning resources.', + icon: Article, }, { - key: 'course_files', label: 'Files', description: 'Permissions for viewing and managing course pages and additional learning resources.', icon: Folder, + key: 'course_files', + label: 'Files', + description: 'Permissions for viewing and managing course pages and additional learning resources.', + icon: Folder, }, { - key: 'course_schedule_details', label: 'Schedule & details', description: 'Permissions for viewing and editing the course schedule and course information.', icon: Calendar, + key: 'course_schedule_details', + label: 'Schedule & details', + description: 'Permissions for viewing and editing the course schedule and course information.', + icon: Calendar, }, { - key: 'course_grading', label: 'Grading', description: 'Permissions related to viewing and managing grading configuration and grading policies.', icon: Award, + key: 'course_grading', + label: 'Grading', + description: 'Permissions related to viewing and managing grading configuration and grading policies.', + icon: Award, }, { - key: 'course_team_group', label: 'Course team & groups', description: 'Permissions for viewing and managing the course team, learner groups, and group configurations.', icon: Group, + key: 'course_team_group', + label: 'Course team & groups', + description: 'Permissions for viewing and managing the course team, learner groups, and group configurations.', + icon: Group, }, { - key: 'course_tags_taxonomies', label: 'Tags', description: 'Permissions for managing tags used to organize course content.', icon: LocalOffer, + key: 'course_tags_taxonomies', + label: 'Tags', + description: 'Permissions for managing tags used to organize course content.', + icon: LocalOffer, }, { - key: 'course_advanced_certificates', label: 'Advanced & certificates', description: 'Permissions for managing advanced course settings and course certificates.', icon: CheckCircle, + key: 'course_advanced_certificates', + label: 'Advanced & certificates', + description: 'Permissions for managing advanced course settings and course certificates.', + icon: CheckCircle, }, { - key: 'course_import_export', label: 'Import / export', description: 'Permissions for importing and exporting course content and related data.', icon: Download, + key: 'course_import_export', + label: 'Import / export', + description: 'Permissions for importing and exporting course content and related data.', + icon: Download, }, { - key: 'course_other', label: 'Other', description: 'Additional permissions not included in other categories, such as viewing checklists and platform-level course roles.', icon: DrawShapes, + key: 'course_other', + label: 'Other', + description: 'Additional permissions not included in other categories, such as viewing checklists and platform-level course roles.', + icon: DrawShapes, }, - ]; export const coursePermissions: PermissionMetadata[] = [ @@ -329,150 +364,136 @@ export const coursePermissions: PermissionMetadata[] = [ }, ]; -// roles hardcoded, todo: need to add the constants from above in order to merge the different permissions array. -export const rolesObject: Role[] = [ +export const courseRolesMetadata: RoleMetadata[] = [ { role: 'course_admin', - contextType: 'course', - scope: '', - permissions: [ - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_UPDATES, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_PAGES_RESOURCES, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_FILES, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GRADING_SETTINGS, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_CHECKLISTS, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GLOBAL_STAFF_SUPER_ADMINS, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_DETAILS, - CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_CONTENT, - CONTENT_COURSE_PERMISSIONS.REVIEW_COURSE_LIBRARY_UPDATES, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_UPDATES, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_PAGES_RESOURCES, - CONTENT_COURSE_PERMISSIONS.CREATE_COURSE_FILES, - CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_FILES, - CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_GRADING_SETTINGS, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_GROUP_CONFIGURATION, - CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_DETAILS, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_TAGS, - CONTENT_COURSE_PERMISSIONS.PUBLISH_COURSE_CONTENT, - CONTENT_COURSE_PERMISSIONS.DELETE_COURSE_FILES, - CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_SCHEDULE, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_ADVANCED_SETTINGS, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_CERTIFICATES, - CONTENT_COURSE_PERMISSIONS.IMPORT_COURSE, - CONTENT_COURSE_PERMISSIONS.EXPORT_COURSE, - CONTENT_COURSE_PERMISSIONS.EXPORT_COURSE_TAGS, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_TEAM, - ], - userCount: 1, name: 'Course Admin', - description: 'course level administration, including access and role management for the course team, plus all Staff capabilities.', + description: 'Can manage the course team and all course settings.', + contextType: 'course', }, - { role: 'course_staff', - contextType: 'course', - scope: '', - permissions: [ - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_UPDATES, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_PAGES_RESOURCES, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_FILES, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GRADING_SETTINGS, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_CHECKLISTS, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GLOBAL_STAFF_SUPER_ADMINS, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_DETAILS, - CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_CONTENT, - CONTENT_COURSE_PERMISSIONS.REVIEW_COURSE_LIBRARY_UPDATES, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_UPDATES, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_PAGES_RESOURCES, - CONTENT_COURSE_PERMISSIONS.CREATE_COURSE_FILES, - CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_FILES, - CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_GRADING_SETTINGS, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_GROUP_CONFIGURATION, - CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_DETAILS, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_TAGS, - CONTENT_COURSE_PERMISSIONS.PUBLISH_COURSE_CONTENT, - CONTENT_COURSE_PERMISSIONS.DELETE_COURSE_FILES, - CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_SCHEDULE, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_ADVANCED_SETTINGS, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_CERTIFICATES, - CONTENT_COURSE_PERMISSIONS.IMPORT_COURSE, - CONTENT_COURSE_PERMISSIONS.EXPORT_COURSE, - CONTENT_COURSE_PERMISSIONS.EXPORT_COURSE_TAGS, - ], - userCount: 1, name: 'Course Staff', - description: 'operating the course lifecycle in Studio, publishing content, handling scheduling, and managing high impact configuration for the course.', + description: 'Can publish content and manage the course lifecycle in Studio.', + contextType: 'course', }, { role: 'course_editor', - contextType: 'course', - scope: '', - permissions: [ - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_UPDATES, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_PAGES_RESOURCES, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_FILES, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GRADING_SETTINGS, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_CHECKLISTS, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GLOBAL_STAFF_SUPER_ADMINS, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_DETAILS, - CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_CONTENT, - CONTENT_COURSE_PERMISSIONS.REVIEW_COURSE_LIBRARY_UPDATES, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_UPDATES, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_PAGES_RESOURCES, - CONTENT_COURSE_PERMISSIONS.CREATE_COURSE_FILES, - CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_FILES, - CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_GRADING_SETTINGS, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_GROUP_CONFIGURATION, - CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_DETAILS, - CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_TAGS, - ], - userCount: 1, name: 'Course Editor', - description: 'building and maintaining course content and supporting assets, without operational controls or high impact actions that can affect a live course.', + description: 'Can create and edit course content, but cannot publish or change critical course settings.', + contextType: 'course', disabled: true, }, { role: 'course_auditor', - contextType: 'course', - scope: '', - permissions: [ - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_UPDATES, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_PAGES_RESOURCES, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_FILES, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GRADING_SETTINGS, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_CHECKLISTS, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_DETAILS, - ], - userCount: 1, name: 'Course Auditor', - description: ' QA, compliance review, content review, and general oversight, no changes in Studio.', + description: 'Can view course content and settings, but cannot make changes.', + contextType: 'course', disabled: true, }, - -]; -export const courseRolesMetadata: RoleMetadata[] = [ - { - role: 'course_admin', name: 'Course Admin', description: 'Can manage the course team and all course settings.', contextType: 'course', - }, - { - role: 'course_staff', name: 'Course Staff', description: 'Can publish content and manage the course lifecycle in Studio.', contextType: 'course', - }, - { - role: 'course_editor', name: 'Course Editor', description: 'Can create and edit course content, but cannot publish or change critical course settings.', contextType: 'course', disabled: true, - }, - { - role: 'course_auditor', name: 'Course Auditor', description: 'Can view course content and settings, but cannot make changes.', contextType: 'course', disabled: true, - }, ]; + +// Permission keys granted to each course role. +const COURSE_ROLE_PERMISSIONS: Record = { + course_admin: [ + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_UPDATES, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_PAGES_RESOURCES, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_FILES, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GRADING_SETTINGS, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_CHECKLISTS, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GLOBAL_STAFF_SUPER_ADMINS, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_DETAILS, + CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_CONTENT, + CONTENT_COURSE_PERMISSIONS.REVIEW_COURSE_LIBRARY_UPDATES, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_UPDATES, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_PAGES_RESOURCES, + CONTENT_COURSE_PERMISSIONS.CREATE_COURSE_FILES, + CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_FILES, + CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_GRADING_SETTINGS, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_GROUP_CONFIGURATION, + CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_DETAILS, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_TAGS, + CONTENT_COURSE_PERMISSIONS.PUBLISH_COURSE_CONTENT, + CONTENT_COURSE_PERMISSIONS.DELETE_COURSE_FILES, + CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_SCHEDULE, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_ADVANCED_SETTINGS, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_CERTIFICATES, + CONTENT_COURSE_PERMISSIONS.IMPORT_COURSE, + CONTENT_COURSE_PERMISSIONS.EXPORT_COURSE, + CONTENT_COURSE_PERMISSIONS.EXPORT_COURSE_TAGS, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_TEAM, + ], + course_staff: [ + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_UPDATES, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_PAGES_RESOURCES, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_FILES, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GRADING_SETTINGS, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_CHECKLISTS, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GLOBAL_STAFF_SUPER_ADMINS, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_DETAILS, + CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_CONTENT, + CONTENT_COURSE_PERMISSIONS.REVIEW_COURSE_LIBRARY_UPDATES, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_UPDATES, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_PAGES_RESOURCES, + CONTENT_COURSE_PERMISSIONS.CREATE_COURSE_FILES, + CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_FILES, + CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_GRADING_SETTINGS, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_GROUP_CONFIGURATION, + CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_DETAILS, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_TAGS, + CONTENT_COURSE_PERMISSIONS.PUBLISH_COURSE_CONTENT, + CONTENT_COURSE_PERMISSIONS.DELETE_COURSE_FILES, + CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_SCHEDULE, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_ADVANCED_SETTINGS, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_CERTIFICATES, + CONTENT_COURSE_PERMISSIONS.IMPORT_COURSE, + CONTENT_COURSE_PERMISSIONS.EXPORT_COURSE, + CONTENT_COURSE_PERMISSIONS.EXPORT_COURSE_TAGS, + ], + course_editor: [ + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_UPDATES, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_PAGES_RESOURCES, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_FILES, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GRADING_SETTINGS, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_CHECKLISTS, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GLOBAL_STAFF_SUPER_ADMINS, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_DETAILS, + CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_CONTENT, + CONTENT_COURSE_PERMISSIONS.REVIEW_COURSE_LIBRARY_UPDATES, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_UPDATES, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_PAGES_RESOURCES, + CONTENT_COURSE_PERMISSIONS.CREATE_COURSE_FILES, + CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_FILES, + CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_GRADING_SETTINGS, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_GROUP_CONFIGURATION, + CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_DETAILS, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_TAGS, + ], + course_auditor: [ + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_UPDATES, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_PAGES_RESOURCES, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_FILES, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GRADING_SETTINGS, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_CHECKLISTS, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_DETAILS, + ], +}; + +export const courseRolesWithPermissions: Role[] = courseRolesMetadata.map((meta) => ({ + ...meta, + scope: '', + userCount: 1, + permissions: COURSE_ROLE_PERMISSIONS[meta.role] ?? [], +})); diff --git a/src/authz-module/roles-permissions/index.ts b/src/authz-module/roles-permissions/index.ts index ea81797e..2d46d3dd 100644 --- a/src/authz-module/roles-permissions/index.ts +++ b/src/authz-module/roles-permissions/index.ts @@ -6,7 +6,7 @@ export { libraryResourceTypes, libraryPermissions, libraryRolesMetadata, - rolesLibraryObject, + libraryRolesWithPermissions, } from './library/constants'; export const LIBRARY_ROLE_KEYS = _libraryRolesMetadata.map((r) => r.role).join(','); @@ -15,7 +15,7 @@ export { CONTENT_COURSE_PERMISSIONS, courseResourceTypes, coursePermissions, - rolesObject, + courseRolesWithPermissions, courseRolesMetadata, } from './course/constants'; diff --git a/src/authz-module/roles-permissions/library/constants.ts b/src/authz-module/roles-permissions/library/constants.ts index 27320ede..0a5c121f 100644 --- a/src/authz-module/roles-permissions/library/constants.ts +++ b/src/authz-module/roles-permissions/library/constants.ts @@ -37,76 +37,156 @@ export const CONTENT_LIBRARY_PERMISSIONS = { // but for the MVP we decided to manage it in the frontend export const libraryRolesMetadata: RoleMetadata[] = [ { - role: 'library_admin', name: 'Library Admin', description: 'The Library Admin has full control over the library, including managing users, modifying content, and handling publishing workflows. They ensure content is properly maintained and accessible as needed.', contextType: 'library', + role: 'library_admin', + name: 'Library Admin', + description: 'The Library Admin has full control over the library, including managing users, modifying content, and handling publishing workflows. They ensure content is properly maintained and accessible as needed.', + contextType: 'library', }, { - role: 'library_author', name: 'Library Author', description: 'The Library Author is responsible for creating, editing, and publishing content within a library. They can manage tags and collections but cannot delete libraries or manage users.', contextType: 'library', + role: 'library_author', + name: 'Library Author', + description: 'The Library Author is responsible for creating, editing, and publishing content within a library. They can manage tags and collections but cannot delete libraries or manage users.', + contextType: 'library', }, { - role: 'library_contributor', name: 'Library Contributor', description: 'The Library Contributor can create and edit content within a library but cannot publish it. They support the authoring process while leaving final publishing to Authors or Admins.', contextType: 'library', + role: 'library_contributor', + name: 'Library Contributor', + description: 'The Library Contributor can create and edit content within a library but cannot publish it. They support the authoring process while leaving final publishing to Authors or Admins.', + contextType: 'library', }, { - role: 'library_user', name: 'Library User', description: 'The Library User can view and reuse content but cannot edit or delete any resource.', contextType: 'library', + role: 'library_user', + name: 'Library User', + description: 'The Library User can view and reuse content but cannot edit or delete any resource.', + contextType: 'library', }, ]; export const libraryResourceTypes: ResourceMetadata[] = [ { - key: 'library', label: 'Library', description: 'Permissions related to viewing, managing, and publishing the library structure and metadata.', icon: CollectionsBookmark, + key: 'library', + label: 'Library', + description: 'Permissions related to viewing, managing, and publishing the library structure and metadata.', + icon: CollectionsBookmark, }, { - key: 'library_content', label: 'Content', description: 'Permissions for creating, editing, deleting, and publishing content within the library.', icon: Notes, + key: 'library_content', + label: 'Content', + description: 'Permissions for creating, editing, deleting, and publishing content within the library.', + icon: Notes, }, { - key: 'library_team', label: 'Team', description: 'Permissions for viewing and managing users who have access to the library.', icon: Group, + key: 'library_team', + label: 'Team', + description: 'Permissions for viewing and managing users who have access to the library.', + icon: Group, }, { - key: 'library_collection', label: 'Collection', description: 'Permissions for creating and managing content collections within the library.', icon: AutoAwesomeMosaic, + key: 'library_collection', + label: 'Collection', + description: 'Permissions for creating and managing content collections within the library.', + icon: AutoAwesomeMosaic, }, ]; export const libraryPermissions: PermissionMetadata[] = [ { - key: CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY, resource: 'library', label: 'View', description: 'See the library in Studio and access its content in read-only mode.', icon: RemoveRedEye, + key: CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY, + resource: 'library', + label: 'View', + description: 'See the library in Studio and access its content in read-only mode.', + icon: RemoveRedEye, }, { - key: CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TAGS, resource: 'library', label: 'Manage tags', description: 'Create, edit, and delete tags on this library.', icon: Settings, + key: CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TAGS, + resource: 'library', + label: 'Manage tags', + description: 'Create, edit, and delete tags on this library.', + icon: Settings, }, { - key: CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY, resource: 'library', label: 'Delete', description: 'Allows users to delete the entire content library.', icon: Delete, + key: CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY, + resource: 'library', + label: 'Delete', + description: 'Allows users to delete the entire content library.', + icon: Delete, }, { - key: CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_CONTENT, resource: 'library_content', label: 'Create', description: 'Create new content items in the library.', icon: Plus, + key: CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_CONTENT, + resource: 'library_content', + label: 'Create', + description: 'Create new content items in the library.', + icon: Plus, }, { - key: CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_CONTENT, resource: 'library_content', label: 'Edit', description: 'Edit existing content items in the library.', icon: EditOutline, + key: CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_CONTENT, + resource: 'library_content', + label: 'Edit', + description: 'Edit existing content items in the library.', + icon: EditOutline, }, { - key: CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_CONTENT, resource: 'library_content', label: 'Delete', description: 'Permanently remove content items from the library.', icon: Delete, + key: CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_CONTENT, + resource: 'library_content', + label: 'Delete', + description: 'Permanently remove content items from the library.', + icon: Delete, }, { - key: CONTENT_LIBRARY_PERMISSIONS.PUBLISH_LIBRARY_CONTENT, resource: 'library_content', label: 'Publish', description: 'Publish individual content items to make them available for reuse in courses.', icon: DownloadDone, + key: CONTENT_LIBRARY_PERMISSIONS.PUBLISH_LIBRARY_CONTENT, + resource: 'library_content', + label: 'Publish', + description: 'Publish individual content items to make them available for reuse in courses.', + icon: DownloadDone, }, { - key: CONTENT_LIBRARY_PERMISSIONS.REUSE_LIBRARY_CONTENT, resource: 'library_content', label: 'Reuse', description: 'Add published content from this library to a course.', icon: SpinnerIcon, + key: CONTENT_LIBRARY_PERMISSIONS.REUSE_LIBRARY_CONTENT, + resource: 'library_content', + label: 'Reuse', + description: 'Add published content from this library to a course.', + icon: SpinnerIcon, }, { - key: CONTENT_LIBRARY_PERMISSIONS.IMPORT_LIBRARY_CONTENT, resource: 'library_content', label: 'Import Content from Course', description: ' Import content from an existing course into this library.', icon: FileDownload, + key: CONTENT_LIBRARY_PERMISSIONS.IMPORT_LIBRARY_CONTENT, + resource: 'library_content', + label: 'Import Content from Course', + description: ' Import content from an existing course into this library.', + icon: FileDownload, }, { - key: CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM, resource: 'library_team', label: 'View', description: 'See the list of users with a role assigned to this library.', icon: RemoveRedEye, + key: CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM, + resource: 'library_team', + label: 'View', + description: 'See the list of users with a role assigned to this library.', + icon: RemoveRedEye, }, { - key: CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TEAM, resource: 'library_team', label: 'Manage', description: 'Add, change, or remove role assignments for this library from the Roles and Permissions console.', icon: Settings, + key: CONTENT_LIBRARY_PERMISSIONS.MANAGE_LIBRARY_TEAM, + resource: 'library_team', + label: 'Manage', + description: 'Add, change, or remove role assignments for this library from the Roles and Permissions console.', + icon: Settings, }, { - key: CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_COLLECTION, resource: 'library_collection', label: 'Create', description: 'Create new collections to organize content within the library.', icon: Plus, + key: CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_COLLECTION, + resource: 'library_collection', + label: 'Create', + description: 'Create new collections to organize content within the library.', + icon: Plus, }, { - key: CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_COLLECTION, resource: 'library_collection', label: 'Edit', description: 'Update the name and contents of existing collections.', icon: EditOutline, + key: CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_COLLECTION, + resource: 'library_collection', + label: 'Edit', + description: 'Update the name and contents of existing collections.', + icon: EditOutline, }, { - key: CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_COLLECTION, resource: 'library_collection', label: 'Delete', description: 'Permanently remove collections from the library.', icon: Delete, + key: CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_COLLECTION, + resource: 'library_collection', + label: 'Delete', + description: 'Permanently remove collections from the library.', + icon: Delete, }, ]; @@ -161,7 +241,7 @@ const LIBRARY_ROLE_PERMISSIONS: Record = { ], }; -export const rolesLibraryObject: Role[] = libraryRolesMetadata.map((meta) => ({ +export const libraryRolesWithPermissions: Role[] = libraryRolesMetadata.map((meta) => ({ ...meta, scope: '', userCount: 1, From 405ad6713759fc60f43ca4b8bcf0313dfedacaa3 Mon Sep 17 00:00:00 2001 From: Diana Olarte Date: Thu, 23 Jul 2026 14:34:04 +1000 Subject: [PATCH 3/5] fix: align libraries table with backend documentation --- .../roles-permissions/library/constants.ts | 38 +------------------ 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/src/authz-module/roles-permissions/library/constants.ts b/src/authz-module/roles-permissions/library/constants.ts index 0a5c121f..dc15f162 100644 --- a/src/authz-module/roles-permissions/library/constants.ts +++ b/src/authz-module/roles-permissions/library/constants.ts @@ -10,7 +10,6 @@ import { EditOutline, Delete, SpinnerIcon, - FileDownload, } from '@openedx/paragon/icons'; export const CONTENT_LIBRARY_PERMISSIONS = { @@ -18,12 +17,9 @@ export const CONTENT_LIBRARY_PERMISSIONS = { MANAGE_LIBRARY_TAGS: 'content_libraries.manage_library_tags', VIEW_LIBRARY: 'content_libraries.view_library', - CREATE_LIBRARY_CONTENT: 'content_libraries.create_library_content', EDIT_LIBRARY_CONTENT: 'content_libraries.edit_library_content', - DELETE_LIBRARY_CONTENT: 'content_libraries.delete_library_content', PUBLISH_LIBRARY_CONTENT: 'content_libraries.publish_library_content', REUSE_LIBRARY_CONTENT: 'content_libraries.reuse_library_content', - IMPORT_LIBRARY_CONTENT: 'content_libraries.import_library_content', MANAGE_LIBRARY_TEAM: 'content_libraries.manage_library_team', VIEW_LIBRARY_TEAM: 'content_libraries.view_library_team', @@ -72,7 +68,7 @@ export const libraryResourceTypes: ResourceMetadata[] = [ { key: 'library_content', label: 'Content', - description: 'Permissions for creating, editing, deleting, and publishing content within the library.', + description: 'Permissions for editing, publishing, and reusing content within the library.', icon: Notes, }, { @@ -111,27 +107,13 @@ export const libraryPermissions: PermissionMetadata[] = [ description: 'Allows users to delete the entire content library.', icon: Delete, }, - { - key: CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_CONTENT, - resource: 'library_content', - label: 'Create', - description: 'Create new content items in the library.', - icon: Plus, - }, { key: CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_CONTENT, resource: 'library_content', label: 'Edit', - description: 'Edit existing content items in the library.', + description: 'Create, edit, and delete content items in the library.', icon: EditOutline, }, - { - key: CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_CONTENT, - resource: 'library_content', - label: 'Delete', - description: 'Permanently remove content items from the library.', - icon: Delete, - }, { key: CONTENT_LIBRARY_PERMISSIONS.PUBLISH_LIBRARY_CONTENT, resource: 'library_content', @@ -146,13 +128,6 @@ export const libraryPermissions: PermissionMetadata[] = [ description: 'Add published content from this library to a course.', icon: SpinnerIcon, }, - { - key: CONTENT_LIBRARY_PERMISSIONS.IMPORT_LIBRARY_CONTENT, - resource: 'library_content', - label: 'Import Content from Course', - description: ' Import content from an existing course into this library.', - icon: FileDownload, - }, { key: CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY_TEAM, resource: 'library_team', @@ -202,10 +177,7 @@ const LIBRARY_ROLE_PERMISSIONS: Record = { CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_COLLECTION, CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_COLLECTION, CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_COLLECTION, - CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_CONTENT, CONTENT_LIBRARY_PERMISSIONS.REUSE_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.IMPORT_LIBRARY_CONTENT, ], library_author: [ CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY, @@ -217,9 +189,6 @@ const LIBRARY_ROLE_PERMISSIONS: Record = { CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_COLLECTION, CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_COLLECTION, CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_COLLECTION, - CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.IMPORT_LIBRARY_CONTENT, ], library_contributor: [ CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY, @@ -230,9 +199,6 @@ const LIBRARY_ROLE_PERMISSIONS: Record = { CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_COLLECTION, CONTENT_LIBRARY_PERMISSIONS.EDIT_LIBRARY_COLLECTION, CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_COLLECTION, - CONTENT_LIBRARY_PERMISSIONS.CREATE_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.DELETE_LIBRARY_CONTENT, - CONTENT_LIBRARY_PERMISSIONS.IMPORT_LIBRARY_CONTENT, ], library_user: [ CONTENT_LIBRARY_PERMISSIONS.VIEW_LIBRARY, From 492a6f8796c99536f7288dfe7a1807006487562f Mon Sep 17 00:00:00 2001 From: Diana Olarte Date: Thu, 23 Jul 2026 15:27:04 +1000 Subject: [PATCH 4/5] fix: align permissions with the backend --- .../roles-permissions/course/constants.ts | 105 +++++++----------- 1 file changed, 41 insertions(+), 64 deletions(-) diff --git a/src/authz-module/roles-permissions/course/constants.ts b/src/authz-module/roles-permissions/course/constants.ts index 219a95e5..80b27556 100644 --- a/src/authz-module/roles-permissions/course/constants.ts +++ b/src/authz-module/roles-permissions/course/constants.ts @@ -27,7 +27,7 @@ export const CONTENT_COURSE_PERMISSIONS = { EDIT_COURSE_CONTENT: 'courses.edit_course_content', PUBLISH_COURSE_CONTENT: 'courses.publish_course_content', - REVIEW_COURSE_LIBRARY_UPDATES: 'courses.manage_library_updates', + MANAGE_COURSE_LIBRARY_UPDATES: 'courses.manage_library_updates', VIEW_COURSE_UPDATES: 'courses.view_course_updates', MANAGE_COURSE_UPDATES: 'courses.manage_course_updates', @@ -40,9 +40,8 @@ export const CONTENT_COURSE_PERMISSIONS = { EDIT_COURSE_FILES: 'courses.edit_files', DELETE_COURSE_FILES: 'courses.delete_files', - VIEW_COURSE_SCHEDULE: 'courses.view_schedule', + VIEW_COURSE_SCHEDULE_AND_DETAILS: 'courses.view_schedule_and_details', EDIT_COURSE_SCHEDULE: 'courses.edit_schedule', - VIEW_COURSE_DETAILS: 'courses.view_details', EDIT_COURSE_DETAILS: 'courses.edit_details', VIEW_COURSE_GRADING_SETTINGS: 'courses.view_grading_settings', @@ -62,7 +61,6 @@ export const CONTENT_COURSE_PERMISSIONS = { EXPORT_COURSE_TAGS: 'courses.export_tags', VIEW_COURSE_CHECKLISTS: 'courses.view_checklists', - VIEW_COURSE_GLOBAL_STAFF_SUPER_ADMINS: 'courses.view_global_staff_and_superadmins', }; export const courseResourceTypes: ResourceMetadata[] = [ @@ -135,7 +133,7 @@ export const courseResourceTypes: ResourceMetadata[] = [ { key: 'course_other', label: 'Other', - description: 'Additional permissions not included in other categories, such as viewing checklists and platform-level course roles.', + description: 'Additional permissions not included in other categories, such as viewing checklists.', icon: DrawShapes, }, ]; @@ -144,7 +142,7 @@ export const coursePermissions: PermissionMetadata[] = [ { key: CONTENT_COURSE_PERMISSIONS.VIEW_COURSE, resource: 'course_access_content', - description: 'View course in the course list, access the course outline in read only mode, includes the "View Live" entry point.', + description: 'See the course in the Studio home and access the course outline in read-only mode. Includes the "View Live" option to preview the course as a learner in the LMS.', label: 'View course', icon: RemoveRedEye, }, @@ -158,37 +156,37 @@ export const coursePermissions: PermissionMetadata[] = [ { key: CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_CONTENT, resource: 'course_access_content', - description: 'Edit course content, outline, units, components.', + description: 'Edit the course outline, units, and components.', label: 'Edit course content', icon: EditOutline, }, { key: CONTENT_COURSE_PERMISSIONS.PUBLISH_COURSE_CONTENT, resource: 'course_access_content', - description: 'Publish course content.', + description: 'Make course content visible to learners.', label: 'Publish course content', icon: DownloadDone, }, { - key: CONTENT_COURSE_PERMISSIONS.REVIEW_COURSE_LIBRARY_UPDATES, + key: CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_LIBRARY_UPDATES, resource: 'course_library_updates', - description: 'Accept or reject library updates in Studio.', - label: 'Review library updates', + description: 'Accept or reject pending updates from content libraries linked to this course.', + label: 'Manage library updates', icon: Checklist, }, { key: CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_UPDATES, resource: 'course_updates_handouts', - description: 'View course updates and handouts.', + description: 'See course announcements and handouts visible to learners.', label: 'View course updates', icon: RemoveRedEye, }, { key: CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_UPDATES, resource: 'course_updates_handouts', - description: 'Manage course updates and handouts, create, edit, delete.', + description: 'Create, edit, and delete course announcements and handouts.', label: 'Manage course updates', icon: Settings, }, @@ -196,14 +194,14 @@ export const coursePermissions: PermissionMetadata[] = [ { key: CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_PAGES_RESOURCES, resource: 'course_pages_resources', - description: 'View Pages and Resources.', + description: 'See the Pages & Resources section in Studio.', label: 'View pages & resources', icon: RemoveRedEye, }, { key: CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_PAGES_RESOURCES, resource: 'course_pages_resources', - description: 'Edit Pages and Resources, including toggles and content managed from that section.', + description: 'Enable or disable course features such as Discussions, the Wiki, Notes, Calculator, and Live. Create and edit Textbooks and Custom pages, and manage their configurations.', label: 'Manage pages & resources', icon: Settings, }, @@ -211,57 +209,50 @@ export const coursePermissions: PermissionMetadata[] = [ { key: CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_FILES, resource: 'course_files', - description: 'View the Files page.', + description: 'See the list of files and assets uploaded to the course.', label: 'View files', icon: RemoveRedEye, }, { key: CONTENT_COURSE_PERMISSIONS.CREATE_COURSE_FILES, resource: 'course_files', - description: 'Upload files.', + description: 'Upload new files and assets to the course.', label: 'Create files', icon: Plus, }, { key: CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_FILES, resource: 'course_files', - description: 'Non destructive file actions, for example lock or unlock, exact actions depend on implementation.', + description: 'Perform non-destructive actions on files, such as locking or unlocking them.', label: 'Edit files', icon: EditOutline, }, { key: CONTENT_COURSE_PERMISSIONS.DELETE_COURSE_FILES, resource: 'course_files', - description: 'Delete files.', + description: 'Permanently remove files and assets from the course.', label: 'Delete files', icon: Delete, }, { - key: CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE, + key: CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE_AND_DETAILS, resource: 'course_schedule_details', - description: 'View course schedule.', - label: 'View schedule', + description: 'See the course schedule (start and end dates, enrollment dates, and pacing settings) and course details (summary, pacing, and prerequisites).', + label: 'View schedule & details', icon: RemoveRedEye, }, { key: CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_SCHEDULE, resource: 'course_schedule_details', - description: 'Edit course schedule.', + description: 'Update course start and end dates, enrollment dates, and pacing settings.', label: 'Edit schedule', icon: EditOutline, }, - { - key: CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_DETAILS, - resource: 'course_schedule_details', - description: 'View course details.', - label: 'View course details', - icon: RemoveRedEye, - }, { key: CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_DETAILS, resource: 'course_schedule_details', - description: 'Edit course details, includes Course Summary, Course Pacing, Course Details, Course Pre requisite.', + description: 'Update course information including the course summary, pacing, and prerequisites.', label: 'Edit course details', icon: EditOutline, }, @@ -269,14 +260,14 @@ export const coursePermissions: PermissionMetadata[] = [ { key: CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GRADING_SETTINGS, resource: 'course_grading', - description: 'View grading settings page.', + description: 'See the grading configuration for the course, including assignment types and grading scale.', label: 'View grading settings', icon: RemoveRedEye, }, { key: CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_GRADING_SETTINGS, resource: 'course_grading', - description: 'Edit grading settings.', + description: 'Update the grading configuration for the course, including assignment types and grading scale.', label: 'Edit grading settings', icon: EditOutline, }, @@ -284,21 +275,21 @@ export const coursePermissions: PermissionMetadata[] = [ { key: CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM, resource: 'course_team_group', - description: 'View the course team roster.', + description: 'See the list of users with a role assigned to this course.', label: 'View course team', icon: RemoveRedEye, }, { key: CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_TEAM, resource: 'course_team_group', - description: 'Edit course team membership and roles.', + description: 'Add, change, or remove role assignments for this course from the Roles and Permissions console.', label: 'Manage course team', icon: Settings, }, { key: CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_GROUP_CONFIGURATION, resource: 'course_team_group', - description: 'Manage content groups.', + description: 'Create and manage content groups used to target course content to specific learners.', label: 'Manage group configuration', icon: Settings, }, @@ -306,7 +297,7 @@ export const coursePermissions: PermissionMetadata[] = [ { key: CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_TAGS, resource: 'course_tags_taxonomies', - description: 'Create, edit, delete tags.', + description: 'Create, edit, and delete tags on this course.', label: 'Manage tags', icon: Settings, }, @@ -314,14 +305,14 @@ export const coursePermissions: PermissionMetadata[] = [ { key: CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_ADVANCED_SETTINGS, resource: 'course_advanced_certificates', - description: 'Access and edit Advanced Settings.', + description: 'Access and edit the Advanced Settings page in Studio. This covers a wide range of technical course configurations, including proctoring, timed exams, LTI tools, enrollment limits, and custom display options.', label: 'Manage advanced settings', icon: Settings, }, { key: CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_CERTIFICATES, resource: 'course_advanced_certificates', - description: 'Access and edit Certificates.', + description: 'Create and edit course certificates, including certificate design and eligibility settings.', label: 'Manage certificates', icon: Settings, }, @@ -329,21 +320,21 @@ export const coursePermissions: PermissionMetadata[] = [ { key: CONTENT_COURSE_PERMISSIONS.IMPORT_COURSE, resource: 'course_import_export', - description: 'Show Import in Studio, this is treated as a high privilege action and effectively implies most authoring permissions.', + description: 'Import course content from a file. This is a high-privilege action that can overwrite most course content and settings.', label: 'Import course', icon: Download, }, { key: CONTENT_COURSE_PERMISSIONS.EXPORT_COURSE, resource: 'course_import_export', - description: 'Show Export in Studio.', + description: 'Download the course content as a file for backup or reuse in another platform.', label: 'Export course', icon: Upload, }, { key: CONTENT_COURSE_PERMISSIONS.EXPORT_COURSE_TAGS, resource: 'course_import_export', - description: 'Export tags.', + description: 'Download the tag data associated with this course.', label: 'Export tags', icon: Upload, }, @@ -351,17 +342,10 @@ export const coursePermissions: PermissionMetadata[] = [ { key: CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_CHECKLISTS, resource: 'course_other', - description: 'View checklists.', + description: 'See the course launch checklist in Studio.', label: 'View checklists', icon: RemoveRedEye, }, - { - key: CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GLOBAL_STAFF_SUPER_ADMINS, - resource: 'course_other', - description: 'Allow course or library admins to view the list of global Staff and Super Admin users.', - label: 'View global staff & super admins', - icon: RemoveRedEye, - }, ]; export const courseRolesMetadata: RoleMetadata[] = [ @@ -402,12 +386,10 @@ const COURSE_ROLE_PERMISSIONS: Record = { CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_FILES, CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GRADING_SETTINGS, CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_CHECKLISTS, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GLOBAL_STAFF_SUPER_ADMINS, CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_DETAILS, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE_AND_DETAILS, CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_CONTENT, - CONTENT_COURSE_PERMISSIONS.REVIEW_COURSE_LIBRARY_UPDATES, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_LIBRARY_UPDATES, CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_UPDATES, CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_PAGES_RESOURCES, CONTENT_COURSE_PERMISSIONS.CREATE_COURSE_FILES, @@ -433,12 +415,10 @@ const COURSE_ROLE_PERMISSIONS: Record = { CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_FILES, CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GRADING_SETTINGS, CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_CHECKLISTS, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GLOBAL_STAFF_SUPER_ADMINS, CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_DETAILS, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE_AND_DETAILS, CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_CONTENT, - CONTENT_COURSE_PERMISSIONS.REVIEW_COURSE_LIBRARY_UPDATES, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_LIBRARY_UPDATES, CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_UPDATES, CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_PAGES_RESOURCES, CONTENT_COURSE_PERMISSIONS.CREATE_COURSE_FILES, @@ -463,12 +443,10 @@ const COURSE_ROLE_PERMISSIONS: Record = { CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_FILES, CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GRADING_SETTINGS, CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_CHECKLISTS, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GLOBAL_STAFF_SUPER_ADMINS, CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_DETAILS, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE_AND_DETAILS, CONTENT_COURSE_PERMISSIONS.EDIT_COURSE_CONTENT, - CONTENT_COURSE_PERMISSIONS.REVIEW_COURSE_LIBRARY_UPDATES, + CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_LIBRARY_UPDATES, CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_UPDATES, CONTENT_COURSE_PERMISSIONS.MANAGE_COURSE_PAGES_RESOURCES, CONTENT_COURSE_PERMISSIONS.CREATE_COURSE_FILES, @@ -486,8 +464,7 @@ const COURSE_ROLE_PERMISSIONS: Record = { CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_GRADING_SETTINGS, CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_CHECKLISTS, CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_TEAM, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE, - CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_DETAILS, + CONTENT_COURSE_PERMISSIONS.VIEW_COURSE_SCHEDULE_AND_DETAILS, ], }; From 76614671188b1a9ee29a13b29fa7b1159fc6f7ea Mon Sep 17 00:00:00 2001 From: Diana Olarte Date: Fri, 24 Jul 2026 21:49:10 +1000 Subject: [PATCH 5/5] fix: update files description --- src/authz-module/roles-permissions/course/constants.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/authz-module/roles-permissions/course/constants.ts b/src/authz-module/roles-permissions/course/constants.ts index 80b27556..5b0f1049 100644 --- a/src/authz-module/roles-permissions/course/constants.ts +++ b/src/authz-module/roles-permissions/course/constants.ts @@ -66,7 +66,7 @@ export const CONTENT_COURSE_PERMISSIONS = { export const courseResourceTypes: ResourceMetadata[] = [ { key: 'course_access_content', - label: 'Course Access & content', + label: 'Course access & content', description: 'Permissions related to accessing the course and managing core course content, including creating, editing, and publishing materials.', icon: BookOpen, }, @@ -91,7 +91,7 @@ export const courseResourceTypes: ResourceMetadata[] = [ { key: 'course_files', label: 'Files', - description: 'Permissions for viewing and managing course pages and additional learning resources.', + description: 'Permissions for viewing and managing files and assets uploaded to the course.', icon: Folder, }, {