Skip to content

Release 1.145.1#3468

Merged
odlbot merged 8 commits into
releasefrom
release-candidate
Apr 8, 2026
Merged

Release 1.145.1#3468
odlbot merged 8 commits into
releasefrom
release-candidate

Conversation

@odlbot
Copy link
Copy Markdown
Contributor

@odlbot odlbot commented Apr 7, 2026

Nathan Levesque

James Kachel

annagav

Asad Ali

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 7, 2026

OpenAPI Changes

Show/hide ## Changes for v0.yaml:
## Changes for v0.yaml:
7 changes: 0 error, 0 warning, 7 info
info	[endpoint-added] at head/openapi/specs/v0.yaml	
	in API GET /api/v0/b2b/manager/organizations/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v0.yaml	
	in API GET /api/v0/b2b/manager/organizations/{id}/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v0.yaml	
	in API GET /api/v0/b2b/manager/organizations/{parent_lookup_organization}/contracts/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v0.yaml	
	in API GET /api/v0/b2b/manager/organizations/{parent_lookup_organization}/contracts/{id}/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v0.yaml	
	in API GET /api/v0/b2b/manager/organizations/{parent_lookup_organization}/contracts/{id}/codes/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v0.yaml	
	in API GET /api/v0/b2b/manager/organizations/{parent_lookup_organization}/contracts/{id}/course_runs/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v0.yaml	
	in API GET /api/v0/b2b/manager/organizations/{parent_lookup_organization}/contracts/{id}/course_runs/{course_run_id}/enrollments/
		endpoint added



## Changes for v1.yaml:
7 changes: 0 error, 0 warning, 7 info
info	[endpoint-added] at head/openapi/specs/v1.yaml	
	in API GET /api/v0/b2b/manager/organizations/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v1.yaml	
	in API GET /api/v0/b2b/manager/organizations/{id}/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v1.yaml	
	in API GET /api/v0/b2b/manager/organizations/{parent_lookup_organization}/contracts/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v1.yaml	
	in API GET /api/v0/b2b/manager/organizations/{parent_lookup_organization}/contracts/{id}/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v1.yaml	
	in API GET /api/v0/b2b/manager/organizations/{parent_lookup_organization}/contracts/{id}/codes/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v1.yaml	
	in API GET /api/v0/b2b/manager/organizations/{parent_lookup_organization}/contracts/{id}/course_runs/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v1.yaml	
	in API GET /api/v0/b2b/manager/organizations/{parent_lookup_organization}/contracts/{id}/course_runs/{course_run_id}/enrollments/
		endpoint added



## Changes for v2.yaml:
7 changes: 0 error, 0 warning, 7 info
info	[endpoint-added] at head/openapi/specs/v2.yaml	
	in API GET /api/v0/b2b/manager/organizations/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v2.yaml	
	in API GET /api/v0/b2b/manager/organizations/{id}/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v2.yaml	
	in API GET /api/v0/b2b/manager/organizations/{parent_lookup_organization}/contracts/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v2.yaml	
	in API GET /api/v0/b2b/manager/organizations/{parent_lookup_organization}/contracts/{id}/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v2.yaml	
	in API GET /api/v0/b2b/manager/organizations/{parent_lookup_organization}/contracts/{id}/codes/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v2.yaml	
	in API GET /api/v0/b2b/manager/organizations/{parent_lookup_organization}/contracts/{id}/course_runs/
		endpoint added

info	[endpoint-added] at head/openapi/specs/v2.yaml	
	in API GET /api/v0/b2b/manager/organizations/{parent_lookup_organization}/contracts/{id}/course_runs/{course_run_id}/enrollments/
		endpoint added



Unexpected changes? Ensure your branch is up-to-date with main (consider rebasing).

Comment thread b2b/views/v0/manager.py
Comment on lines +249 to +255
return Response(
ManagerEnrollmentCodeSerializer(
[discounts.order_by("id").first()],
context={"contract": contract},
many=True,
).data
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The codes action can pass [None] to the serializer if a contract has no discount codes, causing an AttributeError when the serializer tries to access an attribute on None.
Severity: HIGH

Suggested Fix

Add a check to handle the case where discounts.order_by("id").first() returns None. Instead of passing [None] to the serializer, return a response with an empty list [] to represent the absence of codes, which the serializer can handle gracefully.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: b2b/views/v0/manager.py#L249-L255

Potential issue: In the `codes` action of `ManagerContractViewSet`, if a contract has no
learner limit (`max_learners` is falsy) and no associated discount codes, the query
`discounts.order_by("id").first()` returns `None`. This `None` value is then wrapped in
a list and passed to `ManagerEnrollmentCodeSerializer` with `many=True`. The serializer
will then raise an `AttributeError` when it attempts to access an attribute like
`discount_code` on the `None` object, causing the endpoint to crash.

Did we get this right? 👍 / 👎 to inform future reviews.

Comment thread b2b/views/v0/manager.py
Comment on lines +146 to +150
.filter(
organization__organization_users__user=self.request.user,
organization__organization_users__is_manager=True,
)
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The get_queryset in ManagerContractViewSet incorrectly filters out contracts for superusers because it lacks a bypass, even though the permission class grants them access.
Severity: MEDIUM

Suggested Fix

Update ManagerContractViewSet.get_queryset to include a bypass for superusers, similar to the logic in ManagerOrganizationViewSet. If self.request.user.is_superuser is true, return the unfiltered queryset; otherwise, apply the existing filter for regular managers.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: b2b/views/v0/manager.py#L146-L150

Potential issue: The `get_queryset` method in `ManagerContractViewSet` unconditionally
filters contracts to only those where the requesting user is an organization manager.
However, the `IsOrganizationManager` permission class explicitly allows superusers. This
creates a mismatch where a superuser is granted permission but the queryset returns no
results if they are not also explicitly a manager of the organization. This prevents
superusers from viewing contracts they should have access to, unlike in the
`ManagerOrganizationViewSet` which correctly bypasses this filter for superusers.

Did we get this right? 👍 / 👎 to inform future reviews.

@odlbot odlbot merged commit 1d22914 into release Apr 8, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants