diff --git a/edx_solutions_api_integration/courses/tests.py b/edx_solutions_api_integration/courses/tests.py index 5859771e..34e8d9e4 100644 --- a/edx_solutions_api_integration/courses/tests.py +++ b/edx_solutions_api_integration/courses/tests.py @@ -37,7 +37,6 @@ from django_comment_common.models import FORUM_ROLE_MODERATOR, Role from freezegun import freeze_time from instructor.access import allow_access -from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangolib.testing.utils import CacheIsolationTestCase from requests.exceptions import ConnectionError from rest_framework import status @@ -53,6 +52,8 @@ ) from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory +from course_metadata.models import CourseAggregatedMetaData + from edx_solutions_api_integration.courseware_access import get_course_descriptor, get_course_key from edx_solutions_api_integration.test_utils import ( APIClientMixin, CourseGradingMixin, SignalDisconnectTestMixin, @@ -340,7 +341,6 @@ def setUpClass(cls): end=cls.course_end_date, language=cls.language, ) - cls.course_overview = CourseOverview.get_from_id(cls.course.id) cls.test_data = '{}'.format(str(uuid.uuid4())) cls.chapter = ItemFactory.create( @@ -1023,14 +1023,14 @@ def test_courses_overview_get_unparsed(self): self.assertGreater(len(response.data), 0) asset_id = self.test_course_id.split(":")[1] self.assertEqual(response.data['overview_html'], self.overview.data.format(asset_id, asset_id)[1:]) - self.assertEqual(self.course_overview.image_urls, response.data['course_image_urls']) + self.assertIn(self.course.course_image, response.data['course_image_url']) def test_courses_overview_get_parsed(self): test_uri = self.base_courses_uri + '/' + self.test_course_id + '/overview?parse=true' response = self.do_get(test_uri) self.assertEqual(response.status_code, 200) self.assertGreater(len(response.data), 0) - self.assertEqual(self.course_overview.image_urls, response.data['course_image_urls']) + self.assertIn(self.course.course_image, response.data['course_image_url']) sections = response.data['sections'] self.assertEqual(len(sections), 4) self.assertIsNotNone(self._find_item_by_class(sections, 'about')) @@ -1592,6 +1592,9 @@ def test_courses_users_list_get_attributes(self, store): user_completions, course_total_assesments = 50, 100 CourseEnrollmentFactory.create(user=user, course_id=course.id) + CourseAggregatedMetaData.objects.update_or_create( + id=course.id, defaults={'total_assessments': course_total_assesments} + ) section_breakdown = [ { "category": "Homework", @@ -2433,6 +2436,9 @@ def test_courses_data_metrics(self): self.login() users_to_add, user_grade, user_completions, total_assessments = 5, 0.6, 10, 20 course = CourseFactory() + CourseAggregatedMetaData.objects.update_or_create( + id=course.id, defaults={'total_assessments': total_assessments} + ) for idx in xrange(0, users_to_add): user = UserFactory() created_user_id = user.id diff --git a/edx_solutions_api_integration/courses/views.py b/edx_solutions_api_integration/courses/views.py index 22d98e64..579a8db4 100644 --- a/edx_solutions_api_integration/courses/views.py +++ b/edx_solutions_api_integration/courses/views.py @@ -25,6 +25,7 @@ from completion.models import BlockCompletion from completion_aggregator.models import Aggregator +from course_metadata.models import CourseAggregatedMetaData from courseware.courses import ( get_course_about_section, get_course_info_section, @@ -995,9 +996,10 @@ def get(self, request, course_id): response_data['sections'] = _parse_overview_html(existing_content) else: response_data['overview_html'] = existing_content - - course_overview = CourseOverview.get_from_id(course_key) - response_data['course_image_urls'] = course_overview.image_urls + image_url = '' + if hasattr(course_descriptor, 'course_image') and course_descriptor.course_image: + image_url = course_image_url(course_descriptor) + response_data['course_image_url'] = image_url response_data['course_video'] = get_course_about_section(request, course_descriptor, 'video') return Response(response_data, status=status.HTTP_200_OK) @@ -1206,6 +1208,7 @@ class CoursesUsersList(MobileListAPIView): """ serializer_class = UserSerializer course_key = None + course_meta_data = None user_organizations = [] def post(self, request, course_id): @@ -1254,6 +1257,11 @@ def get(self, request, course_id): # pylint: disable=W0221 if not course_exists(course_id): return Response({}, status=status.HTTP_404_NOT_FOUND) self.course_key = get_course_key(course_id) + try: + self.course_meta_data = CourseAggregatedMetaData.objects.get(id=self.course_key) + except CourseAggregatedMetaData.DoesNotExist: + self.course_meta_data = None + return super(CoursesUsersList, self).list(request) def get_serializer_context(self): @@ -1286,6 +1294,7 @@ def get_serializer_context(self): serializer_context.update({ 'course_id': self.course_key, 'default_fields': default_fields, + 'course_meta_data': self.course_meta_data, 'active_attributes': active_attributes, }) return serializer_context diff --git a/edx_solutions_api_integration/test_utils.py b/edx_solutions_api_integration/test_utils.py index 550f0344..655b0bd1 100644 --- a/edx_solutions_api_integration/test_utils.py +++ b/edx_solutions_api_integration/test_utils.py @@ -20,6 +20,9 @@ from xmodule.modulestore.django import SignalHandler from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory +from course_metadata.signals import ( + course_publish_handler_in_course_metadata as listener_in_course_metadata +) from gradebook.signals import on_course_grade_changed @@ -272,6 +275,9 @@ def connect_signals(): """ connects signals defined in solutions apps """ + SignalHandler.course_published.connect( + listener_in_course_metadata, dispatch_uid='course_metadata' + ) PROBLEM_WEIGHTED_SCORE_CHANGED.connect(on_course_grade_changed) @staticmethod @@ -279,6 +285,9 @@ def disconnect_signals(): """ Disconnects signals defined in solutions apps """ + SignalHandler.course_published.disconnect( + listener_in_course_metadata, dispatch_uid='course_metadata' + ) PROBLEM_WEIGHTED_SCORE_CHANGED.disconnect(on_course_grade_changed) diff --git a/edx_solutions_api_integration/urls.py b/edx_solutions_api_integration/urls.py index c0942f9d..16137ae4 100644 --- a/edx_solutions_api_integration/urls.py +++ b/edx_solutions_api_integration/urls.py @@ -31,7 +31,6 @@ url(r'^mobile/v1/', include('edx_solutions_api_integration.mobile_api.urls')), url(r'^imports/*', include('edx_solutions_api_integration.imports.urls')), url(r'^courses_metadata/', include('course_metadata.urls')), - # we have to explicitly define url for workgroup users detail view # to wrap it around non_atomic_requests decorator url( diff --git a/edx_solutions_api_integration/users/views.py b/edx_solutions_api_integration/users/views.py index 175513a9..6949684a 100644 --- a/edx_solutions_api_integration/users/views.py +++ b/edx_solutions_api_integration/users/views.py @@ -45,6 +45,7 @@ from openedx.core.djangoapps.user_api.preferences.api import set_user_preference from openedx.core.djangoapps.user_api.accounts.image_helpers import get_profile_image_names, get_profile_image_storage from edx_notifications.lib.consumer import mark_notification_read +from course_metadata.models import CourseAggregatedMetaData, CourseSetting from completion_aggregator.models import Aggregator from student.models import CourseEnrollment, CourseEnrollmentException, PasswordHistory, UserProfile, LoginFailures from student.roles import ( @@ -1093,7 +1094,7 @@ def get(self, request, user_id): "start": enrollment.course_overview.start, "end": enrollment.course_overview.end, "effort": enrollment.course_overview.effort, - "course_image_urls": enrollment.course_overview.image_urls, + "course_image_url": enrollment.course_overview.course_image_url, } response_data.append(course_data) @@ -1783,6 +1784,8 @@ def get(self, request, *args, **kwargs): # pylint: disable=unused-argument aggregation_name='course' ).values('course_key', 'earned', 'possible', 'percent') } + course_meta_data = CourseAggregatedMetaData.objects.filter(id__in=course_keys)\ + .values('id', 'total_assessments') course_overview = CourseOverview.objects.filter(id__in=course_keys) if str2bool(mobile_only): course_overview = course_overview.filter(mobile_available=True) @@ -1801,6 +1804,7 @@ def get(self, request, *args, **kwargs): # pylint: disable=unused-argument serializer = CourseProgressSerializer(enrollments, many=True, context={ 'student_progress': student_progress, 'course_overview': course_overview, + 'course_metadata': course_meta_data, 'user_grades': user_grades, })