From d7cc866280561acffc6dc2edbe6988679bea3728 Mon Sep 17 00:00:00 2001 From: Matthew Piatetsky Date: Wed, 6 Oct 2021 12:28:06 -0400 Subject: [PATCH] feat: surface goals in courseware api (#28952) --- .../djangoapps/courseware_api/serializers.py | 2 ++ .../courseware_api/tests/test_views.py | 12 +++++++++ .../core/djangoapps/courseware_api/views.py | 27 +++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/openedx/core/djangoapps/courseware_api/serializers.py b/openedx/core/djangoapps/courseware_api/serializers.py index 0daaa6ce73..78fe663e5b 100644 --- a/openedx/core/djangoapps/courseware_api/serializers.py +++ b/openedx/core/djangoapps/courseware_api/serializers.py @@ -5,6 +5,7 @@ Course API Serializers. Representing course catalog data from rest_framework import serializers from lms.djangoapps.course_home_api.progress.serializers import CertificateDataSerializer +from lms.djangoapps.course_home_api.outline.serializers import CourseGoalsSerializer from openedx.core.lib.api.fields import AbsoluteURLField @@ -81,6 +82,7 @@ class CourseInfoSerializer(serializers.Serializer): # pylint: disable=abstract- access_expiration = serializers.DictField() can_show_upgrade_sock = serializers.BooleanField() content_type_gating_enabled = serializers.BooleanField() + course_goals = CourseGoalsSerializer() effort = serializers.CharField() end = serializers.DateTimeField() enrollment = serializers.DictField() diff --git a/openedx/core/djangoapps/courseware_api/tests/test_views.py b/openedx/core/djangoapps/courseware_api/tests/test_views.py index a6f4bda366..c8d6412ad1 100644 --- a/openedx/core/djangoapps/courseware_api/tests/test_views.py +++ b/openedx/core/djangoapps/courseware_api/tests/test_views.py @@ -99,6 +99,7 @@ class BaseCoursewareTests(SharedModuleStoreTestCase): @ddt.ddt @override_waffle_flag(COURSEWARE_MICROFRONTEND_PROGRESS_MILESTONES, active=True) @override_waffle_flag(COURSEWARE_MICROFRONTEND_PROGRESS_MILESTONES_STREAK_CELEBRATION, active=True) +@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') class CourseApiTestViews(BaseCoursewareTests, MasqueradeMixin): """ Tests for the courseware REST API @@ -164,6 +165,16 @@ class CourseApiTestViews(BaseCoursewareTests, MasqueradeMixin): assert found, 'external link not in course tabs' assert not response.data['user_has_passing_grade'] + + # This import errors in cms if it is imported at the top level + from lms.djangoapps.course_goals.api import get_course_goal + selected_goal = get_course_goal(self.user, self.course.id) + if selected_goal: + assert response.data['course_goals']['selected_goal'] == { + 'days_per_week': selected_goal.days_per_week, + 'subscribed_to_reminders': selected_goal.subscribed_to_reminders, + } + if enrollment_mode == 'audit': assert response.data['verify_identity_url'] is None assert response.data['verification_status'] == 'none' # lint-amnesty, pylint: disable=literal-comparison @@ -201,6 +212,7 @@ class CourseApiTestViews(BaseCoursewareTests, MasqueradeMixin): check_public_access.assert_called() assert response.data['enrollment']['mode'] is None assert response.data['course_access']['has_access'] + assert response.data['course_goals'] is None else: assert not response.data['course_access']['has_access'] diff --git a/openedx/core/djangoapps/courseware_api/views.py b/openedx/core/djangoapps/courseware_api/views.py index 67a9cfebe9..d6dc8ebef8 100644 --- a/openedx/core/djangoapps/courseware_api/views.py +++ b/openedx/core/djangoapps/courseware_api/views.py @@ -23,6 +23,8 @@ from lms.djangoapps.certificates.api import get_certificate_url from lms.djangoapps.certificates.models import GeneratedCertificate from lms.djangoapps.course_api.api import course_detail from lms.djangoapps.course_goals.models import UserActivity +from lms.djangoapps.course_goals.api import get_course_goal +from lms.djangoapps.course_goals.toggles import COURSE_GOALS_NUMBER_OF_DAYS_GOALS from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.access_response import ( CoursewareMicrofrontendDisabledAccessError, @@ -48,6 +50,7 @@ from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiv from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin from openedx.core.lib.courses import get_course_by_id from openedx.features.course_experience import DISPLAY_COURSE_SOCK_FLAG +from openedx.features.course_experience import ENABLE_COURSE_GOALS from openedx.features.content_type_gating.models import ContentTypeGatingConfig from openedx.features.course_duration_limits.access import get_access_expiration_data from openedx.features.discounts.utils import generate_offer_data @@ -210,6 +213,26 @@ class CoursewareMeta: celebrations = get_celebrations_dict(self.effective_user, self.enrollment_object, self.course, browser_timezone) return celebrations + @property + def course_goals(self): + """ + Returns a dict of course goals + """ + if COURSE_GOALS_NUMBER_OF_DAYS_GOALS.is_enabled(): + course_goals = { + 'goal_options': [], + 'selected_goal': None + } + user_is_enrolled = CourseEnrollment.is_enrolled(self.effective_user, self.course_key) + if (user_is_enrolled and ENABLE_COURSE_GOALS.is_enabled(self.course_key)): + selected_goal = get_course_goal(self.effective_user, self.course_key) + if selected_goal: + course_goals['selected_goal'] = { + 'days_per_week': selected_goal.days_per_week, + 'subscribed_to_reminders': selected_goal.subscribed_to_reminders, + } + return course_goals + @property def user_has_passing_grade(self): """ Returns a boolean on if the effective_user has a passing grade in the course """ @@ -357,6 +380,10 @@ class CoursewareInformation(RetrieveAPIView): * masquerading_expired_course: (bool) Whether this course is expired for the masqueraded user * upgrade_deadline: (str) Last chance to upgrade, in ISO 8601 notation (or None if can't upgrade anymore) * upgrade_url: (str) Upgrade linke (or None if can't upgrade anymore) + course_goals: + selected_goal: + days_per_week: (int) The number of days the learner wants to learn per week + subscribed_to_reminders: (bool) Whether the learner wants email reminders about their goal * effort: A textual description of the weekly hours of effort expected in the course. * end: Date the course ends, in ISO 8601 notation