Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 10 additions & 20 deletions cms/djangoapps/contentstore/views/preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def preview_component(request, location):

return render_to_response('component.html', {
'preview': get_preview_html(request, component, 0),
'editor': component.runtime.render(component, None, 'studio_view').content,
'editor': component.render('studio_view').content,
})


Expand All @@ -95,11 +95,6 @@ def preview_module_system(request, preview_id, descriptor):
descriptor: An XModuleDescriptor
"""

def preview_field_data(descriptor):
"Helper method to create a DbModel from a descriptor"
student_data = DbModel(SessionKeyValueStore(request))
return lms_field_data(descriptor._field_data, student_data)

course_id = get_course_for_item(descriptor.location).location.course_id

if descriptor.location.category == 'static_tab':
Expand All @@ -118,7 +113,6 @@ def preview_field_data(descriptor):
debug=True,
replace_urls=partial(static_replace.replace_static_urls, data_directory=None, course_id=course_id),
user=request.user,
xmodule_field_data=preview_field_data,
can_execute_unsafe_code=(lambda: can_execute_unsafe_code(course_id)),
mixins=settings.XBLOCK_MIXINS,
course_id=course_id,
Expand All @@ -136,7 +130,8 @@ def preview_field_data(descriptor):
getattr(descriptor, 'data_dir', descriptor.location.course),
course_id=descriptor.location.org + '/' + descriptor.location.course + '/BOGUS_RUN_REPLACE_WHEN_AVAILABLE',
),
)
),
error_descriptor_class=ErrorDescriptor,
)


Expand All @@ -148,17 +143,12 @@ def load_preview_module(request, preview_id, descriptor):
preview_id (str): An identifier specifying which preview this module is used for
descriptor: An XModuleDescriptor
"""
system = preview_module_system(request, preview_id, descriptor)
try:
module = descriptor.xmodule(system)
except:
log.debug("Unable to load preview module", exc_info=True)
module = ErrorDescriptor.from_descriptor(
descriptor,
error_msg=exc_info_to_str(sys.exc_info())
).xmodule(system)

return module
student_data = DbModel(SessionKeyValueStore(request))
descriptor.bind_for_student(
preview_module_system(request, preview_id, descriptor),
lms_field_data(descriptor._field_data, student_data), # pylint: disable=protected-access
)
return descriptor

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where did the try/except go?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Into the _xmodule property of XModuleDescriptor. We're lazily creating the XModule when it's needed, rather than on load.



