feat: apply OEP-66 queryset-scoping pattern to Enrollments v2 API - #39037
feat: apply OEP-66 queryset-scoping pattern to Enrollments v2 API#39037Abdul-Muqadim-Arbisoft wants to merge 1 commit into
Conversation
Adopt the OEP-66 "Separating Authorization Concerns in List Endpoints"
record-visibility layer on the admin enrollment list, using the shared
building blocks now published in edx-drf-extensions.
EnrollmentsAdminListView is an ORM-backed ListAPIView, so it wires the three
authorization concerns separately:
* Endpoint access — permission_classes = (IsAdminUser,).
* Record visibility — ScopedQuerysetMixin applies AdminEnrollmentScopingPolicy
to the base queryset in get_queryset(). The policy is an intentional
pass-through for platform admins today, documented as the single seam where
an openedx-authz scope-set filter (e.g. restricting a delegated, org-scoped
admin to their organization's enrollments) will plug in later; behavior is
unchanged.
* User-driven filtering — the form-based course_key/course_keys/username/
email/ordering filtering moves from get_queryset() into filter_queryset(),
so it runs after scoping and only narrows the already-authorized queryset.
Bumps edx-drf-extensions 10.6.0 -> 10.7.0, the release that adds the reusable
ScopingPolicy (a typing.Protocol) and ScopedQuerysetMixin. Adds
TestEnrollmentsAdminListView regression tests covering endpoint access
(401/403), pass-through scoping (admin sees all rows), the course_key/username
filters, the 400-on-invalid-params path, the ADR 0033 Deprecation header, and
the scoping-policy pass-through.
Follows up the closed PR openedx#38847: per review, the shared ScopingPolicy /
ScopedQuerysetMixin tooling moved to edx-drf-extensions (#569) as a
subject-based typing.Protocol with a duck-typed mixin check, and this change
consumes it rather than defining it locally.
78d3f46 to
3678f4c
Compare
| def test_filter_by_username_narrows(self): | ||
| """User-driven filter (filter_queryset) still narrows by username.""" | ||
| self.client.force_authenticate(user=self.admin) | ||
| response = self.client.get(self.url, {"username": self.learner_b.username}) |
There was a problem hiding this comment.
This should only work for admins correct? we should have the inverted test validating that users can't see eachothers enrollments by passing eachothers names in.
| OEP-66 record-visibility policy for the admin enrollment list. | ||
|
|
||
| Implements the ``ScopingPolicy`` protocol from | ||
| ``edx_rest_framework_extensions.scoping`` by duck typing (a ``scope`` | ||
| method); it does not need to inherit from it. |
There was a problem hiding this comment.
This is all relevant to our review but not really relevant as a long term comment is it?
I'm seeing this in a bunch of places, where LLMs drop in content relevant to the current task in the comments that won't really be relevant long term to the code they are adding it to. We should re-read these and make sure the comments are useful and relevant to future readers.
|
|
||
| def scope(self, queryset, subject): | ||
| # Platform admins (IsAdminUser) see all enrollments; nothing to narrow yet. | ||
| return queryset |
There was a problem hiding this comment.
This is a lot of boilerplate for essentially a no-op on scoping, can we simplify this? Maybe we have some sort of a "FullScopePolicy" that can be used in many places for things like this?
| """ | ||
| Admin-only paginated enrollment list with OEP-68 filter aliases. | ||
|
|
||
| OEP-66 — this ORM-backed list endpoint wires the three authorization layers |
There was a problem hiding this comment.
We don't need the names of our OEPs in the code, the code should just follow the standards.
Adopt the OEP-66 "Separating Authorization Concerns in List Endpoints" record-visibility layer on the admin enrollment list, using the shared building blocks now published in edx-drf-extensions.
EnrollmentsAdminListView is an ORM-backed ListAPIView, so it wires the three authorization concerns separately:
Bumps edx-drf-extensions 10.6.0 -> 10.7.0, the release that adds the reusable ScopingPolicy (a typing.Protocol) and ScopedQuerysetMixin. Adds TestEnrollmentsAdminListView regression tests covering endpoint access (401/403), pass-through scoping (admin sees all rows), the course_key/username filters, the 400-on-invalid-params path, the ADR 0033 Deprecation header, and the scoping-policy pass-through.
Follows up the closed PR #38847: per review, the shared ScopingPolicy / ScopedQuerysetMixin tooling moved to edx-drf-extensions (#569) as a subject-based typing.Protocol with a duck-typed mixin check, and this change consumes it rather than defining it locally.