Skip to content

Conversation

@dcoa
Copy link
Contributor

@dcoa dcoa commented Oct 2, 2025

Create LibrariesUserManager view to manage roles for a specific user

Description

This PR introduces a second view for managing user roles and permissions. When a team member is selected via the edit button in the table, the user is redirected to this new view to configure their roles and permissions.

Warning

This PR depends on #5 for getting the roles and permissions metadata.

Changes overview

  • Integrate Link component in the Layout to manage the Breadcrumbs redirections.
  • Introduces a reusable RoleCard component that displays individual roles in a card layout. Each card includes a collapsible section listing the associated permissions, organized by resource.
    • Permissions are grouped by resource (e.g., Team, Collections).
    • Each permission is displayed as a chip.
    • Chips are enabled or disabled based on the actions allowed by the role.
    • Designed for reuse across views where role-permission mapping needs to be displayed or managed.
  • LibrariesUserManager view to manage a specific user role assignment and integrate it in the module router.

Out of scope

  • Error handling
  • Edit/Delete/Add roles for the current user.

Evidence

2025-10-02.19-39-35.mov

Testing instructions

  1. Create and setup a local environment (Tutor recommended)
  2. Run LMS and CMS, then clone the repo in the current branch and run the dev server npm run dev
  3. Add the URL to the CORS_WHITELIST in both LMS/CMS settings.py