def get_preview_html(request, descriptor, idx):
Expand All @@ -167,4 +157,4 @@ def get_preview_html(request, descriptor, idx):
specified by the descriptor and idx.
"""
module = load_preview_module(request, str(idx), descriptor)
return module.runtime.render(module, None, "student_view").content
return module.render("student_view").content
8 changes: 4 additions & 4 deletions common/djangoapps/xmodule_modifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,15 @@ def add_histogram(user, block, view, frag, context): # pylint: disable=unused-a
return frag

block_id = block.id
if block.descriptor.has_score:
if block.has_score:
histogram = grade_histogram(block_id)
render_histogram = len(histogram) > 0
else:
histogram = None
render_histogram = False

if settings.MITX_FEATURES.get('ENABLE_LMS_MIGRATION'):
[filepath, filename] = getattr(block.descriptor, 'xml_attributes', {}).get('filename', ['', None])
[filepath, filename] = getattr(block, 'xml_attributes', {}).get('filename', ['', None])
osfs = block.system.filestore
if filename is not None and osfs.exists(filename):
# if original, unmangled filename exists then use it (github
Expand All @@ -163,13 +163,13 @@ def add_histogram(user, block, view, frag, context): # pylint: disable=unused-a
# TODO (ichuang): use _has_access_descriptor.can_load in lms.courseware.access, instead of now>mstart comparison here
now = datetime.datetime.now(UTC())
is_released = "unknown"
mstart = block.descriptor.start
mstart = block.start

if mstart is not None:
is_released = "<font color='red'>Yes!</font>" if (now > mstart) else "<font color='green'>Not yet</font>"

staff_context = {'fields': [(name, field.read_from(block)) for name, field in block.fields.items()],
'xml_attributes': getattr(block.descriptor, 'xml_attributes', {}),
'xml_attributes': getattr(block, 'xml_attributes', {}),
'location': block.location,
'xqa_key': block.xqa_key,
'source_file': source_file,
Expand Down
32 changes: 31 additions & 1 deletion common/lib/xmodule/xmodule/capa_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
ResponseError, LoncapaProblemError
from capa.util import convert_files_to_filenames
from .progress import Progress
from xmodule.x_module import XModule
from xmodule.x_module import XModule, module_attr
from xmodule.raw_module import RawDescriptor
from xmodule.exceptions import NotFoundError, ProcessingError
from xblock.fields import Scope, String, Boolean, Dict, Integer, Float
Expand Down Expand Up @@ -1193,3 +1193,33 @@ def non_editable_metadata_fields(self):
CapaDescriptor.force_save_button, CapaDescriptor.markdown,
CapaDescriptor.text_customization])
return non_editable_fields

# Proxy to CapaModule for access to any of its attributes
answer_available = module_attr('answer_available')
check_button_name = module_attr('check_button_name')
check_problem = module_attr('check_problem')
choose_new_seed = module_attr('choose_new_seed')
closed = module_attr('closed')
get_answer = module_attr('get_answer')
get_problem = module_attr('get_problem')
get_problem_html = module_attr('get_problem_html')
get_state_for_lcp = module_attr('get_state_for_lcp')
handle_input_ajax = module_attr('handle_input_ajax')
handle_problem_html_error = module_attr('handle_problem_html_error')
handle_ungraded_response = module_attr('handle_ungraded_response')
is_attempted = module_attr('is_attempted')
is_correct = module_attr('is_correct')
is_past_due = module_attr('is_past_due')
is_submitted = module_attr('is_submitted')
lcp = module_attr('lcp')
make_dict_of_responses = module_attr('make_dict_of_responses')
new_lcp = module_attr('new_lcp')
publish_grade = module_attr('publish_grade')
rescore_problem = module_attr('rescore_problem')
reset_problem = module_attr('reset_problem')
save_problem = module_attr('save_problem')
set_state_from_lcp = module_attr('set_state_from_lcp')
should_show_check_button = module_attr('should_show_check_button')
should_show_reset_button = module_attr('should_show_reset_button')
should_show_save_button = module_attr('should_show_save_button')
update_score = module_attr('update_score')
2 changes: 1 addition & 1 deletion common/lib/xmodule/xmodule/combined_open_ended_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ class CombinedOpenEndedDescriptor(CombinedOpenEndedFields, RawDescriptor):
metadata_translations = {
'is_graded': 'graded',
'attempts': 'max_attempts',
}
}

def get_context(self):
_context = RawDescriptor.get_context(self)
Expand Down
3 changes: 2 additions & 1 deletion common/lib/xmodule/xmodule/conditional_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@


class ConditionalFields(object):
has_children = True
show_tag_list = List(help="Poll answers", scope=Scope.content)


Expand Down Expand Up @@ -148,7 +149,7 @@ def handle_ajax(self, _dispatch, _data):
context)
return json.dumps({'html': [html], 'message': bool(message)})

html = [self.runtime.render_child(child, None, 'student_view').content for child in self.get_display_items()]
html = [child.render('student_view').content for child in self.get_display_items()]

return json.dumps({'html': html})

Expand Down
10 changes: 5 additions & 5 deletions common/lib/xmodule/xmodule/crowdsource_hinter.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,17 @@ def get_html(self):

try:
child = self.get_display_items()[0]
out = self.runtime.render_child(child, None, 'student_view').content
out = child.render('student_view').content
# The event listener uses the ajax url to find the child.
child_url = child.runtime.ajax_url
child_id = child.id
except IndexError:
out = u"Error in loading crowdsourced hinter - can't find child problem."
child_url = ''
child_id = ''

# Wrap the module in a <section>. This lets us pass data attributes to the javascript.
out += u'<section class="crowdsource-wrapper" data-url="{ajax_url}" data-child-url="{child_url}"> </section>'.format(
out += u'<section class="crowdsource-wrapper" data-url="{ajax_url}" data-child-id="{child_id}"> </section>'.format(
ajax_url=self.runtime.ajax_url,
child_url=child_url
child_id=child_id
)

return out
Expand Down
2 changes: 1 addition & 1 deletion common/lib/xmodule/xmodule/error_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class ErrorDescriptor(ErrorFields, XModuleDescriptor):
module_class = ErrorModule

def get_html(self):
return ''
return u''

@classmethod
def _construct(cls, system, contents, error_msg, location):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<li id="vert-0" data-id="i4x://Me/19.002/crowdsource_hinter/crowdsource_hinter_def7a1142dd0">


<section class="xmodule_display xmodule_CrowdsourceHinterModule" data-type="Hinter" id="hinter-root">


<section class="xmodule_display xmodule_CapaModule" data-type="Problem" id="problem">
<section id="problem_i4x-Me-19_002-problem-Numerical_Input" class="problems-wrapper" data-problem-id="i4x://Me/19.002/problem/Numerical_Input" data-url="/courses/Me/19.002/Test/modx/i4x://Me/19.002/problem/Numerical_Input" data-progress_status="done" data-progress_detail="1/1">
Expand Down Expand Up @@ -44,7 +44,7 @@ <h2 class="problem-header">



<section class="crowdsource-wrapper" data-url="/courses/Me/19.002/Test/modx/i4x://Me/19.002/crowdsource_hinter/crowdsource_hinter_def7a1142dd0" data-child-url="/courses/Me/19.002/Test/modx/i4x://Me/19.002/problem/Numerical_Input" style="display: none;"> </section>
<section class="crowdsource-wrapper" data-url="/courses/Me/19.002/Test/modx/i4x://Me/19.002/crowdsource_hinter/crowdsource_hinter_def7a1142dd0" data-child-id="i4x://Me/19.002/problem/Numerical_Input" style="display: none;"> </section>
</section>


Expand Down
4 changes: 2 additions & 2 deletions common/lib/xmodule/xmodule/js/spec/capa/display_spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,12 @@ describe 'Problem', ->

it 'log the problem_graded event, after the problem is done grading.', ->
spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) ->
response =
response =
success: 'correct'
contents: 'mock grader response'
callback(response)
@problem.check()
expect(Logger.log).toHaveBeenCalledWith 'problem_graded', ['foo=1&bar=2', 'mock grader response'], @problem.url
expect(Logger.log).toHaveBeenCalledWith 'problem_graded', ['foo=1&bar=2', 'mock grader response'], @problem.id

it 'submit the answer for check', ->
spyOn $, 'postWithPrefix'
Expand Down
4 changes: 2 additions & 2 deletions common/lib/xmodule/xmodule/js/src/capa/display.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ class @Problem
@updateProgress response
else
@gentle_alert response.success
Logger.log 'problem_graded', [@answers, response.contents], @url
Logger.log 'problem_graded', [@answers, response.contents], @id

if not abort_submission
$.ajaxWithPrefix("#{@url}/problem_check", settings)
Expand All @@ -271,7 +271,7 @@ class @Problem
@el.removeClass 'showed'
else
@gentle_alert response.success
Logger.log 'problem_graded', [@answers, response.contents], @url
Logger.log 'problem_graded', [@answers, response.contents], @id

reset: =>
Logger.log 'problem_reset', @answers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class @Hinter
constructor: (element) ->
@el = $(element).find('.crowdsource-wrapper')
@url = @el.data('url')
Logger.listen('problem_graded', @el.data('child-url'), @capture_problem)
Logger.listen('problem_graded', @el.data('child-id'), @capture_problem)
@render()

capture_problem: (event_type, data, element) =>
Expand Down
6 changes: 3 additions & 3 deletions common/lib/xmodule/xmodule/modulestore/mongo/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def get(self, key):
else:
return self._data[key.field_name]
else:
raise InvalidScopeError(key.scope)
raise InvalidScopeError(key)

def set(self, key, value):
if key.scope == Scope.children:
Expand All @@ -94,7 +94,7 @@ def set(self, key, value):
else:
self._data[key.field_name] = value
else:
raise InvalidScopeError(key.scope)
raise InvalidScopeError(key)

def delete(self, key):
if key.scope == Scope.children:
Expand All @@ -108,7 +108,7 @@ def delete(self, key):
else:
del self._data[key.field_name]
else:
raise InvalidScopeError(key.scope)
raise InvalidScopeError(key)

def has(self, key):
if key.scope in (Scope.children, Scope.parent):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ def get(self, key):

raise KeyError()
else:
raise InvalidScopeError(key.scope)
raise InvalidScopeError(key)

def set(self, key, value):
# handle any special cases
if key.scope not in [Scope.children, Scope.settings, Scope.content]:
raise InvalidScopeError(key.scope)
raise InvalidScopeError(key)
if key.scope == Scope.content:
self._load_definition()

Expand All @@ -75,7 +75,7 @@ def set(self, key, value):
def delete(self, key):
# handle any special cases
if key.scope not in [Scope.children, Scope.settings, Scope.content]:
raise InvalidScopeError(key.scope)
raise InvalidScopeError(key)
if key.scope == Scope.content:
self._load_definition()

Expand Down
44 changes: 27 additions & 17 deletions common/lib/xmodule/xmodule/modulestore/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

from xmodule.modulestore import Location
from xmodule.x_module import XModuleDescriptor
from xmodule.course_module import CourseDescriptor


class Dummy(object):
Expand Down Expand Up @@ -124,38 +123,49 @@ def _create(cls, target_class, **kwargs):
:target_class: is ignored
"""

