Commit 7cc11934 by Clinton Blackburn

Merge pull request #3 from edx/recent-activity

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