From 67f30a476c11fd87101cbb4c8b58597ea9e2ee57 Mon Sep 17 00:00:00 2001 From: farhan Date: Fri, 3 Apr 2026 13:02:09 +0500 Subject: [PATCH 1/4] feat: Adds imagemodal, submit-and-compare & schoolyourself xblocks --- .gitignore | 3 + pyproject.toml | 9 + src/imagemodal/__init__.py | 4 + src/imagemodal/conf/locale/config.yaml | 4 + .../conf/locale/en/LC_MESSAGES/django.po | 62 ++++ .../conf/locale/en/LC_MESSAGES/text.po | 1 + src/imagemodal/mixins/__init__.py | 3 + src/imagemodal/mixins/fragment.py | 90 ++++++ src/imagemodal/mixins/scenario.py | 23 ++ src/imagemodal/models.py | 70 ++++ src/imagemodal/public/draggabilly.pkgd.min.js | 8 + src/imagemodal/public/view.css | 89 +++++ src/imagemodal/public/view.js | 170 ++++++++++ src/imagemodal/public/view.less | 110 +++++++ src/imagemodal/scenarios/image-modal-many.xml | 14 + .../scenarios/image-modal-single.xml | 7 + src/imagemodal/settings.py | 18 ++ src/imagemodal/templates/view.html | 34 ++ src/imagemodal/tests/__init__.py | 0 src/imagemodal/tests/test_display.py | 51 +++ src/imagemodal/tests/test_workbench.py | 49 +++ src/imagemodal/translations | 1 + src/imagemodal/views.py | 50 +++ src/imagemodal/xblocks.py | 20 ++ src/schoolyourself/__init__.py | 2 + src/schoolyourself/public/review_icon.png | Bin 0 -> 9131 bytes src/schoolyourself/public/sylib.css | 1 + src/schoolyourself/public/sylib.js | 7 + src/schoolyourself/schoolyourself.py | 232 +++++++++++++ src/schoolyourself/schoolyourself_lesson.py | 84 +++++ src/schoolyourself/schoolyourself_review.py | 170 ++++++++++ .../schoolyourself_review_test.py | 122 +++++++ .../static/css/student_view.css | 137 ++++++++ .../static/js/lesson_student_view.js | 8 + .../static/js/review_student_view.js | 61 ++++ src/schoolyourself/static/js/studio_view.js | 21 ++ .../templates/lesson_student_view.html | 15 + .../templates/review_student_view.html | 21 ++ src/schoolyourself/templates/studio_view.html | 57 ++++ src/submit_and_compare/__init__.py | 3 + .../conf/locale/config.yaml | 4 + src/submit_and_compare/mixins/__init__.py | 3 + src/submit_and_compare/mixins/dates.py | 34 ++ src/submit_and_compare/mixins/events.py | 67 ++++ src/submit_and_compare/mixins/fragment.py | 96 ++++++ src/submit_and_compare/mixins/scenario.py | 24 ++ src/submit_and_compare/models.py | 118 +++++++ src/submit_and_compare/public/edit.js | 36 +++ src/submit_and_compare/public/view.css | 65 ++++ src/submit_and_compare/public/view.js | 161 +++++++++ src/submit_and_compare/public/view.less | 67 ++++ .../scenarios/submit-and-compare-single.xml | 3 + src/submit_and_compare/settings.py | 16 + src/submit_and_compare/templates/edit.html | 78 +++++ src/submit_and_compare/templates/view.html | 37 +++ src/submit_and_compare/tests/__init__.py | 0 src/submit_and_compare/tests/test_all.py | 207 ++++++++++++ src/submit_and_compare/views.py | 306 ++++++++++++++++++ src/submit_and_compare/xblocks.py | 24 ++ 59 files changed, 3177 insertions(+) create mode 100644 src/imagemodal/__init__.py create mode 100644 src/imagemodal/conf/locale/config.yaml create mode 100644 src/imagemodal/conf/locale/en/LC_MESSAGES/django.po create mode 120000 src/imagemodal/conf/locale/en/LC_MESSAGES/text.po create mode 100644 src/imagemodal/mixins/__init__.py create mode 100644 src/imagemodal/mixins/fragment.py create mode 100644 src/imagemodal/mixins/scenario.py create mode 100644 src/imagemodal/models.py create mode 100644 src/imagemodal/public/draggabilly.pkgd.min.js create mode 100644 src/imagemodal/public/view.css create mode 100644 src/imagemodal/public/view.js create mode 100644 src/imagemodal/public/view.less create mode 100644 src/imagemodal/scenarios/image-modal-many.xml create mode 100644 src/imagemodal/scenarios/image-modal-single.xml create mode 100644 src/imagemodal/settings.py create mode 100644 src/imagemodal/templates/view.html create mode 100644 src/imagemodal/tests/__init__.py create mode 100644 src/imagemodal/tests/test_display.py create mode 100755 src/imagemodal/tests/test_workbench.py create mode 120000 src/imagemodal/translations create mode 100644 src/imagemodal/views.py create mode 100644 src/imagemodal/xblocks.py create mode 100644 src/schoolyourself/__init__.py create mode 100644 src/schoolyourself/public/review_icon.png create mode 100644 src/schoolyourself/public/sylib.css create mode 100644 src/schoolyourself/public/sylib.js create mode 100644 src/schoolyourself/schoolyourself.py create mode 100644 src/schoolyourself/schoolyourself_lesson.py create mode 100644 src/schoolyourself/schoolyourself_review.py create mode 100644 src/schoolyourself/schoolyourself_review_test.py create mode 100644 src/schoolyourself/static/css/student_view.css create mode 100644 src/schoolyourself/static/js/lesson_student_view.js create mode 100644 src/schoolyourself/static/js/review_student_view.js create mode 100644 src/schoolyourself/static/js/studio_view.js create mode 100644 src/schoolyourself/templates/lesson_student_view.html create mode 100644 src/schoolyourself/templates/review_student_view.html create mode 100644 src/schoolyourself/templates/studio_view.html create mode 100644 src/submit_and_compare/__init__.py create mode 100644 src/submit_and_compare/conf/locale/config.yaml create mode 100644 src/submit_and_compare/mixins/__init__.py create mode 100644 src/submit_and_compare/mixins/dates.py create mode 100644 src/submit_and_compare/mixins/events.py create mode 100644 src/submit_and_compare/mixins/fragment.py create mode 100644 src/submit_and_compare/mixins/scenario.py create mode 100644 src/submit_and_compare/models.py create mode 100644 src/submit_and_compare/public/edit.js create mode 100644 src/submit_and_compare/public/view.css create mode 100644 src/submit_and_compare/public/view.js create mode 100644 src/submit_and_compare/public/view.less create mode 100644 src/submit_and_compare/scenarios/submit-and-compare-single.xml create mode 100644 src/submit_and_compare/settings.py create mode 100644 src/submit_and_compare/templates/edit.html create mode 100644 src/submit_and_compare/templates/view.html create mode 100644 src/submit_and_compare/tests/__init__.py create mode 100644 src/submit_and_compare/tests/test_all.py create mode 100644 src/submit_and_compare/views.py create mode 100644 src/submit_and_compare/xblocks.py diff --git a/.gitignore b/.gitignore index 0bcd497..db789c2 100644 --- a/.gitignore +++ b/.gitignore @@ -217,3 +217,6 @@ __marimo__/ # Sphinx documentation docs/_build/ + +# macOS system files +**/.DS_Store \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 77bc520..e2685a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,6 +30,7 @@ keywords = [ dependencies = [ "XBlock", "Django>=4.2", + "six" ] [project.urls] @@ -46,6 +47,10 @@ test = [ "pytest>=7.0", "pytest-cov", "pytest-django", + "coverage", + "edx-lint", + "edx-opaque-keys", + "mock", ] docs = [ "sphinx", @@ -54,6 +59,10 @@ docs = [ [project.entry-points."xblock.v1"] audio = "audio:AudioXBlock" +imagemodal = "imagemodal.xblocks:ImageModal" +submit-and-compare = "submit_and_compare.xblocks:SubmitAndCompareXBlock" +schoolyourself_lesson = "schoolyourself:SchoolYourselfLessonXBlock" +schoolyourself_review = "schoolyourself:SchoolYourselfReviewXBlock" # Packages live in src/ but are installed without the src prefix # e.g., src/foo_xblock/ is installed as foo_xblock diff --git a/src/imagemodal/__init__.py b/src/imagemodal/__init__.py new file mode 100644 index 0000000..7ea114f --- /dev/null +++ b/src/imagemodal/__init__.py @@ -0,0 +1,4 @@ +""" +A fullscreen, zooming image modal XBlock +""" +from .xblocks import ImageModal diff --git a/src/imagemodal/conf/locale/config.yaml b/src/imagemodal/conf/locale/config.yaml new file mode 100644 index 0000000..a968d94 --- /dev/null +++ b/src/imagemodal/conf/locale/config.yaml @@ -0,0 +1,4 @@ +# Configuration for i18n workflow. + +locales: + - en # English - Source Language diff --git a/src/imagemodal/conf/locale/en/LC_MESSAGES/django.po b/src/imagemodal/conf/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000..38ceb7b --- /dev/null +++ b/src/imagemodal/conf/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,62 @@ +# Stanford's Image Modal XBlock. +# Copyright (C) 2019 +# This file is distributed under the same license as the package. +# Steven Burch , 2019. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-03-09 18:45-0600\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Steven Burch \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: imagemodal/imagemodal.py:35 +msgid "Display Name" +msgstr "" + +#: imagemodal/imagemodal.py:38 +msgid "This is the XBlock's display name" +msgstr "" + +#: imagemodal/imagemodal.py:42 +msgid "Image URL" +msgstr "" + +#: imagemodal/imagemodal.py:51 +msgid "This is the location of the full-screen image to be displayed." +msgstr "" + +#: imagemodal/imagemodal.py:56 +msgid "Thumbnail URL" +msgstr "" + +#: imagemodal/imagemodal.py:60 +msgid "" +"This is the (optional) location of a thumbnail image to be displayed before " +"the main image has been enlarged." +msgstr "" + +#: imagemodal/imagemodal.py:66 +msgid "Description" +msgstr "" + +#: imagemodal/imagemodal.py:69 +msgid "Description text, displayed to screen readers" +msgstr "" + +#: imagemodal/imagemodal.py:74 +msgid "Alt Text" +msgstr "" + +#: imagemodal/imagemodal.py:78 +msgid "" +"This field allows you to add alternate or descriptive text that pertains to " +"your image." +msgstr "" diff --git a/src/imagemodal/conf/locale/en/LC_MESSAGES/text.po b/src/imagemodal/conf/locale/en/LC_MESSAGES/text.po new file mode 120000 index 0000000..0082074 --- /dev/null +++ b/src/imagemodal/conf/locale/en/LC_MESSAGES/text.po @@ -0,0 +1 @@ +django.po \ No newline at end of file diff --git a/src/imagemodal/mixins/__init__.py b/src/imagemodal/mixins/__init__.py new file mode 100644 index 0000000..ccb716c --- /dev/null +++ b/src/imagemodal/mixins/__init__.py @@ -0,0 +1,3 @@ +""" +Mixin behavior to XBlocks +""" diff --git a/src/imagemodal/mixins/fragment.py b/src/imagemodal/mixins/fragment.py new file mode 100644 index 0000000..860caf1 --- /dev/null +++ b/src/imagemodal/mixins/fragment.py @@ -0,0 +1,90 @@ +""" +Mixin fragment/html behavior into XBlocks + +Note: We should resume test coverage for all lines in this file once +split into its own library. +""" +from django.template.context import Context +from xblock.core import XBlock + + +try: + from web_fragments.fragment import Fragment +except Exception: + from xblock.fragment import Fragment # For backward compatibility with quince and earlier. + + +class XBlockFragmentBuilderMixin: + """ + Create a default XBlock fragment builder + """ + static_css = [ + 'view.css', + ] + static_js = [ + 'view.js', + ] + static_js_init = None + template = 'view.html' + + def provide_context(self, context): # pragma: no cover + """ + Build a context dictionary to render the student view + + This should generally be overriden by child classes. + """ + context = context or {} + context = dict(context) + return context + + @XBlock.supports('multi_device') + def student_view(self, context=None): + """ + Build the fragment for the default student view + """ + template = self.template + context = self.provide_context(context) + static_css = self.static_css or [] + static_js = self.static_js or [] + js_init = self.static_js_init + fragment = self.build_fragment( + template=template, + context=context, + css=static_css, + js=static_js, + js_init=js_init, + ) + return fragment + + def build_fragment(self, *, template='', + context=None, css=None, + js=None, js_init=None): + """ + Creates a fragment for display. + """ + context = context or {} + css = css or [] + js = js or [] + rendered_template = '' + if template: # pragma: no cover + template = 'templates/' + template + rendered_template = self.loader.render_django_template( + template, + context=Context(context), + i18n_service=self.runtime.service(self, 'i18n'), + ) + fragment = Fragment(rendered_template) + for item in css: + if item.startswith('/'): + url = item + else: + item = 'public/' + item + url = self.runtime.local_resource_url(self, item) + fragment.add_css_url(url) + for item in js: + item = 'public/' + item + url = self.runtime.local_resource_url(self, item) + fragment.add_javascript_url(url) + if js_init: # pragma: no cover + fragment.initialize_js(js_init) + return fragment diff --git a/src/imagemodal/mixins/scenario.py b/src/imagemodal/mixins/scenario.py new file mode 100644 index 0000000..cfb13ff --- /dev/null +++ b/src/imagemodal/mixins/scenario.py @@ -0,0 +1,23 @@ +""" +Mixin workbench behavior into XBlocks +""" +try: + from xblock.utils.resources import ResourceLoader +except ModuleNotFoundError: + from xblockutils.resources import ResourceLoader + + +loader = ResourceLoader(__name__) + + +class XBlockWorkbenchMixin: + """ + Provide a default test workbench for the XBlock + """ + + @classmethod + def workbench_scenarios(cls): + """ + Gather scenarios to be displayed in the workbench + """ + return loader.load_scenarios_from_path("../scenarios") diff --git a/src/imagemodal/models.py b/src/imagemodal/models.py new file mode 100644 index 0000000..9fe6f29 --- /dev/null +++ b/src/imagemodal/models.py @@ -0,0 +1,70 @@ +""" +Handle data access logic for the XBlock +""" +from django.utils.translation import gettext_lazy as _ +from xblock.fields import Scope +from xblock.fields import String + + +class ImageModalModelMixin: + """ + Handle data access for Image Modal XBlock instances + """ + + editable_fields = [ + 'display_name', + 'image_url', + 'thumbnail_url', + 'description', + 'alt_text', + ] + + show_in_read_only_mode = True + + display_name = String( + display_name=_('Display Name'), + default='Image Modal XBlock', + scope=Scope.settings, + help=_("This is the XBlock's display name"), + ) + + image_url = String( + display_name=_('Image URL'), + default=( + 'http://upload.wikimedia.org/' + 'wikipedia/commons/4/48/' + '1853_Kaei_6_Japanese_Map_of_the_World_-_' + 'Geographicus_-_ChikyuBankokuHozu-nakajima-1853.jpg' + ), + scope=Scope.settings, + help=_( + 'This is the location of the full-screen image to be displayed.' + ), + ) + + thumbnail_url = String( + display_name=_('Thumbnail URL'), + default='', + scope=Scope.settings, + help=_( + 'This is the (optional) location of a thumbnail image to be ' + 'displayed before the main image has been enlarged.' + ), + ) + + description = String( + display_name=_('Description'), + default='', + scope=Scope.settings, + help=_('Description text, displayed to screen readers'), + multiline_editor=True, + ) + + alt_text = String( + display_name=_('Alt Text'), + default='', + scope=Scope.settings, + help=_( + 'This field allows you to add alternate or descriptive text that pertains to your image.' + ), + ) diff --git a/src/imagemodal/public/draggabilly.pkgd.min.js b/src/imagemodal/public/draggabilly.pkgd.min.js new file mode 100644 index 0000000..11861d9 --- /dev/null +++ b/src/imagemodal/public/draggabilly.pkgd.min.js @@ -0,0 +1,8 @@ +/*! + * Draggabilly PACKAGED v1.2.4 + * Make that shiz draggable + * http://draggabilly.desandro.com + * MIT license + */ + +!function(t){function e(){}function n(t){function n(e){e.prototype.option||(e.prototype.option=function(e){t.isPlainObject(e)&&(this.options=t.extend(!0,this.options,e))})}function o(e,n){t.fn[e]=function(o){if("string"==typeof o){for(var s=i.call(arguments,1),a=0,p=this.length;p>a;a++){var u=this[a],d=t.data(u,e);if(d)if(t.isFunction(d[o])&&"_"!==o.charAt(0)){var c=d[o].apply(d,s);if(void 0!==c)return c}else r("no such method '"+o+"' for "+e+" instance");else r("cannot call methods on "+e+" prior to initialization; attempted to call '"+o+"'")}return this}return this.each(function(){var i=t.data(this,e);i?(i.option(o),i._init()):(i=new n(this,o),t.data(this,e,i))})}}if(t){var r="undefined"==typeof console?e:function(t){console.error(t)};return t.bridget=function(t,e){n(e),o(t,e)},t.bridget}}var i=Array.prototype.slice;"function"==typeof define&&define.amd?define("jquery-bridget/jquery.bridget",["jquery"],n):n("object"==typeof exports?require("jquery"):t.jQuery)}(window),function(t){function e(t){return new RegExp("(^|\\s+)"+t+"(\\s+|$)")}function n(t,e){var n=i(t,e)?r:o;n(t,e)}var i,o,r;"classList"in document.documentElement?(i=function(t,e){return t.classList.contains(e)},o=function(t,e){t.classList.add(e)},r=function(t,e){t.classList.remove(e)}):(i=function(t,n){return e(n).test(t.className)},o=function(t,e){i(t,e)||(t.className=t.className+" "+e)},r=function(t,n){t.className=t.className.replace(e(n)," ")});var s={hasClass:i,addClass:o,removeClass:r,toggleClass:n,has:i,add:o,remove:r,toggle:n};"function"==typeof define&&define.amd?define("classie/classie",s):"object"==typeof exports?module.exports=s:t.classie=s}(window),function(t){function e(t){if(t){if("string"==typeof i[t])return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(var e,o=0,r=n.length;r>o;o++)if(e=n[o]+t,"string"==typeof i[e])return e}}var n="Webkit Moz ms Ms O".split(" "),i=document.documentElement.style;"function"==typeof define&&define.amd?define("get-style-property/get-style-property",[],function(){return e}):"object"==typeof exports?module.exports=e:t.getStyleProperty=e}(window),function(t){function e(t){var e=parseFloat(t),n=-1===t.indexOf("%")&&!isNaN(e);return n&&e}function n(){}function i(){for(var t={width:0,height:0,innerWidth:0,innerHeight:0,outerWidth:0,outerHeight:0},e=0,n=s.length;n>e;e++){var i=s[e];t[i]=0}return t}function o(n){function o(){if(!h){h=!0;var i=t.getComputedStyle;if(u=function(){var t=i?function(t){return i(t,null)}:function(t){return t.currentStyle};return function(e){var n=t(e);return n||r("Style returned "+n+". Are you running this code in a hidden iframe on Firefox? See http://bit.ly/getsizebug1"),n}}(),d=n("boxSizing")){var o=document.createElement("div");o.style.width="200px",o.style.padding="1px 2px 3px 4px",o.style.borderStyle="solid",o.style.borderWidth="1px 2px 3px 4px",o.style[d]="border-box";var s=document.body||document.documentElement;s.appendChild(o);var a=u(o);c=200===e(a.width),s.removeChild(o)}}}function a(t){if(o(),"string"==typeof t&&(t=document.querySelector(t)),t&&"object"==typeof t&&t.nodeType){var n=u(t);if("none"===n.display)return i();var r={};r.width=t.offsetWidth,r.height=t.offsetHeight;for(var a=r.isBorderBox=!(!d||!n[d]||"border-box"!==n[d]),h=0,f=s.length;f>h;h++){var l=s[h],g=n[l];g=p(t,g);var v=parseFloat(g);r[l]=isNaN(v)?0:v}var y=r.paddingLeft+r.paddingRight,m=r.paddingTop+r.paddingBottom,E=r.marginLeft+r.marginRight,b=r.marginTop+r.marginBottom,P=r.borderLeftWidth+r.borderRightWidth,x=r.borderTopWidth+r.borderBottomWidth,_=a&&c,w=e(n.width);w!==!1&&(r.width=w+(_?0:y+P));var S=e(n.height);return S!==!1&&(r.height=S+(_?0:m+x)),r.innerWidth=r.width-(y+P),r.innerHeight=r.height-(m+x),r.outerWidth=r.width+E,r.outerHeight=r.height+b,r}}function p(e,n){if(t.getComputedStyle||-1===n.indexOf("%"))return n;var i=e.style,o=i.left,r=e.runtimeStyle,s=r&&r.left;return s&&(r.left=e.currentStyle.left),i.left=n,n=i.pixelLeft,i.left=o,s&&(r.left=s),n}var u,d,c,h=!1;return a}var r="undefined"==typeof console?n:function(t){console.error(t)},s=["paddingLeft","paddingRight","paddingTop","paddingBottom","marginLeft","marginRight","marginTop","marginBottom","borderLeftWidth","borderRightWidth","borderTopWidth","borderBottomWidth"];"function"==typeof define&&define.amd?define("get-size/get-size",["get-style-property/get-style-property"],o):"object"==typeof exports?module.exports=o(require("desandro-get-style-property")):t.getSize=o(t.getStyleProperty)}(window),function(t){function e(e){var n=t.event;return n.target=n.target||n.srcElement||e,n}var n=document.documentElement,i=function(){};n.addEventListener?i=function(t,e,n){t.addEventListener(e,n,!1)}:n.attachEvent&&(i=function(t,n,i){t[n+i]=i.handleEvent?function(){var n=e(t);i.handleEvent.call(i,n)}:function(){var n=e(t);i.call(t,n)},t.attachEvent("on"+n,t[n+i])});var o=function(){};n.removeEventListener?o=function(t,e,n){t.removeEventListener(e,n,!1)}:n.detachEvent&&(o=function(t,e,n){t.detachEvent("on"+e,t[e+n]);try{delete t[e+n]}catch(i){t[e+n]=void 0}});var r={bind:i,unbind:o};"function"==typeof define&&define.amd?define("eventie/eventie",r):"object"==typeof exports?module.exports=r:t.eventie=r}(window),function(){function t(){}function e(t,e){for(var n=t.length;n--;)if(t[n].listener===e)return n;return-1}function n(t){return function(){return this[t].apply(this,arguments)}}var i=t.prototype,o=this,r=o.EventEmitter;i.getListeners=function(t){var e,n,i=this._getEvents();if(t instanceof RegExp){e={};for(n in i)i.hasOwnProperty(n)&&t.test(n)&&(e[n]=i[n])}else e=i[t]||(i[t]=[]);return e},i.flattenListeners=function(t){var e,n=[];for(e=0;ee;e++){var i=t[e];if(i.identifier==this.pointerIdentifier)return i}},o.prototype.onmousedown=function(t){var e=t.button;e&&0!==e&&1!==e||this._pointerDown(t,t)},o.prototype.ontouchstart=function(t){this._pointerDown(t,t.changedTouches[0])},o.prototype.onMSPointerDown=o.prototype.onpointerdown=function(t){this._pointerDown(t,t)},o.prototype._pointerDown=function(t,e){this.isPointerDown||(this.isPointerDown=!0,this.pointerIdentifier=void 0!==e.pointerId?e.pointerId:e.identifier,this.pointerDown(t,e))},o.prototype.pointerDown=function(t,e){this._bindPostStartEvents(t),this.emitEvent("pointerDown",[t,e])};var r={mousedown:["mousemove","mouseup"],touchstart:["touchmove","touchend","touchcancel"],pointerdown:["pointermove","pointerup","pointercancel"],MSPointerDown:["MSPointerMove","MSPointerUp","MSPointerCancel"]};return o.prototype._bindPostStartEvents=function(e){if(e){for(var i=r[e.type],o=e.preventDefault?t:document,s=0,a=i.length;a>s;s++){var p=i[s];n.bind(o,p,this)}this._boundPointerEvents={events:i,node:o}}},o.prototype._unbindPostStartEvents=function(){var t=this._boundPointerEvents;if(t&&t.events){for(var e=0,i=t.events.length;i>e;e++){var o=t.events[e];n.unbind(t.node,o,this)}delete this._boundPointerEvents}},o.prototype.onmousemove=function(t){this._pointerMove(t,t)},o.prototype.onMSPointerMove=o.prototype.onpointermove=function(t){t.pointerId==this.pointerIdentifier&&this._pointerMove(t,t)},o.prototype.ontouchmove=function(t){var e=this.getTouch(t.changedTouches);e&&this._pointerMove(t,e)},o.prototype._pointerMove=function(t,e){this.pointerMove(t,e)},o.prototype.pointerMove=function(t,e){this.emitEvent("pointerMove",[t,e])},o.prototype.onmouseup=function(t){this._pointerUp(t,t)},o.prototype.onMSPointerUp=o.prototype.onpointerup=function(t){t.pointerId==this.pointerIdentifier&&this._pointerUp(t,t)},o.prototype.ontouchend=function(t){var e=this.getTouch(t.changedTouches);e&&this._pointerUp(t,e)},o.prototype._pointerUp=function(t,e){this._pointerDone(),this.pointerUp(t,e)},o.prototype.pointerUp=function(t,e){this.emitEvent("pointerUp",[t,e])},o.prototype._pointerDone=function(){this.isPointerDown=!1,delete this.pointerIdentifier,this._unbindPostStartEvents(),this.pointerDone()},o.prototype.pointerDone=i,o.prototype.onMSPointerCancel=o.prototype.onpointercancel=function(t){t.pointerId==this.pointerIdentifier&&this._pointerCancel(t,t)},o.prototype.ontouchcancel=function(t){var e=this.getTouch(t.changedTouches);e&&this._pointerCancel(t,e)},o.prototype._pointerCancel=function(t,e){this._pointerDone(),this.pointerCancel(t,e)},o.prototype.pointerCancel=function(t,e){this.emitEvent("pointerCancel",[t,e])},o.getPointerPoint=function(t){return{x:void 0!==t.pageX?t.pageX:t.clientX,y:void 0!==t.pageY?t.pageY:t.clientY}},o}),function(t,e){"function"==typeof define&&define.amd?define("unidragger/unidragger",["eventie/eventie","unipointer/unipointer"],function(n,i){return e(t,n,i)}):"object"==typeof exports?module.exports=e(t,require("eventie"),require("unipointer")):t.Unidragger=e(t,t.eventie,t.Unipointer)}(window,function(t,e,n){function i(){}function o(t){t.preventDefault?t.preventDefault():t.returnValue=!1}function r(t){for(;t!=document.body;)if(t=t.parentNode,"A"==t.nodeName)return t}function s(){}function a(){return!1}s.prototype=new n,s.prototype.bindHandles=function(){this._bindHandles(!0)},s.prototype.unbindHandles=function(){this._bindHandles(!1)};var p=t.navigator;s.prototype._bindHandles=function(t){t=void 0===t?!0:!!t;var n;n=p.pointerEnabled?function(e){e.style.touchAction=t?"none":""}:p.msPointerEnabled?function(e){e.style.msTouchAction=t?"none":""}:function(){t&&d(s)};for(var i=t?"bind":"unbind",o=0,r=this.handles.length;r>o;o++){var s=this.handles[o];this._bindStartEvent(s,t),n(s),e[i](s,"click",this)}};var u="attachEvent"in document.documentElement,d=u?function(t){"IMG"==t.nodeName&&(t.ondragstart=a);for(var e=t.querySelectorAll("img"),n=0,i=e.length;i>n;n++){var o=e[n];o.ondragstart=a}}:i,c=s.allowTouchstartNodes={INPUT:!0,A:!0,BUTTON:!0,SELECT:!0};return s.prototype.pointerDown=function(t,e){this._dragPointerDown(t,e);var n=document.activeElement;n&&n.blur&&n.blur(),this._bindPostStartEvents(t),this.emitEvent("pointerDown",[t,e])},s.prototype._dragPointerDown=function(t,e){this.pointerDownPoint=n.getPointerPoint(e);var i=t.target.nodeName,s="touchstart"==t.type&&(c[i]||r(t.target));s||"SELECT"==i||o(t)},s.prototype.pointerMove=function(t,e){var n=this._dragPointerMove(t,e);this.emitEvent("pointerMove",[t,e,n]),this._dragMove(t,e,n)},s.prototype._dragPointerMove=function(t,e){var i=n.getPointerPoint(e),o={x:i.x-this.pointerDownPoint.x,y:i.y-this.pointerDownPoint.y};return!this.isDragging&&this.hasDragStarted(o)&&this._dragStart(t,e),o},s.prototype.hasDragStarted=function(t){return Math.abs(t.x)>3||Math.abs(t.y)>3},s.prototype.pointerUp=function(t,e){this.emitEvent("pointerUp",[t,e]),this._dragPointerUp(t,e)},s.prototype._dragPointerUp=function(t,e){this.isDragging?this._dragEnd(t,e):this._staticClick(t,e)},s.prototype._dragStart=function(t,e){this.isDragging=!0,this.dragStartPoint=s.getPointerPoint(e),this.isPreventingClicks=!0,this.dragStart(t,e)},s.prototype.dragStart=function(t,e){this.emitEvent("dragStart",[t,e])},s.prototype._dragMove=function(t,e,n){this.isDragging&&this.dragMove(t,e,n)},s.prototype.dragMove=function(t,e,n){this.emitEvent("dragMove",[t,e,n])},s.prototype._dragEnd=function(t,e){this.isDragging=!1;var n=this;setTimeout(function(){delete n.isPreventingClicks}),this.dragEnd(t,e)},s.prototype.dragEnd=function(t,e){this.emitEvent("dragEnd",[t,e])},s.prototype.onclick=function(t){this.isPreventingClicks&&o(t)},s.prototype._staticClick=function(t,e){"INPUT"==t.target.nodeName&&"text"==t.target.type&&t.target.focus(),this.staticClick(t,e)},s.prototype.staticClick=function(t,e){this.emitEvent("staticClick",[t,e])},s.getPointerPoint=function(t){return{x:void 0!==t.pageX?t.pageX:t.clientX,y:void 0!==t.pageY?t.pageY:t.clientY}},s.getPointerPoint=n.getPointerPoint,s}),function(t,e){"function"==typeof define&&define.amd?define(["classie/classie","get-style-property/get-style-property","get-size/get-size","unidragger/unidragger"],function(n,i,o,r){return e(t,n,i,o,r)}):"object"==typeof exports?module.exports=e(t,require("desandro-classie"),require("desandro-get-style-property"),require("get-size"),require("unidragger")):t.Draggabilly=e(t,t.classie,t.getStyleProperty,t.getSize,t.Unidragger)}(window,function(t,e,n,i,o){function r(){}function s(t,e){for(var n in e)t[n]=e[n];return t}function a(t,e){this.element="string"==typeof t?d.querySelector(t):t,P&&(this.$element=P(this.element)),this.options=s({},this.constructor.defaults),this.option(e),this._create()}function p(t,e,n){return n=n||"round",e?Math[n](t/e)*e:t}for(var u,d=t.document,c=d.defaultView,h=c&&c.getComputedStyle?function(t){return c.getComputedStyle(t,null)}:function(t){return t.currentStyle},f="object"==typeof HTMLElement?function(t){return t instanceof HTMLElement}:function(t){return t&&"object"==typeof t&&1==t.nodeType&&"string"==typeof t.nodeName},l=0,g="webkit moz ms o".split(" "),v=t.requestAnimationFrame,y=t.cancelAnimationFrame,m=0;m 0 && maskWidth > 0) { + image.parent().css({ + left: -maskLeft, + top: -maskTop, + width: maskWidth, + height: maskHeight, + }); + image.css({ + top: maskTop / 2, + left: maskLeft / 2, + }); + draggie.enable(); + } else { + draggie.enable(); + } + } + + /** + * Close the image modal + * @returns {boolean} False to stop event bubbling + */ + function closeModal() { + body.css('overflow', ''); + curtain.hide(); + body.off('.imagemodal'); + buttonZoom.off('.imagemodal'); + curtain.off('.imagemodal'); + image.off('.imagemodal'); + return false; + } + + /** + * Zoom out from the image + * @returns {undefined} nothing + */ + function zoomOut() { + buttonZoomText.text('Zoom In'); + buttonZoomIcon.removeClass('icon-zoom-out'); + buttonZoomIcon.addClass('icon-zoom-in'); + image.off('.imagemodal'); + // eslint-disable-next-line no-use-before-define + image.on('click.imagemodal_zoomout', openModal); + image.removeClass('zoomed'); + image.parent().css({ + left: 0, + top: 0, + width: '100%', + height: '100%', + }); + image.css({ + left: 0, + top: 0, + }); + if (draggie) { + draggie.disable(); + draggie = null; + } + } + + /** + * Toggle the zoom state in and out + * @returns {boolean} False to stop event bubbling + */ + function toggleZoom() { + var isZoomed = image.hasClass('zoomed'); + if (isZoomed) { + zoomOut(); + } else { + zoomIn(); + } + return false; + } + + /** + * Open the image modal div + * @returns {boolean} False to stop event bubbling + */ + function openModal() { + curtain.show(); + body.css('overflow', 'hidden'); + body.on('keyup.imagemodal', function(event) { + if (event.which === KEY_ESCAPE) { + return closeModal(); + } + if (event.which === KEY_ENTER) { + return toggleZoom(); + } + return true; + }); + buttonZoom.on('click.imagemodal', toggleZoom); + curtain.on('click.imagemodal', closeModal); + image.on('click.imagemodal', toggleZoom); + return false; + } + + closeModal(); + if ($element.attr('data-runtime-class') === 'PreviewRuntime') { + anchor.on('click.imagemodal', preventDefault); + } else { + anchor.on('click.imagemodal', openModal); + buttonFullScreen.on('click.imagemodal', openModal); + } +} diff --git a/src/imagemodal/public/view.less b/src/imagemodal/public/view.less new file mode 100644 index 0000000..a6f5f01 --- /dev/null +++ b/src/imagemodal/public/view.less @@ -0,0 +1,110 @@ +.imagemodal_block { + @dark: #2e2d29; + @light: #fbfbf9; + + P { + cursor: pointer; + } + + IMG { + max-width: 100%; + } + + A, + BUTTON { + cursor: pointer; + } + + BUTTON { + border: 2px solid @dark; + background: @light; + color: @dark; + border-radius: 5px; + cursor: pointer; + opacity: 0.9; + padding: 5px 7px 7px; + font-weight: bold; + font-size: 1em; + + I { + // Override Studio's italic style + font-style: normal; + } + } + + .close { + position: absolute; + top: 10px; + right: 10px; + } + + .zoom { + position: absolute; + bottom: 10px; + right: 10px; + } + + .fullscreen { + position: absolute; + top: 10px; + left: 10px; + } + + .wrapper { + position: relative; + } + + .count { + font-weight: bold; + } + + .curtain { + display: none; + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + background-color: #000; + background-color: rgba(0, 0, 0, 0.7); + cursor: no-drop; + + /* + Override LMS's sequence-nav (z-index: 99;) + and modal-backdrop (z-index: 1000;) + */ + z-index: 1001; + + .mask { + height: 95%; + width: 95%; + margin: auto; + overflow: hidden; + position: relative; + top: 2.5%; + + .wrapper { + height: 100%; + width: 100%; + top: 0; + left: 0; + position: relative; + + IMG { + display: block; + margin: auto; + max-height: 100%; + max-width: 100%; + position: relative; + cursor: zoom-in; + } + + .zoomed { + max-height: none; + max-width: none; + cursor: move; + } + } + } + } +} diff --git a/src/imagemodal/scenarios/image-modal-many.xml b/src/imagemodal/scenarios/image-modal-many.xml new file mode 100644 index 0000000..fc9e649 --- /dev/null +++ b/src/imagemodal/scenarios/image-modal-many.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/src/imagemodal/scenarios/image-modal-single.xml b/src/imagemodal/scenarios/image-modal-single.xml new file mode 100644 index 0000000..93ab147 --- /dev/null +++ b/src/imagemodal/scenarios/image-modal-single.xml @@ -0,0 +1,7 @@ + + + diff --git a/src/imagemodal/settings.py b/src/imagemodal/settings.py new file mode 100644 index 0000000..3295392 --- /dev/null +++ b/src/imagemodal/settings.py @@ -0,0 +1,18 @@ +""" +Stub settings for xblock +""" + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + # 'NAME': 'intentionally-omitted', + }, +} +INSTALLED_APPS = ( + 'imagemodal', +) +LOCALE_PATHS = [ + 'imagemodal/translations', +] +SECRET_KEY = 'SECRET_KEY' +DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' diff --git a/src/imagemodal/templates/view.html b/src/imagemodal/templates/view.html new file mode 100644 index 0000000..a926876 --- /dev/null +++ b/src/imagemodal/templates/view.html @@ -0,0 +1,34 @@ +{% load i18n %} + +
+