# All class attributes (from this class and base classes) are
# passed in via **kwargs. However, some of those aren't actual field values,
# so pop those off for use separately

DETACHED_CATEGORIES = ['about', 'static_tab', 'course_info']
# catch any old style users before they get into trouble
assert not 'template' in kwargs
data = kwargs.get('data')
category = kwargs.get('category')
display_name = kwargs.get('display_name')
metadata = kwargs.get('metadata', {})
location = kwargs.get('location')
if kwargs.get('boilerplate') is not None:
template_id = kwargs.get('boilerplate')
assert 'template' not in kwargs
parent_location = Location(kwargs.pop('parent_location', None))
data = kwargs.pop('data', None)
category = kwargs.pop('category', None)
display_name = kwargs.pop('display_name', None)
metadata = kwargs.pop('metadata', {})
location = kwargs.pop('location')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume we desire things to error out if 'location' isn't present in kwargs?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

location will always be in **kwargs, because it's defined as an attribute earlier in the class.

assert location != parent_location

store = kwargs.pop('modulestore')

# This code was based off that in cms/djangoapps/contentstore/views.py
parent = kwargs.pop('parent', None) or store.get_item(parent_location)

if 'boilerplate' in kwargs:
template_id = kwargs.pop('boilerplate')
clz = XModuleDescriptor.load_class(category)
template = clz.get_template(template_id)
assert template is not None
metadata.update(template.get('metadata', {}))
if not isinstance(data, basestring):
data.update(template.get('data'))

