Commit 275ee7a9 by Jonathan Piacenti

Further refinement and test stubs added.

parent db084466
"""TO-DO: Write a description of what this XBlock is."""
from collections import OrderedDict
import bleach
from django.template import Template, Context
from markdown import markdown
import pkg_resources
from xblock.core import XBlock
from xblock.fields import Scope, List, String, Dict
from xblock.fragment import Fragment
from xblockutils.resources import ResourceLoader
ALLOWED_TAGS = {
'h1': [], 'h2': [], 'h3': [], 'h4': [], 'h5': [], 'h6': [],
'a': ['target', 'href', 'class'], 'strong': [], 'em': [], 'blockquote': [],
'pre': [], 'li': [], 'ul': [], 'ol': [], 'code': ['class'], 'p': [],
}
def process_markdown(raw_text):
return bleach.clean(markdown(raw_text), tags=ALLOWED_TAGS, strip_comments=False)
from .utils import process_markdown
class PollBlock(XBlock):
......@@ -35,12 +24,14 @@ class PollBlock(XBlock):
('Other', 'Other')),
scope=Scope.settings, help="The question on this poll."
)
feedback = String(help="Text to display after the user votes.")
feedback = String(default='', help="Text to display after the user votes.")
tally = Dict(default={'Red': 0, 'Blue': 0, 'Green': 0, 'Other': 0},
scope=Scope.user_state_summary,
help="Total tally of answers from students.")
choice = String(scope=Scope.user_state, help="The student's answer")
loader = ResourceLoader(__name__)
def resource_string(self, path):
"""Handy helper for getting resources from our kit."""
data = pkg_resources.resource_string(__name__, path)
......@@ -49,7 +40,6 @@ class PollBlock(XBlock):
@XBlock.json_handler
def get_results(self, data, suffix=''):
detail, total = self.tally_detail()
print process_markdown(self.feedback)
return {
'question': process_markdown(self.question), 'tally': detail,
'total': total, 'feedback': process_markdown(self.feedback),
......@@ -117,14 +107,13 @@ class PollBlock(XBlock):
choice = self.get_choice()
print bleach.ALLOWED_ATTRIBUTES
context.update({
'choice': choice,
# Offset so choices will always be True.
'answers': self.answers,
'question': process_markdown(self.question),
'feedback': process_markdown(self.feedback),
# Mustache is treating an empty string as true.
'feedback': process_markdown(self.feedback) or False,
'js_template': js_template,
})
......
......@@ -67,4 +67,5 @@ li.poll-result {
.poll-footnote {
margin-top: 1em;
margin-bottom: 1em;
font-size: smaller;
}
\ No newline at end of file
......@@ -4,7 +4,7 @@
{{#each tally}}
<li class="poll-result">
<div class="poll-result-input-container">
<input id="answer-{{key}}" type="radio" disabled {{#choice}}checked="True"{{/choice}} />
<input id="answer-{{key}}" type="radio" disabled {{#if choice}}checked="True"{{/if}} />
</div>
<div class="percentage-gauge-container">
<div class="percentage-gauge" style="width:{{percent}}%;">
......@@ -12,7 +12,7 @@
</div>
</div>
<div class="poll-percent-container">
<span class="poll-percent-display{{#top}} poll-top-choice{{/top}}">{{percent}}%</span>
<span class="poll-percent-display{{#if top}} poll-top-choice{{/if}}">{{percent}}%</span>
</div>
</li>
{{^last}}
......@@ -22,11 +22,11 @@
{{/each}}
</ul>
<input type="submit" name="poll-submit" onclick="return false;" value="Submit" disabled>
<div class="poll-footnote"><small>Results gathered from {{total}} respondent(s).</small></div>
{{#feedback}}
<div class="poll-footnote">Results gathered from {{total}} respondent(s).</div>
{{#if feedback}}
<hr />
<div class="poll-feedback">
{{{this}}}
{{{feedback}}}
</div>
{{/feedback}}
{{/if}}
</script>
\ No newline at end of file
import bleach
from markdown import markdown
ALLOWED_TAGS = {
'h1': [], 'h2': [], 'h3': [], 'h4': [], 'h5': [], 'h6': [],
'a': ['target', 'href', 'class'], 'strong': [], 'em': [], 'blockquote': [],
'pre': [], 'li': [], 'ul': [], 'ol': [], 'code': ['class'], 'p': [],
}
def process_markdown(raw_text):
return bleach.clean(markdown(raw_text), tags=ALLOWED_TAGS, strip_comments=False)
\ No newline at end of file
-e .
bleach
markdown
-e git+https://github.com/edx-solutions/xblock-utils.git#egg=xblock-utils
\ No newline at end of file
......@@ -21,15 +21,19 @@ def package_data(pkg, roots):
setup(
name='poll-xblock',
name='xblock-poll',
version='0.1',
description='poll XBlock', # TODO: write a better description.
description='An XBlock for polling users.',
packages=[
'poll',
],
install_requires=[
'XBlock',
'markdown',
'bleach',
'xblock-utils',
],
dependency_links=['http://github.com/edx-solutions/xblock-utils/tarball/master#egg=xblock-utils'],
entry_points={
'xblock.v1': [
'poll = poll:PollBlock',
......
"""
Tests to verify a default poll XBlock is a functional demo.
Deeper investigation should be tested in test_poll_functions.
"""
from xblockutils.base_test import SeleniumBaseTest
class TestDefaults(SeleniumBaseTest):
def test_default_poll(self):
"""
Verifies that a default poll loads, that it can be voted on, and that
the tally displays afterward. Verifies that the feedback section does
not load since it is not enabled by default.
"""
\ No newline at end of file
"""
Tests to make sure that markdown is both useful and secure.
"""
from xblockutils.base_test import SeleniumBaseTest
class MarkdownTestCase(SeleniumBaseTest):
def test_question_markdown(self):
pass
def test_feedback_markdown(self):
pass
\ No newline at end of file
"""
Tests a realistic, configured Poll to make sure that everything works as it
should.
"""
from xblockutils.base_test import SeleniumBaseTest
class TestPollFunctions(SeleniumBaseTest):
def test_first_load(self):
"""
Checks first load.
Verify that the poll loads with the expected choices, that feedback is
not showing, that the submit button is disabled, and that it is enabled
when a choice is selected.
"""
def test_poll_submission(self):
"""
Verify that the user can submit his or her vote, that the vote
influences the tally, and that feedback is shown after the vote.
"""
def test_no_duplicate_vote(self):
"""
Verify that revisiting the page does not re-enable the submit button.
"""
def test_no_ballot_stuffing(self):
"""
Verify that the server rejects a well crafted attempt to force an
additional vote.
"""
\ No newline at end of file
<vertical_demo>
<poll url_name="defaults"/>
</vertical_demo>
\ No newline at end of file
<vertical_demo>
<poll url_name="markdown" question="## This is a test
&lt;h1&gt;This is only a &amp;gt;&amp;lt;test&lt;/h1&gt;
* One
* Two
* Three
1. First
2. Second.
3. Third
We shall find out if markdown is respected.
&gt; &quot;I have not yet begun to code.&quot;" feedback="### This is some feedback
[This is a link](http://www.example.com)
&lt;a href=&quot;http://www.example.com&quot; target=&quot;_blank&quot;&gt;This is also a link.&lt;/a&gt;
This is a paragraph with *emphasized* and **bold** text, and **_both_**." />
</vertical_demo>
\ No newline at end of file
<vertical_demo>
<poll url_name="poll_functions" question="## How long have you been studying with us?"
feedback="### Thank you&#10;&#10;for being a valued student."
tally="{'long': 0, 'short': 0, 'not_saying': 1}"
answers="[[u'long', u'A very long time.'], [u'short', u'Not very long'], [u'not_saying', u'I shall not say.']]"/>
</vertical_demo>
\ No newline at end of file
from unittest import TestCase
from poll.utils import process_markdown
class ProcessMarkdownTest(TestCase):
def test_markdown_escapes(self):
start_string = (
"""
## This is an H2.
<h3>This is an H3</h3>
<a href="http://example.com">This link should be preserved.</a>
[This link should be converted.](http://www.example.com)
This is a paragraph of text, despite being just one sentence.
&lt; This should be a less-than symbol.
< So should this, since it's not attached to anything.
> This is going to be a blockquote.
<script type="text/javascript">breakstuff();</script>
"""
)
end_string = (
"""<h2>This is an H2.</h2>
<h3>This is an H3</h3>
<p><a href="http://example.com">This link should be preserved.</a>
<a href="http://www.example.com">This link should be converted.</a></p>
<p>This is a paragraph of text, despite being just one sentence.</p>
<p>&lt; This should be a less-than symbol.</p>
<p>&lt; So should this, since it's not attached to anything.</p>
<blockquote>
<p>This is going to be a blockquote.</p>
</blockquote>
&lt;script type="text/javascript"&gt;breakstuff();&lt;/script&gt;"""
)
self.assertEqual(end_string, process_markdown(start_string))
\ No newline at end of file
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