diff --git a/common/lib/xmodule/setup.py b/common/lib/xmodule/setup.py index b3a8dabe1bf8a885667341acc1b25dc5ce9623b5..a405d111be03a74e5bf9c7e7f9e67f066d881abf 100644 --- a/common/lib/xmodule/setup.py +++ b/common/lib/xmodule/setup.py @@ -39,7 +39,8 @@ setup( "course_info = xmodule.html_module:CourseInfoDescriptor", "static_tab = xmodule.html_module:StaticTabDescriptor", "custom_tag_template = xmodule.raw_module:RawDescriptor", - "about = xmodule.html_module:AboutDescriptor" + "about = xmodule.html_module:AboutDescriptor", + "poll = xmodule.poll_module:PollDescriptor", ], } ) diff --git a/common/lib/xmodule/xmodule/js/src/poll/display.coffee b/common/lib/xmodule/xmodule/js/src/poll/display.coffee new file mode 100644 index 0000000000000000000000000000000000000000..f72ac8d3199f63801d3a1866832b64d53a5eedd5 --- /dev/null +++ b/common/lib/xmodule/xmodule/js/src/poll/display.coffee @@ -0,0 +1,13 @@ +class @PollModule + constructor: (element) -> + @el = element + @ajaxUrl = @$('.container').data('url') + @$('.upvote').on('click', () => $.postWithPrefix(@url('upvote'), @handleVote)) + @$('.downvote').on('click', () => $.postWithPrefix(@url('downvote'), @handleVote)) + + $: (selector) -> $(selector, @el) + + url: (target) -> "#{@ajaxUrl}/#{target}" + + handleVote: (response) => + @$('.container').replaceWith(response.results) \ No newline at end of file diff --git a/common/lib/xmodule/xmodule/poll_module.py b/common/lib/xmodule/xmodule/poll_module.py new file mode 100644 index 0000000000000000000000000000000000000000..db0b3fd0c42b73ffa21c47aaf0842fd79f29a3d4 --- /dev/null +++ b/common/lib/xmodule/xmodule/poll_module.py @@ -0,0 +1,54 @@ +import json +import logging + +from lxml import etree +from pkg_resources import resource_string, resource_listdir + +from xmodule.x_module import XModule +from xmodule.raw_module import RawDescriptor +from .model import Int, Scope, Boolean + +log = logging.getLogger(__name__) + + +class PollModule(XModule): + + js = {'coffee': [resource_string(__name__, 'js/src/poll/display.coffee')]} + js_module_name = "PollModule" + + upvotes = Int(help="Number of upvotes this poll has recieved", scope=Scope.content, default=0) + downvotes = Int(help="Number of downvotes this poll has recieved", scope=Scope.content, default=0) + voted = Boolean(help="Whether this student has voted on the poll", scope=Scope.student_state, default=False) + + def handle_ajax(self, dispatch, get): + ''' + Handle ajax calls to this video. + TODO (vshnayder): This is not being called right now, so the position + is not being saved. + ''' + if self.voted: + return json.dumps({'error': 'Already Voted!'}) + elif dispatch == 'upvote': + self.upvotes += 1 + self.voted = True + return json.dumps({'results': self.get_html()}) + elif dispatch == 'downvote': + self.downvotes += 1 + self.voted = True + return json.dumps({'results': self.get_html()}) + + return json.dumps({'error': 'Unknown Command!'}) + + def get_html(self): + return self.system.render_template('poll.html', { + 'upvotes': self.upvotes, + 'downvotes': self.downvotes, + 'voted': self.voted, + 'ajax_url': self.system.ajax_url, + }) + + +class PollDescriptor(RawDescriptor): + module_class = PollModule + stores_state = True + template_dir_name = "poll" \ No newline at end of file diff --git a/common/test/data/toy/course/2012_Fall.xml b/common/test/data/toy/course/2012_Fall.xml index 46dba8b8d8ab9621acb4f513d8c4d40981afe63d..31244ef60c1bee184e4b6f2404853512001ddec4 100644 --- a/common/test/data/toy/course/2012_Fall.xml +++ b/common/test/data/toy/course/2012_Fall.xml @@ -3,6 +3,7 @@ <videosequence url_name="Toy_Videos"> <html url_name="secret:toylab"/> <video url_name="Video_Resources" youtube="1.0:1bK-WdDi6Qw"/> + <poll url_name="test_poll" display_name="Test Poll"/> </videosequence> <video url_name="Welcome" youtube="1.0:p2Q6BrNhdh8"/> <video url_name="video_123456789012" youtube="1.0:p2Q6BrNhdh8"/> diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 04dee7de0fb1af076fa69be4917ba953dcddff05..c2a8db0fabe4182553162228d4ae9867c2d51aec 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -231,6 +231,18 @@ def _get_module(user, request, location, student_module_cache, course_id, positi student_module.max_grade = event.get('max_value') student_module.save() + #Bin score into range and increment stats + score_bucket = get_score_bucket(student_module.grade, student_module.max_grade) + org, course_num, run = course_id.split("/") + statsd.increment("lms.courseware.question_answered", + tags=["org:{0}".format(org), + "course:{0}".format(course_num), + "run:{0}".format(run), + "score_bucket:{0}".format(score_bucket), + "type:ajax"]) + + + # TODO (cpennington): When modules are shared between courses, the static # prefix is going to have to be specific to the module, not the directory # that the xml was loaded from diff --git a/lms/templates/poll.html b/lms/templates/poll.html new file mode 100644 index 0000000000000000000000000000000000000000..6ae2af50d1d288bcba0f8d00be26512befac70c8 --- /dev/null +++ b/lms/templates/poll.html @@ -0,0 +1,9 @@ +<div class='container' data-url="${ajax_url}"> +% if voted: + <div>Upvotes: ${upvotes}</div> + <div>Downvotes: ${downvotes}</div> +% else: + <a class="upvote">Yes</a> + <a class="downvote">No</a> +% endif +</div> \ No newline at end of file