Commit 34d200ff by Chris Dodge

allow for student profile downloads to query into 'meta' field in the UserProfile json blob

parent 5855587a
...@@ -3,6 +3,7 @@ Student and course analytics. ...@@ -3,6 +3,7 @@ Student and course analytics.
Serve miscellaneous course and student data Serve miscellaneous course and student data
""" """
import json
from shoppingcart.models import ( from shoppingcart.models import (
PaidCourseRegistration, CouponRedemption, Invoice, CourseRegCodeItem, PaidCourseRegistration, CouponRedemption, Invoice, CourseRegCodeItem,
OrderTypes, RegistrationCodeRedemption, CourseRegistrationCode OrderTypes, RegistrationCodeRedemption, CourseRegistrationCode
...@@ -187,6 +188,15 @@ def enrolled_students_features(course_key, features): ...@@ -187,6 +188,15 @@ def enrolled_students_features(course_key, features):
student_features = [x for x in STUDENT_FEATURES if x in 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] 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)) student_dict = dict((feature, getattr(student, feature))
for feature in student_features) for feature in student_features)
profile = student.profile profile = student.profile
...@@ -195,6 +205,11 @@ def enrolled_students_features(course_key, features): ...@@ -195,6 +205,11 @@ def enrolled_students_features(course_key, features):
for feature in profile_features) for feature in profile_features)
student_dict.update(profile_dict) 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: if include_cohort_column:
# Note that we use student.course_groups.all() here instead of # Note that we use student.course_groups.all() here instead of
# student.course_groups.filter(). The latter creates a fresh query, # student.course_groups.filter(). The latter creates a fresh query,
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
Tests for instructor.basic Tests for instructor.basic
""" """
import json
from student.models import CourseEnrollment from student.models import CourseEnrollment
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from mock import patch from mock import patch
...@@ -32,6 +33,12 @@ class TestAnalyticsBasic(ModuleStoreTestCase): ...@@ -32,6 +33,12 @@ class TestAnalyticsBasic(ModuleStoreTestCase):
self.ces = tuple(CourseEnrollment.enroll(user, self.course_key) self.ces = tuple(CourseEnrollment.enroll(user, self.course_key)
for user in self.users) for user in self.users)
self.instructor = InstructorFactory(course_key=self.course_key) 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): def test_enrolled_students_features_username(self):
self.assertIn('username', AVAILABLE_FEATURES) self.assertIn('username', AVAILABLE_FEATURES)
...@@ -54,6 +61,19 @@ class TestAnalyticsBasic(ModuleStoreTestCase): ...@@ -54,6 +61,19 @@ class TestAnalyticsBasic(ModuleStoreTestCase):
self.assertIn(userreport['email'], [user.email for user in self.users]) self.assertIn(userreport['email'], [user.email for user in self.users])
self.assertIn(userreport['name'], [user.profile.name 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): def test_enrolled_students_features_keys_cohorted(self):
course = CourseFactory.create(course_key=self.course_key) course = CourseFactory.create(course_key=self.course_key)
course.cohort_config = {'cohorted': True, 'auto_cohort': True, 'auto_cohort_groups': ['cohort']} course.cohort_config = {'cohorted': True, 'auto_cohort': True, 'auto_cohort_groups': ['cohort']}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment