diff --git a/lms/djangoapps/instructor_analytics/basic.py b/lms/djangoapps/instructor_analytics/basic.py index d928ddd989..b6e73e1626 100644 --- a/lms/djangoapps/instructor_analytics/basic.py +++ b/lms/djangoapps/instructor_analytics/basic.py @@ -3,6 +3,7 @@ Student and course analytics. Serve miscellaneous course and student data """ +import json from shoppingcart.models import ( PaidCourseRegistration, CouponRedemption, Invoice, CourseRegCodeItem, OrderTypes, RegistrationCodeRedemption, CourseRegistrationCode @@ -187,6 +188,15 @@ def enrolled_students_features(course_key, features): student_features = [x for x in STUDENT_FEATURES if x in features] profile_features = [x for x in PROFILE_FEATURES if x in features] + # For data extractions on the 'meta' field + # the feature name should be in the format of 'meta.foo' where + # 'foo' is the keyname in the meta dictionary + meta_features = [] + for feature in features: + if 'meta.' in feature: + meta_key = feature.split('.')[1] + meta_features.append((feature, meta_key)) + student_dict = dict((feature, getattr(student, feature)) for feature in student_features) profile = student.profile @@ -195,6 +205,11 @@ def enrolled_students_features(course_key, features): for feature in profile_features) student_dict.update(profile_dict) + # now featch the requested meta fields + meta_dict = json.loads(profile.meta) if profile.meta else {} + for meta_feature, meta_key in meta_features: + student_dict[meta_feature] = meta_dict.get(meta_key) + if include_cohort_column: # Note that we use student.course_groups.all() here instead of # student.course_groups.filter(). The latter creates a fresh query, diff --git a/lms/djangoapps/instructor_analytics/tests/test_basic.py b/lms/djangoapps/instructor_analytics/tests/test_basic.py index c933e7e343..3f681d7b6c 100644 --- a/lms/djangoapps/instructor_analytics/tests/test_basic.py +++ b/lms/djangoapps/instructor_analytics/tests/test_basic.py @@ -2,6 +2,7 @@ Tests for instructor.basic """ +import json from student.models import CourseEnrollment from django.core.urlresolvers import reverse from mock import patch @@ -32,6 +33,12 @@ class TestAnalyticsBasic(ModuleStoreTestCase): self.ces = tuple(CourseEnrollment.enroll(user, self.course_key) for user in self.users) self.instructor = InstructorFactory(course_key=self.course_key) + for user in self.users: + user.profile.meta = json.dumps({ + "position": "edX expert {}".format(user.id), + "company": "Open edX Inc {}".format(user.id), + }) + user.profile.save() def test_enrolled_students_features_username(self): self.assertIn('username', AVAILABLE_FEATURES) @@ -54,6 +61,19 @@ class TestAnalyticsBasic(ModuleStoreTestCase): self.assertIn(userreport['email'], [user.email for user in self.users]) self.assertIn(userreport['name'], [user.profile.name for user in self.users]) + def test_enrolled_students_meta_features_keys(self): + """ + Assert that we can query individual fields in the 'meta' field in the UserProfile + """ + query_features = ('meta.position', 'meta.company') + with self.assertNumQueries(1): + userreports = enrolled_students_features(self.course_key, query_features) + self.assertEqual(len(userreports), len(self.users)) + for userreport in userreports: + self.assertEqual(set(userreport.keys()), set(query_features)) + self.assertIn(userreport['meta.position'], ["edX expert {}".format(user.id) for user in self.users]) + self.assertIn(userreport['meta.company'], ["Open edX Inc {}".format(user.id) for user in self.users]) + def test_enrolled_students_features_keys_cohorted(self): course = CourseFactory.create(course_key=self.course_key) course.cohort_config = {'cohorted': True, 'auto_cohort': True, 'auto_cohort_groups': ['cohort']}