feat: add serializer for recommendations api (#31270)

This commit is contained in:
Zainab Amir
2022-11-09 03:05:28 +05:00
committed by GitHub
parent c281f32595
commit 4b5f4f1eff
4 changed files with 145 additions and 17 deletions

View File

@@ -515,6 +515,26 @@ class UnfulfilledEntitlementSerializer(serializers.Serializer):
).data
class RecommendedCourseSerializer(serializers.Serializer):
"""Serializer for a recommended course from the recommendation engine"""
courseKey = serializers.CharField(source="course_key")
logoImageUrl = serializers.URLField(source="logo_image_url")
marketingUrl = serializers.URLField(source="marketing_url")
title = serializers.CharField()
class CourseRecommendationSerializer(serializers.Serializer):
"""Recommended courses by the Amplitude"""
courses = serializers.ListField(
child=RecommendedCourseSerializer(), allow_empty=True
)
isPersonalizedRecommendation = serializers.BooleanField(
source="is_personalized_recommendation"
)
class SuggestedCourseSerializer(serializers.Serializer):
"""Serializer for a suggested course from recommendation engine"""

View File

@@ -30,6 +30,7 @@ from openedx.core.djangoapps.content.course_overviews.tests.factories import (
from lms.djangoapps.learner_home.serializers import (
CertificateSerializer,
CourseProviderSerializer,
CourseRecommendationSerializer,
CourseRunSerializer,
CourseSerializer,
EmailConfirmationSerializer,
@@ -960,6 +961,81 @@ class TestUnfulfilledEntitlementSerializer(LearnerDashboardBaseTest):
assert expected_keys == actual_keys
class TestCourseRecommendationSerializer(TestCase):
"""High-level tests for CourseRecommendationSerializer"""
@classmethod
def mock_recommended_courses(cls, courses_count=2):
"""Sample course data"""
recommended_courses = []
for _ in range(courses_count):
recommended_courses.append(
{
"course_key": str(uuid4()),
"logo_image_url": random_url(),
"marketing_url": random_url(),
"title": str(uuid4()),
},
)
return recommended_courses
def test_no_recommended_courses(self):
"""That that data serializes correctly for empty courses list"""
recommended_courses = self.mock_recommended_courses(courses_count=0)
output_data = CourseRecommendationSerializer(
{
"courses": recommended_courses,
"is_personalized_recommendation": False,
}
).data
self.assertDictEqual(
output_data,
{
"courses": [],
"isPersonalizedRecommendation": False,
},
)
def test_happy_path(self):
"""Test that data serializes correctly"""
recommended_courses = self.mock_recommended_courses()
output_data = CourseRecommendationSerializer(
{
"courses": recommended_courses,
"is_personalized_recommendation": True,
}
).data
self.assertDictEqual(
output_data,
{
"courses": [
{
"courseKey": recommended_courses[0]["course_key"],
"logoImageUrl": recommended_courses[0]["logo_image_url"],
"marketingUrl": recommended_courses[0]["marketing_url"],
"title": recommended_courses[0]["title"],
},
{
"courseKey": recommended_courses[1]["course_key"],
"logoImageUrl": recommended_courses[1]["logo_image_url"],
"marketingUrl": recommended_courses[1]["marketing_url"],
"title": recommended_courses[1]["title"],
},
],
"isPersonalizedRecommendation": True,
},
)
class TestSuggestedCourseSerializer(TestCase):
"""High-level tests for SuggestedCourseSerializer"""

View File

@@ -890,7 +890,8 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
@override_waffle_flag(ENABLE_LEARNER_HOME_AMPLITUDE_RECOMMENDATIONS, active=True)
@mock.patch(
"lms.djangoapps.learner_home.views.get_personalized_course_recommendations", Mock(side_effect=Exception)
"lms.djangoapps.learner_home.views.get_personalized_course_recommendations",
Mock(side_effect=Exception),
)
def test_amplitude_api_unexpected_error(self):
"""
@@ -920,9 +921,11 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data.get("is_personalized_recommendation"), True)
response_content = json.loads(response.content)
self.assertEqual(response_content.get("isPersonalizedRecommendation"), True)
self.assertEqual(
len(response.data.get("courses")), expected_recommendations_length
len(response_content.get("courses")), expected_recommendations_length
)
@override_waffle_flag(ENABLE_LEARNER_HOME_AMPLITUDE_RECOMMENDATIONS, active=True)
@@ -930,7 +933,9 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
@mock.patch(
"lms.djangoapps.learner_home.views.get_personalized_course_recommendations"
)
def test_general_recommendations(self, mocked_get_personalized_course_recommendations):
def test_general_recommendations(
self, mocked_get_personalized_course_recommendations
):
"""
Test that a user gets general recommendations for the control group.
"""
@@ -941,8 +946,26 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data.get("is_personalized_recommendation"), False)
self.assertEqual(response.data.get("courses"), self.GENERAL_RECOMMENDATIONS)
response_content = json.loads(response.content)
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"],
},
],
)
@override_waffle_flag(ENABLE_LEARNER_HOME_AMPLITUDE_RECOMMENDATIONS, active=True)
@mock.patch(
@@ -975,5 +998,7 @@ class TestCourseRecommendationApiView(SharedModuleStoreTestCase):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data.get("is_personalized_recommendation"), True)
self.assertEqual(len(response.data.get("courses")), expected_recommendations)
response_content = json.loads(response.content)
self.assertEqual(response_content.get("isPersonalizedRecommendation"), True)
self.assertEqual(len(response_content.get("courses")), expected_recommendations)

View File

@@ -48,7 +48,10 @@ from lms.djangoapps.courseware.access import administrative_accesses_to_course_f
from lms.djangoapps.courseware.access_utils import (
check_course_open_for_learner,
)
from lms.djangoapps.learner_home.serializers import LearnerDashboardSerializer
from lms.djangoapps.learner_home.serializers import (
CourseRecommendationSerializer,
LearnerDashboardSerializer,
)
from lms.djangoapps.learner_home.waffle import (
should_show_learner_home_amplitude_recommendations,
)
@@ -581,10 +584,12 @@ class CourseRecommendationApiView(APIView):
if is_control:
return Response(
{
"courses": settings.GENERAL_RECOMMENDATIONS,
"is_personalized_recommendation": False,
},
CourseRecommendationSerializer(
{
"courses": settings.GENERAL_RECOMMENDATIONS,
"is_personalized_recommendation": False,
}
).data,
status=200,
)
@@ -622,9 +627,11 @@ class CourseRecommendationApiView(APIView):
{"count": len(recommended_courses)},
)
return Response(
{
"courses": recommended_courses,
"is_personalized_recommendation": not is_control,
},
CourseRecommendationSerializer(
{
"courses": recommended_courses,
"is_personalized_recommendation": not is_control,
}
).data,
status=200,
)