Commit 9a116529 by Braden MacDonald

Add module key and library source info to problem events

parent 3a973d42
...@@ -755,6 +755,7 @@ def _invoke_xblock_handler(request, course_id, usage_id, handler, suffix, user): ...@@ -755,6 +755,7 @@ def _invoke_xblock_handler(request, course_id, usage_id, handler, suffix, user):
try: try:
descriptor = modulestore().get_item(usage_key) descriptor = modulestore().get_item(usage_key)
descriptor_orig_usage_key, descriptor_orig_version = modulestore().get_block_original_usage(usage_key)
except ItemNotFoundError: except ItemNotFoundError:
log.warn( log.warn(
"Invalid location for course id {course_id}: {usage_key}".format( "Invalid location for course id {course_id}: {usage_key}".format(
...@@ -768,8 +769,13 @@ def _invoke_xblock_handler(request, course_id, usage_id, handler, suffix, user): ...@@ -768,8 +769,13 @@ def _invoke_xblock_handler(request, course_id, usage_id, handler, suffix, user):
tracking_context = { tracking_context = {
'module': { 'module': {
'display_name': descriptor.display_name_with_default, 'display_name': descriptor.display_name_with_default,
'usage_key': unicode(descriptor.location),
} }
} }
# For blocks that are inherited from a content library, we add some additional metadata:
if descriptor_orig_usage_key is not None:
tracking_context['module']['original_usage_key'] = unicode(descriptor_orig_usage_key)
tracking_context['module']['original_usage_version'] = unicode(descriptor_orig_version)
field_data_cache = FieldDataCache.cache_for_descriptor_descendents( field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
course_id, course_id,
......
...@@ -5,6 +5,7 @@ Test for lms courseware app, module render unit ...@@ -5,6 +5,7 @@ Test for lms courseware app, module render unit
from functools import partial from functools import partial
import json import json
from bson import ObjectId
import ddt import ddt
from django.http import Http404, HttpResponse from django.http import Http404, HttpResponse
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
...@@ -13,6 +14,7 @@ from django.test.client import RequestFactory ...@@ -13,6 +14,7 @@ from django.test.client import RequestFactory
from django.test.utils import override_settings from django.test.utils import override_settings
from django.contrib.auth.models import AnonymousUser from django.contrib.auth.models import AnonymousUser
from mock import MagicMock, patch, Mock from mock import MagicMock, patch, Mock
from opaque_keys.edx.keys import UsageKey
from opaque_keys.edx.locations import SlashSeparatedCourseKey from opaque_keys.edx.locations import SlashSeparatedCourseKey
from xblock.field_data import FieldData from xblock.field_data import FieldData
from xblock.runtime import Runtime from xblock.runtime import Runtime
...@@ -971,12 +973,13 @@ class TestModuleTrackingContext(ModuleStoreTestCase): ...@@ -971,12 +973,13 @@ class TestModuleTrackingContext(ModuleStoreTestCase):
def test_context_contains_display_name(self, mock_tracker): def test_context_contains_display_name(self, mock_tracker):
problem_display_name = u'Option Response Problem' problem_display_name = u'Option Response Problem'
actual_display_name = self.handle_callback_and_get_display_name_from_event(mock_tracker, problem_display_name) module_info = self.handle_callback_and_get_module_info_from_event(mock_tracker, problem_display_name)
self.assertEquals(problem_display_name, actual_display_name) self.assertEquals(problem_display_name, module_info['display_name'])
def handle_callback_and_get_display_name_from_event(self, mock_tracker, problem_display_name=None): def handle_callback_and_get_module_info_from_event(self, mock_tracker, problem_display_name=None):
""" """
Creates a fake module, invokes the callback and extracts the display name from the emitted problem_check event. Creates a fake module, invokes the callback and extracts the 'module'
metadata from the emitted problem_check event.
""" """
descriptor_kwargs = { descriptor_kwargs = {
'category': 'problem', 'category': 'problem',
...@@ -1000,12 +1003,27 @@ class TestModuleTrackingContext(ModuleStoreTestCase): ...@@ -1000,12 +1003,27 @@ class TestModuleTrackingContext(ModuleStoreTestCase):
event = mock_call[1][0] event = mock_call[1][0]
self.assertEquals(event['event_type'], 'problem_check') self.assertEquals(event['event_type'], 'problem_check')
return event['context']['module']['display_name'] return event['context']['module']
def test_missing_display_name(self, mock_tracker): def test_missing_display_name(self, mock_tracker):
actual_display_name = self.handle_callback_and_get_display_name_from_event(mock_tracker) actual_display_name = self.handle_callback_and_get_module_info_from_event(mock_tracker)['display_name']
self.assertTrue(actual_display_name.startswith('problem')) self.assertTrue(actual_display_name.startswith('problem'))
def test_library_source_information(self, mock_tracker):
"""
Check that XBlocks that are inherited from a library include the
information about their library block source in events.
We patch the modulestore to avoid having to create a library.
"""
original_usage_key = UsageKey.from_string(u'block-v1:A+B+C+type@problem+block@abcd1234')
original_usage_version = ObjectId()
with patch('xmodule.modulestore.mixed.MixedModuleStore.get_block_original_usage', lambda _, key: (original_usage_key, original_usage_version)):
module_info = self.handle_callback_and_get_module_info_from_event(mock_tracker)
self.assertIn('original_usage_key', module_info)
self.assertEqual(module_info['original_usage_key'], unicode(original_usage_key))
self.assertIn('original_usage_version', module_info)
self.assertEqual(module_info['original_usage_version'], unicode(original_usage_version))
class TestXmoduleRuntimeEvent(TestSubmittingProblems): class TestXmoduleRuntimeEvent(TestSubmittingProblems):
""" """
......
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