feat: implement view and edit permission checks for pages and resources#3031
Conversation
|
Thanks for the pull request, @bra-i-am! This repository is currently maintained by Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review. 🔘 Get product approvalIf you haven't already, check this list to see if your contribution needs to go through the product review process.
🔘 Provide contextTo help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:
🔘 Get a green buildIf one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green. DetailsWhere can I find more information?If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources: When can I expect my changes to be merged?Our goal is to get community contributions seen and reviewed as efficiently as possible. However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:
💡 As a result it may take up to several weeks or months to complete a review and merge your PR. |
5bf47e2 to
bf1f32a
Compare
27c140e to
2768600
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3031 +/- ##
==========================================
+ Coverage 95.53% 95.55% +0.01%
==========================================
Files 1393 1393
Lines 33009 32999 -10
Branches 7403 7661 +258
==========================================
- Hits 31535 31532 -3
+ Misses 1419 1401 -18
- Partials 55 66 +11 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
7bed3bd to
c842c4a
Compare
8d98c60 to
699af15
Compare
bradenmacdonald
left a comment
There was a problem hiding this comment.
Thanks @bra-i-am ! The code looks good to me. ✅
Once someone else has tested it and merged the other PRs, I will approve and merge this for you. I have not tested it myself, just read the code.
|
As a suggestion remove the page and resources scope in the PR title and just describe I think my comment about displaying/hiding option in the navigation header suits better here, so I just reference it #2991 (comment) Specially because the header implantation for Advanced Settings displayed is still validating "can manage" instead of "can view" permission. Screencast.from.2026-05-09.12-27-27.webmBeside that all is working as described: Advanced settings Screencast.from.2026-05-09.12-44-31.webmPages and Resources Screencast.from.2026-05-09.12-47-22.webm |
c9af2f3 to
cfc7598
Compare
|
@bra-i-am Is this ready to merge? |
…/resources access
…d refactor related components
… related components
…ove accessibility attributes
…onfigForm and PageCard tests
ef39044 to
5f4b0f6
Compare
|
@dcoa, @bradenmacdonald: thanks a lot for your help with this PR! I turned this PR into a draft while I solved some doubts about openedx/openedx-authz#272 and openedx/openedx-platform#38462, which is required to make some changes work as expected. |
09a559c to
7a59df6
Compare
…proved permission handling
|
Given the roles and permission sets already discussed at https://openedx.atlassian.net/wiki/spaces/OEPM/pages/5638619138/Authoring+Roles+and+Permissions#2.-Roles-and-permission-sets, neither
This PR was modified so that Advanced Settings remains a binary allow/deny gate (based on
cc. @MaferMazu |
|
@bradenmacdonald, @dcoa: could you please help me review this again? 🙏 |
MaferMazu
left a comment
There was a problem hiding this comment.
Thanks for this @bra-i-am.
I test it locally, and it works as expected ✅
I have a small comment: please fix "the course_editor has full access" in the PR description (because they don't have advanced settings, which affects the wiki and progress section). I know you mentioned this elsewhere, but in the PR description's summary box, it says they have full access, and they don't.
I asked a Gemini for feedback, and in general, it is good. I'll leave its comments. The only one I think is important is the first one.
Here is my review for the PR. Overall, the implementation looks solid and cleanly preserves legacy behavior when AuthZ is disabled. The refactoring of the header hooks to use unified permission helpers is a great architectural cleanup.
However, there are a few important issues and improvements that should be addressed before merging:
- Context Dependency Array Bug (Potential Stale State)
Insrc/pages-and-resources/PagesAndResourcesProvider.tsx, you addedisEditableto the context object but forgot to include it in theuseMemodependency array.// src/pages-and-resources/PagesAndResourcesProvider.tsx const contextValue = useMemo(() => ({ courseId, path: `/course/${courseId}/pages-and-resources`, isEditable, }), [courseId, isEditable]); // <--- FIX: Add isEditable hereWhy it matters: Without this, changes to the user's permissions won't propagate correctly to child components because the context will retain the stale value from the initial render.
Redundant Event Handling Override
In src/pages-and-resources/pages/PageSettingButton.jsx, you are conditionally setting onClick to undefined when the button is disabled.// src/pages-and-resources/pages/PageSettingButton.jsx return ( <IconButton src={Settings} iconAs={Icon} size="inline" alt={formatMessage(messages.settings)} disabled={isGearDisabled} onClick={() => navigate(`${pagesAndResourcesPath}/${id}/settings`)} // <--- Clean this up /> );Why it matters: Paragon's IconButton automatically suppresses standard HTML pointer events and updates accessibility attributes when disabled is true. Overriding onClick manually is redundant and can break if the design system changes its internal rendering element.
- Suboptimal Loading UX (White Flash)
In src/pages-and-resources/PagesAndResources.tsx, you block the UI by returning an empty fragment (<></>) while isLoadingUserPermissions is active.// src/pages-and-resources/PagesAndResources.tsx if (loadingStatus === RequestStatus.IN_PROGRESS || isLoadingUserPermissions) { return <Loading />; // <--- FIX: Use the imported Loading component }Why it matters: Returning an empty fragment introduces a jarring visual blink ("white flash") for the user while waiting for the AuthZ API to respond. Since the Loading component is already imported in this file, we should leverage it here for a smoother UX.
Please judge those recommendations as they came from AI. And the rest looks good to me. Let me know if some of the recommendations make sense to you. Thanks again @bra-i-am ✨
|
@MaferMazu, thanks for your review! I already changed the PR's description and title And according to the Gemini's points:
|
d2cdcf2 to
d3a7263
Compare



Description
Implements role-based access control (RBAC) for the Pages and Resources section and adds permission-gated gear icons for Progress and Wiki apps, using the existing
MANAGE_ADVANCED_SETTINGSpermission.This PR closes #2933.
What this PR does
Pages and Resources (closes #2933)
VIEW_PAGES_AND_RESOURCESandMANAGE_PAGES_AND_RESOURCESpermission constants tosrc/authz/constants.tsgetPagesAndResourcesPermissionshelper insrc/authz/permissionHelpers.tsisEditablefrom resolved permissions:!isAuthzEnabled || !!canManagePagesAndResourcesisEditable = true— legacy behavior fully preservedisEditableistrueonly for users with MANAGE permissionisEditablethroughPagesAndResourcesContextto all child componentsdisabled={!isEditable}to all interactive elements: app cards inAppCard.jsx, the "Next" button inAppListNextButton.jsx, app list inAppList.jsx, page setting buttons inPageSettingButton.jsx, and app settings modal controls inAppSettingsModal.jsxPermissionDeniedAlertgate for users who lack both VIEW and MANAGE permissionsProgress and Wiki gear icons
getAdvancedSettingsPermissionshelper insrc/authz/permissionHelpers.tsPageSettingButtonfetchescanManageAdvancedSettingsdirectly using its owncourseIdprop (no context pollution)MANAGE_ADVANCED_SETTINGSHeader menu (hooks refactor)
useContentMenuItemsanduseSettingMenuItemsnow useuseCourseUserPermissionsinstead of the lower-leveluseUserPermissions, eliminating manualisAuthzEnabledguards and per-hook fallback logichooks.tsxreplaced with helper functions frompermissionHelpers.tsCOURSE_PERMISSIONSis no longer imported inhooks.tsxRole impact
course_auditorcourse_editorcourse_staff/course_adminTesting instructions
AUTHZ_COURSE_AUTHORING_FLAGfeature flag.course_auditorrole to a test user for a specific course.PermissionDeniedAlertmust be shown.course_editor: Pages & Resources must be fully interactive, Advanced Settings must showPermissionDeniedAlert, and Progress and Wiki gear icons must be disabled.course_stafforcourse_adminand verify full access everywhere.AUTHZ_COURSE_AUTHORING_FLAGand verify legacy fallback works correctly for all roles.Best Practices Checklist
src/authz/permissionHelpers.test.ts)isEditablepropagated via React Context — no prop drillingcanManageAdvancedSettingsfetched at point of use — no context pollutiongetXPermissions) consistently across the codebase