@@ -14,6 +14,8 @@ import { AdditionalCoursePluginSlot } from '@src/plugin-slots/AdditionalCoursePl
1414import { AdditionalCourseContentPluginSlot } from '@src/plugin-slots/AdditionalCourseContentPluginSlot' ;
1515import { useCourseAuthoringContext } from '@src/CourseAuthoringContext' ;
1616import { DeprecatedReduxState } from '@src/store' ;
17+ import { useCourseUserPermissions } from '@src/authz/hooks' ;
18+ import { getPagesAndResourcesPermissions } from '@src/authz/permissionHelpers' ;
1719
1820import messages from './messages' ;
1921import DiscussionsSettings from './discussions' ;
@@ -28,6 +30,13 @@ const PagesAndResources = () => {
2830 const { courseId, courseDetails } = useCourseAuthoringContext ( ) ;
2931 document . title = getPageHeadTitle ( courseDetails ?. name || '' , intl . formatMessage ( messages . heading ) ) ;
3032
33+ const {
34+ isLoading : isLoadingUserPermissions ,
35+ isAuthzEnabled,
36+ canViewPagesAndResources,
37+ canEditPagesAndResources,
38+ } = useCourseUserPermissions ( courseId , getPagesAndResourcesPermissions ( courseId ) ) ;
39+
3140 const dispatch = useDispatch ( ) ;
3241 useEffect ( ( ) => {
3342 dispatch ( fetchCourseApps ( courseId ) ) ;
@@ -56,19 +65,33 @@ const PagesAndResources = () => {
5665 }
5766 } ) ;
5867
59- if ( loadingStatus === RequestStatus . IN_PROGRESS ) {
68+ if ( loadingStatus === RequestStatus . IN_PROGRESS || isLoadingUserPermissions ) {
6069 // eslint-disable-next-line react/jsx-no-useless-fragment
6170 return < > </ > ;
6271 }
6372
64- if ( courseAppsApiStatus === RequestStatus . DENIED ) {
73+ // Gate: if user has neither VIEW nor MANAGE permission, show permission denied
74+ const hasNoAccess = ( ! isAuthzEnabled && courseAppsApiStatus === RequestStatus . DENIED )
75+ || ( isAuthzEnabled && ! isLoadingUserPermissions && ! canViewPagesAndResources && ! canEditPagesAndResources ) ;
76+
77+ if ( hasNoAccess ) {
6578 return < PermissionDeniedAlert /> ;
6679 }
6780
81+ const isEditable = ! isLoadingUserPermissions && canEditPagesAndResources ;
6882 const hasAdditionalCoursePlugin = getConfig ( ) ?. pluginSlots ?. additional_course_plugin != null ;
6983
84+ // Read-only mode: has VIEW permission but not MANAGE (auditor)
85+ const isReadOnly = isAuthzEnabled
86+ && ! isLoadingUserPermissions
87+ && canViewPagesAndResources
88+ && ! canEditPagesAndResources ;
89+
90+ // For the modal: if readOnly, isEditable should be false (show disabled fields)
91+ const isEditableForModal = isReadOnly ? false : isEditable ;
92+
7093 return (
71- < PagesAndResourcesProvider courseId = { courseId } >
94+ < PagesAndResourcesProvider courseId = { courseId } isEditable = { isEditableForModal } >
7295 < main className = "container container-mw-md px-3" >
7396 < div className = "d-flex justify-content-between my-4 my-md-5 align-items-center" >
7497 < h3 className = "m-0" > { intl . formatMessage ( messages . heading ) } </ h3 >
@@ -81,7 +104,6 @@ const PagesAndResources = () => {
81104 < Button variant = "outline-primary" className = "p-2" > { intl . formatMessage ( messages . viewLiveButton ) } </ Button >
82105 </ Hyperlink >
83106 </ div >
84-
85107 < Routes >
86108 < Route
87109 path = "discussion/configure/:appId"
@@ -117,14 +139,23 @@ const PagesAndResources = () => {
117139 />
118140 </ Routes >
119141
120- < PageGrid pages = { pages } pluginSlotComponent = { < AdditionalCoursePluginSlot /> } courseId = { courseId } />
142+ < PageGrid
143+ pages = { pages }
144+ pluginSlotComponent = { < AdditionalCoursePluginSlot /> }
145+ courseId = { courseId }
146+ readOnly = { isReadOnly }
147+ />
121148 { ( contentPermissionsPages . length > 0 || hasAdditionalCoursePlugin )
122149 && (
123150 < >
124151 < div className = "d-flex justify-content-between my-4 my-md-5 align-items-center" >
125152 < h3 className = "m-0" > { intl . formatMessage ( messages . contentPermissions ) } </ h3 >
126153 </ div >
127- < PageGrid pages = { contentPermissionsPages } pluginSlotComponent = { < AdditionalCourseContentPluginSlot /> } />
154+ < PageGrid
155+ pages = { contentPermissionsPages }
156+ pluginSlotComponent = { < AdditionalCourseContentPluginSlot /> }
157+ readOnly = { isReadOnly }
158+ />
128159 </ >
129160 ) }
130161 </ main >
0 commit comments