Commit ed40affe by Braden MacDonald Committed by GitHub

Merge pull request #31 from msaqib52/master

Add student_view_data to poll and survey xblock
parents 7ba819b9 9db6b11d
......@@ -250,3 +250,153 @@ tx pull -f --mode=reviewed -l en,ar,es_419,fr,he,hi,ko_KR,pt_BR,ru,zh_CN
```
[transifex-client]: https://docs.transifex.com/client/installing-the-client
## API for native mobile frontends
**Retrieve fixed data for all poll/survey XBlocks in a course:**
```
GET https://<lms_server_url>/api/courses/v1/blocks/?course_id=<course_id>&username=<username>&depth=all&requested_fields=student_view_data
```
Example poll return value:
```
"student_view_data": {
"question": "Did the explanation above make sense to you?",
"answers": [
[
"R",
{
"img_alt": "",
"img": "",
"label": "Yes, completely"
}
],
[
"B",
{
"img_alt": "",
"img": "",
"label": "Yes, for the most part"
}
],
[
"G",
{
"img_alt": "",
"img": "",
"label": "Not really"
}
],
[
"O",
{
"img_alt": "",
"img": "",
"label": "Not at all"
}
]
]
},
```
Example survey return value:
```
"student_view_data": {
"answers": [
[
"Y",
"Yes"
],
[
"N",
"No"
],
[
"M",
"Maybe"
],
[
"1464806559402",
"Unsure"
]
],
"questions": [
[
"enjoy",
{
"img_alt": "",
"img": "",
"label": "Do you think you will use Polls in your course?"
}
],
[
"recommend",
{
"img_alt": "",
"img": "",
"label": "Do you think you will use Surveys in your course?"
}
],
[
"learn",
{
"img_alt": "",
"img": "",
"label": "Do you think the ability to query students is useful?"
}
],
[
"1464806513240",
{
"img_alt": "",
"img": "",
"label": "Do you like taking Polls and/or Surveys?"
}
]
]
},
```
**Retrieve current poll tally and current user's vote**
```
GET https://<lms_server_url>/courses/<course_id>/xblock/<poll_xblock_id>/handler/student_view_user_state
```
Example return value:
```
{"tally": {"B": 0, "R": 1, "O": 0, "G": 0}, "submissions_count": 1, "choice": "R"}
```
**Retrieve current survey tally and current user's vote**
```
GET https://<lms_server_url>/courses/<course_id>/xblock/<survey_xblock_id>/handler/student_view_user_state
```
Example return value:
```
{
"tally":{
"enjoy":{
"Y":1,
"M":0,
"N":0
},
"learn":{
"Y":0,
"M":1,
"N":0
},
"recommend":{
"Y":0,
"M":0,
"N":1
}
},
"submissions_count":1,
"choices":{
"enjoy":"Y",
"recommend":"N",
"learn":"M"
}
}
```
# pylint: disable=too-many-lines
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 McKinsey Academy
......@@ -20,12 +21,10 @@
# along with this program in a file in the toplevel directory called
# "AGPLv3". If not, see <http://www.gnu.org/licenses/>.
#
from collections import OrderedDict
import functools
import json
from django.template import Template, Context
from markdown import markdown
import pkg_resources
from webob import Response
......@@ -41,6 +40,7 @@ from .utils import _
try:
# pylint: disable=import-error
from django.conf import settings
from django.template import Template, Context
from api_manager.models import GroupProfile
HAS_GROUP_PROFILE = True
except ImportError:
......@@ -133,7 +133,7 @@ class PollBase(XBlock, ResourceMixin, PublishEventMixin):
"""
if hasattr(self, 'location'):
return self.location.html_id() # pylint: disable=no-member
else:
return unicode(self.scope_ids.usage_id)
def img_alt_mandatory(self):
......@@ -393,7 +393,7 @@ class PollBlock(PollBase):
"""
if self.choice and self.choice in dict(self.answers):
return self.choice
else:
return None
def student_view(self, context=None):
......@@ -434,6 +434,33 @@ class PollBlock(PollBase):
context, "public/html/poll.html", "public/css/poll.css",
"public/js/poll.js", "PollBlock")
def student_view_data(self, context=None):
"""
Returns a JSON representation of the poll Xblock, that can be retrieved
using Course Block API.
"""
return {
'question': self.question,
'answers': self.answers,
}
@XBlock.handler
def student_view_user_state(self, data, suffix=''):
"""
Returns a JSON representation of the student data for Poll Xblock
"""
response = {
'choice': self.get_choice(),
'tally': self.tally,
'submissions_count': self.submissions_count,
}
return Response(
json.dumps(response),
content_type='application/json',
charset='utf8'
)
def studio_view(self, context=None):
if not context:
context = {}
......@@ -664,6 +691,33 @@ class SurveyBlock(PollBase):
context, "public/html/survey.html", "public/css/poll.css",
"public/js/poll.js", "SurveyBlock")
def student_view_data(self, context=None):
"""
Returns a JSON representation of survey XBlock, that can be retrieved
using Course Block API.
"""
return {
'questions': self.questions,
'answers': self.answers,
}
@XBlock.handler
def student_view_user_state(self, data, suffix=''):
"""
Returns a JSON representation of the student data for Survey Xblock
"""
response = {
'choices': self.get_choices(),
'tally': self.tally,
'submissions_count': self.submissions_count,
}
return Response(
json.dumps(response),
content_type='application/json',
charset='utf8'
)
def renderable_answers(self, questions, choices):
"""
Render markdown for questions, and annotate with answers
......
......@@ -44,7 +44,7 @@ def package_data(pkg, roots):
setup(
name='xblock-poll',
version='1.2.7',
version='1.3.0',
description='An XBlock for polling users.',
packages=[
'poll',
......
import unittest
import json
from xblock.field_data import DictFieldData
from poll.poll import PollBlock, SurveyBlock
from ..utils import MockRuntime, make_request
class TestPollBlock(unittest.TestCase):
"""
Tests for XBlock Poll.
"""
def setUp(self):
"""
Test case setup
"""
super(TestPollBlock, self).setUp()
self.runtime = MockRuntime()
self.poll_data = {
'display_name': 'My Poll',
'question': 'What is your favorite color?',
'answers': [
['R', {'label': 'Red'}],
['B', {'label': 'Blue'}],
['G', {'label': 'Green'}],
['O', {'label': 'Other'}],
],
'submissions_count': 5,
}
self.poll_block = PollBlock(
self.runtime,
DictFieldData(self.poll_data),
None
)
def test_student_view_data(self):
"""
Test the student_view_data results.
"""
expected_poll_data = {
'question': self.poll_data['question'],
'answers': self.poll_data['answers'],
}
student_view_data = self.poll_block.student_view_data()
self.assertEqual(student_view_data, expected_poll_data)
def test_student_view_user_state_handler(self):
"""
Test the student_view_user_state handler results.
"""
response = json.loads(
self.poll_block.handle(
'student_view_user_state',
make_request('', method='GET')
).body
)
expected_response = {
u'choice': None,
u'submissions_count': 5,
u'tally': {'R': 0, 'B': 0, 'G': 0, 'O': 0},
}
self.assertEqual(response, expected_response)
class TestSurveyBlock(unittest.TestCase):
"""
Tests for XBlock Survey.
"""
def setUp(self):
"""
Test case setup
"""
super(TestSurveyBlock, self).setUp()
self.runtime = MockRuntime()
self.survery_data = {
'display_name': 'My Survey',
'questions': [
['enjoy', {'label': 'Are you enjoying the course?'}],
['recommend', {'label': 'Would you recommend this course to your friends?'}],
['learn', {'label': 'Do you think you will learn a lot?'}]
],
'answers': [
['Y', 'Yes'],
['N', 'No'],
['M', 'Maybe']
],
'submissions_count': 5
}
self.survey_block = SurveyBlock(
self.runtime,
DictFieldData(self.survery_data),
None
)
def test_student_view_data(self):
"""
Test the student_view_data results.
"""
expected_survery_data = {
'questions': self.survery_data['questions'],
'answers': self.survery_data['answers'],
}
student_view_data = self.survey_block.student_view_data()
self.assertEqual(student_view_data, expected_survery_data)
def test_student_view_user_state_handler(self):
"""
Test the student_view_user_state handler results.
"""
response = json.loads(
self.survey_block.handle(
'student_view_user_state',
make_request('', method='GET')
).body
)
expected_response = {
u'choices': None,
u'submissions_count': 5,
u'tally': {
u'enjoy': {u'M': 0, u'N': 0, u'Y': 0},
u'learn': {u'M': 0, u'N': 0, u'Y': 0},
u'recommend': {u'M': 0, u'N': 0, u'Y': 0},
},
}
self.assertEqual(response, expected_response)
# Test mocks and helpers
from webob import Request
from xblock.runtime import DictKeyValueStore, KvsFieldData
from xblock.test.tools import TestRuntime
def make_request(body, method='POST'):
"""
Helper method to make request
"""
request = Request.blank('/')
request.body = body.encode('utf-8')
request.method = method
return request
# pylint: disable=abstract-method
class MockRuntime(TestRuntime):
"""
Provides a mock XBlock runtime object.
"""
def __init__(self, **kwargs):
field_data = kwargs.get('field_data', KvsFieldData(DictKeyValueStore()))
super(MockRuntime, self).__init__(field_data=field_data)
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