Commit 6a3f0c14 by David Baumgold

Merge pull request #564 from edx/db/xblock-student-view

XBlock integration for Studio: student view
parents 0db8ad28 32f76988
...@@ -1353,7 +1353,7 @@ class ContentStoreTest(ModuleStoreTestCase): ...@@ -1353,7 +1353,7 @@ class ContentStoreTest(ModuleStoreTestCase):
'course': loc.course, 'course': loc.course,
'name': loc.name})) 'name': loc.name}))
self.assertEqual(200, resp.status_code) self.assert2XX(resp.status_code)
self.assertContains(resp, 'Chapter 2') self.assertContains(resp, 'Chapter 2')
# go to various pages # go to various pages
...@@ -1363,92 +1363,92 @@ class ContentStoreTest(ModuleStoreTestCase): ...@@ -1363,92 +1363,92 @@ class ContentStoreTest(ModuleStoreTestCase):
kwargs={'org': loc.org, kwargs={'org': loc.org,
'course': loc.course, 'course': loc.course,
'name': loc.name})) 'name': loc.name}))
self.assertEqual(200, resp.status_code) self.assert2XX(resp.status_code)
# export page # export page
resp = self.client.get(reverse('export_course', resp = self.client.get(reverse('export_course',
kwargs={'org': loc.org, kwargs={'org': loc.org,
'course': loc.course, 'course': loc.course,
'name': loc.name})) 'name': loc.name}))
self.assertEqual(200, resp.status_code) self.assert2XX(resp.status_code)
# manage users # manage users
resp = self.client.get(reverse('manage_users', resp = self.client.get(reverse('manage_users',
kwargs={'org': loc.org, kwargs={'org': loc.org,
'course': loc.course, 'course': loc.course,
'name': loc.name})) 'name': loc.name}))
self.assertEqual(200, resp.status_code) self.assert2XX(resp.status_code)
# course info # course info
resp = self.client.get(reverse('course_info', resp = self.client.get(reverse('course_info',
kwargs={'org': loc.org, kwargs={'org': loc.org,
'course': loc.course, 'course': loc.course,
'name': loc.name})) 'name': loc.name}))
self.assertEqual(200, resp.status_code) self.assert2XX(resp.status_code)
# settings_details # settings_details
resp = self.client.get(reverse('settings_details', resp = self.client.get(reverse('settings_details',
kwargs={'org': loc.org, kwargs={'org': loc.org,
'course': loc.course, 'course': loc.course,
'name': loc.name})) 'name': loc.name}))
self.assertEqual(200, resp.status_code) self.assert2XX(resp.status_code)
# settings_details # settings_details
resp = self.client.get(reverse('settings_grading', resp = self.client.get(reverse('settings_grading',
kwargs={'org': loc.org, kwargs={'org': loc.org,
'course': loc.course, 'course': loc.course,
'name': loc.name})) 'name': loc.name}))
self.assertEqual(200, resp.status_code) self.assert2XX(resp.status_code)
# static_pages # static_pages
resp = self.client.get(reverse('static_pages', resp = self.client.get(reverse('static_pages',
kwargs={'org': loc.org, kwargs={'org': loc.org,
'course': loc.course, 'course': loc.course,
'coursename': loc.name})) 'coursename': loc.name}))
self.assertEqual(200, resp.status_code) self.assert2XX(resp.status_code)
# static_pages # static_pages
resp = self.client.get(reverse('asset_index', resp = self.client.get(reverse('asset_index',
kwargs={'org': loc.org, kwargs={'org': loc.org,
'course': loc.course, 'course': loc.course,
'name': loc.name})) 'name': loc.name}))
self.assertEqual(200, resp.status_code) self.assert2XX(resp.status_code)
# go look at a subsection page # go look at a subsection page
subsection_location = loc.replace(category='sequential', name='test_sequence') subsection_location = loc.replace(category='sequential', name='test_sequence')
resp = self.client.get(reverse('edit_subsection', resp = self.client.get(reverse('edit_subsection',
kwargs={'location': subsection_location.url()})) kwargs={'location': subsection_location.url()}))
self.assertEqual(200, resp.status_code) self.assert2XX(resp.status_code)
# go look at the Edit page # go look at the Edit page
unit_location = loc.replace(category='vertical', name='test_vertical') unit_location = loc.replace(category='vertical', name='test_vertical')
resp = self.client.get(reverse('edit_unit', resp = self.client.get(reverse('edit_unit',
kwargs={'location': unit_location.url()})) kwargs={'location': unit_location.url()}))
self.assertEqual(200, resp.status_code) self.assert2XX(resp.status_code)
# delete a component # delete a component
del_loc = loc.replace(category='html', name='test_html') del_loc = loc.replace(category='html', name='test_html')
resp = self.client.post(reverse('delete_item'), resp = self.client.post(reverse('delete_item'),
json.dumps({'id': del_loc.url()}), "application/json") json.dumps({'id': del_loc.url()}), "application/json")
self.assertEqual(200, resp.status_code) self.assert2XX(resp.status_code)
# delete a unit # delete a unit
del_loc = loc.replace(category='vertical', name='test_vertical') del_loc = loc.replace(category='vertical', name='test_vertical')
resp = self.client.post(reverse('delete_item'), resp = self.client.post(reverse('delete_item'),
json.dumps({'id': del_loc.url()}), "application/json") json.dumps({'id': del_loc.url()}), "application/json")
self.assertEqual(200, resp.status_code) self.assert2XX(resp.status_code)
# delete a unit # delete a unit
del_loc = loc.replace(category='sequential', name='test_sequence') del_loc = loc.replace(category='sequential', name='test_sequence')
resp = self.client.post(reverse('delete_item'), resp = self.client.post(reverse('delete_item'),
json.dumps({'id': del_loc.url()}), "application/json") json.dumps({'id': del_loc.url()}), "application/json")
self.assertEqual(200, resp.status_code) self.assert2XX(resp.status_code)
# delete a chapter # delete a chapter
del_loc = loc.replace(category='chapter', name='chapter_2') del_loc = loc.replace(category='chapter', name='chapter_2')
resp = self.client.post(reverse('delete_item'), resp = self.client.post(reverse('delete_item'),
json.dumps({'id': del_loc.url()}), "application/json") json.dumps({'id': del_loc.url()}), "application/json")
self.assertEqual(200, resp.status_code) self.assert2XX(resp.status_code)
def test_import_into_new_course_id(self): def test_import_into_new_course_id(self):
module_store = modulestore('direct') module_store = modulestore('direct')
......
...@@ -34,7 +34,7 @@ class DeleteItem(CourseTestCase): ...@@ -34,7 +34,7 @@ class DeleteItem(CourseTestCase):
resp.content, resp.content,
"application/json" "application/json"
) )
self.assertEqual(resp.status_code, 200) self.assert2XX(resp.status_code)
class TestCreateItem(CourseTestCase): class TestCreateItem(CourseTestCase):
......
import json
from uuid import uuid4 from uuid import uuid4
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.http import HttpResponse
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from xmodule.modulestore import Location from xmodule.modulestore import Location
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from xmodule.modulestore.inheritance import own_metadata from xmodule.modulestore.inheritance import own_metadata
from util.json_request import expect_json from util.json_request import expect_json, JsonResponse
from ..utils import get_modulestore from ..utils import get_modulestore
from .access import has_access from .access import has_access
from .requests import _xmodule_recurse from .requests import _xmodule_recurse
...@@ -20,6 +18,7 @@ __all__ = ['save_item', 'create_item', 'delete_item'] ...@@ -20,6 +18,7 @@ __all__ = ['save_item', 'create_item', 'delete_item']
# cdodge: these are categories which should not be parented, they are detached from the hierarchy # cdodge: these are categories which should not be parented, they are detached from the hierarchy
DETACHED_CATEGORIES = ['about', 'static_tab', 'course_info'] DETACHED_CATEGORIES = ['about', 'static_tab', 'course_info']
@login_required @login_required
@expect_json @expect_json
def save_item(request): def save_item(request):
...@@ -80,7 +79,7 @@ def save_item(request): ...@@ -80,7 +79,7 @@ def save_item(request):
# commit to datastore # commit to datastore
store.update_metadata(item_location, own_metadata(existing_item)) store.update_metadata(item_location, own_metadata(existing_item))
return HttpResponse() return JsonResponse()
# [DHM] A hack until we implement a permanent soln. Proposed perm solution is to make namespace fields also top level # [DHM] A hack until we implement a permanent soln. Proposed perm solution is to make namespace fields also top level
...@@ -139,13 +138,17 @@ def create_item(request): ...@@ -139,13 +138,17 @@ def create_item(request):
if display_name is not None: if display_name is not None:
metadata['display_name'] = display_name metadata['display_name'] = display_name
get_modulestore(category).create_and_save_xmodule(dest_location, definition_data=data, get_modulestore(category).create_and_save_xmodule(
metadata=metadata, system=parent.system) dest_location,
definition_data=data,
metadata=metadata,
system=parent.system,
)
if category not in DETACHED_CATEGORIES: if category not in DETACHED_CATEGORIES:
get_modulestore(parent.location).update_children(parent_location, parent.children + [dest_location.url()]) get_modulestore(parent.location).update_children(parent_location, parent.children + [dest_location.url()])
return HttpResponse(json.dumps({'id': dest_location.url()})) return JsonResponse({'id': dest_location.url()})
@login_required @login_required
...@@ -184,4 +187,4 @@ def delete_item(request): ...@@ -184,4 +187,4 @@ def delete_item(request):
parent.children = children parent.children = children
modulestore('direct').update_children(parent.location, parent.children) modulestore('direct').update_children(parent.location, parent.children)
return HttpResponse() return JsonResponse()
...@@ -76,7 +76,7 @@ def preview_component(request, location): ...@@ -76,7 +76,7 @@ def preview_component(request, location):
component = modulestore().get_item(location) component = modulestore().get_item(location)
return render_to_response('component.html', { return render_to_response('component.html', {
'preview': get_module_previews(request, component)[0], 'preview': get_preview_html(request, component, 0),
'editor': wrap_xmodule(component.get_html, component, 'xmodule_edit.html')(), 'editor': wrap_xmodule(component.get_html, component, 'xmodule_edit.html')(),
}) })
...@@ -163,15 +163,10 @@ def load_preview_module(request, preview_id, descriptor): ...@@ -163,15 +163,10 @@ def load_preview_module(request, preview_id, descriptor):
return module return module
def get_module_previews(request, descriptor): def get_preview_html(request, descriptor, idx):
""" """
Returns a list of preview XModule html contents. One preview is returned for each Returns the HTML returned by the XModule's student_view,
pair of states returned by get_sample_state() for the supplied descriptor. specified by the descriptor and idx.
descriptor: An XModuleDescriptor
""" """
preview_html = [] module = load_preview_module(request, str(idx), descriptor)
for idx, (_instance_state, _shared_state) in enumerate(descriptor.get_sample_state()): return module.runtime.render(module, None, "student_view").content
module = load_preview_module(request, str(idx), descriptor)
preview_html.append(module.get_html())
return preview_html
...@@ -711,20 +711,20 @@ class XModuleDescriptor(XModuleFields, HTMLSnippet, ResourceTemplates, XBlock): ...@@ -711,20 +711,20 @@ class XModuleDescriptor(XModuleFields, HTMLSnippet, ResourceTemplates, XBlock):
# =============================== BUILTIN METHODS ========================== # =============================== BUILTIN METHODS ==========================
def __eq__(self, other): def __eq__(self, other):
eq = (self.__class__ == other.__class__ and return (self.__class__ == other.__class__ and
all(getattr(self, attr, None) == getattr(other, attr, None) all(getattr(self, attr, None) == getattr(other, attr, None)
for attr in self.equality_attributes)) for attr in self.equality_attributes))
return eq
def __repr__(self): def __repr__(self):
return ("{class_}({system!r}, location={location!r}," return (
" model_data={model_data!r})".format( "{class_}({system!r}, location={location!r},"
class_=self.__class__.__name__, " model_data={model_data!r})".format(
system=self.system, class_=self.__class__.__name__,
location=self.location, system=self.system,
model_data=self._model_data, location=self.location,
)) model_data=self._model_data,
)
)
@property @property
def non_editable_metadata_fields(self): def non_editable_metadata_fields(self):
...@@ -785,15 +785,17 @@ class XModuleDescriptor(XModuleFields, HTMLSnippet, ResourceTemplates, XBlock): ...@@ -785,15 +785,17 @@ class XModuleDescriptor(XModuleFields, HTMLSnippet, ResourceTemplates, XBlock):
editor_type = "Float" editor_type = "Float"
elif isinstance(field, List): elif isinstance(field, List):
editor_type = "List" editor_type = "List"
metadata_fields[field.name] = {'field_name': field.name, metadata_fields[field.name] = {
'type': editor_type, 'field_name': field.name,
'display_name': field.display_name, 'type': editor_type,
'value': field.to_json(value), 'display_name': field.display_name,
'options': [] if values is None else values, 'value': field.to_json(value),
'default_value': field.to_json(default_value), 'options': [] if values is None else values,
'inheritable': inheritable, 'default_value': field.to_json(default_value),
'explicitly_set': explicitly_set, 'inheritable': inheritable,
'help': field.help} 'explicitly_set': explicitly_set,
'help': field.help,
}
return metadata_fields return metadata_fields
...@@ -885,28 +887,14 @@ class ModuleSystem(Runtime): ...@@ -885,28 +887,14 @@ class ModuleSystem(Runtime):
Note that these functions can be closures over e.g. a django request Note that these functions can be closures over e.g. a django request
and user, or other environment-specific info. and user, or other environment-specific info.
''' '''
def __init__(self, def __init__(
ajax_url, self, ajax_url, track_function, get_module, render_template,
track_function, replace_urls, xblock_model_data, user=None, filestore=None,
get_module, debug=False, xqueue=None, publish=None, node_path="",
render_template, anonymous_student_id='', course_id=None,
replace_urls, open_ended_grading_interface=None, s3_interface=None,
xblock_model_data, cache=None, can_execute_unsafe_code=None, replace_course_urls=None,
user=None, replace_jump_to_id_urls=None):
filestore=None,
debug=False,
xqueue=None,
publish=None,
node_path="",
anonymous_student_id='',
course_id=None,
open_ended_grading_interface=None,
s3_interface=None,
cache=None,
can_execute_unsafe_code=None,
replace_course_urls=None,
replace_jump_to_id_urls=None
):
''' '''
Create a closure around the system environment. Create a closure around the system environment.
......
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