feat: Implement scopes endpoint for admin console#257
Conversation
|
Thanks for the pull request, @rodmgwgu! 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. |
There was a problem hiding this comment.
Pull request overview
Implements a new Admin Console-facing endpoint (/api/authz/v1/scopes/) to list course and library scopes, with pagination and filtering driven by the calling user’s permissions.
Changes:
- Added
AdminConsoleScopesAPIViewwith org-sorted listing, search, pagination, and optional “management-permission-only” filtering. - Added request/response serializers for scope listing and expanded scope data classes to expose “manage” permissions.
- Added REST API tests, URL wiring, and bumped version/changelog.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| openedx_authz/rest_api/v1/views.py | Adds AdminConsoleScopesAPIView and its query/permission filtering logic. |
| openedx_authz/rest_api/v1/serializers.py | Adds query param validator and scope response serializer. |
| openedx_authz/rest_api/v1/urls.py | Registers the new scopes/ route. |
| openedx_authz/tests/rest_api/test_views.py | Adds tests for auth, sorting, pagination, and permission filtering for scopes. |
| openedx_authz/api/data.py | Introduces get_admin_manage_permission() and implements it for relevant scope types. |
| openedx_authz/init.py | Version bump. |
| CHANGELOG.rst | Adds release entry documenting the new endpoint. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| libraries_qs = self._get_libraries_queryset(allowed_library_pairs, allowed_library_orgs, search=search) | ||
|
|
||
| # Union the requested querysets and sort by org at the DB level. | ||
| return self._build_queryset(courses_qs, libraries_qs) |
There was a problem hiding this comment.
I wonder how this could be extended for additional scope types. What do you think we could do to make this extensibility proof?
There was a problem hiding this comment.
Good point, in this implementation I tried to offload the work to MySQL as much as possible, what I'm doing here mostly is creating a query to the corresponding parent model (model-dependent), then normalize the data with annotate, and then joining that into a single queryset to be used downstream for pagination, sorting, etc.
Now, the challenge here will be:
-
New scopes will be different models, we could standardize a way to generate the normalized queryset, but this may not always be possible depending on the model specifics and the django ORM / SQL constraints.
-
New scopes may even be something completely different not stored in the DB.
We could generalize this further to cover both cases, but we will have to sacrifice performance doing it all on memory, or in some other way.
I think this is a challenge to be researched for future phases when we work on extensibility.
There was a problem hiding this comment.
Yes, I agree! I think this could also be related to my question here: https://github.com/openedx/openedx-authz/pull/257/changes#r3092897006
Can we document this somewhere?
There was a problem hiding this comment.
Sure, Created a spike ticket in tech debt: #264
There was a problem hiding this comment.
Another idea: we could index the scopes in meilisearch, we would create an interface as part of the openedx-authz extensibility API where a consumer module would specify how to index their specific model.
Then we could query meilisearch directly here
1208048 to
2149087
Compare
| libraries_qs = self._get_libraries_queryset(allowed_library_pairs, allowed_library_orgs, search=search) | ||
|
|
||
| # Union the requested querysets and sort by org at the DB level. | ||
| return self._build_queryset(courses_qs, libraries_qs) |
There was a problem hiding this comment.
Yes, I agree! I think this could also be related to my question here: https://github.com/openedx/openedx-authz/pull/257/changes#r3092897006
Can we document this somewhere?
mariajgrimaldi
left a comment
There was a problem hiding this comment.
LGTM! Thanks for addressing all of my comments :)
wgu-taylor-payne
left a comment
There was a problem hiding this comment.
Looks good to me!
| status.HTTP_200_OK: ScopeSerializer(many=True), | ||
| status.HTTP_400_BAD_REQUEST: "The request parameters are invalid", | ||
| status.HTTP_401_UNAUTHORIZED: "The user is not authenticated", | ||
| status.HTTP_403_FORBIDDEN: "The user does not have the required permisisons", |
There was a problem hiding this comment.
| status.HTTP_403_FORBIDDEN: "The user does not have the required permisisons", | |
| status.HTTP_403_FORBIDDEN: "The user does not have the required permissions", |
| import os | ||
|
|
||
| __version__ = "1.8.0" | ||
| __version__ = "1.9.0" |
There was a problem hiding this comment.
Looks like 1.9.0 has already been released.
| __version__ = "1.9.0" | |
| __version__ = "1.10.0" |
f844423 to
b91a835
Compare
Description
Closes: #229
Implement the
/api/authz/v1/scopes/endpoint to list all scopes (courses and libraries), sorted by org, with search and pagination support, to be used in the admin console.Scopes are always ordered by org.
Query Parameters
Response Format
Returns a paginated list of scope objects, each containing:
Authentication and Permissions
Deadline: Verawood
How to test
Using a local dev tutor installation, call the following endpoint with required credentials:
http://local.openedx.io:8000/api/authz/v1/scopes/The user you use to test this should have permission to at least view one course or library.
You should see a response similar to this:
{ "count": 2, "next": null, "previous": null, "results": [ { "external_key": "course-v1:OpenedX+DemoX+DemoCourse", "display_name": "Open edX Demo Course", "org": { "id": 1, "created": "2026-04-02T19:30:36.779095Z", "modified": "2026-04-02T19:30:36.779095Z", "name": "OpenedX", "short_name": "OpenedX", "description": "", "logo": null, "active": true } }, { "external_key": "lib:WGU:CSPROB", "display_name": "Computer Science Problems", "org": { "id": 2, "created": "2026-04-02T19:31:21.196446Z", "modified": "2026-04-02T19:31:21.196446Z", "name": "WGU", "short_name": "WGU", "description": "", "logo": null, "active": true } } ] }You can also test with params, for example:
http://local.openedx.io:8000/api/authz/v1/scopes/?search=demo&page=1&page_size=2&management_permission_only=trueOther information
Co-authored by Amazon Q using Claude Sonnet 4.6.
Merge checklist:
Check off if complete or not applicable: