Skip to content

Commit

Permalink
feat: add capabilty in queryset method to exclude hidden runs
Browse files Browse the repository at this point in the history
  • Loading branch information
AfaqShuaib09 committed Sep 12, 2024
1 parent 34355f4 commit 4d886c0
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ jobs:
uses: actions/download-artifact@v4
- name: Run coverage
run: make ci_coverage
- uses: codecov/codecov-action@v1
- uses: codecov/codecov-action@v4

quality:
runs-on: ubuntu-latest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def get_products(self, product_type, product_source):
]

if product_type in ['executive_education', 'bootcamp', 'ocm_course']:
queryset = Course.objects.available().select_related('partner', 'type')
queryset = Course.objects.available(exclude_hidden_runs=True).select_related('partner', 'type')

if product_type == 'ocm_course':
queryset = queryset.filter(type__slug__in=ocm_course_catalog_types)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ def setUp(self):
self.course_run_2 = CourseRunFactory.create_batch(
2, course=Course.objects.all()[1]
)
self.course_run_3 = CourseRunFactory(
course=Course.objects.all()[1],
status=CourseRunStatus.Published,
hidden=True,
)
self.hidden_run_seat = SeatFactory.create(course_run=self.course_run_3)
self.program_type = ProgramTypeFactory.create(slug=ProgramType.MICROMASTERS)
self.degrees = DegreeFactory.create_batch(
2,
Expand Down Expand Up @@ -79,6 +85,65 @@ def test_populate_product_catalog(self):
self.assertIn("Marketing URL", row)
self.assertIn("Marketing Image", row)

def test_populate_product_catalog_for_courses_with_hidden_and_non_hidden_published_runs(self):
"""
Test populate_product_catalog command for course having hidden and non-hidden published runs
and verify data has been populated successfully.
"""
hidden_course_run = CourseRunFactory(
course=Course.objects.all()[1],
status=CourseRunStatus.Published,
hidden=True,
)
SeatFactory.create(course_run=hidden_course_run)

with NamedTemporaryFile() as output_csv:
call_command(
"populate_product_catalog",
product_type="ocm_course",
output_csv=output_csv.name,
product_source="edx",
gspread_client_flag=False,
)

with open(output_csv.name, "r") as output_csv_file:
csv_reader = csv.DictReader(output_csv_file)
rows = list(csv_reader)
assert len(rows) == 1
matching_rows = [row for row in rows if row["UUID"] == str(self.courses[0].uuid.hex)]
self.assertEqual(len(matching_rows), 1)

matching_rows = [row for row in rows if row["UUID"] == str(self.courses[1].uuid.hex)]
self.assertEqual(
len(matching_rows), 0, "Courses having hidden published runs shouldn't be in the csv"
)

non_hidden_course_run = CourseRunFactory(
course=Course.objects.all()[1],
status=CourseRunStatus.Published,
hidden=False,
)
SeatFactory.create(course_run=non_hidden_course_run)

with NamedTemporaryFile() as output_csv:
call_command(
"populate_product_catalog",
product_type="ocm_course",
output_csv=output_csv.name,
product_source="edx",
gspread_client_flag=False,
)

with open(output_csv.name, "r") as output_csv_file:
csv_reader = csv.DictReader(output_csv_file)
rows = list(csv_reader)
assert len(rows) == 2
matching_rows = [row for row in rows if row["UUID"] == str(self.courses[0].uuid.hex)]
self.assertEqual(len(matching_rows), 1)

matching_rows = [row for row in rows if row["UUID"] == str(self.courses[1].uuid.hex)]
self.assertEqual(len(matching_rows), 1)

def test_populate_product_catalog_for_degrees(self):
"""
Test populate_product_catalog command for all degree products and verify data has been populated successfully.
Expand Down Expand Up @@ -197,7 +262,7 @@ def test_populate_product_catalog_excludes_non_marketable_degrees(self):
# Check that non-marketable degrees are not in the CSV
for degree in non_marketable_degrees:
with self.subTest(degree=degree):
matching_rows = [row for row in rows if row["UUID"] == str(degree.uuid)]
matching_rows = [row for row in rows if row["UUID"] == str(degree.uuid.hex)]
self.assertEqual(
len(matching_rows), 0, f"Non-marketable degree '{degree.title}' should not be in the CSV"
)
Expand Down
11 changes: 8 additions & 3 deletions course_discovery/apps/course_metadata/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@


class CourseQuerySet(models.QuerySet):
def available(self):
def available(self, exclude_hidden_runs=False):
"""
A Course is considered to be "available" if it contains at least one CourseRun
that can be enrolled in immediately, is ongoing or yet to start, and appears
on the marketing site.
"""
now = datetime.datetime.now(pytz.UTC)

# A CourseRun is "enrollable" if its enrollment start date has passed,
# is now, or is None, and its enrollment end date is in the future or is None.

enrollable = (
(
Q(course_runs__enrollment_start__lte=now) |
Expand Down Expand Up @@ -54,7 +54,12 @@ def available(self):
# By itself, the query performs a join across several tables and would return
# the id of the same course multiple times (a separate copy for each available
# seat in each available run).
ids = self.filter(enrollable & not_ended & marketable).values('id').distinct()
if exclude_hidden_runs:
# A CourseRun is "hidden" if it has a "hidden" attribute set to True.
hidden = ~Q(course_runs__hidden=True)
ids = self.filter(enrollable & not_ended & marketable & hidden).values('id').distinct()
else:
ids = self.filter(enrollable & not_ended & marketable).values('id').distinct()

# Now return the full object for each of the selected ids
return self.filter(id__in=ids)
Expand Down

0 comments on commit 4d886c0

Please sign in to comment.