Commit 8d427271 by Clinton Blackburn

Rewrote course recent_activity methods

- Using single method with parameter to specify activity type
- Added modules with accepted activity types and demographics
- Converting course_id to unicode in Course constructor (to un-offically support OpaqueKey)
- Removing trailing slash from Client base_url

Change-Id: Ic21a381380fde67993b314fcf3a4529a1cf0a85b
parent 8e8afa54
"""
Course activity types.
"""
ANY = 'any'
ATTEMPTED_PROBLEM = 'attempted_problem'
PLAYED_VIDEO = 'played_video'
POSTED_FORUM = 'posted_form'
......@@ -27,7 +27,7 @@ class Client(object):
base_url (str): URL of the API server (e.g. http://analytics.edx.org/api/v0)
auth_token (str): Authentication token
"""
self.base_url = base_url
self.base_url = base_url.rstrip('/')
self.auth_token = auth_token
self.timeout = 0.1
......
import analyticsclient.activity_type as at
class Course(object):
"""
Course-related analytics.
"""
......@@ -17,23 +17,22 @@ class Course(object):
"""
self.client = client
self.course_id = course_id
@property
def recent_active_user_count(self):
"""A count of users who have recently interacted with the course in any way."""
# TODO: should we return something more structured than a python dict?
return self.client.get('courses/{0}/recent_activity'.format(self.course_id))
@property
def recent_problem_activity_count(self):
"""A count of users who have recently attempted a problem."""
# TODO: Can we avoid passing around strings like "ATTEMPTED_PROBLEM" in the data pipeline and the client?
return self.client.get(
'courses/{0}/recent_activity?activity_type=ATTEMPTED_PROBLEM'.format(self.course_id))
def enrollment(self, demographic=None):
uri = 'courses/{0}/enrollment'.format(self.course_id)
if demographic:
uri += '/%s' % demographic
return self.client.get(uri)
self.course_id = unicode(course_id)
def enrollment(self, demographic):
"""
Get course enrollment data grouped by demographic.
Arguments:
demographic (str): Demographic by which enrollment data should be grouped.
"""
return self.client.get('courses/{0}/enrollment/{1}'.format(self.course_id, demographic))
def recent_activity(self, activity_type=at.ANY):
"""
Get the recent course activity.
Arguments:
activity_type (str): The type of recent activity to return. Defaults to ANY.
"""
return self.client.get('courses/{0}/recent_activity?activity_type={1}'.format(self.course_id, activity_type))
"""
Course demographics
"""
BIRTH_YEAR = 'birth_year'
EDUCATION = 'education'
GENDER = 'gender'
......@@ -41,3 +41,12 @@ class ClientTests(ClientTestCase):
httpretty.register_uri(httpretty.GET, self.test_uri, body=json.dumps(data)[:6])
with self.assertRaises(ClientError):
self.client.get(self.test_endpoint)
def test_strip_trailing_slash(self):
url = 'http://example.com'
client = Client(url)
self.assertEqual(client.base_url, url)
url_with_slash = 'http://example.com/'
client = Client(url_with_slash)
self.assertEqual(client.base_url, url)
import json
import httpretty
from analyticsclient import activity_type as at
from analyticsclient import demographic as demo
from analyticsclient.tests import ClientTestCase
......@@ -16,19 +18,6 @@ class CoursesTests(ClientTestCase):
super(CoursesTests, self).tearDown()
httpretty.disable()
def test_recent_active_user_count(self):
body = {
u'course_id': u'edX/DemoX/Demo_Course',
u'interval_start': u'2014-05-24T00:00:00Z',
u'interval_end': u'2014-06-01T00:00:00Z',
u'activity_type': u'any',
u'count': 300,
}
uri = self.get_api_url('courses/{0}/recent_activity'.format(self.course_id))
httpretty.register_uri(httpretty.GET, uri, body=json.dumps(body))
self.assertDictEqual(body, self.course.recent_active_user_count)
def assertEnrollmentResponseData(self, course, data, demographic=None):
uri = self.get_api_url('courses/{0}/enrollment'.format(course.course_id))
if demographic:
......@@ -36,18 +25,18 @@ class CoursesTests(ClientTestCase):
httpretty.register_uri(httpretty.GET, uri, body=json.dumps(data))
self.assertDictEqual(data, course.enrollment(demographic))
def test_recent_problem_activity_count(self):
def assertRecentActivityResponseData(self, course, activity_type):
body = {
u'course_id': u'edX/DemoX/Demo_Course',
u'course_id': unicode(course.course_id),
u'interval_start': u'2014-05-24T00:00:00Z',
u'interval_end': u'2014-06-01T00:00:00Z',
u'activity_type': u'attempted_problem',
u'activity_type': unicode(activity_type),
u'count': 200,
}
uri = self.get_api_url('courses/{0}/recent_activity?activity_type=attempted_problem'.format(self.course_id))
uri = self.get_api_url('courses/{0}/recent_activity?activity_type={1}'.format(self.course_id, activity_type))
httpretty.register_uri(httpretty.GET, uri, body=json.dumps(body))
self.assertDictEqual(body, self.course.recent_problem_activity_count)
self.assertDictEqual(body, self.course.recent_activity(activity_type))
def test_enrollment_birth_year(self):
data = {
......@@ -56,7 +45,7 @@ class CoursesTests(ClientTestCase):
u'1895': 19
}
}
self.assertEnrollmentResponseData(self.course, data, 'birth_year')
self.assertEnrollmentResponseData(self.course, data, demo.BIRTH_YEAR)
def test_enrollment_education(self):
data = {
......@@ -73,7 +62,7 @@ class CoursesTests(ClientTestCase):
}
}
self.assertEnrollmentResponseData(self.course, data, 'education')
self.assertEnrollmentResponseData(self.course, data, demo.EDUCATION)
def test_enrollment_gender(self):
data = {
......@@ -83,4 +72,10 @@ class CoursesTests(ClientTestCase):
u'f': 77495
}
}
self.assertEnrollmentResponseData(self.course, data, 'gender')
self.assertEnrollmentResponseData(self.course, data, demo.GENDER)
def test_recent_activity(self):
self.assertRecentActivityResponseData(self.course, at.ANY)
self.assertRecentActivityResponseData(self.course, at.ATTEMPTED_PROBLEM)
self.assertRecentActivityResponseData(self.course, at.PLAYED_VIDEO)
self.assertRecentActivityResponseData(self.course, at.POSTED_FORUM)
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