Commit 468a2c86 by E. Kolpakov

AnswerMixin student_view_user_state override + tests

parent 89da0f43
......@@ -32,7 +32,7 @@ from xblock.validation import ValidationMessage
from xblockutils.resources import ResourceLoader
from xblockutils.studio_editable import StudioEditableXBlockMixin, XBlockWithPreviewMixin
from problem_builder.sub_api import SubmittingXBlockMixin, sub_api
from .mixins import QuestionMixin, XBlockWithTranslationServiceMixin
from .mixins import QuestionMixin, XBlockWithTranslationServiceMixin, StudentViewUserStateMixin
import uuid
......@@ -49,7 +49,7 @@ def _(text):
# Classes ###########################################################
class AnswerMixin(XBlockWithPreviewMixin, XBlockWithTranslationServiceMixin):
class AnswerMixin(XBlockWithPreviewMixin, XBlockWithTranslationServiceMixin, StudentViewUserStateMixin):
"""
Mixin to give an XBlock the ability to read/write data to the Answers DB table.
"""
......@@ -115,6 +115,20 @@ class AnswerMixin(XBlockWithPreviewMixin, XBlockWithTranslationServiceMixin):
if not data.name:
add_error(u"A Question ID is required.")
def student_view_user_state(self, context=None):
"""
Returns a JSON representation of the student data of this XBlock,
retrievable from the Course Block API.
"""
result = super(AnswerMixin, self).student_view_user_state(context)
answer_data = self.get_model_object()
result["answer_data"] = {
"student_input": answer_data.student_input,
"created_on": answer_data.created_on,
"modified_on": answer_data.modified_on,
}
return result
@XBlock.needs("i18n")
class AnswerBlock(SubmittingXBlockMixin, AnswerMixin, QuestionMixin, StudioEditableXBlockMixin, XBlock):
......
from lazy import lazy
from xblock.core import XBlock
from xblock.fields import String, Boolean, Float, Scope, UNIQUE_ID
from xblock.fragment import Fragment
from xblockutils.helpers import child_isinstance
......@@ -180,21 +179,28 @@ class NoSettingsMixin(object):
class StudentViewUserStateMixin(object):
"""
Mixin to provide student_view_user_state view
"""
NESTED_BLOCKS_KEY = "components"
INCLUDE_SCOPES = (Scope.user_state, Scope.user_info, Scope.preferences)
def student_user_view_user_state(self, context=None):
def student_view_user_state(self, context=None):
"""
Returns a JSON representation of the student data of this XBlock,
retrievable from the Course Block API.
"""
result = {}
for _, field in self.fields.iteritems():
if field.scope in self.INCLUDE_SCOPES:
result[field.name] = field.read_from(self)
if self.has_children:
if getattr(self, "has_children", False):
components = []
for child_id in self.children:
child = self.runtime.get_block(child_id)
if hasattr(child, 'student_user_view_user_state'):
components.append(child.student_user_view_user_state(context))
if hasattr(child, 'student_view_user_state'):
components.append(child.student_view_user_state(context))
result[self.NESTED_BLOCKS_KEY] = components
......
......@@ -3,6 +3,8 @@ Unit tests for AnswerMixin.
"""
import unittest
from collections import namedtuple
from datetime import datetime
from django.utils.crypto import get_random_string
from problem_builder.answer import AnswerMixin
......@@ -28,6 +30,8 @@ class TestAnswerMixin(unittest.TestCase):
answer_mixin = AnswerMixin()
answer_mixin.name = name
answer_mixin.runtime = self.FakeRuntime(course_id, student_id)
answer_mixin.fields = {}
answer_mixin.has_children = False
return answer_mixin
def test_creates_model_instance(self):
......@@ -57,3 +61,26 @@ class TestAnswerMixin(unittest.TestCase):
answer_mixin = self.make_answer_mixin(course_id=course_id)
model = answer_mixin.get_model_object()
self.assertEqual(model.course_key, course_id)
def test_student_view_user_state(self):
name = 'test-course-key-2'
existing_model = Answer(
name=name,
student_id=self.anonymous_student_id,
course_key=self.course_id,
student_input="Test",
created_on=datetime(2017, 1, 2, 3, 4, 5),
modified_on=datetime(2017, 7, 8, 9, 10, 11),
)
existing_model.save()
answer_mixin = self.make_answer_mixin(name=name)
student_view_user_state = answer_mixin.student_view_user_state()
expected_user_state_data = {
"answer_data": {
"student_input": existing_model.student_input,
"created_on": existing_model.created_on,
"modified_on": existing_model.modified_on,
}
}
self.assertEqual(student_view_user_state, expected_user_state_data)
......@@ -76,7 +76,7 @@ class TestStudentViewUserStateMixin(unittest.TestCase):
def test_no_user_state_returns_empty(self):
block = self._build_block(XBlockWithNoUserState, {"scope_settings": "qwe", "scope_content": "ASD"})
self.assertEqual(block.student_user_view_user_state(), {})
self.assertEqual(block.student_view_user_state(), {})
def test_no_child_blocks_with_user_state(self):
user_fields = {
......@@ -91,13 +91,13 @@ class TestStudentViewUserStateMixin(unittest.TestCase):
block_fields = self._merge_dicts(user_fields, other_fields)
block = self._build_block(XBlockNoChildrenWithUserState, block_fields)
self.assertEqual(block.student_user_view_user_state(), user_fields)
self.assertEqual(block.student_view_user_state(), user_fields)
def test_children_empty_no_user_state(self):
block = self._build_block(XBlockChildrenNoUserState, {"scope_settings": "qwe", "scope_content": "ASD"})
self.assertEqual(block.children, []) # precondition
self.assertEqual(block.student_user_view_user_state(), {"components": []})
self.assertEqual(block.student_view_user_state(), {"components": []})
def test_children_no_user_state(self):
block = self._build_block(XBlockChildrenNoUserState, {"scope_settings": "qwe", "scope_content": "ASD"})
......@@ -111,7 +111,7 @@ class TestStudentViewUserStateMixin(unittest.TestCase):
self.assertEqual(self._runtime.get_block("child1"), no_user_state1)
self.assertEqual(self._runtime.get_block("child2"), no_user_state2)
student_user_state = block.student_user_view_user_state()
student_user_state = block.student_view_user_state()
expected = {"components": [{}, {}]}
self.assertEqual(student_user_state, expected)
......@@ -146,7 +146,7 @@ class TestStudentViewUserStateMixin(unittest.TestCase):
self.assertEqual(self._runtime.get_block("child1"), user_state1)
self.assertEqual(self._runtime.get_block("child2"), user_state2)
student_user_state = block.student_user_view_user_state()
student_user_state = block.student_view_user_state()
expected = {"components": [user_fields1, user_fields2]}
self.assertEqual(student_user_state, expected)
......@@ -181,7 +181,7 @@ class TestStudentViewUserStateMixin(unittest.TestCase):
self.assertEqual(block.children, nested.keys())
self.assertEqual(self._runtime.get_block("child1"), user_state)
student_user_state = block.student_user_view_user_state()
student_user_state = block.student_view_user_state()
expected = user_fields.copy()
expected["components"] = [nested_user_fields]
......
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