Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure old problems work on new version. #98

Merged
merged 2 commits into from
Aug 30, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
53 changes: 30 additions & 23 deletions drag_and_drop_v2/drag_and_drop_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -638,25 +638,11 @@ def _expand_static_url(self, url):
def _get_user_state(self):
""" Get all user-specific data, and any applicable feedback """
item_state = self._get_item_state()
for item_id, item in item_state.iteritems():
# If information about zone is missing
# (because problem was completed before a11y enhancements were implemented),
# deduce zone in which item is placed from definition:
if item.get('zone') is None:
valid_zones = self._get_item_zones(int(item_id))
if valid_zones:
# If we get to this point, then the item was placed prior to support for
# multiple correct zones being added. As a result, it can only be correct
# on a single zone, and so we can trust that the item was placed on the
# zone with index 0.
item['zone'] = valid_zones[0]
else:
item['zone'] = 'unknown'

# In assessment mode, if item is placed correctly and than the page is refreshed, "correct"
# will spill to the frontend, making item "disabled", thus allowing students to obtain answer by trial
# and error + refreshing the page. In order to avoid that, we remove "correct" from an item here
if self.mode == self.ASSESSMENT_MODE:
# In assessment mode, if item is placed correctly and than the page is refreshed, "correct"
# will spill to the frontend, making item "disabled", thus allowing students to obtain answer by trial
# and error + refreshing the page. In order to avoid that, we remove "correct" from an item here
Copy link
Contributor

Choose a reason for hiding this comment

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

@mtyaka @mtyaka Typo: "than" should be "then"

And I know you just copied an existing comment, but I'm not sure what

making item "disabled", thus allowing students to obtain answer by trial and error ...

means (esp. the first part)? It would be great if you could clarify :)

if self.mode == self.ASSESSMENT_MODE:
for item in item_state.values():
del item["correct"]

overall_feedback_msgs, __ = self._get_feedback()
Expand All @@ -682,11 +668,32 @@ def _get_item_state(self):
# handler and manipulated there to hide correctness of items placed
Copy link
Contributor

Choose a reason for hiding this comment

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

@mtyaka "... and the data it returns is manipulated there ..."?

(Again, this is an existing comment, but since there's a lot going on in this code I think it's worth being precise in any comments that explain what's going on.)

state = {}

for item_id, item in self.item_state.iteritems():
if isinstance(item, dict):
state[item_id] = item.copy() # items are manipulated in _get_user_state, so we protect actual data
for item_id, raw_item in self.item_state.iteritems():
if isinstance(raw_item, dict):
# Items are manipulated in _get_user_state, so we protect actual data.
item = copy.deepcopy(raw_item)
else:
state[item_id] = {'top': item[0], 'left': item[1]}
item = {'top': raw_item[0], 'left': raw_item[1]}
# If information about zone is missing
# (because problem was completed before a11y enhancements were implemented),
# deduce zone in which item is placed from definition:
if item.get('zone') is None:
valid_zones = self._get_item_zones(int(item_id))
if valid_zones:
# If we get to this point, then the item was placed prior to support for
# multiple correct zones being added. As a result, it can only be correct
# on a single zone, and so we can trust that the item was placed on the
# zone with index 0.
item['zone'] = valid_zones[0]
else:
item['zone'] = 'unknown'
# If correctness information is missing
# (because problem was completed before assessment mode was implemented),
# assume the item is in correct zone (in standard mode, only items placed
# into correct zone are stored in item state).
if item.get('correct') is None:
item['correct'] = True
state[item_id] = item

return state

Expand Down
28 changes: 28 additions & 0 deletions tests/unit/test_basics.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,34 @@ def assert_user_state_empty():
self.assertTrue(self.block.completed)
assert_user_state_empty()

def test_legacy_state_support(self):
"""
The form of items stored in user item_state has changed several times.
This test makes sure that legacy forms are properly converted to compatible format.
"""
self.assertEqual(self.block.item_state, {})
self.assertEqual(self.call_handler('get_user_state')['items'], {})

self.block.item_state = {
# Legacy tuple (top, left) representation.
'0': [60, 20],
# Legacy dict with absolute values and no correctness or zone info.
'1': {'top': 45, 'left': 99},
# Legacy dict with no correctness info.
'2': {'x_percent': '99%', 'y_percent': '95%', 'zone': BOTTOM_ZONE_ID},
# Current dict form.
'3': {'x_percent': '67%', 'y_percent': '80%', 'zone': BOTTOM_ZONE_ID, 'correct': False},
}
self.block.save()

self.assertEqual(self.call_handler('get_user_state')['items'], {
# Legacy top/left values are converted to x/y percentage on the client.
'0': {'top': 60, 'left': 20, 'correct': True, 'zone': TOP_ZONE_ID},
'1': {'top': 45, 'left': 99, 'correct': True, 'zone': MIDDLE_ZONE_ID},
'2': {'x_percent': '99%', 'y_percent': '95%', 'correct': True, 'zone': BOTTOM_ZONE_ID},
'3': {'x_percent': '67%', 'y_percent': '80%', 'correct': False, "zone": BOTTOM_ZONE_ID},
})

def test_studio_submit(self):
body = {
'display_name': "Test Drag & Drop",
Expand Down