Skip to content

Add academy association to Enterprise catalog client#210

Merged
vshaikismail-sonata merged 15 commits into
mainfrom
11883-2
Jun 25, 2026
Merged

Add academy association to Enterprise catalog client#210
vshaikismail-sonata merged 15 commits into
mainfrom
11883-2

Conversation

@vshaikismail-sonata

Copy link
Copy Markdown
Contributor

Description:
Add a description of your changes here.

Jira:
ENT-XXXX

Merge checklist:

  • ./manage.py makemigrations has been run
    • Note: This must be run if you modified any models.
      • It may or may not make a migration depending on exactly what you modified, but it should still be run.

Post merge:

  • Ensure that your changes went out to the stage instance
  • Deploy to prod instance

@vshaikismail-sonata vshaikismail-sonata requested review from a team as code owners June 22, 2026 17:33
@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.58%. Comparing base (0854543) to head (8db556b).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #210      +/-   ##
==========================================
+ Coverage   86.52%   86.58%   +0.05%     
==========================================
  Files         154      155       +1     
  Lines       12920    12953      +33     
  Branches     1233     1239       +6     
==========================================
+ Hits        11179    11215      +36     
+ Misses       1425     1423       -2     
+ Partials      316      315       -1     

☔ View full report in Codecov by Harness.
📢 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.

@rthota-sonata-hue rthota-sonata-hue left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Changes are requested.

@rthota-sonata-hue rthota-sonata-hue self-requested a review June 23, 2026 07:52
@rthota-sonata-hue rthota-sonata-hue dismissed their stale review June 23, 2026 07:54

wrongly commented.

@rthota-sonata-hue rthota-sonata-hue left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Please resolve the patch check before sharing to Alex. Looks Good for merge. Approved.

response.raise_for_status()
raw_payload = response.json()

def normalize_page(payload):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this feels overly-defensive for handling an API response of an endpoint that we own/maintain. Just have it expect the schema that the endpoint actually uses.

Comment on lines +284 to +298
while next_url:
next_resp = self.client.get(next_url)
next_resp.raise_for_status()
next_payload = next_resp.json()
next_data, next_explicit = normalize_page(next_payload)
if isinstance(data.get('results'), list) and isinstance(next_data.get('results'), list):
data['results'].extend(next_data.get('results', []))
data['next'] = next_data.get('next')
data['previous'] = data.get('previous') or next_data.get('previous')
explicit = explicit and next_explicit
if not explicit:
data['count'] = len(data.get('results', []))
next_url = data.get('next')

return data

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Instead of using this duplicated pattern, it would be better to extract the pattern used here:

def get_learner_subscription_licenses_for_admin(
into a shared helper/utility method, and then use that utility method inside this new client methods.

Comment on lines +62 to +63
if not params:
params = None

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why not just pass in empty params?

Comment on lines +71 to +81
while next_url:
next_resp = self.client.get(next_url)
next_resp.raise_for_status()

next_data = next_resp.json()
data['results'].extend(next_data.get('results', []))
# update pagination markers
data['next'] = next_data.get('next')
data['previous'] = data.get('previous') or next_data.get('previous')
next_url = data.get('next')
return data

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Use the utility method you abstracted here.

try:
return response.json()
except ValueError:
return {}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we should at least log something here instead of silently swallowing the exception.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This comment also addressed but it s not showing outdated....!!!

Comment on lines +231 to +243
for next_payload in get_paginated_payloads(self.client, data.get("next")):
next_data, next_explicit = normalize_page(next_payload)

if isinstance(data.get('results'), list) and isinstance(next_data.get('results'), list):
data['results'].extend(next_data.get('results', []))

data['next'] = next_data.get('next')
data['previous'] = data.get('previous') or next_data.get('previous')

explicit = explicit and next_explicit

if not explicit:
data['count'] = len(data.get('results', []))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A lot of this seems like reusable stuff that should live inside of the utility function

Comment on lines +190 to +222
def normalize_page(payload):
"""Normalize a response payload into a paginated dict.

This mirrors `get_academies()` defensive behavior so callers can
safely handle dict or list payloads from upstream services.
Returns a tuple of (paginated_dict, explicit_count_flag) when
payload is dict-like, or (list_payload, False) when payload is
a raw list. When payload is None, return an empty paginated shape
and False for explicit flag.
"""
if payload is None:
return ({'count': 0, 'results': [], 'next': None, 'previous': None}, False)
if isinstance(payload, list):
return payload, False
if isinstance(payload, dict):
results = payload.get('results')
if not isinstance(results, list):
results = []
raw_count = payload.get('count', None)
try:
count = int(raw_count) if raw_count is not None else None
except (ValueError, TypeError):
count = None
explicit_count = count is not None
if count is None:
count = len(results)
return ({
'count': count,
'results': results,
'next': payload.get('next'),
'previous': payload.get('previous'),
}, explicit_count)
return ({'count': 1, 'results': [payload], 'next': None, 'previous': None}, False)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There's really no need to be this defensive - the endpoint we're calling should have a consistent and expected response schema.

"""


def get_paginated_payloads(client, next_url):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's push the accumulation into the helper too, that'll help simplify things quite a bit:

  def fetch_all_results(client, url, params=None):
      response = client.get(url, params=params)
      response.raise_for_status()
      data = response.json()
      while data.get('next'):
          resp = client.get(data['next'])
          resp.raise_for_status()
          page = resp.json()
          data['results'].extend(page.get('results', []))
          data['next'] = page.get('next')
      return data

Callers become:

  def get_academies(self, academy_uuid=None, is_active=None):
      if not self.academies_endpoint:
          return {'count': 0, 'next': None, 'previous': None, 'results': []}
      params = {}
      if academy_uuid:
          params['academy_uuid'] = academy_uuid
      if is_active is not None:
          params['is_active'] = bool(is_active)
      return fetch_all_results(self.client, self.academies_endpoint, params=params or None)

  def get_catalogs(self, enterprise_customer_uuid=None):
      params = {'enterprise_customer': enterprise_customer_uuid} if enterprise_customer_uuid else None
      return fetch_all_results(self.client, self.enterprise_catalog_endpoint, params=params)

Copilot AI review requested due to automatic review settings June 25, 2026 14:03

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@vshaikismail-sonata vshaikismail-sonata force-pushed the 11883-2 branch 3 times, most recently from f6639a3 to f1bf8a4 Compare June 25, 2026 15:30
@vshaikismail-sonata vshaikismail-sonata merged commit 1ac224a into main Jun 25, 2026
6 checks passed
@vshaikismail-sonata vshaikismail-sonata deleted the 11883-2 branch June 25, 2026 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants