feat: show general recommendations (#31278)
Show general recommendations for * API failure * and when no enrollable courses are present VAN-1158
This commit is contained in:
committed by
GitHub
parent
fe15171209
commit
9478b5f422
@@ -838,6 +838,21 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
|
||||
},
|
||||
]
|
||||
|
||||
SERIALIZED_GENERAL_RECOMMENDATIONS = [
|
||||
{
|
||||
"courseKey": GENERAL_RECOMMENDATIONS[0]["course_key"],
|
||||
"logoImageUrl": GENERAL_RECOMMENDATIONS[0]["logo_image_url"],
|
||||
"marketingUrl": GENERAL_RECOMMENDATIONS[0]["marketing_url"],
|
||||
"title": GENERAL_RECOMMENDATIONS[0]["title"],
|
||||
},
|
||||
{
|
||||
"courseKey": GENERAL_RECOMMENDATIONS[1]["course_key"],
|
||||
"logoImageUrl": GENERAL_RECOMMENDATIONS[1]["logo_image_url"],
|
||||
"marketingUrl": GENERAL_RECOMMENDATIONS[1]["marketing_url"],
|
||||
"title": GENERAL_RECOMMENDATIONS[1]["title"],
|
||||
},
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user = UserFactory()
|
||||
@@ -854,6 +869,18 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
|
||||
"NYUx+FCS.NET.1",
|
||||
"MichinX+101x",
|
||||
]
|
||||
self.course_run_keys = [
|
||||
"course-v1:MITx+6.00.1x+Run_0",
|
||||
"course-v1:IBM+PY0101EN+Run_0",
|
||||
"course-v1:HarvardX+CS50P+Run_0",
|
||||
"course-v1:UQx+IELTSx+Run_0",
|
||||
"course-v1:HarvardX+CS50x+Run_0",
|
||||
"course-v1:Harvard+CS50z+Run_0",
|
||||
"course-v1:BabsonX+EPS03x+Run_0",
|
||||
"course-v1:TUMx+QPLS2x+Run_0",
|
||||
"course-v1:NYUx+FCS.NET.1+Run_0",
|
||||
"course-v1:MichinX+101x+Run_0"
|
||||
]
|
||||
self.course_data = {
|
||||
"course_key": "MITx+6.00.1x",
|
||||
"title": "Introduction to Computer Science and Programming Using Python",
|
||||
@@ -871,35 +898,48 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
|
||||
self.assertEqual(response.data, None)
|
||||
|
||||
@override_waffle_flag(ENABLE_LEARNER_HOME_AMPLITUDE_RECOMMENDATIONS, active=True)
|
||||
@mock.patch("django.conf.settings.GENERAL_RECOMMENDATIONS", GENERAL_RECOMMENDATIONS)
|
||||
@mock.patch(
|
||||
"lms.djangoapps.learner_home.views.get_personalized_course_recommendations"
|
||||
)
|
||||
@mock.patch("lms.djangoapps.learner_home.views.get_course_data")
|
||||
def test_no_recommendations_from_amplitude(
|
||||
self, mocked_get_course_data, mocked_get_personalized_course_recommendations
|
||||
self, mocked_get_personalized_course_recommendations
|
||||
):
|
||||
"""
|
||||
Verify API returns 404 if no course recommendations from amplitude.
|
||||
Verify API returns general recommendations if no course recommendations from amplitude.
|
||||
"""
|
||||
mocked_get_personalized_course_recommendations.return_value = [False, []]
|
||||
mocked_get_course_data.return_value = self.course_data
|
||||
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
self.assertEqual(response.data, None)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
response_content = json.loads(response.content)
|
||||
self.assertEqual(response_content.get("isPersonalizedRecommendation"), False)
|
||||
self.assertEqual(
|
||||
response_content.get("courses"),
|
||||
self.SERIALIZED_GENERAL_RECOMMENDATIONS,
|
||||
)
|
||||
|
||||
@override_waffle_flag(ENABLE_LEARNER_HOME_AMPLITUDE_RECOMMENDATIONS, active=True)
|
||||
@mock.patch("django.conf.settings.GENERAL_RECOMMENDATIONS", GENERAL_RECOMMENDATIONS)
|
||||
@mock.patch(
|
||||
"lms.djangoapps.learner_home.views.get_personalized_course_recommendations",
|
||||
Mock(side_effect=Exception),
|
||||
)
|
||||
def test_amplitude_api_unexpected_error(self):
|
||||
"""
|
||||
Test that if the Amplitude API gives an unexpected error, 500 is returned.
|
||||
Test that if the Amplitude API gives an unexpected error, general recommendations are returned.
|
||||
"""
|
||||
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 500)
|
||||
self.assertEqual(response.data, None)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
response_content = json.loads(response.content)
|
||||
self.assertEqual(response_content.get("isPersonalizedRecommendation"), False)
|
||||
self.assertEqual(
|
||||
response_content.get("courses"),
|
||||
self.SERIALIZED_GENERAL_RECOMMENDATIONS,
|
||||
)
|
||||
|
||||
@override_waffle_flag(ENABLE_LEARNER_HOME_AMPLITUDE_RECOMMENDATIONS, active=True)
|
||||
@mock.patch(
|
||||
@@ -951,20 +991,7 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
|
||||
self.assertEqual(response_content.get("isPersonalizedRecommendation"), False)
|
||||
self.assertEqual(
|
||||
response_content.get("courses"),
|
||||
[
|
||||
{
|
||||
"courseKey": self.GENERAL_RECOMMENDATIONS[0]["course_key"],
|
||||
"logoImageUrl": self.GENERAL_RECOMMENDATIONS[0]["logo_image_url"],
|
||||
"marketingUrl": self.GENERAL_RECOMMENDATIONS[0]["marketing_url"],
|
||||
"title": self.GENERAL_RECOMMENDATIONS[0]["title"],
|
||||
},
|
||||
{
|
||||
"courseKey": self.GENERAL_RECOMMENDATIONS[1]["course_key"],
|
||||
"logoImageUrl": self.GENERAL_RECOMMENDATIONS[1]["logo_image_url"],
|
||||
"marketingUrl": self.GENERAL_RECOMMENDATIONS[1]["marketing_url"],
|
||||
"title": self.GENERAL_RECOMMENDATIONS[1]["title"],
|
||||
},
|
||||
],
|
||||
self.SERIALIZED_GENERAL_RECOMMENDATIONS,
|
||||
)
|
||||
|
||||
@override_waffle_flag(ENABLE_LEARNER_HOME_AMPLITUDE_RECOMMENDATIONS, active=True)
|
||||
@@ -983,18 +1010,10 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
|
||||
self.recommended_courses,
|
||||
]
|
||||
mocked_get_course_data.return_value = self.course_data
|
||||
course_keys = [
|
||||
"course-v1:IBM+PY0101EN+Run_0",
|
||||
"course-v1:UQx+IELTSx+Run_0",
|
||||
"course-v1:MITx+6.00.1x+Run_0",
|
||||
"course-v1:HarvardX+CS50P+Run_0",
|
||||
"course-v1:Harvard+CS50z+Run_0",
|
||||
"course-v1:TUMx+QPLS2x+Run_0",
|
||||
]
|
||||
expected_recommendations = 4
|
||||
# enrolling in 6 courses
|
||||
for course_key in course_keys:
|
||||
CourseEnrollmentFactory(course_id=course_key, user=self.user)
|
||||
for course_run_key in self.course_run_keys[:6]:
|
||||
CourseEnrollmentFactory(course_id=course_run_key, user=self.user)
|
||||
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
@@ -1002,3 +1021,36 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
|
||||
response_content = json.loads(response.content)
|
||||
self.assertEqual(response_content.get("isPersonalizedRecommendation"), True)
|
||||
self.assertEqual(len(response_content.get("courses")), expected_recommendations)
|
||||
|
||||
@override_waffle_flag(ENABLE_LEARNER_HOME_AMPLITUDE_RECOMMENDATIONS, active=True)
|
||||
@mock.patch("django.conf.settings.GENERAL_RECOMMENDATIONS", GENERAL_RECOMMENDATIONS)
|
||||
@mock.patch(
|
||||
"lms.djangoapps.learner_home.views.get_personalized_course_recommendations"
|
||||
)
|
||||
@mock.patch("lms.djangoapps.learner_home.views.get_course_data")
|
||||
def test_no_enrollable_course(
|
||||
self, mocked_get_course_data, mocked_get_personalized_course_recommendations
|
||||
):
|
||||
"""
|
||||
Test that if after filtering already enrolled courses from Amplitude recommendations
|
||||
we are left with zero personalized recommendations, we return general recommendations.
|
||||
"""
|
||||
mocked_get_personalized_course_recommendations.return_value = [
|
||||
False,
|
||||
self.recommended_courses,
|
||||
]
|
||||
mocked_get_course_data.return_value = self.course_data
|
||||
|
||||
# Enrolling in all courses
|
||||
for course_run_key in self.course_run_keys:
|
||||
CourseEnrollmentFactory(course_id=course_run_key, user=self.user)
|
||||
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
response_content = json.loads(response.content)
|
||||
self.assertEqual(response_content.get("isPersonalizedRecommendation"), False)
|
||||
self.assertEqual(
|
||||
response_content.get("courses"),
|
||||
self.SERIALIZED_GENERAL_RECOMMENDATIONS,
|
||||
)
|
||||
|
||||
@@ -572,12 +572,22 @@ class CourseRecommendationApiView(APIView):
|
||||
if not should_show_learner_home_amplitude_recommendations():
|
||||
return Response(status=404)
|
||||
|
||||
general_recommendations_response = Response(
|
||||
CourseRecommendationSerializer(
|
||||
{
|
||||
"courses": settings.GENERAL_RECOMMENDATIONS,
|
||||
"is_personalized_recommendation": False,
|
||||
}
|
||||
).data,
|
||||
status=200,
|
||||
)
|
||||
|
||||
try:
|
||||
user_id = request.user.id
|
||||
is_control, course_keys = get_personalized_course_recommendations(user_id)
|
||||
except Exception as ex: # pylint: disable=broad-except
|
||||
logger.warning(f"Cannot get recommendations from Amplitude: {ex}")
|
||||
return Response(status=500)
|
||||
return general_recommendations_response
|
||||
|
||||
# Emits an event to track student dashboard page visits.
|
||||
segment.track(
|
||||
@@ -588,19 +598,8 @@ class CourseRecommendationApiView(APIView):
|
||||
},
|
||||
)
|
||||
|
||||
if is_control:
|
||||
return Response(
|
||||
CourseRecommendationSerializer(
|
||||
{
|
||||
"courses": settings.GENERAL_RECOMMENDATIONS,
|
||||
"is_personalized_recommendation": False,
|
||||
}
|
||||
).data,
|
||||
status=200,
|
||||
)
|
||||
|
||||
if not course_keys:
|
||||
return Response(status=404)
|
||||
if is_control or not course_keys:
|
||||
return general_recommendations_response
|
||||
|
||||
recommended_courses = []
|
||||
user_enrolled_course_keys = set()
|
||||
@@ -627,6 +626,12 @@ class CourseRecommendationApiView(APIView):
|
||||
}
|
||||
)
|
||||
|
||||
# If no courses are left after filtering already enrolled courses from
|
||||
# the list of amplitude recommendations, show general recommendations
|
||||
# to the user.
|
||||
if not recommended_courses:
|
||||
return general_recommendations_response
|
||||
|
||||
return Response(
|
||||
CourseRecommendationSerializer(
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user