Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: filter restricted runs on APIs #4356

Merged
merged 1 commit into from
Jun 14, 2024

Conversation

zawan-ila
Copy link
Contributor

@zawan-ila zawan-ila commented May 13, 2024

Internal tickets: PROD-4005 + PROD-4006

Hide restricted runs across APIs by default. Also do not include them when calculating fields like course_run_statuses. If a query-param include_restricted=<some_value> is present, do not hide them

Testing

  1. Create restricted runs in your system and link them with courses, programs, etc.
  2. Run update_index
  3. Verify that runs are hidden on all APIs by default and are revealed on adding the query params.

@@ -198,6 +199,9 @@ def increment_character(character):
"""
return chr(ord(character) + 1) if character != 'z' else 'a'

def get_forbidden_runs(request):
Copy link
Contributor

@DawoudSheraz DawoudSheraz May 13, 2024

Choose a reason for hiding this comment

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

We should use get_restricted_runs (and restricted_runs as a variable) for consistency. Forbidden_runs can mislead when someone else is reading the code (with little to no context). (and to add to following comment, this method is only returning restriction type(s), not actual course runs. That is also misleading.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have updated some names. Hopefully it's good enough now

@@ -198,6 +199,9 @@ def increment_character(character):
"""
return chr(ord(character) + 1) if character != 'z' else 'a'

def get_forbidden_runs(request):
Copy link
Contributor

@DawoudSheraz DawoudSheraz May 13, 2024

Choose a reason for hiding this comment

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

  • nit: missing docstring.
  • the method is not really returning runs but rather restriction types.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have updated some names. Hopefully it's good enough now

@zawan-ila zawan-ila mentioned this pull request May 15, 2024
@@ -47,7 +47,7 @@ def prepare_position(self, obj):
return []
return [position.title, position.organization_override]

def get_queryset(self):
def get_queryset(self, excluded_restriction_types=[]):
Copy link
Contributor

Choose a reason for hiding this comment

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

why do we need this default but unused argument?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Due to this change, the get_queryset method is called with the excluded_restriction_types for all documents. We don't really use excluded_restriction_type in the get_queryset of some documents but the argument is still passed. Hence, this is to prevent an error.

We could have a condition to check the document type, and only pass it in for those documents which need it, but I think it is neater this way

Copy link
Contributor

Choose a reason for hiding this comment

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

Right. It would be good to have this context in docstrings/context for future's sake.

Copy link
Contributor

@DawoudSheraz DawoudSheraz left a comment

Choose a reason for hiding this comment

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

Played around a bit with this locally, looks good.
One thing: search/<> endpoints are missing restriction_type field on course_run serializers.

Copy link
Contributor

@AfaqShuaib09 AfaqShuaib09 left a comment

Choose a reason for hiding this comment

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

Did some playaround with the include_restricted in api/v1 endpoints & search endpoints on local. Changes look good.

[thinking] One thing we can do in a followup PR to check for N+1 queries.

course_discovery/apps/api/v1/views/search.py Outdated Show resolved Hide resolved
course_discovery/apps/api/v1/views/search.py Outdated Show resolved Hide resolved
course_discovery/apps/api/v1/views/search.py Outdated Show resolved Hide resolved
@@ -87,7 +87,8 @@ def _wrap(self, *args, **kwargs):


def get_course_availability(course):
all_runs = course.course_runs.filter(status=CourseRunStatus.Published)
all_runs = course.course_runs.all()
all_runs = filter(lambda r: r.status == CourseRunStatus.Published, all_runs)
Copy link
Contributor

Choose a reason for hiding this comment

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

wondering why this change has been done?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We have prefetched course_runs on course. And in that prefetch, we have excluded restricted runs. Now if we dont make this change, it will go to the database and course.course_runs will return all runs (even restricted ones). This makes sure that the prefetched course runs are used.

Comment on lines +310 to +311
self.assertEqual(set(response.data['course_run_keys']), {run_not_restricted.key, run_restricted.key})
self.assertEqual(
Copy link
Contributor

Choose a reason for hiding this comment

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

if block is doing assertListEqual, this is doing assertEqual. Since the context is same, we should try to keep the code consistent where applicable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have converted both to assertEqual.

Comment on lines 59 to 60
if include_restricted_run:
RestrictedCourseRunFactory(course_run=course_run, restriction_type='custom-b2c') # pylint: disable=possibly-used-before-assignment
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: if we move this if include_restricted_run: under if block at 55, will we still need pylint disable checks there? Considering we can't restriction without run, it makes sense to nest this if block.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have nested the block, and have also removed the pylint disable.

@zawan-ila zawan-ila merged commit 13714a7 into openedx:master Jun 14, 2024
26 checks passed
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.

3 participants