Convert PollModule to PollBlock.

This commit is contained in:
Usman Khalid
2021-03-02 21:24:52 +05:00
committed by David Ormsbee
parent 60ef705944
commit 48290cf837
6 changed files with 85 additions and 54 deletions

View File

@@ -7,7 +7,6 @@ XMODULES = [
"customtag = xmodule.template_module:CustomTagDescriptor",
"discuss = xmodule.backcompat_module:TranslateCustomTagDescriptor",
"image = xmodule.backcompat_module:TranslateCustomTagDescriptor",
"poll_question = xmodule.poll_module:PollDescriptor",
"section = xmodule.backcompat_module:SemanticSectionDescriptor",
"slides = xmodule.backcompat_module:TranslateCustomTagDescriptor",
"videodev = xmodule.backcompat_module:TranslateCustomTagDescriptor",
@@ -29,6 +28,7 @@ XBLOCKS = [
"library_sourced = xmodule.library_sourced_block:LibrarySourcedBlock",
"lti = xmodule.lti_module:LTIBlock",
"nonstaff_error = xmodule.error_module:NonStaffErrorBlock",
"poll_question = xmodule.poll_module:PollBlock",
"problem = xmodule.capa_module:ProblemBlock",
"problemset = xmodule.seq_module:SequenceBlock",
"randomize = xmodule.randomize_module:RandomizeBlock",

View File

@@ -14,19 +14,38 @@ from collections import OrderedDict
from copy import deepcopy
from pkg_resources import resource_string
from web_fragments.fragment import Fragment
from lxml import etree
from openedx.core.djangolib.markup import Text, HTML
from xblock.fields import Boolean, Dict, List, Scope, String # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.mako_module import MakoModuleDescriptor
from xmodule.mako_module import MakoTemplateBlockBase
from xmodule.stringify import stringify_children
from xmodule.x_module import XModule
from xmodule.xml_module import XmlDescriptor
from xmodule.util.xmodule_django import add_webpack_to_fragment
from xmodule.x_module import (
HTMLSnippet,
ResourceTemplates,
shim_xmodule_js,
XModuleMixin,
XModuleDescriptorToXBlockMixin,
XModuleToXBlockMixin,
)
from xmodule.xml_module import XmlMixin
log = logging.getLogger(__name__)
_ = lambda text: text
class PollFields(object): # lint-amnesty, pylint: disable=missing-class-docstring
class PollBlock(
MakoTemplateBlockBase,
XmlMixin,
XModuleDescriptorToXBlockMixin,
XModuleToXBlockMixin,
HTMLSnippet,
ResourceTemplates,
XModuleMixin,
): # pylint: disable=abstract-method
"""Poll Module"""
# Name of poll to use in links to this poll
display_name = String(
help=_("The display name for this component."),
@@ -61,18 +80,33 @@ class PollFields(object): # lint-amnesty, pylint: disable=missing-class-docstri
default=''
)
resources_dir = None
uses_xmodule_styles_setup = True
class PollModule(PollFields, XModule):
"""Poll Module"""
js = {
preview_view_js = {
'js': [
resource_string(__name__, 'js/src/javascript_loader.js'),
resource_string(__name__, 'js/src/poll/poll.js'),
resource_string(__name__, 'js/src/poll/poll_main.js')
]
],
'xmodule_js': resource_string(__name__, 'js/src/xmodule.js'),
}
preview_view_css = {
'scss': [
resource_string(__name__, 'css/poll/display.scss')
],
}
# There is no studio_view() for this XBlock but this is needed to make the
# the static_content command happy.
studio_view_js = {
'js': [],
'xmodule_js': resource_string(__name__, 'js/src/xmodule.js')
}
studio_view_css = {
'scss': []
}
css = {'scss': [resource_string(__name__, 'css/poll/display.scss')]}
js_module_name = "Poll"
def handle_ajax(self, dispatch, data): # lint-amnesty, pylint: disable=unused-argument
"""Ajax handler.
@@ -103,7 +137,7 @@ class PollModule(PollFields, XModule):
'total': sum(self.poll_answers.values())
})
elif dispatch == 'reset_poll' and self.voted and \
self.descriptor.xml_attributes.get('reset', 'True').lower() != 'false':
self.xml_attributes.get('reset', 'True').lower() != 'false':
self.voted = False
# FIXME: fix this, when xblock will support mutable types.
@@ -117,16 +151,21 @@ class PollModule(PollFields, XModule):
else: # return error message
return json.dumps({'error': 'Unknown Command!'})
def get_html(self):
"""Renders parameters to template."""
def student_view(self, _context):
"""
Renders the student view.
"""
fragment = Fragment()
params = {
'element_id': self.location.html_id(),
'element_class': self.location.block_type,
'ajax_url': self.system.ajax_url,
'ajax_url': self.ajax_url,
'configuration_json': self.dump_poll(),
}
self.content = self.system.render_template('poll.html', params) # lint-amnesty, pylint: disable=attribute-defined-outside-init
return self.content
fragment.add_content(self.system.render_template('poll.html', params))
add_webpack_to_fragment(fragment, 'PollBlockPreview')
shim_xmodule_js(fragment, 'Poll')
return fragment
def dump_poll(self):
"""Dump poll information.
@@ -160,17 +199,12 @@ class PollModule(PollFields, XModule):
'poll_answer': self.poll_answer,
'poll_answers': self.poll_answers if self.voted else {},
'total': sum(self.poll_answers.values()) if self.voted else 0,
'reset': str(self.descriptor.xml_attributes.get('reset', 'true')).lower()
'reset': str(self.xml_attributes.get('reset', 'true')).lower()
})
class PollDescriptor(PollFields, MakoModuleDescriptor, XmlDescriptor): # lint-amnesty, pylint: disable=missing-class-docstring
_tag_name = 'poll_question'
_child_tag_name = 'answer'
module_class = PollModule
resources_dir = None
@classmethod
def definition_from_xml(cls, xml_object, system):
"""Pull out the data into dictionary.

View File

@@ -26,6 +26,7 @@ from xmodule.conditional_module import ConditionalBlock
from xmodule.html_module import AboutBlock, CourseInfoBlock, HtmlBlock, StaticTabBlock
from xmodule.library_content_module import LibraryContentBlock
from xmodule.lti_module import LTIBlock
from xmodule.poll_module import PollBlock
from xmodule.seq_module import SequenceBlock
from xmodule.split_test_module import SplitTestBlock
from xmodule.word_cloud_module import WordCloudBlock
@@ -77,6 +78,7 @@ XBLOCK_CLASSES = [
HtmlBlock,
LibraryContentBlock,
LTIBlock,
PollBlock,
ProblemBlock,
SequenceBlock,
SplitTestBlock,

View File

@@ -191,29 +191,6 @@ class ModelsTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-cl
assert str(vc) == vc_str
class LogicTest(unittest.TestCase):
"""Base class for testing xmodule logic."""
descriptor_class = None
raw_field_data = {}
def setUp(self):
super(LogicTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
self.system = get_test_system()
self.descriptor = Mock(name="descriptor", url_name='', category='test')
self.xmodule_class = self.descriptor_class.module_class
usage_key = self.system.course_id.make_usage_key(self.descriptor.category, 'test_loc')
# ScopeIds has 4 fields: user_id, block_type, def_id, usage_id
scope_ids = ScopeIds(1, self.descriptor.category, usage_key, usage_key)
self.xmodule = self.xmodule_class(
self.descriptor, self.system, DictFieldData(self.raw_field_data), scope_ids
)
def ajax_request(self, dispatch, data):
"""Call Xmodule.handle_ajax."""
return json.loads(self.xmodule.handle_ajax(dispatch, data))
def map_references(value, field, actual_course_key):
"""
Map the references in value to actual_course_key and return value

