Skip to content

only respond with enrolled contract on enrollment code redemption#3551

Merged
gumaerc merged 3 commits intomainfrom
cg/enrollment-code-attach-response-contract-scope
May 6, 2026
Merged

only respond with enrolled contract on enrollment code redemption#3551
gumaerc merged 3 commits intomainfrom
cg/enrollment-code-attach-response-contract-scope

Conversation

@gumaerc
Copy link
Copy Markdown
Contributor

@gumaerc gumaerc commented May 5, 2026

What are the relevant tickets?

Pre-requisite for https://github.com/mitodl/hq/issues/11112

Description (What does it do?)

This PR changes the B2B enrollment code attach endpoint to return only the contract that you have enrolled in that is tied to the enrollment code you are redeeming. Previously it returned a list of all the users contracts every time.

How can this be tested?

  • Generate an enrollment code using the b2b management commands
  • Redeem the code using the API and ensure that you only get the contract tied to the code in the response

…only return the contract you were enrolled in or null
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 5, 2026

OpenAPI Changes

Show/hide ## Changes for v0.yaml:
## Changes for v0.yaml:
No changes to report, but the specs are different

## Changes for v1.yaml:
No changes to report, but the specs are different

## Changes for v2.yaml:
No changes to report, but the specs are different

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

Comment thread b2b/views/v0/__init__.py Outdated
Comment on lines 208 to 214
else None
)

if contracts_attached:
return Response(serialized_contracts, status=status.HTTP_201_CREATED)
return Response(serialized_contract, status=status.HTTP_201_CREATED)

if contract_full:
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_eligible_contracts function is missing an active=True filter, allowing users to join inactive contracts and causing the API to return a null response, violating its schema.
Severity: HIGH

Suggested Fix

Add an active=True filter to the contract query within the _get_eligible_contracts function. This will ensure users can only be attached to active contracts, aligning the business logic with the response generation and preventing the schema violation.

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/__init__.py#L208-L214

Potential issue: The `_get_eligible_contracts` function, which identifies contracts a
user can join, omits a filter for `active=True`. This allows a user with a valid
enrollment code to be attached to an inactive contract. Subsequently, the
`_get_active_code_user_contract` function, which was added in the pull request to fetch
the contract for the response, correctly filters for active contracts. Since the user
was attached to an inactive one, this function returns `None`. As a result, the endpoint
returns a `null` body with a `201 Created` status, violating the OpenAPI schema that
expects a `ContractPage` object and potentially causing client-side errors.

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

@dsubak dsubak self-assigned this May 6, 2026
Copy link
Copy Markdown
Contributor

@ChristopherChudzicki ChristopherChudzicki left a comment

Choose a reason for hiding this comment

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

Will leave rest of review to someone else, but i was just looking at the API schema concern and have a concern. Let me know if i am incorrect!

Comment thread b2b/views/v0/__init__.py Outdated
- 404: Invalid or expired enrollment code
- 409: Code valid but no available seats in associated contract(s)
- list of ContractPageSerializer - the contracts for the user
- ContractPageSerializer (or null) - the active contract associated with the code
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@gumaerc This is a breaking change in the API, right? Previously returned an array of objects, now returns a single object. I think that will break Learn here: https://github.com/mitodl/mit-learn/blob/6063a3d2dab070229ce3ff3dbb4f235eeb64ad5b/frontends/main/src/app-pages/EnrollmentCodePage/EnrollmentCodePage.tsx#L45-L47

I agree that returning a single object is more natural.

But to avoid breaking the schema—which is consequential here—I would suggest we return [singleObject]

Comment thread openapi/specs/v0.yaml
Comment thread b2b/views/v0/__init__.py
Copy link
Copy Markdown
Contributor

@dsubak dsubak left a comment

Choose a reason for hiding this comment

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

Functionality looks good to me, was able to verify that I only get back the contract related to the code passed in in cases where I would've gotten everything back before.

Looks like @ChristopherChudzicki feedback has been addressed as well, so if ya'll are happy with it I think this'll play

Copy link
Copy Markdown
Contributor

@ChristopherChudzicki ChristopherChudzicki left a comment

Choose a reason for hiding this comment

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

I haven't tested (left to dan + you) but the spec change is fixed, thanks!

@gumaerc gumaerc merged commit c031ff0 into main May 6, 2026
10 checks passed
@gumaerc gumaerc deleted the cg/enrollment-code-attach-response-contract-scope branch May 6, 2026 16:17
@odlbot odlbot mentioned this pull request May 6, 2026
4 tasks
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.

3 participants