store = kwargs.get('modulestore')

# replace the display name with an optional parameter passed in from the caller
if display_name is not None:
metadata['display_name'] = display_name
store.create_and_save_xmodule(location, metadata=metadata, definition_data=data)
module = store.create_and_save_xmodule(location, metadata=metadata, definition_data=data)

if location.category not in DETACHED_CATEGORIES:
module = store.get_item(location)

parent_location = Location(kwargs.get('parent_location'))
assert location != parent_location
for attr, val in kwargs.items():
setattr(module, attr, val)
module.save()

# This code was based off that in cms/djangoapps/contentstore/views.py
parent = kwargs.get('parent') or store.get_item(parent_location)
store.save_xmodule(module)

if location.category not in DETACHED_CATEGORIES:
parent.children.append(location.url())
store.update_children(parent_location, parent.children)

Expand Down
2 changes: 1 addition & 1 deletion common/lib/xmodule/xmodule/modulestore/xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ def fallback_name(orig_name=None):
descriptor.save()
return descriptor

render_template = lambda: ''
render_template = lambda template, context: u''
# TODO (vshnayder): we are somewhat architecturally confused in the loading code:
# load_item should actually be get_instance, because it expects the course-specific
# policy to be loaded. For now, just add the course_id here...
Expand Down
Loading