Skip to content

Commit

Permalink
Fix Featured Items on Homepage (#2232)
Browse files Browse the repository at this point in the history
* update to use Q filter and start writing test to verify the number is correct

* Test update
  • Loading branch information
JenniWhitman authored Jun 4, 2024
1 parent c39fdfe commit c82cf83
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 6 deletions.
2 changes: 1 addition & 1 deletion cms/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from cms.constants import CERTIFICATE_INDEX_SLUG, INSTRUCTOR_INDEX_SLUG
from cms.exceptions import WagtailSpecificPageError
from cms.models import Page
from courses.constants import HOMEPAGE_CACHE_AGE
from courses.models import Course, Program
from courses.utils import (
get_enrollable_courseruns_qs,
Expand All @@ -39,7 +40,6 @@
]
RESOURCE_PAGE_SLUGS = [slugify(title) for title in RESOURCE_PAGE_TITLES]
PROGRAM_INDEX_PAGE_PROPERTIES = dict(title="Programs") # noqa: C408
HOMEPAGE_CACHE_AGE = 86400 # 24 hours


def get_home_page(raise_if_missing=True, check_specific=False) -> Page: # noqa: FBT002
Expand Down
12 changes: 7 additions & 5 deletions cms/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,18 +728,20 @@ def get_cached_featured_products(self):
Retrieves teh featured products that were generated using cms/api/create_featured_items either from the
management command or the daily cron job. This is used to display the featured products on the home page.
"""
start_of_day = now_in_utc() - timedelta(days=1)
end_of_day = now_in_utc() + timedelta(days=1)
now = now_in_utc()
redis_cache = caches["redis"]
cached_featured_products = redis_cache.get("CMS_homepage_featured_courses")
if len(cached_featured_products) > 0:
featured_product_ids = [course.id for course in cached_featured_products]
relevant_run_course_ids = (
CourseRun.objects.filter(live=True)
.filter(
course__id__in=featured_product_ids,
enrollment_start__lte=start_of_day,
enrollment_end__gte=end_of_day,
models.Q(course__id__in=featured_product_ids)
& models.Q(enrollment_start__lte=now)
& (
models.Q(enrollment_end__gte=now)
| models.Q(enrollment_end__isnull=True)
)
)
.values_list("course__id", flat=True)
)
Expand Down
81 changes: 81 additions & 0 deletions cms/models_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,20 @@
import pytest
from django.contrib.auth.models import AnonymousUser, Group
from django.contrib.sessions.middleware import SessionMiddleware
from django.core.cache import caches
from django.test.client import RequestFactory
from django.urls import resolve
from mitol.common.factories import UserFactory
from mitol.common.utils.datetime import now_in_utc
from mitol.olposthog.features import is_enabled

from cms.api import create_featured_items
from cms.constants import CMS_EDITORS_GROUP_NAME
from cms.factories import (
CertificatePageFactory,
CoursePageFactory,
FlexiblePricingFormFactory,
HomePageFactory,
InstructorPageFactory,
ProgramPageFactory,
ResourcePageFactory,
Expand All @@ -45,6 +48,7 @@
from flexiblepricing.constants import FlexiblePriceStatus
from flexiblepricing.factories import FlexiblePriceFactory, FlexiblePriceTierFactory
from flexiblepricing.models import FlexiblePrice
from main import features

pytestmark = [pytest.mark.django_db]

Expand Down Expand Up @@ -681,3 +685,80 @@ def test_flexible_pricing_request_form_context(flex_form_for_course):
else:
assert context["product"] is None
assert context["product_page"] == course_page.url


def test_homepage__featured_products(settings, mocker):
settings.FEATURES[features.ENABLE_NEW_DESIGN] = True
now = now_in_utc()
future_date = now + timedelta(days=1)
past_date = now - timedelta(days=1)
further_future_date = future_date + timedelta(days=1)
further_past_date = past_date - timedelta(days=1)
furthest_future_date = further_future_date + timedelta(days=1)
redis_cache = caches["redis"]
# Ensure the key is empty since pytest doesn't clear the cache between tests
featured_courses = redis_cache.get("CMS_homepage_featured_courses")
if featured_courses is not None:
redis_cache.delete("CMS_homepage_featured_courses")
assert redis_cache.get("CMS_homepage_featured_courses") is None

enrollable_future_course = CourseFactory.create(page=None, live=True)
enrollable_future_course_page = CoursePageFactory.create(
course=enrollable_future_course, live=True
)
enrollable_future_courserun = CourseRunFactory.create(
course=enrollable_future_course,
live=True,
start_date=future_date,
enrollment_start=further_past_date,
enrollment_end=further_future_date,
end_date=furthest_future_date,
)
create_featured_items()
assert len(redis_cache.get("CMS_homepage_featured_courses")) == 1
hf = HomePageFactory.create()
assert hf.get_cached_featured_products == [
{
"title": enrollable_future_course_page.title,
"description": enrollable_future_course_page.description,
"feature_image": enrollable_future_course_page.feature_image,
"start_date": enrollable_future_courserun.start_date,
"url_path": enrollable_future_course_page.get_url(),
"is_program": enrollable_future_course_page.is_program_page,
"is_self_paced": False,
"program_type": None,
}
]
# Remove the previous course from the potential courses to be featured, this will also test a course as unenrollable
enrollable_future_course.live = False
enrollable_future_course.save()

enrollable_future_course_with_no_enrollment_end = CourseFactory.create(
page=None, live=True
)
enrollable_future_course_with_no_enrollment_end_page = CoursePageFactory.create(
course=enrollable_future_course_with_no_enrollment_end, live=True
)
enrollable_future_courserun_with_no_enrollment_end = CourseRunFactory.create(
course=enrollable_future_course_with_no_enrollment_end,
live=True,
start_date=future_date,
enrollment_start=further_past_date,
enrollment_end=None,
end_date=furthest_future_date,
)
create_featured_items()
assert len(redis_cache.get("CMS_homepage_featured_courses")) == 1
hf = HomePageFactory.create()
assert hf.get_cached_featured_products == [
{
"title": enrollable_future_course_with_no_enrollment_end_page.title,
"description": enrollable_future_course_with_no_enrollment_end_page.description,
"feature_image": enrollable_future_course_with_no_enrollment_end_page.feature_image,
"start_date": enrollable_future_courserun_with_no_enrollment_end.start_date,
"url_path": enrollable_future_course_with_no_enrollment_end_page.get_url(),
"is_program": enrollable_future_course_with_no_enrollment_end_page.is_program_page,
"is_self_paced": False,
"program_type": None,
}
]
2 changes: 2 additions & 0 deletions courses/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@
zip(ALL_ENROLL_CHANGE_STATUSES, ALL_ENROLL_CHANGE_STATUSES)
)

HOMEPAGE_CACHE_AGE = 86400 # 24 hours

SYNCED_COURSE_RUN_FIELD_MSG = "This value is synced automatically with edX studio."

0 comments on commit c82cf83

Please sign in to comment.