# admin console MFE
CORS_ORIGIN_WHITELIST.append("http://apps.local.openedx.io:2025")
LOGIN_REDIRECT_WHITELIST.append("apps.local.openedx.io:2025")
CSRF_TRUSTED_ORIGINS.append("http://apps.local.openedx.io:2025")
  1. Create a library
  2. Navigate to http://apps.local.openedx.io:2025/admin-console/authz/libraries/:libraryId
  3. Mock the API calls for /authz/* queries, you can use 2 options
    • Use Chrome override https://developer.chrome.com/docs/devtools/overrides
    • Use an API mock tool such as Postman and Mockoon, and replace the API baseUrl with your service and, change getAuthenticatedHttpClient to getHttpClient to avoid user checks from the backend.

Additional information

  1. US: Audit a member’s permissions openedx-authz#48

@openedx-webhooks openedx-webhooks added open-source-contribution PR author is not from Axim or 2U core contributor PR author is a Core Contributor (who may or may not have write access to this repo). labels Oct 2, 2025
@openedx-webhooks
Copy link

openedx-webhooks commented Oct 2, 2025

Thanks for the pull request, @dcoa!

This repository is currently maintained by @openedx/committers-frontend.

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 approval

If you haven't already, check this list to see if your contribution needs to go through the product review process.

  • If it does, you'll need to submit a product proposal for your contribution, and have it reviewed by the Product Working Group.
    • This process (including the steps you'll need to take) is documented here.
  • If it doesn't, simply proceed with the next step.
🔘 Provide context

To 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:

  • Dependencies

    This PR must be merged before / after / at the same time as ...

  • Blockers

    This PR is waiting for OEP-1234 to be accepted.

  • Timeline information

    This PR must be merged by XX date because ...

  • Partner information

    This is for a course on edx.org.

  • Supporting documentation
  • Relevant Open edX discussion forum threads
🔘 Get a green build

If one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green.


Where 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:

  • The size and impact of the changes that it introduces
  • The need for product review
  • Maintenance status of the parent repository

💡 As a result it may take up to several weeks or months to complete a review and merge your PR.

@codecov
Copy link

codecov bot commented Oct 2, 2025

Codecov Report

❌ Patch coverage is 89.47368% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.96%. Comparing base (c5cab49) to head (bcdb656).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
src/authz-module/libraries-manager/index.tsx 0.00% 8 Missing ⚠️
src/authz-module/libraries-manager/utils.ts 90.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master       #6      +/-   ##
==========================================
- Coverage   90.71%   89.96%   -0.75%     
==========================================
  Files          19       25       +6     
  Lines         183      269      +86     
  Branches       23       41      +18     
==========================================
+ Hits          166      242      +76     
- Misses         17       27      +10     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dcoa dcoa force-pushed the dcoa/user-details-view branch from 4e15265 to e9a86ff Compare October 2, 2025 09:31
@dcoa dcoa changed the title feat: [FC-0099] Create LibrariesUserManager view to manage roles for a specific user feat(authz): [FC-0099] Create LibrariesUserManager view to manage roles for a specific user Oct 2, 2025
@mphilbrick211 mphilbrick211 added the FC Relates to an Axim Funded Contribution project label Oct 2, 2025
@mphilbrick211 mphilbrick211 moved this from Needs Triage to Waiting on Author in Contributions Oct 2, 2025
@dcoa dcoa force-pushed the dcoa/user-details-view branch from e9a86ff to 03e57cf Compare October 13, 2025 10:16
@dcoa dcoa marked this pull request as ready for review October 15, 2025 19:19
@dcoa dcoa changed the title feat(authz): [FC-0099] Create LibrariesUserManager view to manage roles for a specific user feat(authz): [FC-0099] create LibrariesUserManager view to manage roles for a specific user Oct 16, 2025
@mphilbrick211 mphilbrick211 moved this from Waiting on Author to Ready for Review in Contributions Oct 16, 2025
@dcoa dcoa force-pushed the dcoa/user-details-view branch from 03e57cf to 591f12b Compare October 20, 2025 04:48
@dcoa
Copy link
Contributor Author

dcoa commented Oct 20, 2025

@arbrandes @jacobo-dominguez-wgu I rebased this PR, it is ready for review!!

@arbrandes
Copy link

Trying to test this. As per the instructions on #3, I pip installed openedx_authz. Couldn't run migrate openedx_authz, though. Django complains about a tag not found. It did show a new migration, so a plain migrate applied it. load_policies seems to have worked. At least, no errors shown.

After creating a library - it's supposed to be a "new" library, right? - and going to the proper URL on port 2025, though, I'm getting a NoAccess error. I surmise this is expected, as all the HTTP responses were 200. How do I get it to give me access, though?

Alternatively, if openedx_authz is not supposed to work with this, yet, can I get a set of mock API responses to use for testing?

@dcoa
Copy link
Contributor Author

dcoa commented Oct 20, 2025

Sorry @arbrandes, the backend is not fully with libraries API yet so it is not granted permissions at the time a library is created, we need to assign the those manually. I will explain how:

  1. Visit http://local.openedx.io:8000/api-docs/?format=openapi
  2. Filter by authz and use the PUT method to add your user as admin as follows
{
  "role": "library_admin",
  "scope": "<libraryId>",
  "users": [
    "<username>"
  ]
}
  1. You will need to add at least 1 more user with role library_admin, library_user, library_author, library_collaborator to be able to access the page (User specific manager page). For that you can use the same endpoint as before. Note: Should be a existent user in the instance.

I will left the mocking data as well just in case, please replace library_id with the proper value

Endpoint: http://local.openedx.io:8000/api/authz/v1/permissions/validate/me
Response:

[
    {
        "action": "view_library_team",
        "scope": "<library_id>",
        "allowed": true
    },
    {
        "action": "manage_library_team",
        "scope": "<library_id>",
        "allowed": true
    }
]

Endpoint: http://local.openedx.io:8000/api/authz/v1/roles/?scope=library_id
Response:

{
    "count": 4,
    "next": null,
    "previous": null,
    "results": [
        {
            "role": "library_admin",
            "permissions": [
                "view_library",
                "manage_library_tags",
                "delete_library",
                "edit_library_content",
                "publish_library_content",
                "reuse_library_content",
                "view_library_team",
                "manage_library_team",
                "create_library_collection",
                "edit_library_collection",
                "delete_library_collection",
                "view_library",
                "manage_library_tags",
                "delete_library",
                "edit_library_content",
                "publish_library_content",
                "reuse_library_content",
                "view_library_team",
                "manage_library_team",
                "create_library_collection",
                "edit_library_collection",
                "delete_library_collection"
            ],
            "user_count": 2
        },
        {
            "role": "library_author",
            "permissions": [
                "view_library",
                "manage_library_tags",
                "edit_library_content",
                "publish_library_content",
                "reuse_library_content",
                "view_library_team",
                "create_library_collection",
                "edit_library_collection",
                "delete_library_collection",
                "view_library",
                "manage_library_tags",
                "edit_library_content",
                "publish_library_content",
                "reuse_library_content",
                "view_library_team",
                "create_library_collection",
                "edit_library_collection",
                "delete_library_collection"
            ],
            "user_count": 4
        },
        {
            "role": "library_collaborator",
            "permissions": [
                "view_library",
                "manage_library_tags",
                "edit_library_content",
                "reuse_library_content",
                "view_library_team",
                "create_library_collection",
                "edit_library_collection",
                "delete_library_collection",
                "view_library",
                "manage_library_tags",
                "edit_library_content",
                "reuse_library_content",
                "view_library_team",
                "create_library_collection",
                "edit_library_collection",
                "delete_library_collection"
            ],
            "user_count": 1
        },
        {
            "role": "library_user",
            "permissions": [
                "view_library",
                "reuse_library_content",
                "view_library_team",
                "view_library",
                "reuse_library_content",
                "view_library_team"
            ],
            "user_count": 0
        }
    ]
}

Endpoint http://local.openedx.io:8000/api/authz/v1/roles/users/?scope=library_id
Response:

{
    "count": 7,
    "next": null,
    "previous": null,
    "results": [
        {
            "username": "admin",
            "full_name": "",
            "email": "admin@edunext.co",
            "roles": [
                "library_admin"
            ]
        },
        {
            "username": "test4",
            "full_name": "",
            "email": "test4@example.com",
            "roles": [
                "library_admin"
            ]
        },
        {
            "username": "test5",
            "full_name": "",
            "email": "test5@example.com",
            "roles": [
                "library_author"
            ]
        },
        {
            "username": "test6",
            "full_name": "",
            "email": "test6@example.com",
            "roles": [
                "library_author"
            ]
        },
        {
            "username": "test7",
            "full_name": "",
            "email": "test7@example.com",
            "roles": [
                "library_collaborator"
            ]
        },
        {
            "username": "test8",
            "full_name": "",
            "email": "test8@example.com",
            "roles": [
                "library_author"
            ]
        },
        {
            "username": "test9",
            "full_name": "",
            "email": "test9@example.com",
            "roles": [
                "library_author"
            ]
        }
    ]
}

Copy link

@arbrandes arbrandes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks fine in general. I had a question and a nit: see below.

More importantly, though, I'm seeing a mismatch between the backend roles/permissions and what the frontend seems to expect. Notably, the openedx_authz backend reports that the library author can edit_library (see first screenshot), but the frontend seems to expect edit_library_content. What gives?

Image

vs

Image

title: string;
userCounter?: number | null;
}
interface RoleCardProps extends CardTitleProps {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: missing empty line

Suggested change
interface RoleCardProps extends CardTitleProps {
interface RoleCardProps extends CardTitleProps {


interface CardTitleProps {
title: string;
userCounter?: number | null;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this property being actually passed down, anywhere. The only instance of RoleCard is in LibrariesUserManager, and it doesn't seem to need userCounter. Will a use for it be added later?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is a reusable component that displays actions when is in the LibrariesUserManagement view, and information when is in the LibrariesTeamManager view.

The use of the prop is relevant for a different PR #7

@dcoa
Copy link
Contributor Author

dcoa commented Oct 20, 2025

This looks fine in general. I had a question and a nit: see below.

More importantly, though, I'm seeing a mismatch between the backend roles/permissions and what the frontend seems to expect. Notably, the openedx_authz backend reports that the library author can edit_library (see first screenshot), but the frontend seems to expect edit_library_content. What gives?

@arbrandes, the expected map of roles and permissions are described here https://openedx-authz.readthedocs.io/en/latest/concepts/core_roles_and_permissions/content_library_roles.html#roles-and-permissions-summary-table

The PR that integrates the final policy openedx/openedx-authz#92 is not merged, creating the described discrepancy.

@@ -0,0 +1,87 @@
import { fireEvent, screen } from '@testing-library/react';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are promoting the use userEvent instead of fireEvent to handle user interactions since it simulates a full user interaction, rather than just a single event, leading to more realistic and robust tests https://testing-library.com/docs/user-event/intro/

const CardTitle = ({ title, userCounter }: CardTitleProps) => (
<div className="d-flex align-items-center">
<span className="mr-4 text-primary">{title}</span>
{userCounter !== null && userCounter !== undefined && (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you just do userCounter !== null handles both null and undefined cases due to JavaScripts loose equality comparison, so it makes the code a bit easier to read.

iconBefore={Edit}
variant="link"
size="sm"
// TODO: update the view with the team member view
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this TODO still valid?

Copy link

@arbrandes arbrandes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, thanks! Approved.

@arbrandes
Copy link

You need to fix a lint error before we merge.

@dcoa dcoa force-pushed the dcoa/user-details-view branch from be0ccae to bcdb656 Compare October 21, 2025 20:58
@brian-smith-tcril brian-smith-tcril merged commit b507311 into openedx:master Oct 21, 2025
4 of 6 checks passed
@github-project-automation github-project-automation bot moved this from Ready for Review to Done in Contributions Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core contributor PR author is a Core Contributor (who may or may not have write access to this repo). FC Relates to an Axim Funded Contribution project open-source-contribution PR author is not from Axim or 2U

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

6 participants