{{display_name}}

+
+ + {{alt_text}} + + +
+
+
+
+ {{alt_text}} +
+ + +
+
+

{{description}}

+
diff --git a/src/imagemodal/tests/__init__.py b/src/imagemodal/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/imagemodal/tests/test_display.py b/src/imagemodal/tests/test_display.py new file mode 100644 index 0000000..04e2b75 --- /dev/null +++ b/src/imagemodal/tests/test_display.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +""" +Test basic XBlock display function +""" +import unittest + +from unittest.mock import Mock +from opaque_keys.edx.locations import SlashSeparatedCourseKey +from xblock.field_data import DictFieldData + +from imagemodal import ImageModal + + +def make_an_xblock(**kwargs): + """ + Helper method that creates a Free-text Response XBlock + """ + course_id = SlashSeparatedCourseKey('foo', 'bar', 'baz') + runtime = Mock( + course_id=course_id, + service=Mock( + # Is there a cleaner mock to the `i18n` service? + return_value=Mock(_catalog={}), + ), + ) + scope_ids = Mock() + field_data = DictFieldData(kwargs) + xblock = ImageModal(runtime, field_data, scope_ids) + xblock.xmodule_runtime = runtime + return xblock + + +class TestRender(unittest.TestCase): + """ + Test the HTML rendering of the XBlock + """ + + def setUp(self): + super().setUp() + self.xblock = make_an_xblock() + + def test_render(self): + student_view = self.xblock.student_view() + html = student_view.content + self.assertIsNotNone(html) + self.assertNotEqual('', html) + self.assertIn('imagemodal_block', html) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/imagemodal/tests/test_workbench.py b/src/imagemodal/tests/test_workbench.py new file mode 100755 index 0000000..5d62c44 --- /dev/null +++ b/src/imagemodal/tests/test_workbench.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +""" +Test XBlock workbench integration +""" +import unittest + +from imagemodal import ImageModal + + +class TestWorkbench(unittest.TestCase): + """ + Test XBlock workbench integration + """ + + def setUp(self): + super().setUp() + self.scenarios = ImageModal.workbench_scenarios() + + def _is_in_any_scenario(self, text): + """ + Check if the text exists in any scenario + """ + contains = any( + True + for scenario in self.scenarios + if text in scenario[1] + ) + return contains + + def test_load(self): + self.assertGreater(len(self.scenarios), 0) + + def test_has_sequence(self): + """ + Make sure at least one scenario contains a sequence + """ + has_sequence = self._is_in_any_scenario('sequence_demo') + self.assertTrue(has_sequence) + + def test_has_vertical(self): + """ + Make sure at least one scenario contains a vertical + """ + has_sequence = self._is_in_any_scenario('vertical_demo') + self.assertTrue(has_sequence) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/imagemodal/translations b/src/imagemodal/translations new file mode 120000 index 0000000..618b7e2 --- /dev/null +++ b/src/imagemodal/translations @@ -0,0 +1 @@ +conf/locale \ No newline at end of file diff --git a/src/imagemodal/views.py b/src/imagemodal/views.py new file mode 100644 index 0000000..e0fcf44 --- /dev/null +++ b/src/imagemodal/views.py @@ -0,0 +1,50 @@ +""" +Handle view logic for the XBlock +""" +try: + from xblock.utils.resources import ResourceLoader + from xblock.utils.studio_editable import StudioEditableXBlockMixin +except ModuleNotFoundError: # For backward compatibility with releases older than Quince. + from xblockutils.resources import ResourceLoader + from xblockutils.studio_editable import StudioEditableXBlockMixin + +from .mixins.fragment import XBlockFragmentBuilderMixin + + +URL_FONT_AWESOME_CSS = '//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css' # nopep8 + + +class ImageModalViewMixin( + XBlockFragmentBuilderMixin, + StudioEditableXBlockMixin, +): + """ + Handle view logic for Image Modal XBlock instances + """ + + loader = ResourceLoader(__name__) + static_css = [ + URL_FONT_AWESOME_CSS, + 'view.css', + ] + static_js = [ + 'draggabilly.pkgd.min.js', + 'view.js', + ] + static_js_init = 'ImageModalView' + + def provide_context(self, context=None): + """ + Build a context dictionary to render the student view + """ + context = context or {} + context = dict(context) + context.update({ + 'display_name': self.display_name, + 'image_url': self.image_url, + 'thumbnail_url': self.thumbnail_url or self.image_url, + 'description': self.description, + 'xblock_id': str(self.scope_ids.usage_id), + 'alt_text': self.alt_text or self.display_name, + }) + return context diff --git a/src/imagemodal/xblocks.py b/src/imagemodal/xblocks.py new file mode 100644 index 0000000..1aecdae --- /dev/null +++ b/src/imagemodal/xblocks.py @@ -0,0 +1,20 @@ +""" +This is the core logic for the XBlock +""" +from xblock.core import XBlock + +from .mixins.scenario import XBlockWorkbenchMixin +from .models import ImageModalModelMixin +from .views import ImageModalViewMixin + + +@XBlock.needs('i18n') +class ImageModal( + ImageModalModelMixin, + ImageModalViewMixin, + XBlockWorkbenchMixin, + XBlock, +): + """ + A fullscreen image modal XBlock. + """ diff --git a/src/schoolyourself/__init__.py b/src/schoolyourself/__init__.py new file mode 100644 index 0000000..8fc0284 --- /dev/null +++ b/src/schoolyourself/__init__.py @@ -0,0 +1,2 @@ +from .schoolyourself_lesson import SchoolYourselfLessonXBlock +from .schoolyourself_review import SchoolYourselfReviewXBlock diff --git a/src/schoolyourself/public/review_icon.png b/src/schoolyourself/public/review_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e9a6d07424ab469caa60e36454a6926c53d22593 GIT binary patch literal 9131 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"":a>b?"scale("+1/a+")":"scale("+1/b+")");m(this.i,"transform-origin","0 0")}}; +schoolyourself.g.prototype.u=function(a){var b=k("iframe",this.i,"player-viewport-frame");b.setAttribute("tabindex",0);b.focus();b.src=a;b.scrolling="no";this.k=b;a=this.h;b=a.getAttribute("class");if(null===b)a.setAttribute("class","open");else{var c=a.getAttribute("class");null!==c&&-1!=c.split(" ").indexOf("open")||a.setAttribute("class",b+" open")}this.l=!0;this.resize()};schoolyourself.g.prototype.openFrame=schoolyourself.g.prototype.u; +schoolyourself.g.prototype.close=function(){if(!this.q||this.q()){this.l=!1;this.i.innerHTML="";var a=this.h,b=a.getAttribute("class");if(null!==b){for(var b=b.split(" "),c="",d=0;d + + + """), + ] diff --git a/src/schoolyourself/schoolyourself_review.py b/src/schoolyourself/schoolyourself_review.py new file mode 100644 index 0000000..06cdb22 --- /dev/null +++ b/src/schoolyourself/schoolyourself_review.py @@ -0,0 +1,170 @@ +"""An XBlock that displays School Yourself reviews and may publish grades.""" + +import hashlib +import hmac +from six import text_type +import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error + +from xblock.core import XBlock +from xblock.fields import Scope, String +from xblock.fragment import Fragment + +from .schoolyourself import SchoolYourselfXBlock + + +class SchoolYourselfReviewXBlock(SchoolYourselfXBlock): + """ + This block renders a launcher button for a School Yourself review, + which is rendered in an iframe. The block transmits the anonymous + user ID and has a handler that receives information from School + Yourself regarding the user's progress and mastery through the + topic being shown. + """ + has_children = False + has_score = True + weight = 1.0 + + def get_display_name(self, module_title): + return "Review: %s" % module_title + + def student_view(self, context=None): + """ + The primary view of the SchoolYourselfReviewXBlock, shown to students + when viewing courses. + """ + # Construct the URL we're going to stuff into the iframe once + # it gets launched: + partner_url_params = self.get_partner_url_params(self.shared_key) + + iframe_url_params = dict(partner_url_params) + iframe_url_params["module"] = self.module_id + + mastery_url_params = dict(partner_url_params) + mastery_url_params["tags"] = self.module_id + + # Set up the screenshot URL: + screenshot_url = "%s/page/screenshot/%s" % (self.base_url, + self.module_id) + + mastery_url = "%s/progress/mastery?%s" % ( + self.base_url, six.moves.urllib.parse.urlencode(mastery_url_params)) + + context = { + "iframe_url": "%s/review/embed?%s" % ( + self.base_url, six.moves.urllib.parse.urlencode(iframe_url_params)), + "title": self.module_title, + "icon_url": self.runtime.local_resource_url(self, + "public/review_icon.png"), + "mastery_url": mastery_url + } + + + + # Now actually render the fragment, which is just a button with + # some JS code that handles the click event on that button. + fragment = Fragment(self.render_template("review_student_view.html", + context)) + + # Load the common JS/CSS libraries: + fragment.add_css_url( + self.runtime.local_resource_url(self, "public/sylib.css")) + fragment.add_javascript_url( + self.runtime.local_resource_url(self, "public/sylib.js")) + + + # And finally the embedded HTML/JS code: + fragment.add_javascript(self.resource_string( + "static/js/review_student_view.js")) + fragment.add_css(self.resource_string( + "static/css/student_view.css")) + fragment.add_css_url("//fonts.googleapis.com/css?family=Open+Sans:700,400,300") + fragment.initialize_js("SchoolYourselfReviewStudentView") + return fragment + + + @XBlock.json_handler + def handle_grade(self, data, suffix=""): + """This is the handler that gets called when we receive grades. + + We will verify the message to make sure that it is signed and + that the signature is valid. If everything is good, then we'll + publish a "grade" event for this module. + + The actual work is done in handle_grade_json(), and this method + just calls that. This method is just here so that it can be wrapped + by XBlock.json_handler, but the unit test covers the code in + handle_grade_json() to avoid having to wrap everything around a + Request/Response object. + """ + return self.handle_grade_json(data) + + + def handle_grade_json(self, data): + if not isinstance(data, dict): + return "bad_request" + + mastery = data.get("mastery", None) + user_id = data.get("user_id", None) + signature = data.get("signature", None) + + if not mastery or not user_id or not signature: + return "forbidden" + + # Check that the module ID we care about is actually in the data + # that was sent. + mastery_level = mastery.get(self.module_id, None) + if mastery_level is None: + return "bad_request" + + try: + # The mastery level being passed in should be a number, otherwise + # things later on in this method will choke. + mastery_level = float(mastery_level) + except ValueError: + return "bad_request" + + # Verify the signature. + sk = self.shared_key + if isinstance(self.shared_key, str): + sk = self.shared_key.encode('utf-8') + verifier = hmac.new(sk, user_id.encode('utf-8'), digestmod='MD5') + for key in sorted(mastery): + verifier.update(key.encode('utf-8')) + # Every entry should be a number. + try: + mastery[key] = float(mastery[key]) + except ValueError: + return "bad_request" + + verifier.update(b"%.2f" % mastery[key]) + + # If the signature is invalid, do nothing. + if signature != verifier.hexdigest(): + return "invalid_signature" + + # If we got here, then everything checks out and we can submit + # a grade for this module. + scaled_mastery_level = min(mastery_level / 0.7, 1.0) + self.runtime.publish(self, "grade", + { "value": scaled_mastery_level, + "max_value": 1.0 }) + return scaled_mastery_level + + + @staticmethod + def workbench_scenarios(): + """A canned scenario for display in the workbench.""" + return [ + ("SchoolYourselfReviewXBlock", + """\ + + + + """), + ] diff --git a/src/schoolyourself/schoolyourself_review_test.py b/src/schoolyourself/schoolyourself_review_test.py new file mode 100644 index 0000000..80a8acb --- /dev/null +++ b/src/schoolyourself/schoolyourself_review_test.py @@ -0,0 +1,122 @@ +"""This file contains a unit test for the SchoolYourselfReviewXBlock.""" + +import unittest + +from .schoolyourself_review import SchoolYourselfReviewXBlock + +from unittest.mock import Mock +from xblock.fields import ScopeIds +from xblock.field_data import DictFieldData + + +class FakeXModuleRuntime: + """ + Depending on whether we're running in the LMS or in the XBlock + workbench, the "xmodule_runtime" attr may or may not be set (in + the LMS, it's set, and that's what production uses). The only field + we ever look at in our XBlock code is "anonymous_student_id", + so this is a dummy object that holds that. + """ + def __init__(self, anonymous_student_id): + self.anonymous_student_id = anonymous_student_id + + +class SchoolYourselfReviewXBlockTest(unittest.TestCase): + def setUp(self): + self.mock_runtime = Mock() + self.block = SchoolYourselfReviewXBlock(self.mock_runtime, + DictFieldData({}), + ScopeIds("foo", "bar", "baz", "x")) + + # This is a fake shared key and a manually computed signature for use + # in this test. + self.block.shared_key = "key" + self.canned_signature = "f0cc345470c322e0c6f41d541fe2b736" + + + def test_default_params(self): + self.assertFalse(SchoolYourselfReviewXBlock.has_children) + self.assertTrue(SchoolYourselfReviewXBlock.has_score) + self.assertAlmostEqual(SchoolYourselfReviewXBlock.weight, 1.0) + + + def test_display_name(self): + """ + Make sure we are correctly overriding the get_display_name() of + the base class. + """ + self.assertEqual(self.block.get_display_name("blah"), "Review: blah") + + + def test_student_id(self): + self.assertEqual(self.block.get_student_id(), "debug") + self.block.xmodule_runtime = FakeXModuleRuntime("abc123") + self.assertEqual(self.block.get_student_id(), "abc123") + + + def test_handle_grade_malformed_input(self): + self.block.module_id = "algebra/multiplication" + + self.assertEqual(self.block.handle_grade_json("foo"), "bad_request") + self.assertEqual(self.block.handle_grade_json(["foo"]), "bad_request") + self.assertEqual(self.block.handle_grade_json({}), "forbidden") + self.assertEqual(self.block.handle_grade_json( + {"mastery": {"invalid_module_id": 1.0}, + "user_id": "foo", + "signature": "asdf"}), "bad_request") + + # Make sure we never publish any grades for situations like this. + self.assertEqual(len(self.mock_runtime.publish.method_calls), 0) + + + def test_handle_grade_malformed_signed_input(self): + """ + This is a test for an unlikely situation where the input is malformed + but the signature is somehow correct. We should at least not start + throwing errors. + """ + self.block.module_id = "algebra/multiplication" + + self.assertEqual(self.block.handle_grade_json( + {"mastery": {"algebra/multiplication": "hello"}, # A non-number! + "user_id": "foo", + "signature": self.canned_signature}), "bad_request") + + + def test_handle_grade(self): + self.block.module_id = "algebra/multiplication" + + self.assertEqual(self.block.handle_grade_json( + {"mastery": {"algebra/multiplication": 0.7}, + "user_id": "foo", + "signature": "asdf"}), "invalid_signature") + + # Invalid signatures should never publish grades. + self.assertEqual(len(self.mock_runtime.publish.method_calls), 0) + + self.assertEqual(self.block.handle_grade_json( + {"mastery": {"algebra/multiplication": 0.7}, + "user_id": "foo", + "signature": self.canned_signature}), 1.0) + + self.mock_runtime.publish.assert_called_with(self.block, "grade", + { "value": 1.0, + "max_value": 1.0 }) + + + def test_get_partner_url_params(self): + # These are the defaults: + self.assertEqual(self.block.get_partner_url_params(), + { "partner": "edx", + "partner_user_id": "debug" }) + + self.block.partner_id = "foo" + self.block.xmodule_runtime = FakeXModuleRuntime("abc123") + + self.assertEqual(self.block.get_partner_url_params(), + { "partner": "foo", + "partner_user_id": "abc123" }) + + +if __name__ == "__main__": + unittest.main() diff --git a/src/schoolyourself/static/css/student_view.css b/src/schoolyourself/static/css/student_view.css new file mode 100644 index 0000000..25d4dd2 --- /dev/null +++ b/src/schoolyourself/static/css/student_view.css @@ -0,0 +1,137 @@ +.schoolyourself-lesson { + padding: 40px; + font-family: "Open Sans", sans-serif; + font-weight: 300; + color: #6eb535; + background: #fafafa; + font-size: 0; + text-align: center; +} + + +.schoolyourself-lesson-block { + display: inline-block; + cursor: hand; + cursor: pointer; + vertical-align: top; + text-align: center; + position: relative; + width: 100%; +} + + +.schoolyourself-lesson-screenshot, +.schoolyourself-review-screenshot { + margin-top: 10px; + margin-right: 20px; + box-shadow: 0px 0px 3px 1px #c1c1c1; + opacity: 0.8; + -webkit-transition: opacity 150ms linear; + -moz-transition: opacity 150ms linear; + -ms-transition: opacity 150ms linear; + -o-transition: opacity 150ms linear; + transition: opacity 150ms linear; + border: 2px solid #6eb535; + border-radius: 2px; + text-align: center; + background: #fff; + + display: inline-block; + width: 256px; + height: 192px; + margin: 0; +} + +.schoolyourself-review-screenshot { + width: 200px; + height: auto; + border: none; + background: transparent; + box-shadow: none; +} + +.schoolyourself-lesson-screenshot > img, +.schoolyourself-review-screenshot > img { + display: inline-block; + vertical-align: middle; + width: 100%; +} + +.schoolyourself-lesson-block:hover .schoolyourself-lesson-screenshot, +.schoolyourself-lesson-block:hover .schoolyourself-review-screenshot { + opacity: 1; +} + + +.schoolyourself-lesson-text { + display: inline-block; + text-align: left; + vertical-align: top; + padding-left: 40px; + overflow: hidden; + max-width: 320px; +} + +.schoolyourself-lesson-title, +.schoolyourself-lesson-title a, +.schoolyourself-lesson-title a:visited { + text-transform: uppercase; + font-size: 24px; + font-weight: 300; + color: #6eb535; + text-decoration: none; + margin-bottom: 0 !important; + margin-top: 0; +} +.schoolyourself-lesson-block:hover .schoolyourself-lesson-title { + color: #6eb535; + text-decoration: underline; +} + + +.schoolyourself-lesson-description { + color: #737c95; + font-size: 21px; + margin-bottom: 5px; +} + +.schoolyourself-review-mastery { + margin-top: 20px; + height: 44px; + color: #737c95; + font-size: 16px; + margin-bottom: 5px; + max-width: 320px; +} + +.schoolyourself-review-mastery-text { + height: 24px; +} + +.schoolyourself-review-mastery-bar { + width: 320px; + background: #ddd; + height: 20px; + position: relative; + + -webkit-transition: background 450ms ease-in-out; + -moz-transition: background 450ms ease-in-out; + -ms-transition: background 450ms ease-in-out; + -o-transition: background 450ms ease-in-out; + transition: background 450ms ease-in-out; +} + +.schoolyourself-review-mastery-bar-filler { + position: absolute; + background: #fcd380; + left: 0; + right: 100%; + top: 0; + bottom: 0; + + -webkit-transition: all 450ms ease-in-out; + -moz-transition: all 450ms ease-in-out; + -ms-transition: all 450ms ease-in-out; + -o-transition: all 450ms ease-in-out; + transition: all 450ms ease-in-out; +} diff --git a/src/schoolyourself/static/js/lesson_student_view.js b/src/schoolyourself/static/js/lesson_student_view.js new file mode 100644 index 0000000..4bcb850 --- /dev/null +++ b/src/schoolyourself/static/js/lesson_student_view.js @@ -0,0 +1,8 @@ +function SchoolYourselfLessonStudentView(runtime, element) { + var viewport = schoolyourself.PlayerViewportBuilder.insert(1024, 768); + $(function ($) { + $('.schoolyourself-lesson-player', element).click(function(eventObject) { + viewport.openFrame(this.getAttribute('data-url')); + }); + }); +} diff --git a/src/schoolyourself/static/js/review_student_view.js b/src/schoolyourself/static/js/review_student_view.js new file mode 100644 index 0000000..f6b049b --- /dev/null +++ b/src/schoolyourself/static/js/review_student_view.js @@ -0,0 +1,61 @@ +function SchoolYourselfReviewStudentView(runtime, element) { + var viewport = schoolyourself.PlayerViewportBuilder.insert(1024, 768); + $(function ($) { + $('.schoolyourself-lesson-player', element).click(function(eventObject) { + viewport.openFrame(this.getAttribute('data-url')); + }); + + window.addEventListener('message', function(event) { + if (event.source != viewport.frame().contentWindow) { + return; + } + var handlerUrl = runtime.handlerUrl(element, 'handle_grade'); + $.post(handlerUrl, JSON.stringify(event.data)); + }, false); + + var masteryUrl = $('.schoolyourself-lesson-player', element)[0].getAttribute('data-mastery-url'); + updateMastery(masteryUrl); + viewport.addAfterCloseHandler(function(){updateMastery(masteryUrl)}); + }); +} + +function renderMastery(masteries) { + var mastery = masteries[0][1]; + + // A mastery level of 0.7 gives full credit -- anything beyond that + // doesn't count toward anything. So we should show a full, green bar + // when scaledMastery >= 0.7. + var scaledMastery = mastery / 0.7; + + var right = (100 - (scaledMastery * 100)) + '%'; + + var color = '#fcd380'; + if (!scaledMastery) { + var text = 'Get started!'; + } else if (scaledMastery < 0.5) { + var text = 'Keep practicing!'; + } else if (scaledMastery < 1) { + var text = 'Almost there!'; + var color = '#f0b300'; + } else { + var text = 'Complete!'; + var color = '#6eb535'; + } + + $('.schoolyourself-review-mastery-text').html(text); + $('.schoolyourself-review-mastery-bar-filler').css('right', right); + $('.schoolyourself-review-mastery-bar-filler').css('background', color); +} + + function updateMastery(masteryUrl) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', masteryUrl, true); + xhr.withCredentials = true; + xhr.send(); + xhr.onreadystatechange = function(event) { + if (xhr.readyState === 4 && + xhr.status === 200) { + renderMastery($.parseJSON(xhr.responseText)); + } + }; +} diff --git a/src/schoolyourself/static/js/studio_view.js b/src/schoolyourself/static/js/studio_view.js new file mode 100644 index 0000000..fe20ea4 --- /dev/null +++ b/src/schoolyourself/static/js/studio_view.js @@ -0,0 +1,21 @@ +function SchoolYourselfStudioView(runtime, element) { + $('.save-button').bind('click', function() { + var data = { + 'module_id': $('.module-id', element).val(), + 'module_title': $('.module-title', element).val(), + 'module_description': $('.module-description', element).val(), + 'player_type': $('.player-type', element).val(), + 'shared_key': $('.shared-key', element).val(), + 'base_url': $('.base-url', element).val(), + 'partner_id': $('.partner-id', element).val() + }; + var handlerUrl = runtime.handlerUrl(element, 'studio_submit'); + $.post(handlerUrl, JSON.stringify(data)).complete(function() { + window.location.reload(false); + }); + }); + + $('.cancel-button').bind('click', function() { + runtime.notify('cancel', {}); + }); +} diff --git a/src/schoolyourself/templates/lesson_student_view.html b/src/schoolyourself/templates/lesson_student_view.html new file mode 100644 index 0000000..e757e82 --- /dev/null +++ b/src/schoolyourself/templates/lesson_student_view.html @@ -0,0 +1,15 @@ +
+
+
+
+ ${title | h} screenshot +
+ +
+

${title | h}

+
${description | h}
+
+
+
+
+ diff --git a/src/schoolyourself/templates/review_student_view.html b/src/schoolyourself/templates/review_student_view.html new file mode 100644 index 0000000..a569885 --- /dev/null +++ b/src/schoolyourself/templates/review_student_view.html @@ -0,0 +1,21 @@ +
+
+
+
+ Review icon +
+ +
+

Review: ${title | h}

+
Practice makes perfect!
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/schoolyourself/templates/studio_view.html b/src/schoolyourself/templates/studio_view.html new file mode 100644 index 0000000..da45e08 --- /dev/null +++ b/src/schoolyourself/templates/studio_view.html @@ -0,0 +1,57 @@ +
+
    + +
  • +
    + + +
    +
  • + +
  • +
    + + +
    +
  • + +
  • +
    + + +
    +
  • + +
  • +
    + + +
    +
  • + +
  • +
    + + +
    +
  • + +
  • +
    + + +
    +
  • +
+ +
+
    +
  • + +
  • +
  • + +
  • +
+
+
diff --git a/src/submit_and_compare/__init__.py b/src/submit_and_compare/__init__.py new file mode 100644 index 0000000..ca7340b --- /dev/null +++ b/src/submit_and_compare/__init__.py @@ -0,0 +1,3 @@ +""" +This is an XBlock for submit and compare +""" diff --git a/src/submit_and_compare/conf/locale/config.yaml b/src/submit_and_compare/conf/locale/config.yaml new file mode 100644 index 0000000..a968d94 --- /dev/null +++ b/src/submit_and_compare/conf/locale/config.yaml @@ -0,0 +1,4 @@ +# Configuration for i18n workflow. + +locales: + - en # English - Source Language diff --git a/src/submit_and_compare/mixins/__init__.py b/src/submit_and_compare/mixins/__init__.py new file mode 100644 index 0000000..ccb716c --- /dev/null +++ b/src/submit_and_compare/mixins/__init__.py @@ -0,0 +1,3 @@ +""" +Mixin behavior to XBlocks +""" diff --git a/src/submit_and_compare/mixins/dates.py b/src/submit_and_compare/mixins/dates.py new file mode 100644 index 0000000..b4afb24 --- /dev/null +++ b/src/submit_and_compare/mixins/dates.py @@ -0,0 +1,34 @@ +""" +Extend XBlocks with datetime helpers +""" +import datetime + + +# pylint: disable=too-few-public-methods +class EnforceDueDates: + """ + xBlock Mixin to allow xblocks to check the due date + (taking the graceperiod into account) of the + subsection in which they are placed + """ + + def is_past_due(self): + """ + Determine if component is past-due + """ + # These values are pulled from platform. + # They are defaulted to None for tests. + due = getattr(self, 'due', None) + graceperiod = getattr(self, 'graceperiod', None) + # Calculate the current DateTime so we can compare the due date to it. + # datetime.utcnow() returns timezone naive date object. + now = datetime.datetime.utcnow() + if due is not None: + # Remove timezone information from platform provided due date. + # Dates are stored as UTC timezone aware objects on platform. + due = due.replace(tzinfo=None) + if graceperiod is not None: + # Compare the datetime objects (both have to be timezone naive) + due = due + graceperiod + return now > due + return False diff --git a/src/submit_and_compare/mixins/events.py b/src/submit_and_compare/mixins/events.py new file mode 100644 index 0000000..2abf7d8 --- /dev/null +++ b/src/submit_and_compare/mixins/events.py @@ -0,0 +1,67 @@ +""" +Provide event-related mixin functionality +""" +from xblock.core import XBlock + + +class EventableMixin: + """ + Mix in standard event logic + """ + + @XBlock.json_handler + def publish_event(self, data, *args, **kwargs): + """ + Publish events + """ + try: + event_type = data.pop('event_type') + except KeyError: + return { + 'result': 'error', + 'message': 'Missing event_type in JSON data', + } + data['user_id'] = self.scope_ids.user_id + data['component_id'] = self._get_unique_id() + self.runtime.publish(self, event_type, data) + result = { + 'result': 'success', + } + return result + + def _get_unique_id(self): + """ + Get a unique component identifier + """ + try: + unique_id = self.location.name + except AttributeError: + # workaround for xblock workbench + unique_id = 'workbench-workaround-id' + return unique_id + + def _publish_grade(self): + """ + Publish a grade event + """ + self.runtime.publish( + self, + 'grade', + { + 'value': self.score, + 'max_value': 1.0, + } + ) + + def _publish_problem_check(self): + """ + Publish a problem_check event + """ + self.runtime.publish( + self, + 'problem_check', + { + 'grade': self.score, + 'max_grade': 1.0, + } + ) diff --git a/src/submit_and_compare/mixins/fragment.py b/src/submit_and_compare/mixins/fragment.py new file mode 100644 index 0000000..b3f47ce --- /dev/null +++ b/src/submit_and_compare/mixins/fragment.py @@ -0,0 +1,96 @@ +""" +Mixin fragment/html behavior into XBlocks + +Note: We should resume test coverage for all lines in this file once +split into its own library. +""" +from django.template.context import Context +from xblock.core import XBlock +from web_fragments.fragment import Fragment + + +class XBlockFragmentBuilderMixin: + """ + Create a default XBlock fragment builder + """ + static_css = [ + 'view.css', + ] + static_js = [ + 'view.js', + ] + static_js_init = None + template = 'view.html' + + def get_i18n_service(self): + """ + Get the i18n service from the runtime + """ + return self.runtime.service(self, 'i18n') + + def provide_context(self, context): # pragma: no cover + """ + Build a context dictionary to render the student view + + This should generally be overriden by child classes. + """ + context = context or {} + context = dict(context) + return context + + @XBlock.supports('multi_device') + def student_view(self, context=None): + """ + Build the fragment for the default student view + """ + template = self.template + context = self.provide_context(context) + static_css = self.static_css or [] + static_js = self.static_js or [] + js_init = self.static_js_init + fragment = self.build_fragment( + template=template, + context=context, + css=static_css, + js=static_js, + js_init=js_init, + ) + return fragment + + def build_fragment( + self, + template='', + context=None, + css=None, + js=None, + js_init=None, + ): + """ + Creates a fragment for display. + """ + context = context or {} + css = css or [] + js = js or [] + rendered_template = '' + if template: # pragma: no cover + template = 'templates/' + template + rendered_template = self.loader.render_django_template( + template, + context=Context(context), + i18n_service=self.get_i18n_service(), + ) + fragment = Fragment(rendered_template) + for item in css: + if item.startswith('/'): + url = item + else: + item = 'public/' + item + url = self.runtime.local_resource_url(self, item) + fragment.add_css_url(url) + for item in js: + item = 'public/' + item + url = self.runtime.local_resource_url(self, item) + fragment.add_javascript_url(url) + if js_init: # pragma: no cover + fragment.initialize_js(js_init) + return fragment diff --git a/src/submit_and_compare/mixins/scenario.py b/src/submit_and_compare/mixins/scenario.py new file mode 100644 index 0000000..3b20c7b --- /dev/null +++ b/src/submit_and_compare/mixins/scenario.py @@ -0,0 +1,24 @@ +""" +Mixin workbench behavior into XBlocks +""" + +try: + from xblock.utils.resources import ResourceLoader +except ModuleNotFoundError: + from xblockutils.resources import ResourceLoader + + +loader = ResourceLoader(__name__) + + +class XBlockWorkbenchMixin: + """ + Provide a default test workbench for the XBlock + """ + + @classmethod + def workbench_scenarios(cls): + """ + Gather scenarios to be displayed in the workbench + """ + return loader.load_scenarios_from_path("../scenarios") diff --git a/src/submit_and_compare/models.py b/src/submit_and_compare/models.py new file mode 100644 index 0000000..7935b47 --- /dev/null +++ b/src/submit_and_compare/models.py @@ -0,0 +1,118 @@ +""" +Handle data access logic for the XBlock +""" +import textwrap + +from xblock.fields import Float +from xblock.fields import Integer +from xblock.fields import List +from xblock.fields import Scope +from xblock.fields import String + + +class SubmitAndCompareModelMixin: + """ + Handle data access logic for the XBlock + """ + + has_score = True + display_name = String( + display_name='Display Name', + default='Submit and Compare', + scope=Scope.settings, + help=( + 'This name appears in the horizontal' + ' navigation at the top of the page' + ), + ) + student_answer = String( + default='', + scope=Scope.user_state, + help='This is the student\'s answer to the question', + ) + max_attempts = Integer( + default=0, + scope=Scope.settings, + ) + count_attempts = Integer( + default=0, + scope=Scope.user_state, + ) + your_answer_label = String( + default='Your Answer:', + scope=Scope.settings, + help='Label for the text area containing the student\'s answer', + ) + our_answer_label = String( + default='Our Answer:', + scope=Scope.settings, + help='Label for the \'expert\' answer', + ) + submit_button_label = String( + default='Submit and Compare', + scope=Scope.settings, + help='Label for the submit button', + ) + hints = List( + default=[], + scope=Scope.content, + help='Hints for the question', + ) + question_string = String( + help='Default question content ', + scope=Scope.content, + multiline_editor=True, + default=textwrap.dedent(""" + + +

+ Before you begin the simulation, + think for a minute about your hypothesis. + What do you expect the outcome of the simulation + will be? What data do you need to gather in order + to prove or disprove your hypothesis? +

+ + +

+ We would expect the simulation to show that + there is no difference between the two scenarios. + Relevant data to gather would include time and + temperature. +

+
+ + + A hypothesis is a proposed explanation for a + phenomenon. In this case, the hypothesis is what + we think the simulation will show. + + + Once you've decided on your hypothesis, which data + would help you determine if that hypothesis is + correct or incorrect? + + +
+ """)) + score = Float( + default=0.0, + scope=Scope.user_state, + ) + weight = Integer( + display_name='Weight', + help='This assigns an integer value representing ' + 'the weight of this problem', + default=0, + scope=Scope.settings, + ) + + def max_score(self): + """ + Returns the configured number of possible points for this component. + Arguments: + None + Returns: + float: The number of possible points for this component + """ + return self.weight diff --git a/src/submit_and_compare/public/edit.js b/src/submit_and_compare/public/edit.js new file mode 100644 index 0000000..2a22067 --- /dev/null +++ b/src/submit_and_compare/public/edit.js @@ -0,0 +1,36 @@ +/* Javascript for Submit and Compare XBlock. */ +function SubmitAndCompareXBlockInitEdit(runtime, element) { + + var xmlEditorTextarea = $('.block-xml-editor', element), + xmlEditor = CodeMirror.fromTextArea(xmlEditorTextarea[0], { mode: 'xml', lineWrapping: true }); + + $(element).find('.action-cancel').bind('click', function() { + runtime.notify('cancel', {}); + }); + + $(element).find('.action-save').bind('click', function() { + var data = { + 'display_name': $('#submit_and_compare_edit_display_name').val(), + 'weight': $('#submit_and_compare_edit_weight').val(), + 'max_attempts': $('#submit_and_compare_edit_max_attempts').val(), + 'your_answer_label': $('#submit_and_compare_edit_your_answer_label').val(), + 'our_answer_label': $('#submit_and_compare_edit_our_answer_label').val(), + 'submit_button_label': $('#submit_and_compare_edit_submit_button_label').val(), + 'data': xmlEditor.getValue(), + }; + + runtime.notify('save', {state: 'start'}); + + var handlerUrl = runtime.handlerUrl(element, 'studio_submit'); + $.post(handlerUrl, JSON.stringify(data)).done(function(response) { + if (response.result === 'success') { + runtime.notify('save', {state: 'end'}); + //Reload the page + //window.location.reload(false); + } else { + runtime.notify('error', {msg: response.message}) + } + }); + }); +} + diff --git a/src/submit_and_compare/public/view.css b/src/submit_and_compare/public/view.css new file mode 100644 index 0000000..ce77d0d --- /dev/null +++ b/src/submit_and_compare/public/view.css @@ -0,0 +1,65 @@ +.submit_and_compare .question_prompt { + text-align: left; +} +.submit_and_compare .student_answer { + color: #3399cc; + font-weight: 600; + padding-bottom: 20px; + padding-top: 20px; +} +.submit_and_compare .answer { + border: 3px solid #cccccc; + height: 120px; + max-width: 100%; + padding: 5px; + width: 100%; +} +.submit_and_compare .expert_answer { + padding-bottom: 20px; + text-align: left; +} +.submit_and_compare .our_answer { + color: #009900; + font-weight: 600; + text-align: left; +} +.submit_and_compare .hint { + padding-bottom: 20px; + text-align: left; +} +.submit_and_compare .reset_button { + font-weight: 600; + height: 40px; + vertical-align: middle; +} +.submit_and_compare .hint_button { + font-weight: 600; + height: 40px; + vertical-align: middle; +} +.submit_and_compare .submit_button { + font-weight: 600; + height: 40px; + vertical-align: middle; +} +.submit_and_compare .problem_progress { + color: #666; + display: inline-block; + font-size: 1em; + font-weight: 100; + padding-left: 5px; +} +.submit_and_compare .problem_header { + display: inline-block; +} +.submit_and_compare .used_attempts_feedback { + color: #666; + font-style: italic; + margin-top: 8px; +} +.submit_and_compare .nodisplay { + display: none; +} +.submit_and_compare .inline { + display: inline; +} diff --git a/src/submit_and_compare/public/view.js b/src/submit_and_compare/public/view.js new file mode 100644 index 0000000..4babad2 --- /dev/null +++ b/src/submit_and_compare/public/view.js @@ -0,0 +1,161 @@ +/* Javascript for submitcompareXBlock. */ +/* eslint-disable no-unused-vars */ +/* eslint-disable require-jsdoc */ +/** + * Initialize the student view + * @param {Object} runtime - The XBlock JS Runtime + * @param {Object} element - The containing DOM element for this instance of the XBlock + * @returns {undefined} nothing + */ +function SubmitAndCompareXBlockInitView(runtime, element) { + 'use strict'; + /* eslint-disable camelcase */ + /* eslint-enable no-unused-vars */ + + var $ = window.jQuery; + var handlerUrl = runtime.handlerUrl(element, 'student_submit'); + var hintUrl = runtime.handlerUrl(element, 'send_hints'); + var publishUrl = runtime.handlerUrl(element, 'publish_event'); + var $element = $(element); + var $xblocksContainer = $('#seq_content'); + var submit_button = $element.find('.submit_button'); + var hint_button = $element.find('hint_button'); + var reset_button = $element.find('.reset_button'); + var problem_progress = $element.find('.problem_progress'); + var used_attempts_feedback = $element.find('.used_attempts_feedback'); + var button_holder = $element.find('.button_holder'); + var answer_textarea = $element.find('.answer'); + var your_answer = $element.find('.your_answer'); + var expert_answer = $element.find('.expert_answer'); + var hint_div = $element.find('.hint'); + var hint_button_holder = $element.find('.hint_button_holder'); + var submit_button_label = $element.find('.submit_button').attr('value'); + var hint; + var hints; + var hint_counter = 0; + var xblock_id = $element.attr('data-usage-id'); + var cached_answer_id = xblock_id + '_cached_answer'; + var problem_progress_id = xblock_id + '_problem_progress'; + var used_attempts_feedback_id = xblock_id + '_used_attempts_feedback'; + if (typeof $xblocksContainer.data(cached_answer_id) !== 'undefined') { + answer_textarea.text($xblocksContainer.data(cached_answer_id)); + problem_progress.text($xblocksContainer.data(problem_progress_id)); + used_attempts_feedback.text($xblocksContainer.data(used_attempts_feedback_id)); + } + + /** + * Parse and display hints + * @param {Object} result - The result payload + * @returns {undefined} nothing + */ + function set_hints(result) { + hints = result.hints; + if (hints.length > 0) { + hint_button.css('display', 'inline'); + hint_button_holder.css('display', 'inline'); + } + } + + $.ajax({ + type: 'POST', + url: hintUrl, + data: JSON.stringify({ requested: true, }), + success: set_hints, + }); + + function publish_event(data) { + $.ajax({ + type: 'POST', + url: publishUrl, + data: JSON.stringify(data), + }); + } + + function pre_submit() { + problem_progress.text('(Loading...)'); + } + + function post_submit(result) { + $xblocksContainer.data(cached_answer_id, $('.answer', element).val()); + $xblocksContainer.data(problem_progress_id, result.problem_progress); + $xblocksContainer.data(used_attempts_feedback_id, result.used_attempts_feedback); + problem_progress.text(result.problem_progress); + button_holder.addClass(result.submit_class); + used_attempts_feedback.text(result.used_attempts_feedback); + } + + function show_answer() { + your_answer.css('display', 'block'); + expert_answer.css('display', 'block'); + submit_button.val('Resubmit'); + + } + + function reset_answer() { + your_answer.css('display', 'none'); + expert_answer.css('display', 'none'); + submit_button.val(submit_button_label); + } + + function reset_hint() { + hint_counter = 0; + hint_div.css('display', 'none'); + } + + function show_hint() { + hint = hints[hint_counter]; + hint_div.html(hint); + hint_div.css('display', 'block'); + publish_event({ + event_type: 'hint_button', + next_hint_index: hint_counter, + }); + if (hint_counter === hints.length - 1) { + hint_counter = 0; + } else { + hint_counter++; + } + } + + $('.submit_button', element).click(function () { + pre_submit(); + $.ajax({ + type: 'POST', + url: handlerUrl, + data: JSON.stringify( + { + answer: $('.answer', element).val(), + action: 'submit', + } + ), + success: post_submit, + }); + show_answer(); + }); + + reset_button.click(function () { + $('.answer', element).val(''); + $.ajax({ + type: 'POST', + url: handlerUrl, + data: JSON.stringify( + { + answer: '', + action: 'reset', + } + ), + success: post_submit, + }); + reset_answer(); + reset_hint(); + }); + + $('.hint_button', element).click(function () { + show_hint(); + }); + + if ($('.answer', element).val() !== '') { + show_answer(); + } + /* eslint-enable camelcase */ +} diff --git a/src/submit_and_compare/public/view.less b/src/submit_and_compare/public/view.less new file mode 100644 index 0000000..ed401fa --- /dev/null +++ b/src/submit_and_compare/public/view.less @@ -0,0 +1,67 @@ +.submit_and_compare { + .question_prompt { + text-align: left; + } + .student_answer { + color: #3399cc; + font-weight: 600; + padding-bottom: 20px; + padding-top: 20px; + } + .answer { + border: 3px solid #cccccc; + height: 120px; + max-width: 100%; + padding: 5px; + width: 100%; + } + .expert_answer { + padding-bottom: 20px; + text-align: left; + } + .our_answer { + color: #009900; + font-weight: 600; + text-align: left; + } + .hint { + padding-bottom: 20px; + text-align: left; + } + .reset_button { + font-weight: 600; + height: 40px; + vertical-align: middle; + } + .hint_button { + font-weight: 600; + height: 40px; + vertical-align: middle; + } + .submit_button { + font-weight: 600; + height: 40px; + vertical-align: middle; + } + .problem_progress { + color: #666; + display: inline-block; + font-size: 1em; + font-weight: 100; + padding-left: 5px; + } + .problem_header { + display: inline-block; + } + .used_attempts_feedback { + color: #666; + font-style: italic; + margin-top: 8px; + } + .nodisplay { + display: none; + } + .inline { + display: inline; + } +} diff --git a/src/submit_and_compare/scenarios/submit-and-compare-single.xml b/src/submit_and_compare/scenarios/submit-and-compare-single.xml new file mode 100644 index 0000000..34ce0fe --- /dev/null +++ b/src/submit_and_compare/scenarios/submit-and-compare-single.xml @@ -0,0 +1,3 @@ + + + diff --git a/src/submit_and_compare/settings.py b/src/submit_and_compare/settings.py new file mode 100644 index 0000000..a48cc2d --- /dev/null +++ b/src/submit_and_compare/settings.py @@ -0,0 +1,16 @@ +""" +Settings for submit_and_compare xblock +""" + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + # 'NAME': 'intentionally-omitted', + }, +} +LOCALE_PATHS = [ + 'submit_and_compare/translations', +] +SECRET_KEY = 'submit_and_compare_SECRET_KEY' + +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" diff --git a/src/submit_and_compare/templates/edit.html b/src/submit_and_compare/templates/edit.html new file mode 100644 index 0000000..4e11ba2 --- /dev/null +++ b/src/submit_and_compare/templates/edit.html @@ -0,0 +1,78 @@ +{% load i18n %} + +
+
    + +
  • +
    + + +
    + {% trans "This name appears in the horizontal navigation at the top of the page" %} +
  • + +
  • +
    + + +
    + {% trans "This assigns an integer value representing the weight of this problem" %} +
  • + +
  • +
    + + +
    + {% trans "This assigns an integer value representing the maximum number of times a student can attempt the problem" %} +
  • + +
  • +
    + + +
    + {% trans "Label for the text area containing the student's answer" %} +
  • + +
  • +
    + + +
    + {% trans "Label for the 'expert' answer" %} +
  • + +
  • +
    + + +
    + {% trans "Label for the submit button" %} +
  • + +
  • +
    + + {% trans "The XML definition for the question and expert answer" %} +
    + +
    +
    +
  • + +
+ + +
+ + diff --git a/src/submit_and_compare/templates/view.html b/src/submit_and_compare/templates/view.html new file mode 100644 index 0000000..7c31be8 --- /dev/null +++ b/src/submit_and_compare/templates/view.html @@ -0,0 +1,37 @@ +
+

{{ display_name }}

+
{{ problem_progress }}
+
{{ prompt }}
+
+
{{ your_answer_label }}
+ +
+
+
{{ our_answer_label }}
+
{{ explanation }}
+
+
{{hint}}
+
+ {% if not is_past_due %} +
+ +
+
+ +
+
+ +
+ {% endif %} +
+
{{ used_attempts_feedback }}
+
diff --git a/src/submit_and_compare/tests/__init__.py b/src/submit_and_compare/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/submit_and_compare/tests/test_all.py b/src/submit_and_compare/tests/test_all.py new file mode 100644 index 0000000..bd3ae5b --- /dev/null +++ b/src/submit_and_compare/tests/test_all.py @@ -0,0 +1,207 @@ +""" +Tests for xblock-submit-and-compare +""" +import re +import unittest +from xml.sax.saxutils import escape + +from unittest import mock +from django.test.client import Client +from opaque_keys.edx.locations import SlashSeparatedCourseKey +from xblock.field_data import DictFieldData + +from ..xblocks import SubmitAndCompareXBlock +from ..views import get_body + + +class SubmitAndCompareXblockTestCase(unittest.TestCase): + # pylint: disable=too-many-instance-attributes, too-many-public-methods + """ + A complete suite of unit tests for the Submit-and-compare XBlock + """ + @classmethod + def make_an_xblock(cls, **kw): + """ + Helper method that creates a Free-text Response XBlock + """ + course_id = SlashSeparatedCourseKey('foo', 'bar', 'baz') + runtime = mock.Mock(course_id=course_id) + scope_ids = mock.Mock() + field_data = DictFieldData(kw) + xblock = SubmitAndCompareXBlock(runtime, field_data, scope_ids) + xblock.xmodule_runtime = runtime + return xblock + + def setUp(self): + self.xblock = SubmitAndCompareXblockTestCase.make_an_xblock() + self.client = Client() + + def test_student_view(self): + # pylint: disable=protected-access + """ + Checks the student view for student specific instance variables. + """ + student_view_html = self.student_view_html() + self.assertIn(self.xblock.display_name, student_view_html) + self.assertIn( + get_body(self.xblock.question_string), + student_view_html, + ) + self.assertIn(self.xblock._get_problem_progress(), student_view_html) + + def test_studio_view(self): + """ + Checks studio view for instance variables specified by the instructor. + """ + with mock.patch( + "submit_and_compare.mixins.fragment.XBlockFragmentBuilderMixin.get_i18n_service", + return_value=None + ): + studio_view_html = self.studio_view_html() + self.assertIn(self.xblock.display_name, studio_view_html) + xblock_body = get_body( + self.xblock.question_string + ) + studio_view_html = re.sub(r'\W+', ' ', studio_view_html.strip()) + xblock_body = re.sub(r'\W+', ' ', xblock_body.strip()) + self.assertIn( + escape(xblock_body), + studio_view_html, + ) + self.assertIn(str(self.xblock.max_attempts), studio_view_html) + + def test_initialization_variables(self): + """ + Checks that all instance variables are initialized correctly + """ + self.assertEqual('Submit and Compare', self.xblock.display_name) + self.assertIn( + 'Before you begin the simulation', + self.xblock.question_string, + ) + self.assertEqual(0.0, self.xblock.score) + self.assertEqual(0, self.xblock.max_attempts) + self.assertEqual('', self.xblock.student_answer) + self.assertEqual(0, self.xblock.count_attempts) + + def student_view_html(self): + """ + Helper method that returns the html of student_view + """ + return self.xblock.student_view().content + + def studio_view_html(self): + """ + Helper method that returns the html of studio_view + """ + return self.xblock.studio_view().content + + def test_problem_progress_weight_zero(self): + # pylint: disable=invalid-name, protected-access + """ + Tests that the the string returned by get_problem_progress + is blank when the weight of the problem is zero + """ + self.xblock.score = 1 + self.xblock.weight = 0 + self.assertEqual('', self.xblock._get_problem_progress()) + + def test_problem_progress_score_zero_weight_singular(self): + # pylint: disable=invalid-name, protected-access + """ + Tests that the the string returned by get_problem_progress + when the weight of the problem is singular, and the score is zero + """ + self.xblock.score = 0 + self.xblock.weight = 1 + self.assertEqual( + '(1 point possible)', + self.xblock._get_problem_progress(), + ) + + def test_problem_progress_score_zero_weight_plural(self): + # pylint: disable=invalid-name, protected-access + """ + Tests that the the string returned by get_problem_progress + when the weight of the problem is plural, and the score is zero + """ + self.xblock.score = 0 + self.xblock.weight = 3 + self.assertEqual( + '(3 points possible)', + self.xblock._get_problem_progress(), + ) + + def test_problem_progress_score_positive_weight_singular(self): + # pylint: disable=invalid-name, protected-access + """ + Tests that the the string returned by get_problem_progress + when the weight of the problem is singular, and the score is positive + """ + self.xblock.score = 1 + self.xblock.weight = 1 + self.assertEqual( + '(1/1 point)', + self.xblock._get_problem_progress(), + ) + + def test_problem_progress_score_positive_weight_plural(self): + # pylint: disable=invalid-name, protected-access + """ + Tests that the the string returned by get_problem_progress + when the weight of the problem is plural, and the score is positive + """ + self.xblock.score = 1 + self.xblock.weight = 3 + self.assertEqual( + '(3/3 points)', + self.xblock._get_problem_progress(), + ) + + def test_used_attempts_feedback_blank(self): + # pylint: disable=invalid-name, protected-access + """ + Tests that get_used_attempts_feedback returns no feedback when + appropriate + """ + self.xblock.max_attempts = 0 + self.assertEqual('', self.xblock._get_used_attempts_feedback()) + + def test_used_attempts_feedback_normal(self): + # pylint: disable=invalid-name, protected-access + """ + Tests that get_used_attempts_feedback returns the expected feedback + """ + self.xblock.max_attempts = 5 + self.xblock.count_attempts = 3 + self.assertEqual( + 'You have used 3 of 5 submissions', + self.xblock._get_used_attempts_feedback(), + ) + + def test_submit_class_blank(self): + # pylint: disable=protected-access + """ + Tests that get_submit_class returns a blank value when appropriate + """ + self.xblock.max_attempts = 0 + self.assertEqual('', self.xblock._get_submit_class()) + + def test_submit_class_nodisplay(self): + # pylint: disable=protected-access + """ + Tests that get_submit_class returns the appropriate class + when the number of attempts has exceeded the maximum number of + permissable attempts + """ + self.xblock.max_attempts = 5 + self.xblock.count_attempts = 6 + self.assertEqual('nodisplay', self.xblock._get_submit_class()) + + def test_max_score(self): + """ + Tests max_score function + Should return the weight + """ + self.xblock.weight = 4 + self.assertEqual(self.xblock.weight, self.xblock.max_score()) diff --git a/src/submit_and_compare/views.py b/src/submit_and_compare/views.py new file mode 100644 index 0000000..40e2e3f --- /dev/null +++ b/src/submit_and_compare/views.py @@ -0,0 +1,306 @@ +""" +Handle view logic for the XBlock +""" +import logging + +from django.utils.translation import ngettext +from django.utils.translation import gettext as _ +from lxml import etree +from six import StringIO +from xblock.core import XBlock +try: + from xblock.utils.resources import ResourceLoader +except ModuleNotFoundError: # For backward compatibility with releases older than Quince. + from xblockutils.resources import ResourceLoader + +from .mixins.fragment import XBlockFragmentBuilderMixin + + +LOG = logging.getLogger(__name__) + + +def _convert_to_int(value_string): + """ + Convert a string to integer + + Default to 0 + """ + try: + value = int(value_string) + except ValueError: + value = 0 + return value + + +def get_body(xmlstring): + """ + Helper method + """ + # pylint: disable=no-member + tree = etree.parse(StringIO(xmlstring)) + body = tree.xpath('/submit_and_compare/body') + body_string = etree.tostring(body[0], method='text', encoding='unicode') + return body_string + + +def _get_explanation(xmlstring): + # pylint: disable=no-member + """ + Helper method + """ + tree = etree.parse(StringIO(xmlstring)) + explanation = tree.xpath('/submit_and_compare/explanation') + explanation_string = etree.tostring( + explanation[0], + method='text', + encoding='unicode', + ) + return explanation_string + + +class SubmitAndCompareViewMixin( + XBlockFragmentBuilderMixin, +): + """ + Handle view logic for Image Modal XBlock instances + """ + + loader = ResourceLoader(__name__) + static_js_init = 'SubmitAndCompareXBlockInitView' + icon_class = 'problem' + editable_fields = [ + 'display_name', + 'weight', + 'max_attempts', + 'your_answer_label', + 'our_answer_label', + 'submit_button_label', + 'question_string', + ] + show_in_read_only_mode = True + + def provide_context(self, context=None): + """ + Build a context dictionary to render the student view + """ + context = context or {} + context = dict(context) + problem_progress = self._get_problem_progress() + used_attempts_feedback = self._get_used_attempts_feedback() + submit_class = self._get_submit_class() + prompt = get_body(self.question_string) + explanation = _get_explanation( + self.question_string + ) + attributes = '' + context.update({ + 'display_name': self.display_name, + 'problem_progress': problem_progress, + 'used_attempts_feedback': used_attempts_feedback, + 'submit_class': submit_class, + 'prompt': prompt, + 'student_answer': self.student_answer, + 'explanation': explanation, + 'your_answer_label': self.your_answer_label, + 'our_answer_label': self.our_answer_label, + 'submit_button_label': self.submit_button_label, + 'attributes': attributes, + 'is_past_due': self.is_past_due(), + }) + return context + + def studio_view(self, context=None): + """ + Build the fragment for the edit/studio view + + Implementation is optional. + """ + context = context or {} + context.update({ + 'display_name': self.display_name, + 'weight': self.weight, + 'max_attempts': self.max_attempts, + 'xml_data': self.question_string, + 'your_answer_label': self.your_answer_label, + 'our_answer_label': self.our_answer_label, + 'submit_button_label': self.submit_button_label, + }) + template = 'edit.html' + fragment = self.build_fragment( + template=template, + context=context, + js_init='SubmitAndCompareXBlockInitEdit', + css=[ + 'edit.css', + ], + js=[ + 'edit.js', + ], + ) + return fragment + + @XBlock.json_handler + def studio_submit(self, data, *args, **kwargs): + """ + Save studio edits + """ + # pylint: disable=unused-argument + self.display_name = data['display_name'] + self.weight = _convert_to_int(data['weight']) + max_attempts = _convert_to_int(data['max_attempts']) + if max_attempts >= 0: + self.max_attempts = max_attempts # pylint: disable=consider-using-min-builtin + self.your_answer_label = data['your_answer_label'] + self.our_answer_label = data['our_answer_label'] + self.submit_button_label = data['submit_button_label'] + xml_content = data['data'] + # pylint: disable=no-member + try: + etree.parse(StringIO(xml_content)) + self.question_string = xml_content + except etree.XMLSyntaxError as error: + return { + 'result': 'error', + 'message': error.message, + } + + return { + 'result': 'success', + } + + @XBlock.json_handler + def student_submit(self, data, *args, **kwargs): + """ + Save student answer + """ + # pylint: disable=unused-argument + # when max_attempts == 0, the user can make unlimited attempts + success = False + # pylint: disable=no-member + if self.max_attempts > 0 and self.count_attempts >= self.max_attempts: + # pylint: enable=no-member + LOG.error( + 'User has already exceeded the maximum ' + 'number of allowed attempts', + ) + elif self.is_past_due(): + LOG.debug( + 'This problem is past due', + ) + else: + self.student_answer = data['answer'] + if data['action'] == 'submit': + self.count_attempts += 1 # pylint: disable=no-member + if self.student_answer: + self.score = 1.0 + else: + self.score = 0.0 + self._publish_grade() + self._publish_problem_check() + success = True + result = { + 'success': success, + 'problem_progress': self._get_problem_progress(), + 'submit_class': self._get_submit_class(), + 'used_attempts_feedback': self._get_used_attempts_feedback(), + } + return result + + @XBlock.json_handler + def send_hints(self, data, *args, **kwargs): + """ + Build hints once for user + This is called once on page load and + js loop through hints on button click + """ + # pylint: disable=unused-argument + # pylint: disable=no-member + tree = etree.parse(StringIO(self.question_string)) + raw_hints = tree.xpath('/submit_and_compare/demandhint/hint') + decorated_hints = [] + total_hints = len(raw_hints) + for i, raw_hint in enumerate(raw_hints, 1): + hint = _('Hint ({number} of {total}): {hint}').format( + number=i, + total=total_hints, + hint=etree.tostring(raw_hint, encoding='unicode'), + ) + decorated_hints.append(hint) + hints = decorated_hints + return { + 'result': 'success', + 'hints': hints, + } + + def _get_used_attempts_feedback(self): + """ + Returns the text with feedback to the user about the number of attempts + they have used if applicable + """ + result = '' + if self.max_attempts > 0: + # pylint: disable=no-member + result = ngettext( + 'You have used {count_attempts} of {max_attempts} submission', + 'You have used {count_attempts} of {max_attempts} submissions', + self.max_attempts, + ).format( + count_attempts=self.count_attempts, + max_attempts=self.max_attempts, + ) + # pylint: enable=no-member + return result + + def _can_submit(self): + """ + Determine if a user can submit a response + """ + if self.is_past_due(): + return False + if self.max_attempts == 0: + return True + # pylint: disable=no-member + if self.count_attempts < self.max_attempts: + return True + # pylint: enable=no-member + return False + + def _get_submit_class(self): + """ + Returns the css class for the submit button + """ + result = '' + if not self._can_submit(): + result = 'nodisplay' + return result + + def _get_problem_progress(self): + """ + Returns a statement of progress for the XBlock, which depends + on the user's current score + """ + if self.weight == 0: + result = '' + elif self.score == 0.0: + result = "({})".format( + ngettext( + '{weight} point possible', + '{weight} points possible', + self.weight, + ).format( + weight=self.weight, + ) + ) + else: + scaled_score = self.score * self.weight + score_string = f'{scaled_score:g}' + result = "({})".format( + ngettext( + score_string + '/' + "{weight} point", + score_string + '/' + "{weight} points", + self.weight, + ).format( + weight=self.weight, + ) + ) + return result diff --git a/src/submit_and_compare/xblocks.py b/src/submit_and_compare/xblocks.py new file mode 100644 index 0000000..f21b0f9 --- /dev/null +++ b/src/submit_and_compare/xblocks.py @@ -0,0 +1,24 @@ +""" +This is the core logic for the XBlock +""" +from xblock.core import XBlock + +from .mixins.dates import EnforceDueDates +from .mixins.events import EventableMixin +from .mixins.scenario import XBlockWorkbenchMixin +from .models import SubmitAndCompareModelMixin +from .views import SubmitAndCompareViewMixin + + +@XBlock.needs('i18n') +class SubmitAndCompareXBlock( + EnforceDueDates, + EventableMixin, + SubmitAndCompareModelMixin, + SubmitAndCompareViewMixin, + XBlockWorkbenchMixin, + XBlock, +): + """ + A Submit-And-Compare XBlock + """ From 4d231e26eaa51698182e340f817a01c190280013 Mon Sep 17 00:00:00 2001 From: farhan Date: Fri, 3 Apr 2026 13:11:42 +0500 Subject: [PATCH 2/4] fix: fix checks --- .gitignore | 2 +- src/imagemodal/__init__.py | 3 +- src/imagemodal/mixins/fragment.py | 29 +- src/imagemodal/mixins/scenario.py | 1 + src/imagemodal/models.py | 54 ++- src/imagemodal/settings.py | 14 +- src/imagemodal/tests/test_display.py | 11 +- src/imagemodal/tests/test_workbench.py | 13 +- src/imagemodal/views.py | 34 +- src/imagemodal/xblocks.py | 11 +- src/schoolyourself/__init__.py | 4 +- src/schoolyourself/schoolyourself.py | 326 +++++++++--------- src/schoolyourself/schoolyourself_lesson.py | 85 +++-- src/schoolyourself/schoolyourself_review.py | 224 ++++++------ .../schoolyourself_review_test.py | 212 ++++++------ src/submit_and_compare/mixins/dates.py | 5 +- src/submit_and_compare/mixins/events.py | 31 +- src/submit_and_compare/mixins/fragment.py | 36 +- src/submit_and_compare/models.py | 44 +-- src/submit_and_compare/settings.py | 8 +- src/submit_and_compare/tests/test_all.py | 43 ++- src/submit_and_compare/views.py | 168 ++++----- src/submit_and_compare/xblocks.py | 15 +- tests/__init__.py | 1 - tests/test_placeholder.py | 6 - 25 files changed, 675 insertions(+), 705 deletions(-) delete mode 100644 tests/__init__.py delete mode 100644 tests/test_placeholder.py diff --git a/.gitignore b/.gitignore index db789c2..0e46e2e 100644 --- a/.gitignore +++ b/.gitignore @@ -219,4 +219,4 @@ __marimo__/ docs/_build/ # macOS system files -**/.DS_Store \ No newline at end of file +**/.DS_Store diff --git a/src/imagemodal/__init__.py b/src/imagemodal/__init__.py index 7ea114f..8c398d9 100644 --- a/src/imagemodal/__init__.py +++ b/src/imagemodal/__init__.py @@ -1,4 +1,5 @@ """ A fullscreen, zooming image modal XBlock """ -from .xblocks import ImageModal + +from .xblocks import ImageModal as ImageModal diff --git a/src/imagemodal/mixins/fragment.py b/src/imagemodal/mixins/fragment.py index 860caf1..96e8eb5 100644 --- a/src/imagemodal/mixins/fragment.py +++ b/src/imagemodal/mixins/fragment.py @@ -4,28 +4,29 @@ Note: We should resume test coverage for all lines in this file once split into its own library. """ + from django.template.context import Context from xblock.core import XBlock - try: from web_fragments.fragment import Fragment except Exception: - from xblock.fragment import Fragment # For backward compatibility with quince and earlier. + from xblock.fragment import Fragment # For backward compatibility with quince and earlier. class XBlockFragmentBuilderMixin: """ Create a default XBlock fragment builder """ + static_css = [ - 'view.css', + "view.css", ] static_js = [ - 'view.js', + "view.js", ] static_js_init = None - template = 'view.html' + template = "view.html" def provide_context(self, context): # pragma: no cover """ @@ -37,7 +38,7 @@ def provide_context(self, context): # pragma: no cover context = dict(context) return context - @XBlock.supports('multi_device') + @XBlock.supports("multi_device") def student_view(self, context=None): """ Build the fragment for the default student view @@ -56,33 +57,31 @@ def student_view(self, context=None): ) return fragment - def build_fragment(self, *, template='', - context=None, css=None, - js=None, js_init=None): + def build_fragment(self, *, template="", context=None, css=None, js=None, js_init=None): """ Creates a fragment for display. """ context = context or {} css = css or [] js = js or [] - rendered_template = '' + rendered_template = "" if template: # pragma: no cover - template = 'templates/' + template + template = "templates/" + template rendered_template = self.loader.render_django_template( template, context=Context(context), - i18n_service=self.runtime.service(self, 'i18n'), + i18n_service=self.runtime.service(self, "i18n"), ) fragment = Fragment(rendered_template) for item in css: - if item.startswith('/'): + if item.startswith("/"): url = item else: - item = 'public/' + item + item = "public/" + item url = self.runtime.local_resource_url(self, item) fragment.add_css_url(url) for item in js: - item = 'public/' + item + item = "public/" + item url = self.runtime.local_resource_url(self, item) fragment.add_javascript_url(url) if js_init: # pragma: no cover diff --git a/src/imagemodal/mixins/scenario.py b/src/imagemodal/mixins/scenario.py index cfb13ff..3b20c7b 100644 --- a/src/imagemodal/mixins/scenario.py +++ b/src/imagemodal/mixins/scenario.py @@ -1,6 +1,7 @@ """ Mixin workbench behavior into XBlocks """ + try: from xblock.utils.resources import ResourceLoader except ModuleNotFoundError: diff --git a/src/imagemodal/models.py b/src/imagemodal/models.py index 9fe6f29..9f3e776 100644 --- a/src/imagemodal/models.py +++ b/src/imagemodal/models.py @@ -1,9 +1,9 @@ """ Handle data access logic for the XBlock """ + from django.utils.translation import gettext_lazy as _ -from xblock.fields import Scope -from xblock.fields import String +from xblock.fields import Scope, String class ImageModalModelMixin: @@ -12,59 +12,55 @@ class ImageModalModelMixin: """ editable_fields = [ - 'display_name', - 'image_url', - 'thumbnail_url', - 'description', - 'alt_text', + "display_name", + "image_url", + "thumbnail_url", + "description", + "alt_text", ] show_in_read_only_mode = True display_name = String( - display_name=_('Display Name'), - default='Image Modal XBlock', + display_name=_("Display Name"), + default="Image Modal XBlock", scope=Scope.settings, help=_("This is the XBlock's display name"), ) image_url = String( - display_name=_('Image URL'), + display_name=_("Image URL"), default=( - 'http://upload.wikimedia.org/' - 'wikipedia/commons/4/48/' - '1853_Kaei_6_Japanese_Map_of_the_World_-_' - 'Geographicus_-_ChikyuBankokuHozu-nakajima-1853.jpg' + "http://upload.wikimedia.org/" + "wikipedia/commons/4/48/" + "1853_Kaei_6_Japanese_Map_of_the_World_-_" + "Geographicus_-_ChikyuBankokuHozu-nakajima-1853.jpg" ), scope=Scope.settings, - help=_( - 'This is the location of the full-screen image to be displayed.' - ), + help=_("This is the location of the full-screen image to be displayed."), ) thumbnail_url = String( - display_name=_('Thumbnail URL'), - default='', + display_name=_("Thumbnail URL"), + default="", scope=Scope.settings, help=_( - 'This is the (optional) location of a thumbnail image to be ' - 'displayed before the main image has been enlarged.' + "This is the (optional) location of a thumbnail image to be " + "displayed before the main image has been enlarged." ), ) description = String( - display_name=_('Description'), - default='', + display_name=_("Description"), + default="", scope=Scope.settings, - help=_('Description text, displayed to screen readers'), + help=_("Description text, displayed to screen readers"), multiline_editor=True, ) alt_text = String( - display_name=_('Alt Text'), - default='', + display_name=_("Alt Text"), + default="", scope=Scope.settings, - help=_( - 'This field allows you to add alternate or descriptive text that pertains to your image.' - ), + help=_("This field allows you to add alternate or descriptive text that pertains to your image."), ) diff --git a/src/imagemodal/settings.py b/src/imagemodal/settings.py index 3295392..162fc51 100644 --- a/src/imagemodal/settings.py +++ b/src/imagemodal/settings.py @@ -3,16 +3,14 @@ """ DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', + "default": { + "ENGINE": "django.db.backends.sqlite3", # 'NAME': 'intentionally-omitted', }, } -INSTALLED_APPS = ( - 'imagemodal', -) +INSTALLED_APPS = ("imagemodal",) LOCALE_PATHS = [ - 'imagemodal/translations', + "imagemodal/translations", ] -SECRET_KEY = 'SECRET_KEY' -DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' +SECRET_KEY = "SECRET_KEY" +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" diff --git a/src/imagemodal/tests/test_display.py b/src/imagemodal/tests/test_display.py index 04e2b75..f29195e 100644 --- a/src/imagemodal/tests/test_display.py +++ b/src/imagemodal/tests/test_display.py @@ -2,9 +2,10 @@ """ Test basic XBlock display function """ -import unittest +import unittest from unittest.mock import Mock + from opaque_keys.edx.locations import SlashSeparatedCourseKey from xblock.field_data import DictFieldData @@ -15,7 +16,7 @@ def make_an_xblock(**kwargs): """ Helper method that creates a Free-text Response XBlock """ - course_id = SlashSeparatedCourseKey('foo', 'bar', 'baz') + course_id = SlashSeparatedCourseKey("foo", "bar", "baz") runtime = Mock( course_id=course_id, service=Mock( @@ -43,9 +44,9 @@ def test_render(self): student_view = self.xblock.student_view() html = student_view.content self.assertIsNotNone(html) - self.assertNotEqual('', html) - self.assertIn('imagemodal_block', html) + self.assertNotEqual("", html) + self.assertIn("imagemodal_block", html) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/src/imagemodal/tests/test_workbench.py b/src/imagemodal/tests/test_workbench.py index 5d62c44..1e80aa1 100755 --- a/src/imagemodal/tests/test_workbench.py +++ b/src/imagemodal/tests/test_workbench.py @@ -2,6 +2,7 @@ """ Test XBlock workbench integration """ + import unittest from imagemodal import ImageModal @@ -20,11 +21,7 @@ def _is_in_any_scenario(self, text): """ Check if the text exists in any scenario """ - contains = any( - True - for scenario in self.scenarios - if text in scenario[1] - ) + contains = any(True for scenario in self.scenarios if text in scenario[1]) return contains def test_load(self): @@ -34,16 +31,16 @@ def test_has_sequence(self): """ Make sure at least one scenario contains a sequence """ - has_sequence = self._is_in_any_scenario('sequence_demo') + has_sequence = self._is_in_any_scenario("sequence_demo") self.assertTrue(has_sequence) def test_has_vertical(self): """ Make sure at least one scenario contains a vertical """ - has_sequence = self._is_in_any_scenario('vertical_demo') + has_sequence = self._is_in_any_scenario("vertical_demo") self.assertTrue(has_sequence) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/src/imagemodal/views.py b/src/imagemodal/views.py index e0fcf44..2bd2ae0 100644 --- a/src/imagemodal/views.py +++ b/src/imagemodal/views.py @@ -1,6 +1,7 @@ """ Handle view logic for the XBlock """ + try: from xblock.utils.resources import ResourceLoader from xblock.utils.studio_editable import StudioEditableXBlockMixin @@ -10,13 +11,12 @@ from .mixins.fragment import XBlockFragmentBuilderMixin - -URL_FONT_AWESOME_CSS = '//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css' # nopep8 +URL_FONT_AWESOME_CSS = "//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" # nopep8 class ImageModalViewMixin( - XBlockFragmentBuilderMixin, - StudioEditableXBlockMixin, + XBlockFragmentBuilderMixin, + StudioEditableXBlockMixin, ): """ Handle view logic for Image Modal XBlock instances @@ -25,13 +25,13 @@ class ImageModalViewMixin( loader = ResourceLoader(__name__) static_css = [ URL_FONT_AWESOME_CSS, - 'view.css', + "view.css", ] static_js = [ - 'draggabilly.pkgd.min.js', - 'view.js', + "draggabilly.pkgd.min.js", + "view.js", ] - static_js_init = 'ImageModalView' + static_js_init = "ImageModalView" def provide_context(self, context=None): """ @@ -39,12 +39,14 @@ def provide_context(self, context=None): """ context = context or {} context = dict(context) - context.update({ - 'display_name': self.display_name, - 'image_url': self.image_url, - 'thumbnail_url': self.thumbnail_url or self.image_url, - 'description': self.description, - 'xblock_id': str(self.scope_ids.usage_id), - 'alt_text': self.alt_text or self.display_name, - }) + context.update( + { + "display_name": self.display_name, + "image_url": self.image_url, + "thumbnail_url": self.thumbnail_url or self.image_url, + "description": self.description, + "xblock_id": str(self.scope_ids.usage_id), + "alt_text": self.alt_text or self.display_name, + } + ) return context diff --git a/src/imagemodal/xblocks.py b/src/imagemodal/xblocks.py index 1aecdae..bae822f 100644 --- a/src/imagemodal/xblocks.py +++ b/src/imagemodal/xblocks.py @@ -1,6 +1,7 @@ """ This is the core logic for the XBlock """ + from xblock.core import XBlock from .mixins.scenario import XBlockWorkbenchMixin @@ -8,12 +9,12 @@ from .views import ImageModalViewMixin -@XBlock.needs('i18n') +@XBlock.needs("i18n") class ImageModal( - ImageModalModelMixin, - ImageModalViewMixin, - XBlockWorkbenchMixin, - XBlock, + ImageModalModelMixin, + ImageModalViewMixin, + XBlockWorkbenchMixin, + XBlock, ): """ A fullscreen image modal XBlock. diff --git a/src/schoolyourself/__init__.py b/src/schoolyourself/__init__.py index 8fc0284..1a79e0d 100644 --- a/src/schoolyourself/__init__.py +++ b/src/schoolyourself/__init__.py @@ -1,2 +1,2 @@ -from .schoolyourself_lesson import SchoolYourselfLessonXBlock -from .schoolyourself_review import SchoolYourselfReviewXBlock +from .schoolyourself_lesson import SchoolYourselfLessonXBlock as SchoolYourselfLessonXBlock +from .schoolyourself_review import SchoolYourselfReviewXBlock as SchoolYourselfReviewXBlock diff --git a/src/schoolyourself/schoolyourself.py b/src/schoolyourself/schoolyourself.py index 0e5c8f2..826fa1d 100644 --- a/src/schoolyourself/schoolyourself.py +++ b/src/schoolyourself/schoolyourself.py @@ -3,14 +3,12 @@ import hashlib import hmac import os -import importlib -import importlib.resources from mako.template import Template - +from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.fields import Scope, String -from web_fragments.fragment import Fragment + try: from xblock.utils.resources import ResourceLoader except ModuleNotFoundError: @@ -38,195 +36,201 @@ class SchoolYourselfXBlock(XBlock): master the topic, then come back later and get subsequent questions wrong. """ + display_name = String( - help="The display name of this component.", - scope=Scope.settings, - default="", - display_name="The display name of this component") + help="The display name of this component.", + scope=Scope.settings, + default="", + display_name="The display name of this component", + ) module_id = String( - help=("The full ID of the module as it would appear on " - "schoolyourself.org, such as 'geometry/lines_rays'."), - scope=Scope.settings, - default="intro/intro_module", - display_name="SY Module ID", - enforce_type=True) + help=("The full ID of the module as it would appear on schoolyourself.org, such as 'geometry/lines_rays'."), + scope=Scope.settings, + default="intro/intro_module", + display_name="SY Module ID", + enforce_type=True, + ) module_title = String( - help=("The human-readable title of the module, such as " - "'Lines and rays'."), - scope=Scope.settings, - default="Introduction", - display_name="SY Module name", - enforce_type=True) + help=("The human-readable title of the module, such as 'Lines and rays'."), + scope=Scope.settings, + default="Introduction", + display_name="SY Module name", + enforce_type=True, + ) module_description = String( - help=("The description text to display underneath the title."), - scope=Scope.settings, - default="Welcome to School Yourself!", - display_name="SY Module description", - enforce_type=True) + help=("The description text to display underneath the title."), + scope=Scope.settings, + default="Welcome to School Yourself!", + display_name="SY Module description", + enforce_type=True, + ) base_url = String( - help=("The base URL that the iframes will be pointing to. Do not put " - "URL params here -- those get added by the view."), - default="https://schoolyourself.org", - scope=Scope.content, - display_name="Base URL", - enforce_type=True) + help=( + "The base URL that the iframes will be pointing to. Do not put " + "URL params here -- those get added by the view." + ), + default="https://schoolyourself.org", + scope=Scope.content, + display_name="Base URL", + enforce_type=True, + ) shared_key = String( - help=("This is the key that we use to verify signed data coming " + help=( + "This is the key that we use to verify signed data coming " "from the School Yourself server about the user. This typically " "includes the user ID and mastery levels of the topic presented " - "in this lesson."), - scope=Scope.content, - display_name="Shared key", - default="", - enforce_type=True) + "in this lesson." + ), + scope=Scope.content, + display_name="Shared key", + default="", + enforce_type=True, + ) partner_id = String( - help=("This is the string that is passed as the partner_id param " + help=( + "This is the string that is passed as the partner_id param " "in all URLs that get generated. For School Yourself courses, " "leave this as the default 'edx'. When testing, you may want " "to set this to something else to indicate to the backend that " - "the request doesn't count as production traffic."""), - scope=Scope.content, - display_name="Partner ID", - default="edx", - enforce_type=True) + "the request doesn't count as production traffic." + "" + ), + scope=Scope.content, + display_name="Partner ID", + default="edx", + enforce_type=True, + ) loader = ResourceLoader(__name__) def get_student_id(self): - """This is a helper that retrieves the student ID. We need this - method because the ID might be different depending on whether we - are running in the LMS or in the XBlock workbench. For more - information, see - https://groups.google.com/forum/#!topic/edx-code/ryPw7a-tK_g - for a discussion on this topic. - - If no student ID is available for some reason, we return None. - - Returns: - A unicode string. - """ - if hasattr(self, "xmodule_runtime"): - return self.xmodule_runtime.anonymous_student_id - - # The following lines give an alternate way of getting a user_id - # in the case of studio or workbench. Currently, studio will - # just give back an ID of "student", whereas workbench lets you - # set it in a URL param. In any case, any module that is not being - # actually viewed by a student should send the user ID "debug" - # back to the SY servers. If you want to change that behavior, - # uncomment the following 3 lines. - # - # if self.scope_ids.user_id is None: - # return None - # return unicode(self.scope_ids.user_id) - - return "debug" - + """This is a helper that retrieves the student ID. We need this + method because the ID might be different depending on whether we + are running in the LMS or in the XBlock workbench. For more + information, see + https://groups.google.com/forum/#!topic/edx-code/ryPw7a-tK_g + for a discussion on this topic. + + If no student ID is available for some reason, we return None. + + Returns: + A unicode string. + """ + if hasattr(self, "xmodule_runtime"): + return self.xmodule_runtime.anonymous_student_id + + # The following lines give an alternate way of getting a user_id + # in the case of studio or workbench. Currently, studio will + # just give back an ID of "student", whereas workbench lets you + # set it in a URL param. In any case, any module that is not being + # actually viewed by a student should send the user ID "debug" + # back to the SY servers. If you want to change that behavior, + # uncomment the following 3 lines. + # + # if self.scope_ids.user_id is None: + # return None + # return unicode(self.scope_ids.user_id) + + return "debug" def resource_string(self, path): - """Handy helper for getting resources from our kit.""" - return self.loader.load_unicode(path) + """Handy helper for getting resources from our kit.""" + return self.loader.load_unicode(path) + def render_template(self, template_name, context=None): + """Another handy helper for rendering Mako templates from our kit.""" - def render_template(self, template_name, context={}): - """Another handy helper for rendering Mako templates from our kit.""" - - template = Template(self.resource_string(os.path.join("templates", - template_name))) - return template.render_unicode(**context) - + if context is None: + context = {} + template = Template(self.resource_string(os.path.join("templates", template_name))) + return template.render_unicode(**context) def get_partner_url_params(self, shared_key=None): - """A helper method that generates a dict of URL params that we can - append to the end of a URL, containing the partner ID and the - user's anonymouse user ID. These are typically transmitted as URL - params. in the iframes. - - If a shared_key is provided and there is a username to encode, - we will sign it with the shared key. - """ - if not self.partner_id: - # Default to "edx" if there's nothing set. - partner_id = "edx" - else: - partner_id = self.partner_id - - url_params = {"partner": partner_id} - user_id = self.get_student_id() - if user_id: - url_params["partner_user_id"] = user_id - if shared_key: - url_params["partner_signature"] = hmac.new( - bytes(shared_key, "utf-8"), - bytes(user_id, "utf-8"), - digestmod=hashlib.md5).hexdigest() - - return url_params - + """A helper method that generates a dict of URL params that we can + append to the end of a URL, containing the partner ID and the + user's anonymouse user ID. These are typically transmitted as URL + params. in the iframes. + + If a shared_key is provided and there is a username to encode, + we will sign it with the shared key. + """ + if not self.partner_id: + # Default to "edx" if there's nothing set. + partner_id = "edx" + else: + partner_id = self.partner_id + + url_params = {"partner": partner_id} + user_id = self.get_student_id() + if user_id: + url_params["partner_user_id"] = user_id + if shared_key: + url_params["partner_signature"] = hmac.new( + bytes(shared_key, "utf-8"), bytes(user_id, "utf-8"), digestmod=hashlib.md5 + ).hexdigest() + + return url_params def get_display_name(self, module_title): - """ - This method generates a string that is usable as the display name - for the component, using the module title (such as "Lines and Rays"). - By default, we just return the module title, but subclasses might - want to do something more specific. - """ - return module_title - + """ + This method generates a string that is usable as the display name + for the component, using the module title (such as "Lines and Rays"). + By default, we just return the module title, but subclasses might + want to do something more specific. + """ + return module_title def studio_view(self, context=None): - """ - This is the view that content authors will see when they click on the - "Edit" button in Studio. It is a form that lets them type in two fields: - module ID and player type. This is the same for both lessons and - reviews. - """ - context = { - "module_id": self.module_id, - "module_title": self.module_title, - "module_description": self.module_description, - "shared_key": self.shared_key, - "base_url": self.base_url, - "partner_id": self.partner_id - } - - fragment = Fragment(self.render_template("studio_view.html", context)) - - fragment.add_javascript( - self.resource_string("static/js/studio_view.js")) - fragment.initialize_js("SchoolYourselfStudioView") - return fragment - + """ + This is the view that content authors will see when they click on the + "Edit" button in Studio. It is a form that lets them type in two fields: + module ID and player type. This is the same for both lessons and + reviews. + """ + context = { + "module_id": self.module_id, + "module_title": self.module_title, + "module_description": self.module_description, + "shared_key": self.shared_key, + "base_url": self.base_url, + "partner_id": self.partner_id, + } + + fragment = Fragment(self.render_template("studio_view.html", context)) + + fragment.add_javascript(self.resource_string("static/js/studio_view.js")) + fragment.initialize_js("SchoolYourselfStudioView") + return fragment @XBlock.json_handler def studio_submit(self, data, suffix=""): - """ - This is the handler that the form in student_view() calls when - new data is inputted. - """ - self.module_id = data.get("module_id", "intro/intro_module") - self.module_title = data.get("module_title", "Introduction") - self.module_description = data.get("module_description", - "Welcome to School Yourself!") - self.base_url = data.get("base_url", - "https://schoolyourself.org") - if "shared_key" in data: - self.shared_key = data.get("shared_key") - - self.display_name = self.get_display_name(self.module_title) - - if "partner_id" in data: - self.partner_id = data.get("partner_id") - - return { "module_id": self.module_id, - "module_title": self.module_title, - "module_description": self.module_description, - "shared_key": self.shared_key, - "base_url": self.base_url, - "partner_id": self.partner_id } + """ + This is the handler that the form in student_view() calls when + new data is inputted. + """ + self.module_id = data.get("module_id", "intro/intro_module") + self.module_title = data.get("module_title", "Introduction") + self.module_description = data.get("module_description", "Welcome to School Yourself!") + self.base_url = data.get("base_url", "https://schoolyourself.org") + if "shared_key" in data: + self.shared_key = data.get("shared_key") + + self.display_name = self.get_display_name(self.module_title) + + if "partner_id" in data: + self.partner_id = data.get("partner_id") + + return { + "module_id": self.module_id, + "module_title": self.module_title, + "module_description": self.module_description, + "shared_key": self.shared_key, + "base_url": self.base_url, + "partner_id": self.partner_id, + } diff --git a/src/schoolyourself/schoolyourself_lesson.py b/src/schoolyourself/schoolyourself_lesson.py index 284033a..f53138d 100644 --- a/src/schoolyourself/schoolyourself_lesson.py +++ b/src/schoolyourself/schoolyourself_lesson.py @@ -1,8 +1,8 @@ """An XBlock that displays School Yourself lessons.""" -import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error - -from xblock.core import XBlock +import six.moves.urllib.error +import six.moves.urllib.parse +import six.moves.urllib.request from xblock.fragment import Fragment from .schoolyourself import SchoolYourselfXBlock @@ -14,62 +14,56 @@ class SchoolYourselfLessonXBlock(SchoolYourselfXBlock): which is rendered in an iframe. The block transmits the anonymous user ID. """ + has_children = False has_score = False def get_display_name(self, module_title): - return "Lesson: %s" % module_title + return f"Lesson: {module_title}" def student_view(self, context=None): - """ - The primary view of the SchoolYourselfLessonXBlock, shown to students - when viewing courses. - """ - # Construct the URL we're going to stuff into the iframe once - # it gets launched: - url_params = self.get_partner_url_params(self.shared_key) - url_params["id"] = self.module_id - - # Set up the screenshot URL: - screenshot_url = "%s/page/screenshot/%s" % (self.base_url, - self.module_id) + """ + The primary view of the SchoolYourselfLessonXBlock, shown to students + when viewing courses. + """ + # Construct the URL we're going to stuff into the iframe once + # it gets launched: + url_params = self.get_partner_url_params(self.shared_key) + url_params["id"] = self.module_id - context = { - "iframe_url": "%s/page/embed?%s" % (self.base_url, - six.moves.urllib.parse.urlencode(url_params)), - "screenshot_url": screenshot_url, - "title": self.module_title, - "description": self.module_description - } + # Set up the screenshot URL: + screenshot_url = f"{self.base_url}/page/screenshot/{self.module_id}" - # Now actually render the fragment, which is just a button with - # some JS code that handles the click event on that button. - fragment = Fragment(self.render_template("lesson_student_view.html", - context)) + context = { + "iframe_url": f"{self.base_url}/page/embed?{six.moves.urllib.parse.urlencode(url_params)}", + "screenshot_url": screenshot_url, + "title": self.module_title, + "description": self.module_description, + } - # Load the common JS/CSS libraries: - fragment.add_css_url( - self.runtime.local_resource_url(self, "public/sylib.css")) - fragment.add_javascript_url( - self.runtime.local_resource_url(self, "public/sylib.js")) + # Now actually render the fragment, which is just a button with + # some JS code that handles the click event on that button. + fragment = Fragment(self.render_template("lesson_student_view.html", context)) - fragment.add_css_url("//fonts.googleapis.com/css?family=Open+Sans:700,400,300") + # Load the common JS/CSS libraries: + fragment.add_css_url(self.runtime.local_resource_url(self, "public/sylib.css")) + fragment.add_javascript_url(self.runtime.local_resource_url(self, "public/sylib.js")) - # And finally the embedded HTML/JS code: - fragment.add_javascript(self.resource_string( - "static/js/lesson_student_view.js")) - fragment.add_css(self.resource_string( - "static/css/student_view.css")) - fragment.initialize_js("SchoolYourselfLessonStudentView") - return fragment + fragment.add_css_url("//fonts.googleapis.com/css?family=Open+Sans:700,400,300") + # And finally the embedded HTML/JS code: + fragment.add_javascript(self.resource_string("static/js/lesson_student_view.js")) + fragment.add_css(self.resource_string("static/css/student_view.css")) + fragment.initialize_js("SchoolYourselfLessonStudentView") + return fragment @staticmethod def workbench_scenarios(): - """A canned scenario for display in the workbench.""" - return [ - ("SchoolYourselfLessonXBlock", - """\ + """A canned scenario for display in the workbench.""" + return [ + ( + "SchoolYourselfLessonXBlock", + """\ - """), + """, + ), ] diff --git a/src/schoolyourself/schoolyourself_review.py b/src/schoolyourself/schoolyourself_review.py index 06cdb22..f739475 100644 --- a/src/schoolyourself/schoolyourself_review.py +++ b/src/schoolyourself/schoolyourself_review.py @@ -1,12 +1,11 @@ """An XBlock that displays School Yourself reviews and may publish grades.""" -import hashlib import hmac -from six import text_type -import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error +import six.moves.urllib.error +import six.moves.urllib.parse +import six.moves.urllib.request from xblock.core import XBlock -from xblock.fields import Scope, String from xblock.fragment import Fragment from .schoolyourself import SchoolYourselfXBlock @@ -20,143 +19,125 @@ class SchoolYourselfReviewXBlock(SchoolYourselfXBlock): Yourself regarding the user's progress and mastery through the topic being shown. """ + has_children = False has_score = True weight = 1.0 def get_display_name(self, module_title): - return "Review: %s" % module_title + return f"Review: {module_title}" def student_view(self, context=None): - """ - The primary view of the SchoolYourselfReviewXBlock, shown to students - when viewing courses. - """ - # Construct the URL we're going to stuff into the iframe once - # it gets launched: - partner_url_params = self.get_partner_url_params(self.shared_key) - - iframe_url_params = dict(partner_url_params) - iframe_url_params["module"] = self.module_id - - mastery_url_params = dict(partner_url_params) - mastery_url_params["tags"] = self.module_id - - # Set up the screenshot URL: - screenshot_url = "%s/page/screenshot/%s" % (self.base_url, - self.module_id) - - mastery_url = "%s/progress/mastery?%s" % ( - self.base_url, six.moves.urllib.parse.urlencode(mastery_url_params)) - - context = { - "iframe_url": "%s/review/embed?%s" % ( - self.base_url, six.moves.urllib.parse.urlencode(iframe_url_params)), - "title": self.module_title, - "icon_url": self.runtime.local_resource_url(self, - "public/review_icon.png"), - "mastery_url": mastery_url - } - - - - # Now actually render the fragment, which is just a button with - # some JS code that handles the click event on that button. - fragment = Fragment(self.render_template("review_student_view.html", - context)) - - # Load the common JS/CSS libraries: - fragment.add_css_url( - self.runtime.local_resource_url(self, "public/sylib.css")) - fragment.add_javascript_url( - self.runtime.local_resource_url(self, "public/sylib.js")) - - - # And finally the embedded HTML/JS code: - fragment.add_javascript(self.resource_string( - "static/js/review_student_view.js")) - fragment.add_css(self.resource_string( - "static/css/student_view.css")) - fragment.add_css_url("//fonts.googleapis.com/css?family=Open+Sans:700,400,300") - fragment.initialize_js("SchoolYourselfReviewStudentView") - return fragment - + """ + The primary view of the SchoolYourselfReviewXBlock, shown to students + when viewing courses. + """ + # Construct the URL we're going to stuff into the iframe once + # it gets launched: + partner_url_params = self.get_partner_url_params(self.shared_key) + + iframe_url_params = dict(partner_url_params) + iframe_url_params["module"] = self.module_id + + mastery_url_params = dict(partner_url_params) + mastery_url_params["tags"] = self.module_id + + mastery_url = f"{self.base_url}/progress/mastery?{six.moves.urllib.parse.urlencode(mastery_url_params)}" + + context = { + "iframe_url": f"{self.base_url}/review/embed?{six.moves.urllib.parse.urlencode(iframe_url_params)}", + "title": self.module_title, + "icon_url": self.runtime.local_resource_url(self, "public/review_icon.png"), + "mastery_url": mastery_url, + } + + # Now actually render the fragment, which is just a button with + # some JS code that handles the click event on that button. + fragment = Fragment(self.render_template("review_student_view.html", context)) + + # Load the common JS/CSS libraries: + fragment.add_css_url(self.runtime.local_resource_url(self, "public/sylib.css")) + fragment.add_javascript_url(self.runtime.local_resource_url(self, "public/sylib.js")) + + # And finally the embedded HTML/JS code: + fragment.add_javascript(self.resource_string("static/js/review_student_view.js")) + fragment.add_css(self.resource_string("static/css/student_view.css")) + fragment.add_css_url("//fonts.googleapis.com/css?family=Open+Sans:700,400,300") + fragment.initialize_js("SchoolYourselfReviewStudentView") + return fragment @XBlock.json_handler def handle_grade(self, data, suffix=""): - """This is the handler that gets called when we receive grades. - - We will verify the message to make sure that it is signed and - that the signature is valid. If everything is good, then we'll - publish a "grade" event for this module. + """This is the handler that gets called when we receive grades. - The actual work is done in handle_grade_json(), and this method - just calls that. This method is just here so that it can be wrapped - by XBlock.json_handler, but the unit test covers the code in - handle_grade_json() to avoid having to wrap everything around a - Request/Response object. - """ - return self.handle_grade_json(data) + We will verify the message to make sure that it is signed and + that the signature is valid. If everything is good, then we'll + publish a "grade" event for this module. + The actual work is done in handle_grade_json(), and this method + just calls that. This method is just here so that it can be wrapped + by XBlock.json_handler, but the unit test covers the code in + handle_grade_json() to avoid having to wrap everything around a + Request/Response object. + """ + return self.handle_grade_json(data) def handle_grade_json(self, data): - if not isinstance(data, dict): - return "bad_request" - - mastery = data.get("mastery", None) - user_id = data.get("user_id", None) - signature = data.get("signature", None) - - if not mastery or not user_id or not signature: - return "forbidden" - - # Check that the module ID we care about is actually in the data - # that was sent. - mastery_level = mastery.get(self.module_id, None) - if mastery_level is None: - return "bad_request" - - try: - # The mastery level being passed in should be a number, otherwise - # things later on in this method will choke. - mastery_level = float(mastery_level) - except ValueError: - return "bad_request" - - # Verify the signature. - sk = self.shared_key - if isinstance(self.shared_key, str): - sk = self.shared_key.encode('utf-8') - verifier = hmac.new(sk, user_id.encode('utf-8'), digestmod='MD5') - for key in sorted(mastery): - verifier.update(key.encode('utf-8')) - # Every entry should be a number. - try: - mastery[key] = float(mastery[key]) - except ValueError: - return "bad_request" + if not isinstance(data, dict): + return "bad_request" - verifier.update(b"%.2f" % mastery[key]) + mastery = data.get("mastery", None) + user_id = data.get("user_id", None) + signature = data.get("signature", None) - # If the signature is invalid, do nothing. - if signature != verifier.hexdigest(): - return "invalid_signature" + if not mastery or not user_id or not signature: + return "forbidden" - # If we got here, then everything checks out and we can submit - # a grade for this module. - scaled_mastery_level = min(mastery_level / 0.7, 1.0) - self.runtime.publish(self, "grade", - { "value": scaled_mastery_level, - "max_value": 1.0 }) - return scaled_mastery_level + # Check that the module ID we care about is actually in the data + # that was sent. + mastery_level = mastery.get(self.module_id, None) + if mastery_level is None: + return "bad_request" + try: + # The mastery level being passed in should be a number, otherwise + # things later on in this method will choke. + mastery_level = float(mastery_level) + except ValueError: + return "bad_request" + + # Verify the signature. + sk = self.shared_key + if isinstance(self.shared_key, str): + sk = self.shared_key.encode("utf-8") + verifier = hmac.new(sk, user_id.encode("utf-8"), digestmod="MD5") + for key in sorted(mastery): + verifier.update(key.encode("utf-8")) + # Every entry should be a number. + try: + mastery[key] = float(mastery[key]) + except ValueError: + return "bad_request" + + verifier.update(b"%.2f" % mastery[key]) + + # If the signature is invalid, do nothing. + if signature != verifier.hexdigest(): + return "invalid_signature" + + # If we got here, then everything checks out and we can submit + # a grade for this module. + scaled_mastery_level = min(mastery_level / 0.7, 1.0) + self.runtime.publish(self, "grade", {"value": scaled_mastery_level, "max_value": 1.0}) + return scaled_mastery_level @staticmethod def workbench_scenarios(): - """A canned scenario for display in the workbench.""" - return [ - ("SchoolYourselfReviewXBlock", - """\ + """A canned scenario for display in the workbench.""" + return [ + ( + "SchoolYourselfReviewXBlock", + """\ - """), + """, + ), ] diff --git a/src/schoolyourself/schoolyourself_review_test.py b/src/schoolyourself/schoolyourself_review_test.py index 80a8acb..14b11dc 100644 --- a/src/schoolyourself/schoolyourself_review_test.py +++ b/src/schoolyourself/schoolyourself_review_test.py @@ -1,122 +1,122 @@ """This file contains a unit test for the SchoolYourselfReviewXBlock.""" import unittest - -from .schoolyourself_review import SchoolYourselfReviewXBlock - from unittest.mock import Mock -from xblock.fields import ScopeIds -from xblock.field_data import DictFieldData - - -class FakeXModuleRuntime: - """ - Depending on whether we're running in the LMS or in the XBlock - workbench, the "xmodule_runtime" attr may or may not be set (in - the LMS, it's set, and that's what production uses). The only field - we ever look at in our XBlock code is "anonymous_student_id", - so this is a dummy object that holds that. - """ - def __init__(self, anonymous_student_id): - self.anonymous_student_id = anonymous_student_id - - -class SchoolYourselfReviewXBlockTest(unittest.TestCase): - def setUp(self): - self.mock_runtime = Mock() - self.block = SchoolYourselfReviewXBlock(self.mock_runtime, - DictFieldData({}), - ScopeIds("foo", "bar", "baz", "x")) - - # This is a fake shared key and a manually computed signature for use - # in this test. - self.block.shared_key = "key" - self.canned_signature = "f0cc345470c322e0c6f41d541fe2b736" - - - def test_default_params(self): - self.assertFalse(SchoolYourselfReviewXBlock.has_children) - self.assertTrue(SchoolYourselfReviewXBlock.has_score) - self.assertAlmostEqual(SchoolYourselfReviewXBlock.weight, 1.0) - - - def test_display_name(self): - """ - Make sure we are correctly overriding the get_display_name() of - the base class. - """ - self.assertEqual(self.block.get_display_name("blah"), "Review: blah") +from xblock.field_data import DictFieldData +from xblock.fields import ScopeIds - def test_student_id(self): - self.assertEqual(self.block.get_student_id(), "debug") - self.block.xmodule_runtime = FakeXModuleRuntime("abc123") - self.assertEqual(self.block.get_student_id(), "abc123") - - - def test_handle_grade_malformed_input(self): - self.block.module_id = "algebra/multiplication" - - self.assertEqual(self.block.handle_grade_json("foo"), "bad_request") - self.assertEqual(self.block.handle_grade_json(["foo"]), "bad_request") - self.assertEqual(self.block.handle_grade_json({}), "forbidden") - self.assertEqual(self.block.handle_grade_json( - {"mastery": {"invalid_module_id": 1.0}, - "user_id": "foo", - "signature": "asdf"}), "bad_request") - - # Make sure we never publish any grades for situations like this. - self.assertEqual(len(self.mock_runtime.publish.method_calls), 0) +from .schoolyourself_review import SchoolYourselfReviewXBlock - def test_handle_grade_malformed_signed_input(self): +class FakeXModuleRuntime: """ - This is a test for an unlikely situation where the input is malformed - but the signature is somehow correct. We should at least not start - throwing errors. + Depending on whether we're running in the LMS or in the XBlock + workbench, the "xmodule_runtime" attr may or may not be set (in + the LMS, it's set, and that's what production uses). The only field + we ever look at in our XBlock code is "anonymous_student_id", + so this is a dummy object that holds that. """ - self.block.module_id = "algebra/multiplication" - - self.assertEqual(self.block.handle_grade_json( - {"mastery": {"algebra/multiplication": "hello"}, # A non-number! - "user_id": "foo", - "signature": self.canned_signature}), "bad_request") + def __init__(self, anonymous_student_id): + self.anonymous_student_id = anonymous_student_id - def test_handle_grade(self): - self.block.module_id = "algebra/multiplication" - self.assertEqual(self.block.handle_grade_json( - {"mastery": {"algebra/multiplication": 0.7}, - "user_id": "foo", - "signature": "asdf"}), "invalid_signature") - - # Invalid signatures should never publish grades. - self.assertEqual(len(self.mock_runtime.publish.method_calls), 0) - - self.assertEqual(self.block.handle_grade_json( - {"mastery": {"algebra/multiplication": 0.7}, - "user_id": "foo", - "signature": self.canned_signature}), 1.0) - - self.mock_runtime.publish.assert_called_with(self.block, "grade", - { "value": 1.0, - "max_value": 1.0 }) - - - def test_get_partner_url_params(self): - # These are the defaults: - self.assertEqual(self.block.get_partner_url_params(), - { "partner": "edx", - "partner_user_id": "debug" }) - - self.block.partner_id = "foo" - self.block.xmodule_runtime = FakeXModuleRuntime("abc123") - - self.assertEqual(self.block.get_partner_url_params(), - { "partner": "foo", - "partner_user_id": "abc123" }) +class SchoolYourselfReviewXBlockTest(unittest.TestCase): + def setUp(self): + self.mock_runtime = Mock() + self.block = SchoolYourselfReviewXBlock( + self.mock_runtime, DictFieldData({}), ScopeIds("foo", "bar", "baz", "x") + ) + + # This is a fake shared key and a manually computed signature for use + # in this test. + self.block.shared_key = "key" + self.canned_signature = "f0cc345470c322e0c6f41d541fe2b736" + + def test_default_params(self): + self.assertFalse(SchoolYourselfReviewXBlock.has_children) + self.assertTrue(SchoolYourselfReviewXBlock.has_score) + self.assertAlmostEqual(SchoolYourselfReviewXBlock.weight, 1.0) + + def test_display_name(self): + """ + Make sure we are correctly overriding the get_display_name() of + the base class. + """ + self.assertEqual(self.block.get_display_name("blah"), "Review: blah") + + def test_student_id(self): + self.assertEqual(self.block.get_student_id(), "debug") + self.block.xmodule_runtime = FakeXModuleRuntime("abc123") + self.assertEqual(self.block.get_student_id(), "abc123") + + def test_handle_grade_malformed_input(self): + self.block.module_id = "algebra/multiplication" + + self.assertEqual(self.block.handle_grade_json("foo"), "bad_request") + self.assertEqual(self.block.handle_grade_json(["foo"]), "bad_request") + self.assertEqual(self.block.handle_grade_json({}), "forbidden") + self.assertEqual( + self.block.handle_grade_json( + {"mastery": {"invalid_module_id": 1.0}, "user_id": "foo", "signature": "asdf"} + ), + "bad_request", + ) + + # Make sure we never publish any grades for situations like this. + self.assertEqual(len(self.mock_runtime.publish.method_calls), 0) + + def test_handle_grade_malformed_signed_input(self): + """ + This is a test for an unlikely situation where the input is malformed + but the signature is somehow correct. We should at least not start + throwing errors. + """ + self.block.module_id = "algebra/multiplication" + + self.assertEqual( + self.block.handle_grade_json( + { + "mastery": {"algebra/multiplication": "hello"}, # A non-number! + "user_id": "foo", + "signature": self.canned_signature, + } + ), + "bad_request", + ) + + def test_handle_grade(self): + self.block.module_id = "algebra/multiplication" + + self.assertEqual( + self.block.handle_grade_json( + {"mastery": {"algebra/multiplication": 0.7}, "user_id": "foo", "signature": "asdf"} + ), + "invalid_signature", + ) + + # Invalid signatures should never publish grades. + self.assertEqual(len(self.mock_runtime.publish.method_calls), 0) + + self.assertEqual( + self.block.handle_grade_json( + {"mastery": {"algebra/multiplication": 0.7}, "user_id": "foo", "signature": self.canned_signature} + ), + 1.0, + ) + + self.mock_runtime.publish.assert_called_with(self.block, "grade", {"value": 1.0, "max_value": 1.0}) + + def test_get_partner_url_params(self): + # These are the defaults: + self.assertEqual(self.block.get_partner_url_params(), {"partner": "edx", "partner_user_id": "debug"}) + + self.block.partner_id = "foo" + self.block.xmodule_runtime = FakeXModuleRuntime("abc123") + + self.assertEqual(self.block.get_partner_url_params(), {"partner": "foo", "partner_user_id": "abc123"}) if __name__ == "__main__": - unittest.main() + unittest.main() diff --git a/src/submit_and_compare/mixins/dates.py b/src/submit_and_compare/mixins/dates.py index b4afb24..7e1e004 100644 --- a/src/submit_and_compare/mixins/dates.py +++ b/src/submit_and_compare/mixins/dates.py @@ -1,6 +1,7 @@ """ Extend XBlocks with datetime helpers """ + import datetime @@ -18,8 +19,8 @@ def is_past_due(self): """ # These values are pulled from platform. # They are defaulted to None for tests. - due = getattr(self, 'due', None) - graceperiod = getattr(self, 'graceperiod', None) + due = getattr(self, "due", None) + graceperiod = getattr(self, "graceperiod", None) # Calculate the current DateTime so we can compare the due date to it. # datetime.utcnow() returns timezone naive date object. now = datetime.datetime.utcnow() diff --git a/src/submit_and_compare/mixins/events.py b/src/submit_and_compare/mixins/events.py index 2abf7d8..137ae26 100644 --- a/src/submit_and_compare/mixins/events.py +++ b/src/submit_and_compare/mixins/events.py @@ -1,6 +1,7 @@ """ Provide event-related mixin functionality """ + from xblock.core import XBlock @@ -15,17 +16,17 @@ def publish_event(self, data, *args, **kwargs): Publish events """ try: - event_type = data.pop('event_type') + event_type = data.pop("event_type") except KeyError: return { - 'result': 'error', - 'message': 'Missing event_type in JSON data', + "result": "error", + "message": "Missing event_type in JSON data", } - data['user_id'] = self.scope_ids.user_id - data['component_id'] = self._get_unique_id() + data["user_id"] = self.scope_ids.user_id + data["component_id"] = self._get_unique_id() self.runtime.publish(self, event_type, data) result = { - 'result': 'success', + "result": "success", } return result @@ -37,7 +38,7 @@ def _get_unique_id(self): unique_id = self.location.name except AttributeError: # workaround for xblock workbench - unique_id = 'workbench-workaround-id' + unique_id = "workbench-workaround-id" return unique_id def _publish_grade(self): @@ -46,11 +47,11 @@ def _publish_grade(self): """ self.runtime.publish( self, - 'grade', + "grade", { - 'value': self.score, - 'max_value': 1.0, - } + "value": self.score, + "max_value": 1.0, + }, ) def _publish_problem_check(self): @@ -59,9 +60,9 @@ def _publish_problem_check(self): """ self.runtime.publish( self, - 'problem_check', + "problem_check", { - 'grade': self.score, - 'max_grade': 1.0, - } + "grade": self.score, + "max_grade": 1.0, + }, ) diff --git a/src/submit_and_compare/mixins/fragment.py b/src/submit_and_compare/mixins/fragment.py index b3f47ce..dde58f4 100644 --- a/src/submit_and_compare/mixins/fragment.py +++ b/src/submit_and_compare/mixins/fragment.py @@ -4,29 +4,31 @@ Note: We should resume test coverage for all lines in this file once split into its own library. """ + from django.template.context import Context -from xblock.core import XBlock from web_fragments.fragment import Fragment +from xblock.core import XBlock class XBlockFragmentBuilderMixin: """ Create a default XBlock fragment builder """ + static_css = [ - 'view.css', + "view.css", ] static_js = [ - 'view.js', + "view.js", ] static_js_init = None - template = 'view.html' + template = "view.html" def get_i18n_service(self): """ Get the i18n service from the runtime """ - return self.runtime.service(self, 'i18n') + return self.runtime.service(self, "i18n") def provide_context(self, context): # pragma: no cover """ @@ -38,7 +40,7 @@ def provide_context(self, context): # pragma: no cover context = dict(context) return context - @XBlock.supports('multi_device') + @XBlock.supports("multi_device") def student_view(self, context=None): """ Build the fragment for the default student view @@ -58,12 +60,12 @@ def student_view(self, context=None): return fragment def build_fragment( - self, - template='', - context=None, - css=None, - js=None, - js_init=None, + self, + template="", + context=None, + css=None, + js=None, + js_init=None, ): """ Creates a fragment for display. @@ -71,9 +73,9 @@ def build_fragment( context = context or {} css = css or [] js = js or [] - rendered_template = '' + rendered_template = "" if template: # pragma: no cover - template = 'templates/' + template + template = "templates/" + template rendered_template = self.loader.render_django_template( template, context=Context(context), @@ -81,14 +83,14 @@ def build_fragment( ) fragment = Fragment(rendered_template) for item in css: - if item.startswith('/'): + if item.startswith("/"): url = item else: - item = 'public/' + item + item = "public/" + item url = self.runtime.local_resource_url(self, item) fragment.add_css_url(url) for item in js: - item = 'public/' + item + item = "public/" + item url = self.runtime.local_resource_url(self, item) fragment.add_javascript_url(url) if js_init: # pragma: no cover diff --git a/src/submit_and_compare/models.py b/src/submit_and_compare/models.py index 7935b47..902eb23 100644 --- a/src/submit_and_compare/models.py +++ b/src/submit_and_compare/models.py @@ -1,13 +1,10 @@ """ Handle data access logic for the XBlock """ + import textwrap -from xblock.fields import Float -from xblock.fields import Integer -from xblock.fields import List -from xblock.fields import Scope -from xblock.fields import String +from xblock.fields import Float, Integer, List, Scope, String class SubmitAndCompareModelMixin: @@ -17,18 +14,15 @@ class SubmitAndCompareModelMixin: has_score = True display_name = String( - display_name='Display Name', - default='Submit and Compare', + display_name="Display Name", + default="Submit and Compare", scope=Scope.settings, - help=( - 'This name appears in the horizontal' - ' navigation at the top of the page' - ), + help=("This name appears in the horizontal navigation at the top of the page"), ) student_answer = String( - default='', + default="", scope=Scope.user_state, - help='This is the student\'s answer to the question', + help="This is the student's answer to the question", ) max_attempts = Integer( default=0, @@ -39,27 +33,27 @@ class SubmitAndCompareModelMixin: scope=Scope.user_state, ) your_answer_label = String( - default='Your Answer:', + default="Your Answer:", scope=Scope.settings, - help='Label for the text area containing the student\'s answer', + help="Label for the text area containing the student's answer", ) our_answer_label = String( - default='Our Answer:', + default="Our Answer:", scope=Scope.settings, - help='Label for the \'expert\' answer', + help="Label for the 'expert' answer", ) submit_button_label = String( - default='Submit and Compare', + default="Submit and Compare", scope=Scope.settings, - help='Label for the submit button', + help="Label for the submit button", ) hints = List( default=[], scope=Scope.content, - help='Hints for the question', + help="Hints for the question", ) question_string = String( - help='Default question content ', + help="Default question content ", scope=Scope.content, multiline_editor=True, default=textwrap.dedent(""" @@ -94,15 +88,15 @@ class SubmitAndCompareModelMixin: - """)) + """), + ) score = Float( default=0.0, scope=Scope.user_state, ) weight = Integer( - display_name='Weight', - help='This assigns an integer value representing ' - 'the weight of this problem', + display_name="Weight", + help="This assigns an integer value representing the weight of this problem", default=0, scope=Scope.settings, ) diff --git a/src/submit_and_compare/settings.py b/src/submit_and_compare/settings.py index a48cc2d..2bad0f7 100644 --- a/src/submit_and_compare/settings.py +++ b/src/submit_and_compare/settings.py @@ -3,14 +3,14 @@ """ DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', + "default": { + "ENGINE": "django.db.backends.sqlite3", # 'NAME': 'intentionally-omitted', }, } LOCALE_PATHS = [ - 'submit_and_compare/translations', + "submit_and_compare/translations", ] -SECRET_KEY = 'submit_and_compare_SECRET_KEY' +SECRET_KEY = "submit_and_compare_SECRET_KEY" DEFAULT_AUTO_FIELD = "django.db.models.AutoField" diff --git a/src/submit_and_compare/tests/test_all.py b/src/submit_and_compare/tests/test_all.py index bd3ae5b..26142c5 100644 --- a/src/submit_and_compare/tests/test_all.py +++ b/src/submit_and_compare/tests/test_all.py @@ -1,17 +1,18 @@ """ Tests for xblock-submit-and-compare """ + import re import unittest +from unittest import mock from xml.sax.saxutils import escape -from unittest import mock from django.test.client import Client from opaque_keys.edx.locations import SlashSeparatedCourseKey from xblock.field_data import DictFieldData -from ..xblocks import SubmitAndCompareXBlock from ..views import get_body +from ..xblocks import SubmitAndCompareXBlock class SubmitAndCompareXblockTestCase(unittest.TestCase): @@ -19,12 +20,13 @@ class SubmitAndCompareXblockTestCase(unittest.TestCase): """ A complete suite of unit tests for the Submit-and-compare XBlock """ + @classmethod def make_an_xblock(cls, **kw): """ Helper method that creates a Free-text Response XBlock """ - course_id = SlashSeparatedCourseKey('foo', 'bar', 'baz') + course_id = SlashSeparatedCourseKey("foo", "bar", "baz") runtime = mock.Mock(course_id=course_id) scope_ids = mock.Mock() field_data = DictFieldData(kw) @@ -54,16 +56,13 @@ def test_studio_view(self): Checks studio view for instance variables specified by the instructor. """ with mock.patch( - "submit_and_compare.mixins.fragment.XBlockFragmentBuilderMixin.get_i18n_service", - return_value=None + "submit_and_compare.mixins.fragment.XBlockFragmentBuilderMixin.get_i18n_service", return_value=None ): studio_view_html = self.studio_view_html() self.assertIn(self.xblock.display_name, studio_view_html) - xblock_body = get_body( - self.xblock.question_string - ) - studio_view_html = re.sub(r'\W+', ' ', studio_view_html.strip()) - xblock_body = re.sub(r'\W+', ' ', xblock_body.strip()) + xblock_body = get_body(self.xblock.question_string) + studio_view_html = re.sub(r"\W+", " ", studio_view_html.strip()) + xblock_body = re.sub(r"\W+", " ", xblock_body.strip()) self.assertIn( escape(xblock_body), studio_view_html, @@ -74,14 +73,14 @@ def test_initialization_variables(self): """ Checks that all instance variables are initialized correctly """ - self.assertEqual('Submit and Compare', self.xblock.display_name) + self.assertEqual("Submit and Compare", self.xblock.display_name) self.assertIn( - 'Before you begin the simulation', + "Before you begin the simulation", self.xblock.question_string, ) self.assertEqual(0.0, self.xblock.score) self.assertEqual(0, self.xblock.max_attempts) - self.assertEqual('', self.xblock.student_answer) + self.assertEqual("", self.xblock.student_answer) self.assertEqual(0, self.xblock.count_attempts) def student_view_html(self): @@ -104,7 +103,7 @@ def test_problem_progress_weight_zero(self): """ self.xblock.score = 1 self.xblock.weight = 0 - self.assertEqual('', self.xblock._get_problem_progress()) + self.assertEqual("", self.xblock._get_problem_progress()) def test_problem_progress_score_zero_weight_singular(self): # pylint: disable=invalid-name, protected-access @@ -115,7 +114,7 @@ def test_problem_progress_score_zero_weight_singular(self): self.xblock.score = 0 self.xblock.weight = 1 self.assertEqual( - '(1 point possible)', + "(1 point possible)", self.xblock._get_problem_progress(), ) @@ -128,7 +127,7 @@ def test_problem_progress_score_zero_weight_plural(self): self.xblock.score = 0 self.xblock.weight = 3 self.assertEqual( - '(3 points possible)', + "(3 points possible)", self.xblock._get_problem_progress(), ) @@ -141,7 +140,7 @@ def test_problem_progress_score_positive_weight_singular(self): self.xblock.score = 1 self.xblock.weight = 1 self.assertEqual( - '(1/1 point)', + "(1/1 point)", self.xblock._get_problem_progress(), ) @@ -154,7 +153,7 @@ def test_problem_progress_score_positive_weight_plural(self): self.xblock.score = 1 self.xblock.weight = 3 self.assertEqual( - '(3/3 points)', + "(3/3 points)", self.xblock._get_problem_progress(), ) @@ -165,7 +164,7 @@ def test_used_attempts_feedback_blank(self): appropriate """ self.xblock.max_attempts = 0 - self.assertEqual('', self.xblock._get_used_attempts_feedback()) + self.assertEqual("", self.xblock._get_used_attempts_feedback()) def test_used_attempts_feedback_normal(self): # pylint: disable=invalid-name, protected-access @@ -175,7 +174,7 @@ def test_used_attempts_feedback_normal(self): self.xblock.max_attempts = 5 self.xblock.count_attempts = 3 self.assertEqual( - 'You have used 3 of 5 submissions', + "You have used 3 of 5 submissions", self.xblock._get_used_attempts_feedback(), ) @@ -185,7 +184,7 @@ def test_submit_class_blank(self): Tests that get_submit_class returns a blank value when appropriate """ self.xblock.max_attempts = 0 - self.assertEqual('', self.xblock._get_submit_class()) + self.assertEqual("", self.xblock._get_submit_class()) def test_submit_class_nodisplay(self): # pylint: disable=protected-access @@ -196,7 +195,7 @@ def test_submit_class_nodisplay(self): """ self.xblock.max_attempts = 5 self.xblock.count_attempts = 6 - self.assertEqual('nodisplay', self.xblock._get_submit_class()) + self.assertEqual("nodisplay", self.xblock._get_submit_class()) def test_max_score(self): """ diff --git a/src/submit_and_compare/views.py b/src/submit_and_compare/views.py index 40e2e3f..fa95a53 100644 --- a/src/submit_and_compare/views.py +++ b/src/submit_and_compare/views.py @@ -1,13 +1,15 @@ """ Handle view logic for the XBlock """ + import logging -from django.utils.translation import ngettext from django.utils.translation import gettext as _ +from django.utils.translation import ngettext from lxml import etree from six import StringIO from xblock.core import XBlock + try: from xblock.utils.resources import ResourceLoader except ModuleNotFoundError: # For backward compatibility with releases older than Quince. @@ -15,7 +17,6 @@ from .mixins.fragment import XBlockFragmentBuilderMixin - LOG = logging.getLogger(__name__) @@ -38,8 +39,8 @@ def get_body(xmlstring): """ # pylint: disable=no-member tree = etree.parse(StringIO(xmlstring)) - body = tree.xpath('/submit_and_compare/body') - body_string = etree.tostring(body[0], method='text', encoding='unicode') + body = tree.xpath("/submit_and_compare/body") + body_string = etree.tostring(body[0], method="text", encoding="unicode") return body_string @@ -49,33 +50,33 @@ def _get_explanation(xmlstring): Helper method """ tree = etree.parse(StringIO(xmlstring)) - explanation = tree.xpath('/submit_and_compare/explanation') + explanation = tree.xpath("/submit_and_compare/explanation") explanation_string = etree.tostring( explanation[0], - method='text', - encoding='unicode', + method="text", + encoding="unicode", ) return explanation_string class SubmitAndCompareViewMixin( - XBlockFragmentBuilderMixin, + XBlockFragmentBuilderMixin, ): """ Handle view logic for Image Modal XBlock instances """ loader = ResourceLoader(__name__) - static_js_init = 'SubmitAndCompareXBlockInitView' - icon_class = 'problem' + static_js_init = "SubmitAndCompareXBlockInitView" + icon_class = "problem" editable_fields = [ - 'display_name', - 'weight', - 'max_attempts', - 'your_answer_label', - 'our_answer_label', - 'submit_button_label', - 'question_string', + "display_name", + "weight", + "max_attempts", + "your_answer_label", + "our_answer_label", + "submit_button_label", + "question_string", ] show_in_read_only_mode = True @@ -89,24 +90,24 @@ def provide_context(self, context=None): used_attempts_feedback = self._get_used_attempts_feedback() submit_class = self._get_submit_class() prompt = get_body(self.question_string) - explanation = _get_explanation( - self.question_string + explanation = _get_explanation(self.question_string) + attributes = "" + context.update( + { + "display_name": self.display_name, + "problem_progress": problem_progress, + "used_attempts_feedback": used_attempts_feedback, + "submit_class": submit_class, + "prompt": prompt, + "student_answer": self.student_answer, + "explanation": explanation, + "your_answer_label": self.your_answer_label, + "our_answer_label": self.our_answer_label, + "submit_button_label": self.submit_button_label, + "attributes": attributes, + "is_past_due": self.is_past_due(), + } ) - attributes = '' - context.update({ - 'display_name': self.display_name, - 'problem_progress': problem_progress, - 'used_attempts_feedback': used_attempts_feedback, - 'submit_class': submit_class, - 'prompt': prompt, - 'student_answer': self.student_answer, - 'explanation': explanation, - 'your_answer_label': self.your_answer_label, - 'our_answer_label': self.our_answer_label, - 'submit_button_label': self.submit_button_label, - 'attributes': attributes, - 'is_past_due': self.is_past_due(), - }) return context def studio_view(self, context=None): @@ -116,25 +117,27 @@ def studio_view(self, context=None): Implementation is optional. """ context = context or {} - context.update({ - 'display_name': self.display_name, - 'weight': self.weight, - 'max_attempts': self.max_attempts, - 'xml_data': self.question_string, - 'your_answer_label': self.your_answer_label, - 'our_answer_label': self.our_answer_label, - 'submit_button_label': self.submit_button_label, - }) - template = 'edit.html' + context.update( + { + "display_name": self.display_name, + "weight": self.weight, + "max_attempts": self.max_attempts, + "xml_data": self.question_string, + "your_answer_label": self.your_answer_label, + "our_answer_label": self.our_answer_label, + "submit_button_label": self.submit_button_label, + } + ) + template = "edit.html" fragment = self.build_fragment( template=template, context=context, - js_init='SubmitAndCompareXBlockInitEdit', + js_init="SubmitAndCompareXBlockInitEdit", css=[ - 'edit.css', + "edit.css", ], js=[ - 'edit.js', + "edit.js", ], ) return fragment @@ -145,27 +148,27 @@ def studio_submit(self, data, *args, **kwargs): Save studio edits """ # pylint: disable=unused-argument - self.display_name = data['display_name'] - self.weight = _convert_to_int(data['weight']) - max_attempts = _convert_to_int(data['max_attempts']) + self.display_name = data["display_name"] + self.weight = _convert_to_int(data["weight"]) + max_attempts = _convert_to_int(data["max_attempts"]) if max_attempts >= 0: - self.max_attempts = max_attempts # pylint: disable=consider-using-min-builtin - self.your_answer_label = data['your_answer_label'] - self.our_answer_label = data['our_answer_label'] - self.submit_button_label = data['submit_button_label'] - xml_content = data['data'] + self.max_attempts = max_attempts # pylint: disable=consider-using-min-builtin + self.your_answer_label = data["your_answer_label"] + self.our_answer_label = data["our_answer_label"] + self.submit_button_label = data["submit_button_label"] + xml_content = data["data"] # pylint: disable=no-member try: etree.parse(StringIO(xml_content)) self.question_string = xml_content except etree.XMLSyntaxError as error: return { - 'result': 'error', - 'message': error.message, + "result": "error", + "message": error.message, } return { - 'result': 'success', + "result": "success", } @XBlock.json_handler @@ -180,16 +183,15 @@ def student_submit(self, data, *args, **kwargs): if self.max_attempts > 0 and self.count_attempts >= self.max_attempts: # pylint: enable=no-member LOG.error( - 'User has already exceeded the maximum ' - 'number of allowed attempts', + "User has already exceeded the maximum number of allowed attempts", ) elif self.is_past_due(): LOG.debug( - 'This problem is past due', + "This problem is past due", ) else: - self.student_answer = data['answer'] - if data['action'] == 'submit': + self.student_answer = data["answer"] + if data["action"] == "submit": self.count_attempts += 1 # pylint: disable=no-member if self.student_answer: self.score = 1.0 @@ -199,10 +201,10 @@ def student_submit(self, data, *args, **kwargs): self._publish_problem_check() success = True result = { - 'success': success, - 'problem_progress': self._get_problem_progress(), - 'submit_class': self._get_submit_class(), - 'used_attempts_feedback': self._get_used_attempts_feedback(), + "success": success, + "problem_progress": self._get_problem_progress(), + "submit_class": self._get_submit_class(), + "used_attempts_feedback": self._get_used_attempts_feedback(), } return result @@ -216,20 +218,20 @@ def send_hints(self, data, *args, **kwargs): # pylint: disable=unused-argument # pylint: disable=no-member tree = etree.parse(StringIO(self.question_string)) - raw_hints = tree.xpath('/submit_and_compare/demandhint/hint') + raw_hints = tree.xpath("/submit_and_compare/demandhint/hint") decorated_hints = [] total_hints = len(raw_hints) for i, raw_hint in enumerate(raw_hints, 1): - hint = _('Hint ({number} of {total}): {hint}').format( + hint = _("Hint ({number} of {total}): {hint}").format( number=i, total=total_hints, - hint=etree.tostring(raw_hint, encoding='unicode'), + hint=etree.tostring(raw_hint, encoding="unicode"), ) decorated_hints.append(hint) hints = decorated_hints return { - 'result': 'success', - 'hints': hints, + "result": "success", + "hints": hints, } def _get_used_attempts_feedback(self): @@ -237,12 +239,12 @@ def _get_used_attempts_feedback(self): Returns the text with feedback to the user about the number of attempts they have used if applicable """ - result = '' + result = "" if self.max_attempts > 0: # pylint: disable=no-member result = ngettext( - 'You have used {count_attempts} of {max_attempts} submission', - 'You have used {count_attempts} of {max_attempts} submissions', + "You have used {count_attempts} of {max_attempts} submission", + "You have used {count_attempts} of {max_attempts} submissions", self.max_attempts, ).format( count_attempts=self.count_attempts, @@ -269,9 +271,9 @@ def _get_submit_class(self): """ Returns the css class for the submit button """ - result = '' + result = "" if not self._can_submit(): - result = 'nodisplay' + result = "nodisplay" return result def _get_problem_progress(self): @@ -280,12 +282,12 @@ def _get_problem_progress(self): on the user's current score """ if self.weight == 0: - result = '' + result = "" elif self.score == 0.0: result = "({})".format( ngettext( - '{weight} point possible', - '{weight} points possible', + "{weight} point possible", + "{weight} points possible", self.weight, ).format( weight=self.weight, @@ -293,11 +295,11 @@ def _get_problem_progress(self): ) else: scaled_score = self.score * self.weight - score_string = f'{scaled_score:g}' + score_string = f"{scaled_score:g}" result = "({})".format( ngettext( - score_string + '/' + "{weight} point", - score_string + '/' + "{weight} points", + score_string + "/" + "{weight} point", + score_string + "/" + "{weight} points", self.weight, ).format( weight=self.weight, diff --git a/src/submit_and_compare/xblocks.py b/src/submit_and_compare/xblocks.py index f21b0f9..1977f34 100644 --- a/src/submit_and_compare/xblocks.py +++ b/src/submit_and_compare/xblocks.py @@ -1,6 +1,7 @@ """ This is the core logic for the XBlock """ + from xblock.core import XBlock from .mixins.dates import EnforceDueDates @@ -10,14 +11,14 @@ from .views import SubmitAndCompareViewMixin -@XBlock.needs('i18n') +@XBlock.needs("i18n") class SubmitAndCompareXBlock( - EnforceDueDates, - EventableMixin, - SubmitAndCompareModelMixin, - SubmitAndCompareViewMixin, - XBlockWorkbenchMixin, - XBlock, + EnforceDueDates, + EventableMixin, + SubmitAndCompareModelMixin, + SubmitAndCompareViewMixin, + XBlockWorkbenchMixin, + XBlock, ): """ A Submit-And-Compare XBlock diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index ba91ba3..0000000 --- a/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Tests for xblocks-extra.""" diff --git a/tests/test_placeholder.py b/tests/test_placeholder.py deleted file mode 100644 index 7f0d09d..0000000 --- a/tests/test_placeholder.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Placeholder test to verify test infrastructure works.""" - - -def test_placeholder(): - """Placeholder test - replace with actual tests when xblocks are added.""" - assert True From cca951e2d0f84c81978a0b4fb0c604a407af8389 Mon Sep 17 00:00:00 2001 From: farhan Date: Thu, 9 Apr 2026 12:12:01 +0500 Subject: [PATCH 3/4] revert: remove school-yourself-xblock --- pyproject.toml | 2 - src/schoolyourself/__init__.py | 2 - src/schoolyourself/public/review_icon.png | Bin 9131 -> 0 bytes src/schoolyourself/public/sylib.css | 1 - src/schoolyourself/public/sylib.js | 7 - src/schoolyourself/schoolyourself.py | 236 ------------------ src/schoolyourself/schoolyourself_lesson.py | 79 ------ src/schoolyourself/schoolyourself_review.py | 152 ----------- .../schoolyourself_review_test.py | 122 --------- .../static/css/student_view.css | 137 ---------- .../static/js/lesson_student_view.js | 8 - .../static/js/review_student_view.js | 61 ----- src/schoolyourself/static/js/studio_view.js | 21 -- .../templates/lesson_student_view.html | 15 -- .../templates/review_student_view.html | 21 -- src/schoolyourself/templates/studio_view.html | 57 ----- 16 files changed, 921 deletions(-) delete mode 100644 src/schoolyourself/__init__.py delete mode 100644 src/schoolyourself/public/review_icon.png delete mode 100644 src/schoolyourself/public/sylib.css delete mode 100644 src/schoolyourself/public/sylib.js delete mode 100644 src/schoolyourself/schoolyourself.py delete mode 100644 src/schoolyourself/schoolyourself_lesson.py delete mode 100644 src/schoolyourself/schoolyourself_review.py delete mode 100644 src/schoolyourself/schoolyourself_review_test.py delete mode 100644 src/schoolyourself/static/css/student_view.css delete mode 100644 src/schoolyourself/static/js/lesson_student_view.js delete mode 100644 src/schoolyourself/static/js/review_student_view.js delete mode 100644 src/schoolyourself/static/js/studio_view.js delete mode 100644 src/schoolyourself/templates/lesson_student_view.html delete mode 100644 src/schoolyourself/templates/review_student_view.html delete mode 100644 src/schoolyourself/templates/studio_view.html diff --git a/pyproject.toml b/pyproject.toml index e2685a4..f63bf67 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,8 +61,6 @@ docs = [ audio = "audio:AudioXBlock" imagemodal = "imagemodal.xblocks:ImageModal" submit-and-compare = "submit_and_compare.xblocks:SubmitAndCompareXBlock" -schoolyourself_lesson = "schoolyourself:SchoolYourselfLessonXBlock" -schoolyourself_review = "schoolyourself:SchoolYourselfReviewXBlock" # Packages live in src/ but are installed without the src prefix # e.g., src/foo_xblock/ is installed as foo_xblock diff --git a/src/schoolyourself/__init__.py b/src/schoolyourself/__init__.py deleted file mode 100644 index 1a79e0d..0000000 --- a/src/schoolyourself/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .schoolyourself_lesson import SchoolYourselfLessonXBlock as SchoolYourselfLessonXBlock -from .schoolyourself_review import SchoolYourselfReviewXBlock as SchoolYourselfReviewXBlock diff --git a/src/schoolyourself/public/review_icon.png b/src/schoolyourself/public/review_icon.png deleted file mode 100644 index e9a6d07424ab469caa60e36454a6926c53d22593..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9131 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"":a>b?"scale("+1/a+")":"scale("+1/b+")");m(this.i,"transform-origin","0 0")}}; -schoolyourself.g.prototype.u=function(a){var b=k("iframe",this.i,"player-viewport-frame");b.setAttribute("tabindex",0);b.focus();b.src=a;b.scrolling="no";this.k=b;a=this.h;b=a.getAttribute("class");if(null===b)a.setAttribute("class","open");else{var c=a.getAttribute("class");null!==c&&-1!=c.split(" ").indexOf("open")||a.setAttribute("class",b+" open")}this.l=!0;this.resize()};schoolyourself.g.prototype.openFrame=schoolyourself.g.prototype.u; -schoolyourself.g.prototype.close=function(){if(!this.q||this.q()){this.l=!1;this.i.innerHTML="";var a=this.h,b=a.getAttribute("class");if(null!==b){for(var b=b.split(" "),c="",d=0;d - - - """, - ), - ] diff --git a/src/schoolyourself/schoolyourself_review.py b/src/schoolyourself/schoolyourself_review.py deleted file mode 100644 index f739475..0000000 --- a/src/schoolyourself/schoolyourself_review.py +++ /dev/null @@ -1,152 +0,0 @@ -"""An XBlock that displays School Yourself reviews and may publish grades.""" - -import hmac - -import six.moves.urllib.error -import six.moves.urllib.parse -import six.moves.urllib.request -from xblock.core import XBlock -from xblock.fragment import Fragment - -from .schoolyourself import SchoolYourselfXBlock - - -class SchoolYourselfReviewXBlock(SchoolYourselfXBlock): - """ - This block renders a launcher button for a School Yourself review, - which is rendered in an iframe. The block transmits the anonymous - user ID and has a handler that receives information from School - Yourself regarding the user's progress and mastery through the - topic being shown. - """ - - has_children = False - has_score = True - weight = 1.0 - - def get_display_name(self, module_title): - return f"Review: {module_title}" - - def student_view(self, context=None): - """ - The primary view of the SchoolYourselfReviewXBlock, shown to students - when viewing courses. - """ - # Construct the URL we're going to stuff into the iframe once - # it gets launched: - partner_url_params = self.get_partner_url_params(self.shared_key) - - iframe_url_params = dict(partner_url_params) - iframe_url_params["module"] = self.module_id - - mastery_url_params = dict(partner_url_params) - mastery_url_params["tags"] = self.module_id - - mastery_url = f"{self.base_url}/progress/mastery?{six.moves.urllib.parse.urlencode(mastery_url_params)}" - - context = { - "iframe_url": f"{self.base_url}/review/embed?{six.moves.urllib.parse.urlencode(iframe_url_params)}", - "title": self.module_title, - "icon_url": self.runtime.local_resource_url(self, "public/review_icon.png"), - "mastery_url": mastery_url, - } - - # Now actually render the fragment, which is just a button with - # some JS code that handles the click event on that button. - fragment = Fragment(self.render_template("review_student_view.html", context)) - - # Load the common JS/CSS libraries: - fragment.add_css_url(self.runtime.local_resource_url(self, "public/sylib.css")) - fragment.add_javascript_url(self.runtime.local_resource_url(self, "public/sylib.js")) - - # And finally the embedded HTML/JS code: - fragment.add_javascript(self.resource_string("static/js/review_student_view.js")) - fragment.add_css(self.resource_string("static/css/student_view.css")) - fragment.add_css_url("//fonts.googleapis.com/css?family=Open+Sans:700,400,300") - fragment.initialize_js("SchoolYourselfReviewStudentView") - return fragment - - @XBlock.json_handler - def handle_grade(self, data, suffix=""): - """This is the handler that gets called when we receive grades. - - We will verify the message to make sure that it is signed and - that the signature is valid. If everything is good, then we'll - publish a "grade" event for this module. - - The actual work is done in handle_grade_json(), and this method - just calls that. This method is just here so that it can be wrapped - by XBlock.json_handler, but the unit test covers the code in - handle_grade_json() to avoid having to wrap everything around a - Request/Response object. - """ - return self.handle_grade_json(data) - - def handle_grade_json(self, data): - if not isinstance(data, dict): - return "bad_request" - - mastery = data.get("mastery", None) - user_id = data.get("user_id", None) - signature = data.get("signature", None) - - if not mastery or not user_id or not signature: - return "forbidden" - - # Check that the module ID we care about is actually in the data - # that was sent. - mastery_level = mastery.get(self.module_id, None) - if mastery_level is None: - return "bad_request" - - try: - # The mastery level being passed in should be a number, otherwise - # things later on in this method will choke. - mastery_level = float(mastery_level) - except ValueError: - return "bad_request" - - # Verify the signature. - sk = self.shared_key - if isinstance(self.shared_key, str): - sk = self.shared_key.encode("utf-8") - verifier = hmac.new(sk, user_id.encode("utf-8"), digestmod="MD5") - for key in sorted(mastery): - verifier.update(key.encode("utf-8")) - # Every entry should be a number. - try: - mastery[key] = float(mastery[key]) - except ValueError: - return "bad_request" - - verifier.update(b"%.2f" % mastery[key]) - - # If the signature is invalid, do nothing. - if signature != verifier.hexdigest(): - return "invalid_signature" - - # If we got here, then everything checks out and we can submit - # a grade for this module. - scaled_mastery_level = min(mastery_level / 0.7, 1.0) - self.runtime.publish(self, "grade", {"value": scaled_mastery_level, "max_value": 1.0}) - return scaled_mastery_level - - @staticmethod - def workbench_scenarios(): - """A canned scenario for display in the workbench.""" - return [ - ( - "SchoolYourselfReviewXBlock", - """\ - - - - """, - ), - ] diff --git a/src/schoolyourself/schoolyourself_review_test.py b/src/schoolyourself/schoolyourself_review_test.py deleted file mode 100644 index 14b11dc..0000000 --- a/src/schoolyourself/schoolyourself_review_test.py +++ /dev/null @@ -1,122 +0,0 @@ -"""This file contains a unit test for the SchoolYourselfReviewXBlock.""" - -import unittest -from unittest.mock import Mock - -from xblock.field_data import DictFieldData -from xblock.fields import ScopeIds - -from .schoolyourself_review import SchoolYourselfReviewXBlock - - -class FakeXModuleRuntime: - """ - Depending on whether we're running in the LMS or in the XBlock - workbench, the "xmodule_runtime" attr may or may not be set (in - the LMS, it's set, and that's what production uses). The only field - we ever look at in our XBlock code is "anonymous_student_id", - so this is a dummy object that holds that. - """ - - def __init__(self, anonymous_student_id): - self.anonymous_student_id = anonymous_student_id - - -class SchoolYourselfReviewXBlockTest(unittest.TestCase): - def setUp(self): - self.mock_runtime = Mock() - self.block = SchoolYourselfReviewXBlock( - self.mock_runtime, DictFieldData({}), ScopeIds("foo", "bar", "baz", "x") - ) - - # This is a fake shared key and a manually computed signature for use - # in this test. - self.block.shared_key = "key" - self.canned_signature = "f0cc345470c322e0c6f41d541fe2b736" - - def test_default_params(self): - self.assertFalse(SchoolYourselfReviewXBlock.has_children) - self.assertTrue(SchoolYourselfReviewXBlock.has_score) - self.assertAlmostEqual(SchoolYourselfReviewXBlock.weight, 1.0) - - def test_display_name(self): - """ - Make sure we are correctly overriding the get_display_name() of - the base class. - """ - self.assertEqual(self.block.get_display_name("blah"), "Review: blah") - - def test_student_id(self): - self.assertEqual(self.block.get_student_id(), "debug") - self.block.xmodule_runtime = FakeXModuleRuntime("abc123") - self.assertEqual(self.block.get_student_id(), "abc123") - - def test_handle_grade_malformed_input(self): - self.block.module_id = "algebra/multiplication" - - self.assertEqual(self.block.handle_grade_json("foo"), "bad_request") - self.assertEqual(self.block.handle_grade_json(["foo"]), "bad_request") - self.assertEqual(self.block.handle_grade_json({}), "forbidden") - self.assertEqual( - self.block.handle_grade_json( - {"mastery": {"invalid_module_id": 1.0}, "user_id": "foo", "signature": "asdf"} - ), - "bad_request", - ) - - # Make sure we never publish any grades for situations like this. - self.assertEqual(len(self.mock_runtime.publish.method_calls), 0) - - def test_handle_grade_malformed_signed_input(self): - """ - This is a test for an unlikely situation where the input is malformed - but the signature is somehow correct. We should at least not start - throwing errors. - """ - self.block.module_id = "algebra/multiplication" - - self.assertEqual( - self.block.handle_grade_json( - { - "mastery": {"algebra/multiplication": "hello"}, # A non-number! - "user_id": "foo", - "signature": self.canned_signature, - } - ), - "bad_request", - ) - - def test_handle_grade(self): - self.block.module_id = "algebra/multiplication" - - self.assertEqual( - self.block.handle_grade_json( - {"mastery": {"algebra/multiplication": 0.7}, "user_id": "foo", "signature": "asdf"} - ), - "invalid_signature", - ) - - # Invalid signatures should never publish grades. - self.assertEqual(len(self.mock_runtime.publish.method_calls), 0) - - self.assertEqual( - self.block.handle_grade_json( - {"mastery": {"algebra/multiplication": 0.7}, "user_id": "foo", "signature": self.canned_signature} - ), - 1.0, - ) - - self.mock_runtime.publish.assert_called_with(self.block, "grade", {"value": 1.0, "max_value": 1.0}) - - def test_get_partner_url_params(self): - # These are the defaults: - self.assertEqual(self.block.get_partner_url_params(), {"partner": "edx", "partner_user_id": "debug"}) - - self.block.partner_id = "foo" - self.block.xmodule_runtime = FakeXModuleRuntime("abc123") - - self.assertEqual(self.block.get_partner_url_params(), {"partner": "foo", "partner_user_id": "abc123"}) - - -if __name__ == "__main__": - unittest.main() diff --git a/src/schoolyourself/static/css/student_view.css b/src/schoolyourself/static/css/student_view.css deleted file mode 100644 index 25d4dd2..0000000 --- a/src/schoolyourself/static/css/student_view.css +++ /dev/null @@ -1,137 +0,0 @@ -.schoolyourself-lesson { - padding: 40px; - font-family: "Open Sans", sans-serif; - font-weight: 300; - color: #6eb535; - background: #fafafa; - font-size: 0; - text-align: center; -} - - -.schoolyourself-lesson-block { - display: inline-block; - cursor: hand; - cursor: pointer; - vertical-align: top; - text-align: center; - position: relative; - width: 100%; -} - - -.schoolyourself-lesson-screenshot, -.schoolyourself-review-screenshot { - margin-top: 10px; - margin-right: 20px; - box-shadow: 0px 0px 3px 1px #c1c1c1; - opacity: 0.8; - -webkit-transition: opacity 150ms linear; - -moz-transition: opacity 150ms linear; - -ms-transition: opacity 150ms linear; - -o-transition: opacity 150ms linear; - transition: opacity 150ms linear; - border: 2px solid #6eb535; - border-radius: 2px; - text-align: center; - background: #fff; - - display: inline-block; - width: 256px; - height: 192px; - margin: 0; -} - -.schoolyourself-review-screenshot { - width: 200px; - height: auto; - border: none; - background: transparent; - box-shadow: none; -} - -.schoolyourself-lesson-screenshot > img, -.schoolyourself-review-screenshot > img { - display: inline-block; - vertical-align: middle; - width: 100%; -} - -.schoolyourself-lesson-block:hover .schoolyourself-lesson-screenshot, -.schoolyourself-lesson-block:hover .schoolyourself-review-screenshot { - opacity: 1; -} - - -.schoolyourself-lesson-text { - display: inline-block; - text-align: left; - vertical-align: top; - padding-left: 40px; - overflow: hidden; - max-width: 320px; -} - -.schoolyourself-lesson-title, -.schoolyourself-lesson-title a, -.schoolyourself-lesson-title a:visited { - text-transform: uppercase; - font-size: 24px; - font-weight: 300; - color: #6eb535; - text-decoration: none; - margin-bottom: 0 !important; - margin-top: 0; -} -.schoolyourself-lesson-block:hover .schoolyourself-lesson-title { - color: #6eb535; - text-decoration: underline; -} - - -.schoolyourself-lesson-description { - color: #737c95; - font-size: 21px; - margin-bottom: 5px; -} - -.schoolyourself-review-mastery { - margin-top: 20px; - height: 44px; - color: #737c95; - font-size: 16px; - margin-bottom: 5px; - max-width: 320px; -} - -.schoolyourself-review-mastery-text { - height: 24px; -} - -.schoolyourself-review-mastery-bar { - width: 320px; - background: #ddd; - height: 20px; - position: relative; - - -webkit-transition: background 450ms ease-in-out; - -moz-transition: background 450ms ease-in-out; - -ms-transition: background 450ms ease-in-out; - -o-transition: background 450ms ease-in-out; - transition: background 450ms ease-in-out; -} - -.schoolyourself-review-mastery-bar-filler { - position: absolute; - background: #fcd380; - left: 0; - right: 100%; - top: 0; - bottom: 0; - - -webkit-transition: all 450ms ease-in-out; - -moz-transition: all 450ms ease-in-out; - -ms-transition: all 450ms ease-in-out; - -o-transition: all 450ms ease-in-out; - transition: all 450ms ease-in-out; -} diff --git a/src/schoolyourself/static/js/lesson_student_view.js b/src/schoolyourself/static/js/lesson_student_view.js deleted file mode 100644 index 4bcb850..0000000 --- a/src/schoolyourself/static/js/lesson_student_view.js +++ /dev/null @@ -1,8 +0,0 @@ -function SchoolYourselfLessonStudentView(runtime, element) { - var viewport = schoolyourself.PlayerViewportBuilder.insert(1024, 768); - $(function ($) { - $('.schoolyourself-lesson-player', element).click(function(eventObject) { - viewport.openFrame(this.getAttribute('data-url')); - }); - }); -} diff --git a/src/schoolyourself/static/js/review_student_view.js b/src/schoolyourself/static/js/review_student_view.js deleted file mode 100644 index f6b049b..0000000 --- a/src/schoolyourself/static/js/review_student_view.js +++ /dev/null @@ -1,61 +0,0 @@ -function SchoolYourselfReviewStudentView(runtime, element) { - var viewport = schoolyourself.PlayerViewportBuilder.insert(1024, 768); - $(function ($) { - $('.schoolyourself-lesson-player', element).click(function(eventObject) { - viewport.openFrame(this.getAttribute('data-url')); - }); - - window.addEventListener('message', function(event) { - if (event.source != viewport.frame().contentWindow) { - return; - } - var handlerUrl = runtime.handlerUrl(element, 'handle_grade'); - $.post(handlerUrl, JSON.stringify(event.data)); - }, false); - - var masteryUrl = $('.schoolyourself-lesson-player', element)[0].getAttribute('data-mastery-url'); - updateMastery(masteryUrl); - viewport.addAfterCloseHandler(function(){updateMastery(masteryUrl)}); - }); -} - -function renderMastery(masteries) { - var mastery = masteries[0][1]; - - // A mastery level of 0.7 gives full credit -- anything beyond that - // doesn't count toward anything. So we should show a full, green bar - // when scaledMastery >= 0.7. - var scaledMastery = mastery / 0.7; - - var right = (100 - (scaledMastery * 100)) + '%'; - - var color = '#fcd380'; - if (!scaledMastery) { - var text = 'Get started!'; - } else if (scaledMastery < 0.5) { - var text = 'Keep practicing!'; - } else if (scaledMastery < 1) { - var text = 'Almost there!'; - var color = '#f0b300'; - } else { - var text = 'Complete!'; - var color = '#6eb535'; - } - - $('.schoolyourself-review-mastery-text').html(text); - $('.schoolyourself-review-mastery-bar-filler').css('right', right); - $('.schoolyourself-review-mastery-bar-filler').css('background', color); -} - - function updateMastery(masteryUrl) { - var xhr = new XMLHttpRequest(); - xhr.open('GET', masteryUrl, true); - xhr.withCredentials = true; - xhr.send(); - xhr.onreadystatechange = function(event) { - if (xhr.readyState === 4 && - xhr.status === 200) { - renderMastery($.parseJSON(xhr.responseText)); - } - }; -} diff --git a/src/schoolyourself/static/js/studio_view.js b/src/schoolyourself/static/js/studio_view.js deleted file mode 100644 index fe20ea4..0000000 --- a/src/schoolyourself/static/js/studio_view.js +++ /dev/null @@ -1,21 +0,0 @@ -function SchoolYourselfStudioView(runtime, element) { - $('.save-button').bind('click', function() { - var data = { - 'module_id': $('.module-id', element).val(), - 'module_title': $('.module-title', element).val(), - 'module_description': $('.module-description', element).val(), - 'player_type': $('.player-type', element).val(), - 'shared_key': $('.shared-key', element).val(), - 'base_url': $('.base-url', element).val(), - 'partner_id': $('.partner-id', element).val() - }; - var handlerUrl = runtime.handlerUrl(element, 'studio_submit'); - $.post(handlerUrl, JSON.stringify(data)).complete(function() { - window.location.reload(false); - }); - }); - - $('.cancel-button').bind('click', function() { - runtime.notify('cancel', {}); - }); -} diff --git a/src/schoolyourself/templates/lesson_student_view.html b/src/schoolyourself/templates/lesson_student_view.html deleted file mode 100644 index e757e82..0000000 --- a/src/schoolyourself/templates/lesson_student_view.html +++ /dev/null @@ -1,15 +0,0 @@ -
-
-
-
- ${title | h} screenshot -
- -
-

${title | h}

-
${description | h}
-
-
-
-
- diff --git a/src/schoolyourself/templates/review_student_view.html b/src/schoolyourself/templates/review_student_view.html deleted file mode 100644 index a569885..0000000 --- a/src/schoolyourself/templates/review_student_view.html +++ /dev/null @@ -1,21 +0,0 @@ -
-
-
-
- Review icon -
- -
-

Review: ${title | h}

-
Practice makes perfect!
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/schoolyourself/templates/studio_view.html b/src/schoolyourself/templates/studio_view.html deleted file mode 100644 index da45e08..0000000 --- a/src/schoolyourself/templates/studio_view.html +++ /dev/null @@ -1,57 +0,0 @@ -
-
    - -
  • -
    - - -
    -
  • - -
  • -
    - - -
    -
  • - -
  • -
    - - -
    -
  • - -
  • -
    - - -
    -
  • - -
  • -
    - - -
    -
  • - -
  • -
    - - -
    -
  • -
- -
-
    -
  • - -
  • -
  • - -
  • -
-
-
From 4406cd815e625aab182fffe490bba35889f2554d Mon Sep 17 00:00:00 2001 From: farhan Date: Thu, 9 Apr 2026 18:47:32 +0500 Subject: [PATCH 4/4] chore: adds readme and docs image files --- src/imagemodal/README.rst | 126 ++++++++++++++++++ src/submit_and_compare/README.md | 52 ++++++++ src/submit_and_compare/README.rst | 126 ++++++++++++++++++ src/submit_and_compare/docs/img/advanced.png | Bin 0 -> 11393 bytes src/submit_and_compare/docs/img/component.png | Bin 0 -> 19791 bytes src/submit_and_compare/docs/img/policy.png | Bin 0 -> 36188 bytes .../docs/img/student_view.png | Bin 0 -> 42319 bytes .../docs/img/studio_view1.png | Bin 0 -> 48816 bytes .../docs/img/studio_view2.png | Bin 0 -> 85871 bytes src/submit_and_compare/docs/img/submitted.png | Bin 0 -> 79008 bytes 10 files changed, 304 insertions(+) create mode 100644 src/imagemodal/README.rst create mode 100644 src/submit_and_compare/README.md create mode 100644 src/submit_and_compare/README.rst create mode 100644 src/submit_and_compare/docs/img/advanced.png create mode 100644 src/submit_and_compare/docs/img/component.png create mode 100644 src/submit_and_compare/docs/img/policy.png create mode 100644 src/submit_and_compare/docs/img/student_view.png create mode 100644 src/submit_and_compare/docs/img/studio_view1.png create mode 100644 src/submit_and_compare/docs/img/studio_view2.png create mode 100644 src/submit_and_compare/docs/img/submitted.png diff --git a/src/imagemodal/README.rst b/src/imagemodal/README.rst new file mode 100644 index 0000000..28af6d9 --- /dev/null +++ b/src/imagemodal/README.rst @@ -0,0 +1,126 @@ +Image Modal XBlock +================== + +A full-screen image modal XBlock, +for use within the Open edX platform. + +|badge-ci| + +The full-screen image tool is another way of enabling participants to +see more detail in your provided images. This tool is useful for large +images with lots of details. A re-sized version of the image displays in +the page, but clicking on the image pops open a full-screen modal with +the full-size version of the image. + +|image-lms-view-normal| + + +Installation +------------ + + +System Administrator +~~~~~~~~~~~~~~~~~~~~ + +To install the XBlock on your platform, +add the following to your `requirements.txt` file: + + xblock-image-modal + +You'll also need to add this to your `INSTALLED_APPS`: + + imagemodal + + +Course Staff +~~~~~~~~~~~~ + +To install the XBlock in your course, +access your `Advanced Module List`: + + Settings -> Advanced Settings -> Advanced Module List + +|image-cms-settings-menu| + +and add the following: + + imagemodal + +|image-cms-advanced-module-list| + + +Use +--- + + +Course Staff +~~~~~~~~~~~~ + +To add a full-screen image to your course: + +- upload the image file onto your course's Files & Uploads page + + - note: you can skip this step if you've already uploaded the image + elsewhere, e.g.: S3. + +- copy the URL on that page +- go to a unit in Studio +- select "Image Modal XBlock" from the Advanced Components menu + +|image-cms-add| + +You can now edit and preview the new component. + +|image-cms-view| + +Using the Studio editor, you can edit the following fields: + +- display name +- image URL +- thumbnail URL (defaults to image URL, if not specified) +- description (useful for screen readers, longer descriptions) +- alt text (useful for screen readers, captions, tags; displays when image does not) + +|image-cms-editor-1| +|image-cms-editor-2| + + +Participants +~~~~~~~~~~~~ + +|image-lms-view-normal| + +Click on the image to zoom in full-screen. + +|image-lms-view-zoom| + +Click on the image again to zoom out. + +Click and drag to pan around. + +`View a demo of the CMS`_ + +`View a demo of the LMS`_ + + +.. |badge-ci| image:: https://github.com/openedx/xblock-image-modal/workflows/Python%20CI/badge.svg?branch=master + :target: https://github.com/openedx/xblock-image-modal/actions?query=workflow%3A%22Python+CI%22 +.. |image-cms-add| image:: https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/cms-add.jpg + :width: 100% +.. |image-cms-advanced-module-list| image:: https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/advanced-module-list.png + :width: 100% +.. |image-cms-editor-1| image:: https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/studio-editor-1.png + :width: 100% +.. |image-cms-editor-2| image:: https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/studio-editor-2.png + :width: 100% +.. |image-cms-settings-menu| image:: https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/settings-menu.png + :width: 100% +.. |image-cms-view| image:: https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/studio-view.png + :width: 100% +.. |image-lms-view-normal| image:: https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/lms-view-normal.png + :width: 100% +.. |image-lms-view-zoom| image:: https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/lms-view-zoom.png + :width: 100% +.. _View a demo of the CMS: https://youtu.be/IcbGYfbav2w +.. _View a demo of the LMS: https://youtu.be/0mpjuThDoyE +.. https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/xblock-image-modal-demo-lms.mov diff --git a/src/submit_and_compare/README.md b/src/submit_and_compare/README.md new file mode 100644 index 0000000..4be0513 --- /dev/null +++ b/src/submit_and_compare/README.md @@ -0,0 +1,52 @@ +Submit and Compare XBlock +========================= +This XBlock provides a way to do an ungraded self assessment activity. It is useful for synthesis questions, or questions which require the student to answer in her own words. After the student submits her answer, she is able to see the instructor's answer, and compare her answer to the expert answer. + +![Completed Question](docs/img/submitted.png) + +Installation +------------ +To install the Submit and Compare XBlock within your edX python environment, simply run this command: + +```bash +$ pip install -r requirements.txt +``` + +Enabling in Studio +------------------ +Go to `Settings -> Advanced Settings` and set `Advanced Module List` to `["submit-and-compare"]`. + +![Advanced Module List](docs/img/policy.png) + +Usage +------------------ +Once the Submit and Compare XBlock is enabled in Studio, you should see it a new Component button labeled `Advanced`: + +![Component Buttons](docs/img/component.png) + +Click the `Advanced` button and you should see the Submit and Compare XBlock listed: + +![Advanced Component List](docs/img/advanced.png) + +After you've selected the Submit and Compare XBlock, a default question will be inserted into your unit: + +![Default Question](docs/img/student_view.png) + +Customization +------------- +The question and expert answer can both be customized by clicking the `Edit` button on the component: + +![Studio View](docs/img/studio_view1.png) +![Studio View](docs/img/studio_view2.png) + +The Submit and Compare XBlock uses a simple XML-based structure as shown below: +```bash + + Insert the question here. You can include html tags like

, , etc. + Insert the expert answer here. You can include html tags like

, , etc. + + Here you can include hints for the student + Here is another hint + + +``` diff --git a/src/submit_and_compare/README.rst b/src/submit_and_compare/README.rst new file mode 100644 index 0000000..1fc64b4 --- /dev/null +++ b/src/submit_and_compare/README.rst @@ -0,0 +1,126 @@ +Submit and Compare XBlock +========================= + +This XBlock provides a way to do an ungraded self assessment activity. +It is useful for synthesis questions, or questions which require the +student to answer in her own words. +After the student submits her answer, she is able to see the +instructor's answer, and compare her answer to the expert answer. + +|badge-ci| +|badge-coveralls| + +|image-lms-view-normal| + + +Installation +------------ + + +System Administrator +~~~~~~~~~~~~~~~~~~~~ + +To install the XBlock on your platform, +add the following to your `requirements.txt` file: + + xblock-submit-and-compare + +You'll also need to add this to your `INSTALLED_APPS`: + + submit_and_compare + + +Course Staff +~~~~~~~~~~~~ + +To install the XBlock in your course, +access your `Advanced Module List`: + + Settings -> Advanced Settings -> Advanced Module List + +|image-cms-settings-menu| + +and add the following: + + submit-and-compare + +|image-cms-advanced-module-list| + + +Use +--- + + +Course Staff +~~~~~~~~~~~~ + +To add a full-screen image to your course: + +- upload the image file onto your course's Files & Uploads page + + - note: you can skip this step if you've already uploaded the image + elsewhere, e.g.: S3. + +- copy the URL on that page +- go to a unit in Studio +- select "Image Modal XBlock" from the Advanced Components menu + +|image-cms-add| + +You can now edit and preview the new component. + +|image-cms-view| + +Using the Studio editor, you can edit the following fields: + +- display name +- image URL +- thumbnail URL (defaults to image URL, if not specified) +- description (useful for screen readers, longer descriptions) +- alt text (useful for screen readers, captions, tags; displays when image does not) + +|image-cms-editor-1| +|image-cms-editor-2| + + +Participants +~~~~~~~~~~~~ + +|image-lms-view-normal| + +Click on the image to zoom in full-screen. + +|image-lms-view-zoom| + +Click on the image again to zoom out. + +Click and drag to pan around. + +`View a demo of the CMS`_ + +`View a demo of the LMS`_ + + +.. |badge-coveralls| image:: https://coveralls.io/repos/github/Stanford-Online/xblock-image-modal/badge.svg?branch=master + :target: https://coveralls.io/github/Stanford-Online/xblock-image-modal?branch=master +.. |badge-ci| image:: https://github.com/openedx/xblock-submit-and-compare/workflows/Python%20CI/badge.svg?branch=master + :target: https://github.com/openedx/xblock-submit-and-compare/actions?query=workflow%3A%22Python+CI%22 +.. |image-cms-add| image:: https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/cms-add.jpg + :width: 100% +.. |image-cms-advanced-module-list| image:: https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/advanced-module-list.png + :width: 100% +.. |image-cms-editor-1| image:: https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/studio-editor-1.png + :width: 100% +.. |image-cms-editor-2| image:: https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/studio-editor-2.png + :width: 100% +.. |image-cms-settings-menu| image:: https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/settings-menu.png + :width: 100% +.. |image-cms-view| image:: https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/studio-view.png + :width: 100% +.. |image-lms-view-normal| image:: https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/lms-view-normal.png + :width: 100% +.. |image-lms-view-zoom| image:: https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/lms-view-zoom.png + :width: 100% +.. _View a demo of the CMS: https://youtu.be/IcbGYfbav2w +.. _View a demo of the LMS: https://youtu.be/0mpjuThDoyE +.. https://s3-us-west-1.amazonaws.com/stanford-openedx-docs/xblocks/image-modal/static/images/xblock-image-modal-demo-lms.mov diff --git a/src/submit_and_compare/docs/img/advanced.png b/src/submit_and_compare/docs/img/advanced.png new file mode 100644 index 0000000000000000000000000000000000000000..b966599e978d1cd13864833d4ce98e5b7479f4f5 GIT binary patch literal 11393 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

GNQ-fC(kvQ&cnjb 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 GzyAwd5VAc0 literal 0 HcmV?d00001 diff --git a/src/submit_and_compare/docs/img/student_view.png b/src/submit_and_compare/docs/img/student_view.png new file mode 100644 index 0000000000000000000000000000000000000000..eb022e8b915364396b87756da272f564a99c98da GIT binary patch literal 42319 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∋9X4&`OE_mBY8)4q-Qc)Gj{<|F^u?^C$Mw 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 t9`rHaBSt6PZJItV!h=`(; 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