View File

@@ -1,24 +1,42 @@
# -*- coding: utf-8 -*-
"""Test for Poll Xmodule functional logic."""
import json
import unittest
from mock import Mock
from xmodule.poll_module import PollDescriptor
from xblock.field_data import DictFieldData
from xblock.fields import ScopeIds
from xmodule.poll_module import PollBlock
from . import LogicTest
from . import get_test_system
from .test_import import DummySystem
class PollModuleTest(LogicTest):
class PollBlockTest(unittest.TestCase):
"""Logic tests for Poll Xmodule."""
descriptor_class = PollDescriptor
raw_field_data = {
'poll_answers': {'Yes': 1, 'Dont_know': 0, 'No': 0},
'voted': False,
'poll_answer': ''
}
def setUp(self):
super().setUp()
self.system = get_test_system()
usage_key = self.system.course_id.make_usage_key(PollBlock.category, 'test_loc')
# ScopeIds has 4 fields: user_id, block_type, def_id, usage_id
scope_ids = ScopeIds(1, PollBlock.category, usage_key, usage_key)
self.xmodule = PollBlock(
self.system, DictFieldData(self.raw_field_data), scope_ids
)
def ajax_request(self, dispatch, data):
"""Call Xmodule.handle_ajax."""
return json.loads(self.xmodule.handle_ajax(dispatch, data))
def test_bad_ajax_request(self):
# Make sure that answer for incorrect request is error json.
response = self.ajax_request('bad_answer', {})
@@ -52,7 +70,7 @@ class PollModuleTest(LogicTest):
</poll_question>
'''
output = PollDescriptor.from_xml(sample_poll_xml, module_system, id_generator)
output = PollBlock.from_xml(sample_poll_xml, module_system, id_generator)
# Update the answer with invalid character.
invalid_characters_poll_answer = output.answers[0]
# Invalid less-than character.

View File

@@ -34,7 +34,7 @@ from xmodule.annotatable_module import AnnotatableBlock
from xmodule.conditional_module import ConditionalBlock
from xmodule.course_module import CourseBlock
from xmodule.html_module import HtmlBlock
from xmodule.poll_module import PollDescriptor
from xmodule.poll_module import PollBlock
from xmodule.randomize_module import RandomizeBlock
from xmodule.seq_module import SequenceBlock
from xmodule.tests import get_test_descriptor_system, get_test_system
@@ -57,7 +57,7 @@ from xmodule.x_module import (
LEAF_XMODULES = {
AnnotatableBlock: [{}],
HtmlBlock: [{}],
PollDescriptor: [{'display_name': 'Poll Display Name'}],
PollBlock: [{'display_name': 'Poll Display Name'}],
WordCloudBlock: [{}],
}
@@ -76,7 +76,7 @@ CONTAINER_XMODULES = {
# These modules are not editable in studio yet
NOT_STUDIO_EDITABLE = (
PollDescriptor,
PollBlock,
)