From 6ed2737c36b4405169569c0eaedbf510508dbafe Mon Sep 17 00:00:00 2001 From: Chris Dodge Date: Wed, 6 Feb 2013 13:29:48 -0500 Subject: [PATCH 01/25] make LMS forum subsystem more robust in case of orphaned discussion modules. Given our draft/non-draft duality, we don't currently have a means to always do proper housekeeping at this point in time. However, we have to stop the LMS Forums from blowing up when encoutering one of these. --- lms/djangoapps/django_comment_client/utils.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lms/djangoapps/django_comment_client/utils.py b/lms/djangoapps/django_comment_client/utils.py index b58e3b30e6..40fd106b40 100644 --- a/lms/djangoapps/django_comment_client/utils.py +++ b/lms/djangoapps/django_comment_client/utils.py @@ -11,6 +11,8 @@ from django.http import HttpResponse from django.utils import simplejson from django_comment_client.models import Role from django_comment_client.permissions import check_permissions_by_view +from xmodule.modulestore.exceptions import NoPathToItem + from mitxmako import middleware import pystache_custom as pystache @@ -158,6 +160,14 @@ def initialize_discussion_info(course): log.warning("Required key '%s' not in discussion %s, leaving out of category map" % (key, module.location)) skip_module = True + # cdodge: pre-compute the path_to_location. Note this can throw an exception for any + # dangling discussion modules + try: + _DISCUSSIONINFO[course.id]['path_to_location'] = path_to_location(modulestore(), course.id, module.location) + except NoPathToItem: + log.warning("Could not compute path_to_location for {0}. Perhaps this is an orphaned discussion module?!? Skipping...".format(module.location)) + skip_module = True + if skip_module: continue @@ -360,7 +370,13 @@ def get_courseware_context(content, course): if id in id_map: location = id_map[id]["location"].url() title = id_map[id]["title"] - (course_id, chapter, section, position) = path_to_location(modulestore(), course.id, location) + + # cdodge: did we pre-compute, if so, then let's use that rather than recomputing + if 'path_to_location' in _DISCUSSIONINFO[course.id]: + (course_id, chapter, section, position) = _DISCUSSIONINFO[course.id]['path_to_location'] + else: + (course_id, chapter, section, position) = path_to_location(modulestore(), course.id, location) + url = reverse('courseware_position', kwargs={"course_id":course_id, "chapter":chapter, "section":section, From 114d800c6a6a6650c49c4cddee40d7866c5e442e Mon Sep 17 00:00:00 2001 From: Chris Dodge Date: Wed, 6 Feb 2013 15:17:47 -0500 Subject: [PATCH 02/25] need to make path_to_location a dictionary since it needs to be keyed by the location --- lms/djangoapps/django_comment_client/utils.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lms/djangoapps/django_comment_client/utils.py b/lms/djangoapps/django_comment_client/utils.py index 0940d065f4..151bde3dd5 100644 --- a/lms/djangoapps/django_comment_client/utils.py +++ b/lms/djangoapps/django_comment_client/utils.py @@ -166,6 +166,7 @@ def initialize_discussion_info(course): # get all discussion models within this course_id all_modules = modulestore().get_items(['i4x', course.location.org, course.location.course, 'discussion', None], course_id=course_id) + path_to_locations = {} for module in all_modules: skip_module = False for key in ('id', 'discussion_category', 'for'): @@ -176,7 +177,7 @@ def initialize_discussion_info(course): # cdodge: pre-compute the path_to_location. Note this can throw an exception for any # dangling discussion modules try: - _DISCUSSIONINFO[course.id]['path_to_location'] = path_to_location(modulestore(), course.id, module.location) + path_to_locations[module.location] = path_to_location(modulestore(), course.id, module.location) except NoPathToItem: log.warning("Could not compute path_to_location for {0}. Perhaps this is an orphaned discussion module?!? Skipping...".format(module.location)) skip_module = True @@ -245,6 +246,7 @@ def initialize_discussion_info(course): _DISCUSSIONINFO[course.id]['id_map'] = discussion_id_map _DISCUSSIONINFO[course.id]['category_map'] = category_map _DISCUSSIONINFO[course.id]['timestamp'] = datetime.now() + _DISCUSSIONINFO[course.id]['path_to_location'] = path_to_locations class JsonResponse(HttpResponse): @@ -402,8 +404,8 @@ def get_courseware_context(content, course): title = id_map[id]["title"] # cdodge: did we pre-compute, if so, then let's use that rather than recomputing - if 'path_to_location' in _DISCUSSIONINFO[course.id]: - (course_id, chapter, section, position) = _DISCUSSIONINFO[course.id]['path_to_location'] + if 'path_to_location' in _DISCUSSIONINFO[course.id] and location in _DISCUSSIONINFO[course.id]['path_to_location']: + (course_id, chapter, section, position) = _DISCUSSIONINFO[course.id]['path_to_location'][location] else: (course_id, chapter, section, position) = path_to_location(modulestore(), course.id, location) From a770e34bec6b339776f64f46ad09faf8659d48e6 Mon Sep 17 00:00:00 2001 From: Julian Arni Date: Wed, 6 Feb 2013 20:36:44 -0500 Subject: [PATCH 03/25] Adding multiple-choice loncapa integration. --- common/lib/capa/capa/responsetypes.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index 78c986a963..1ecba36d50 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -632,8 +632,10 @@ class MultipleChoiceResponse(LoncapaResponse): # define correct choices (after calling secondary setup) xml = self.xml - cxml = xml.xpath('//*[@id=$id]//choice[@correct="true"]', id=xml.get('id')) - self.correct_choices = [contextualize_text(choice.get('name'), self.context) for choice in cxml] + cxml = xml.xpath('//*[@id=$id]//choice', id=xml.get('id')) + self.correct_choices = [contextualize_text(choice.get('name'), + self.context) for choice in cxml if + contextualize_text(choice.get('correct'), self.context) == "true"] def mc_setup_response(self): ''' From faf7c64ea50d7f96fe2645d09abacbd5115fd040 Mon Sep 17 00:00:00 2001 From: Chris Dodge Date: Thu, 7 Feb 2013 10:32:13 -0500 Subject: [PATCH 04/25] add try/catch and fallback to returning a path to the root of the course --- lms/djangoapps/django_comment_client/utils.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lms/djangoapps/django_comment_client/utils.py b/lms/djangoapps/django_comment_client/utils.py index 151bde3dd5..877c730539 100644 --- a/lms/djangoapps/django_comment_client/utils.py +++ b/lms/djangoapps/django_comment_client/utils.py @@ -407,7 +407,12 @@ def get_courseware_context(content, course): if 'path_to_location' in _DISCUSSIONINFO[course.id] and location in _DISCUSSIONINFO[course.id]['path_to_location']: (course_id, chapter, section, position) = _DISCUSSIONINFO[course.id]['path_to_location'][location] else: - (course_id, chapter, section, position) = path_to_location(modulestore(), course.id, location) + try: + (course_id, chapter, section, position) = path_to_location(modulestore(), course.id, location) + except NoPathToItem: + # Object is not in the graph any longer, let's just get path to the base of the course + # so that we can at least return something to the caller + (course_id, chapter, section, position) = path_to_location(modulestore(), course.id, course.location) url = reverse('courseware_position', kwargs={"course_id":course_id, "chapter":chapter, From 8a75e1ad19894101863bfbcdb3814955488b9d98 Mon Sep 17 00:00:00 2001 From: Julian Arni Date: Thu, 7 Feb 2013 14:50:18 -0500 Subject: [PATCH 05/25] Added comment --- common/lib/capa/capa/responsetypes.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index 1ecba36d50..0ecbfdc55d 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -633,9 +633,11 @@ class MultipleChoiceResponse(LoncapaResponse): # define correct choices (after calling secondary setup) xml = self.xml cxml = xml.xpath('//*[@id=$id]//choice', id=xml.get('id')) - self.correct_choices = [contextualize_text(choice.get('name'), - self.context) for choice in cxml if - contextualize_text(choice.get('correct'), self.context) == "true"] + # contextualize correct attribute and then select ones for which + # correct = "true" + self.correct_choices = [contextualize_text(choice.get('name'), self.context) + for choice in cxml + if contextualize_text(choice.get('correct'), self.context) == "true"] def mc_setup_response(self): ''' From 33009eba7d6cd9915c305894b8a85bf3ec7d42a7 Mon Sep 17 00:00:00 2001 From: Chris Dodge Date: Mon, 11 Feb 2013 14:30:26 -0500 Subject: [PATCH 06/25] add exporting of grading_policy.json --- cms/djangoapps/contentstore/tests/test_contentstore.py | 10 ++++++++++ common/lib/xmodule/xmodule/modulestore/xml_exporter.py | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py index 72ae3821cc..adecd392eb 100644 --- a/cms/djangoapps/contentstore/tests/test_contentstore.py +++ b/cms/djangoapps/contentstore/tests/test_contentstore.py @@ -10,6 +10,7 @@ import json from fs.osfs import OSFS import copy from mock import Mock +from json import dumps, loads from student.models import Registration from django.contrib.auth.models import User @@ -207,6 +208,15 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase): # check for custom_tags self.verify_content_existence(ms, root_dir, location, 'custom_tags', 'custom_tag_template') + # check for graiding_policy.json + fs = OSFS(root_dir / 'test_export/policies/6.002_Spring_2012') + self.assertTrue(fs.exists('grading_policy.json')) + + # compare what's on disk compared to what we have in our course + with fs.open('grading_policy.json','r') as grading_policy: + on_disk = loads(grading_policy.read()) + course = ms.get_item(location) + self.assertEqual(on_disk, course.definition['data']['grading_policy']) # remove old course delete_course(ms, cs, location) diff --git a/common/lib/xmodule/xmodule/modulestore/xml_exporter.py b/common/lib/xmodule/xmodule/modulestore/xml_exporter.py index bdbd5a6133..509a2c7db9 100644 --- a/common/lib/xmodule/xmodule/modulestore/xml_exporter.py +++ b/common/lib/xmodule/xmodule/modulestore/xml_exporter.py @@ -2,6 +2,7 @@ import logging from xmodule.modulestore import Location from xmodule.modulestore.django import modulestore from fs.osfs import OSFS +from json import dumps def export_to_xml(modulestore, contentstore, course_location, root_dir, course_dir): @@ -27,6 +28,12 @@ def export_to_xml(modulestore, contentstore, course_location, root_dir, course_d # export the course updates export_extra_content(export_fs, modulestore, course_location, 'course_info', 'info', '.html') + # export the grading policy + policies_dir = export_fs.makeopendir('policies') + course_run_policy_dir = policies_dir.makeopendir(course.location.name) + with course_run_policy_dir.open('grading_policy.json', 'w') as grading_policy: + grading_policy.write(dumps(course.definition['data']['grading_policy'])) + def export_extra_content(export_fs, modulestore, course_location, category_type, dirname, file_suffix=''): query_loc = Location('i4x', course_location.org, course_location.course, category_type, None) From ae4a854e188165239ebd961df53a557431f0dd9c Mon Sep 17 00:00:00 2001 From: Don Mitchell Date: Mon, 11 Feb 2013 15:46:58 -0500 Subject: [PATCH 07/25] Bug 180 --- cms/static/js/views/overview.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cms/static/js/views/overview.js b/cms/static/js/views/overview.js index 8cbae177a8..d064f24006 100644 --- a/cms/static/js/views/overview.js +++ b/cms/static/js/views/overview.js @@ -202,13 +202,17 @@ function _handleReorder(event, ui, parentIdField, childrenSelector) { children = _.without(children, ui.draggable.data('id')); } // add to this parent (figure out where) - for (var i = 0; i < _els.length; i++) { - if (!ui.draggable.is(_els[i]) && ui.offset.top < $(_els[i]).offset().top) { + for (var i = 0, bump = 0; i < _els.length; i++) { + if (ui.draggable.is(_els[i])) { + bump = -1; // bump indicates that the draggable was passed in the dom but not children's list b/c + // it's not in that list + } + else if (ui.offset.top < $(_els[i]).offset().top) { // insert at i in children and _els ui.draggable.insertBefore($(_els[i])); // TODO figure out correct way to have it remove the style: top:n; setting (and similar line below) ui.draggable.attr("style", "position:relative;"); - children.splice(i, 0, ui.draggable.data('id')); + children.splice(i + bump, 0, ui.draggable.data('id')); break; } } From 565f5f0adc8505966e099b525ec9abe21757745a Mon Sep 17 00:00:00 2001 From: Don Mitchell Date: Mon, 11 Feb 2013 16:28:22 -0500 Subject: [PATCH 08/25] Stop simple clicks from paging to top w/o disrupting dnd --- cms/static/js/views/overview.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cms/static/js/views/overview.js b/cms/static/js/views/overview.js index d064f24006..24b29156cd 100644 --- a/cms/static/js/views/overview.js +++ b/cms/static/js/views/overview.js @@ -58,6 +58,9 @@ $(document).ready(function() { drop: onSectionReordered, greedy: true }); + + // stop clicks on drag bars from doing their thing w/o stopping drag (did this cancel pointer?) + $('.courseware-overview').click(function(e) {e.preventDefault(); }); }); From 777e0ef9c5165afee5a6094a1231c812eb72d085 Mon Sep 17 00:00:00 2001 From: Don Mitchell Date: Mon, 11 Feb 2013 16:36:34 -0500 Subject: [PATCH 09/25] The other one was too inclusive --- cms/static/js/views/overview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cms/static/js/views/overview.js b/cms/static/js/views/overview.js index 24b29156cd..db42c13208 100644 --- a/cms/static/js/views/overview.js +++ b/cms/static/js/views/overview.js @@ -60,7 +60,7 @@ $(document).ready(function() { }); // stop clicks on drag bars from doing their thing w/o stopping drag (did this cancel pointer?) - $('.courseware-overview').click(function(e) {e.preventDefault(); }); + $('.drag-handle').click(function(e) {e.preventDefault(); }); }); From 8bc9564d92304f60def3a384ce78e876bf63e203 Mon Sep 17 00:00:00 2001 From: Don Mitchell Date: Mon, 11 Feb 2013 16:45:36 -0500 Subject: [PATCH 10/25] clean up note to self --- cms/static/js/views/overview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cms/static/js/views/overview.js b/cms/static/js/views/overview.js index db42c13208..7d92ab69ad 100644 --- a/cms/static/js/views/overview.js +++ b/cms/static/js/views/overview.js @@ -59,7 +59,7 @@ $(document).ready(function() { greedy: true }); - // stop clicks on drag bars from doing their thing w/o stopping drag (did this cancel pointer?) + // stop clicks on drag bars from doing their thing w/o stopping drag $('.drag-handle').click(function(e) {e.preventDefault(); }); }); From aa2d0ecaf26f79b7b4bf807a289d415e4a9b3024 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Mon, 11 Feb 2013 17:06:35 -0500 Subject: [PATCH 11/25] We no longer need override_settings, Django has a better one. --- cms/djangoapps/contentstore/tests/test_contentstore.py | 2 +- cms/djangoapps/contentstore/tests/tests.py | 1 - cms/djangoapps/contentstore/tests/utils.py | 1 - common/djangoapps/course_groups/tests/tests.py | 2 +- common/djangoapps/status/tests.py | 2 +- lms/djangoapps/course_wiki/tests/tests.py | 2 +- lms/djangoapps/courseware/tests/tests.py | 2 +- lms/djangoapps/django_comment_client/tests.py | 2 +- lms/djangoapps/instructor/tests.py | 2 +- lms/djangoapps/open_ended_grading/tests.py | 2 +- requirements.txt | 1 - 11 files changed, 8 insertions(+), 11 deletions(-) diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py index adecd392eb..dcd1f408cd 100644 --- a/cms/djangoapps/contentstore/tests/test_contentstore.py +++ b/cms/djangoapps/contentstore/tests/test_contentstore.py @@ -1,7 +1,7 @@ import json import shutil from django.test.client import Client -from override_settings import override_settings +from django.test.utils import override_settings from django.conf import settings from django.core.urlresolvers import reverse from path import path diff --git a/cms/djangoapps/contentstore/tests/tests.py b/cms/djangoapps/contentstore/tests/tests.py index 9af5b09276..d2f18f2e49 100644 --- a/cms/djangoapps/contentstore/tests/tests.py +++ b/cms/djangoapps/contentstore/tests/tests.py @@ -1,7 +1,6 @@ import json import shutil from django.test.client import Client -from override_settings import override_settings from django.conf import settings from django.core.urlresolvers import reverse from path import path diff --git a/cms/djangoapps/contentstore/tests/utils.py b/cms/djangoapps/contentstore/tests/utils.py index 4e3510463f..be028b2836 100644 --- a/cms/djangoapps/contentstore/tests/utils.py +++ b/cms/djangoapps/contentstore/tests/utils.py @@ -2,7 +2,6 @@ import json import copy from time import time from django.test import TestCase -from override_settings import override_settings from django.conf import settings from student.models import Registration diff --git a/common/djangoapps/course_groups/tests/tests.py b/common/djangoapps/course_groups/tests/tests.py index 0fbf863fee..b3ad928b39 100644 --- a/common/djangoapps/course_groups/tests/tests.py +++ b/common/djangoapps/course_groups/tests/tests.py @@ -2,7 +2,7 @@ import django.test from django.contrib.auth.models import User from django.conf import settings -from override_settings import override_settings +from django.test.utils import override_settings from course_groups.models import CourseUserGroup from course_groups.cohorts import (get_cohort, get_course_cohorts, diff --git a/common/djangoapps/status/tests.py b/common/djangoapps/status/tests.py index 98a36f433a..1695663ac5 100644 --- a/common/djangoapps/status/tests.py +++ b/common/djangoapps/status/tests.py @@ -1,7 +1,7 @@ from django.conf import settings from django.test import TestCase import os -from override_settings import override_settings +from django.test.utils import override_settings from tempfile import NamedTemporaryFile from status import get_site_status_msg diff --git a/lms/djangoapps/course_wiki/tests/tests.py b/lms/djangoapps/course_wiki/tests/tests.py index 99f138f0bc..cecc4f9cf9 100644 --- a/lms/djangoapps/course_wiki/tests/tests.py +++ b/lms/djangoapps/course_wiki/tests/tests.py @@ -1,5 +1,5 @@ from django.core.urlresolvers import reverse -from override_settings import override_settings +from django.test.utils import override_settings import xmodule.modulestore.django diff --git a/lms/djangoapps/courseware/tests/tests.py b/lms/djangoapps/courseware/tests/tests.py index efa5ad823e..fb6842d4a9 100644 --- a/lms/djangoapps/courseware/tests/tests.py +++ b/lms/djangoapps/courseware/tests/tests.py @@ -11,7 +11,7 @@ from django.test import TestCase from django.test.client import RequestFactory from django.conf import settings from django.core.urlresolvers import reverse -from override_settings import override_settings +from django.test.utils import override_settings import xmodule.modulestore.django from xmodule.modulestore.mongo import MongoModuleStore diff --git a/lms/djangoapps/django_comment_client/tests.py b/lms/djangoapps/django_comment_client/tests.py index ac059a1e3f..4b5fe2ba5a 100644 --- a/lms/djangoapps/django_comment_client/tests.py +++ b/lms/djangoapps/django_comment_client/tests.py @@ -6,7 +6,7 @@ from django.conf import settings from mock import Mock -from override_settings import override_settings +from django.test.utils import override_settings import xmodule.modulestore.django diff --git a/lms/djangoapps/instructor/tests.py b/lms/djangoapps/instructor/tests.py index 2610e57422..b775aa158a 100644 --- a/lms/djangoapps/instructor/tests.py +++ b/lms/djangoapps/instructor/tests.py @@ -15,7 +15,7 @@ import json from nose import SkipTest from mock import patch, Mock -from override_settings import override_settings +from django.test.utils import override_settings # Need access to internal func to put users in the right group from django.contrib.auth.models import Group diff --git a/lms/djangoapps/open_ended_grading/tests.py b/lms/djangoapps/open_ended_grading/tests.py index 4d220d4baa..ec2fe5ab38 100644 --- a/lms/djangoapps/open_ended_grading/tests.py +++ b/lms/djangoapps/open_ended_grading/tests.py @@ -22,7 +22,7 @@ from mitxmako.shortcuts import render_to_string import logging log = logging.getLogger(__name__) -from override_settings import override_settings +from django.test.utils import override_settings from django.http import QueryDict diff --git a/requirements.txt b/requirements.txt index 0faf2e3ba5..7bfaa11bc6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,7 +24,6 @@ django_nose nosexcover==1.0.7 rednose==0.3.3 GitPython==0.3.2.RC1 -django-override-settings==1.2 mock==0.8.0 PyYAML==3.10 South==0.7.6 From d57c78f9d9ba22d302ad600b68245ce1dba666c3 Mon Sep 17 00:00:00 2001 From: Kevin Chugh Date: Mon, 11 Feb 2013 20:01:09 -0500 Subject: [PATCH 12/25] fix showing less than and greater than in code --- .../src/discussion/views/discussion_thread_show_view.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/static/coffee/src/discussion/views/discussion_thread_show_view.coffee b/common/static/coffee/src/discussion/views/discussion_thread_show_view.coffee index a8e95c2565..6320c3d1e3 100644 --- a/common/static/coffee/src/discussion/views/discussion_thread_show_view.coffee +++ b/common/static/coffee/src/discussion/views/discussion_thread_show_view.coffee @@ -47,7 +47,7 @@ if Backbone? convertMath: -> element = @$(".post-body") - element.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight element.html() + element.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight element.text() MathJax.Hub.Queue ["Typeset", MathJax.Hub, element[0]] toggleVote: (event) -> From 21f4616080bc01de312d85d9ad9207c19c788b6d Mon Sep 17 00:00:00 2001 From: Kevin Chugh Date: Tue, 12 Feb 2013 09:18:46 -0500 Subject: [PATCH 13/25] spread less than and greater than fix to responses and comments, and profile view --- .../src/discussion/views/discussion_thread_profile_view.coffee | 2 +- .../src/discussion/views/response_comment_show_view.coffee | 2 +- .../src/discussion/views/thread_response_show_view.coffee | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/static/coffee/src/discussion/views/discussion_thread_profile_view.coffee b/common/static/coffee/src/discussion/views/discussion_thread_profile_view.coffee index d31a402a99..8b47696c01 100644 --- a/common/static/coffee/src/discussion/views/discussion_thread_profile_view.coffee +++ b/common/static/coffee/src/discussion/views/discussion_thread_profile_view.coffee @@ -50,7 +50,7 @@ if Backbone? convertMath: -> element = @$(".post-body") - element.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight element.html() + element.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight element.text() MathJax.Hub.Queue ["Typeset", MathJax.Hub, element[0]] renderResponses: -> diff --git a/common/static/coffee/src/discussion/views/response_comment_show_view.coffee b/common/static/coffee/src/discussion/views/response_comment_show_view.coffee index e6c8064978..84e7357e1f 100644 --- a/common/static/coffee/src/discussion/views/response_comment_show_view.coffee +++ b/common/static/coffee/src/discussion/views/response_comment_show_view.coffee @@ -26,7 +26,7 @@ if Backbone? convertMath: -> body = @$el.find(".response-body") - body.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight body.html() + body.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight body.text() MathJax.Hub.Queue ["Typeset", MathJax.Hub, body[0]] markAsStaff: -> diff --git a/common/static/coffee/src/discussion/views/thread_response_show_view.coffee b/common/static/coffee/src/discussion/views/thread_response_show_view.coffee index 32683fe6f6..1f305ddf34 100644 --- a/common/static/coffee/src/discussion/views/thread_response_show_view.coffee +++ b/common/static/coffee/src/discussion/views/thread_response_show_view.coffee @@ -30,7 +30,7 @@ if Backbone? convertMath: -> element = @$(".response-body") - element.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight element.html() + element.html DiscussionUtil.postMathJaxProcessor DiscussionUtil.markdownWithHighlight element.text() MathJax.Hub.Queue ["Typeset", MathJax.Hub, element[0]] markAsStaff: -> From 83e4dfaacb49c880b59f123d306a1280a0a6aabc Mon Sep 17 00:00:00 2001 From: Brian Talbot Date: Tue, 12 Feb 2013 09:58:16 -0500 Subject: [PATCH 14/25] lms - pearson: trying to resolve JQUI accordion width bug in IE7 --- lms/static/sass/course/courseware/_sidebar.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/lms/static/sass/course/courseware/_sidebar.scss b/lms/static/sass/course/courseware/_sidebar.scss index 4e893d2455..1ab841e1e5 100644 --- a/lms/static/sass/course/courseware/_sidebar.scss +++ b/lms/static/sass/course/courseware/_sidebar.scss @@ -99,6 +99,7 @@ section.course-index { @include border-radius(0); margin: 0; padding: 9px 0 9px 9px; + overflow: auto; li { border-bottom: 0; From 93d186511fabab6b3ad9f9fb55bd6a2e7c4b9620 Mon Sep 17 00:00:00 2001 From: Chris Dodge Date: Tue, 12 Feb 2013 10:23:32 -0500 Subject: [PATCH 15/25] clean up templates that were removed from disk - we need to remove from DB as well --- common/lib/xmodule/xmodule/templates.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/common/lib/xmodule/xmodule/templates.py b/common/lib/xmodule/xmodule/templates.py index ce37df929f..eaf821155e 100644 --- a/common/lib/xmodule/xmodule/templates.py +++ b/common/lib/xmodule/xmodule/templates.py @@ -56,6 +56,10 @@ def update_templates(): available from the installed plugins """ + # cdodge: build up a list of all existing templates. This will be used to determine which + # templates have been removed from disk - and thus we need to remove from the DB + templates_to_delete = modulestore('direct').get_items(['i4x', 'edx', 'templates', None, None, None]) + for category, templates in all_templates().items(): for template in templates: if 'display_name' not in template.metadata: @@ -85,3 +89,12 @@ def update_templates(): modulestore('direct').update_item(template_location, template.data) modulestore('direct').update_children(template_location, template.children) modulestore('direct').update_metadata(template_location, template.metadata) + + # remove template from list of templates to delete + templates_to_delete = [t for t in templates_to_delete if t.location != template_location] + + # now remove all templates which appear to have removed from disk + if len(templates_to_delete) > 0: + logging.debug('deleting dangling templates = {0}'.format(templates_to_delete)) + for template in templates_to_delete: + modulestore('direct').delete_item(template.location) From f33f7134fbf246de87e6b8d938ef145373196bb8 Mon Sep 17 00:00:00 2001 From: Brian Talbot Date: Tue, 12 Feb 2013 10:34:21 -0500 Subject: [PATCH 16/25] lms - pearson: trying to resolve JQUI accordion width bug in IE7 - enforcing width to chapters --- lms/static/sass/course/courseware/_sidebar.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lms/static/sass/course/courseware/_sidebar.scss b/lms/static/sass/course/courseware/_sidebar.scss index 1ab841e1e5..81b497d4f9 100644 --- a/lms/static/sass/course/courseware/_sidebar.scss +++ b/lms/static/sass/course/courseware/_sidebar.scss @@ -67,7 +67,7 @@ section.course-index { } .chapter { - width: 100%; + width: 100% !important; @include box-sizing(border-box); padding: 11px 14px; @include linear-gradient(top, rgba(255, 255, 255, .6), rgba(255, 255, 255, 0)); @@ -100,6 +100,7 @@ section.course-index { margin: 0; padding: 9px 0 9px 9px; overflow: auto; + width: 100%; li { border-bottom: 0; From 78d3d2006919bf95e0fb29ad2101bb6ece707899 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Wed, 23 Jan 2013 17:11:02 -0500 Subject: [PATCH 17/25] When checking types to convert data, don't forget about longs. 32-bit Pythons make longs from values that are ints on 64-bit Pythons. Conflicts: common/djangoapps/util/converters.py --- common/djangoapps/util/converters.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/common/djangoapps/util/converters.py b/common/djangoapps/util/converters.py index 900371a0dd..ec2d29ecfa 100644 --- a/common/djangoapps/util/converters.py +++ b/common/djangoapps/util/converters.py @@ -18,10 +18,13 @@ def jsdate_to_time(field): """ if field is None: return field - elif isinstance(field, basestring): # iso format but ignores time zone assuming it's Z - d = datetime.datetime(*map(int, re.split('[^\d]', field)[:6])) # stop after seconds. Debatable + elif isinstance(field, basestring): + # ISO format but ignores time zone assuming it's Z. + d = datetime.datetime(*map(int, re.split('[^\d]', field)[:6])) # stop after seconds. Debatable return d.utctimetuple() - elif isinstance(field, int) or isinstance(field, float): + elif isinstance(field, (int, long, float)): return time.gmtime(field / 1000) elif isinstance(field, time.struct_time): return field + else: + raise ValueError("Couldn't convert %r to time" % field) From b5378b04b3402db5c99aaeaf3db456bbd8c5e684 Mon Sep 17 00:00:00 2001 From: Brian Wilson Date: Tue, 12 Feb 2013 12:25:11 -0500 Subject: [PATCH 18/25] change timer to calculate relative duration in javascript --- .../lib/xmodule/xmodule/timelimit_module.py | 4 ++-- lms/djangoapps/courseware/views.py | 19 +++++++++---------- lms/templates/courseware/courseware.html | 17 +++++++++-------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/common/lib/xmodule/xmodule/timelimit_module.py b/common/lib/xmodule/xmodule/timelimit_module.py index 23ed06eb59..9abb5d183f 100644 --- a/common/lib/xmodule/xmodule/timelimit_module.py +++ b/common/lib/xmodule/xmodule/timelimit_module.py @@ -86,8 +86,8 @@ class TimeLimitModule(XModule): modified_duration = self._get_accommodated_duration(duration) self.ending_at = self.beginning_at + modified_duration - def get_end_time_in_ms(self): - return int(self.ending_at * 1000) + def get_remaining_time_in_ms(self): + return int((self.ending_at - time()) * 1000) def get_instance_state(self): state = {} diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py index e8b36ecd2a..fb351e1c01 100644 --- a/lms/djangoapps/courseware/views.py +++ b/lms/djangoapps/courseware/views.py @@ -177,10 +177,10 @@ def check_for_active_timelimit_module(request, course_id, course): raise Http404("No {0} metadata at this location: {1} ".format('time_expired_redirect_url', location)) time_expired_redirect_url = timelimit_descriptor.metadata.get('time_expired_redirect_url') context['time_expired_redirect_url'] = time_expired_redirect_url - # Fetch the end time (in GMT) as stored in the module when it was started. - # This value should be UTC time as number of milliseconds since epoch. - end_date = timelimit_module.get_end_time_in_ms() - context['timer_expiration_datetime'] = end_date + # Fetch the remaining time relative to the end time as stored in the module when it was started. + # This value should be in milliseconds. + remaining_time = timelimit_module.get_remaining_time_in_ms() + context['timer_expiration_duration'] = remaining_time if 'suppress_toplevel_navigation' in timelimit_descriptor.metadata: context['suppress_toplevel_navigation'] = timelimit_descriptor.metadata['suppress_toplevel_navigation'] return_url = reverse('jump_to', kwargs={'course_id':course_id, 'location':location}) @@ -191,7 +191,7 @@ def update_timelimit_module(user, course_id, student_module_cache, timelimit_des ''' Updates the state of the provided timing module, starting it if it hasn't begun. Returns dict with timer-related values to enable display of time remaining. - Returns 'timer_expiration_datetime' in dict if timer is still active, and not if timer has expired. + Returns 'timer_expiration_duration' in dict if timer is still active, and not if timer has expired. ''' context = {} # determine where to go when the exam ends: @@ -215,10 +215,9 @@ def update_timelimit_module(user, course_id, student_module_cache, timelimit_des instance_module.save() # the exam has been started, either because the student is returning to the - # exam page, or because they have just visited it. Fetch the end time (in GMT) as stored - # in the module when it was started. - # This value should be UTC time as number of milliseconds since epoch. - context['timer_expiration_datetime'] = timelimit_module.get_end_time_in_ms() + # exam page, or because they have just visited it. Fetch the remaining time relative to the + # end time as stored in the module when it was started. + context['timer_expiration_duration'] = timelimit_module.get_remaining_time_in_ms() # also use the timed module to determine whether top-level navigation is visible: if 'suppress_toplevel_navigation' in timelimit_descriptor.metadata: context['suppress_toplevel_navigation'] = timelimit_descriptor.metadata['suppress_toplevel_navigation'] @@ -325,7 +324,7 @@ def index(request, course_id, chapter=None, section=None, if section_module.category == 'timelimit': timer_context = update_timelimit_module(request.user, course_id, student_module_cache, section_descriptor, section_module) - if 'timer_expiration_datetime' in timer_context: + if 'timer_expiration_duration' in timer_context: context.update(timer_context) else: # if there is no expiration defined, then we know the timer has expired: diff --git a/lms/templates/courseware/courseware.html b/lms/templates/courseware/courseware.html index 72a4b2cae1..fcbc83d815 100644 --- a/lms/templates/courseware/courseware.html +++ b/lms/templates/courseware/courseware.html @@ -60,14 +60,12 @@ }); -% if timer_expiration_datetime: +% if timer_expiration_duration: - - - -% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']: - <%static:js group='application'/> -% endif - -% if not settings.MITX_FEATURES['USE_DJANGO_PIPELINE']: - % for jsfn in [ '/static/%s' % x.replace('.coffee','.js') for x in settings.PIPELINE_JS['application']['source_filenames'] ]: - - % endfor -% endif - -## codemirror - - - -## alternate codemirror -## -## -## - -## image input: for clicking on images (see imageinput.html) - - - -<%include file="mathjax_include.html" /> - - - - - - -
- -## ----------------------------------------------------------------------------- -## information - -##
-##

Rendition of your problem code

-##
- -## ----------------------------------------------------------------------------- -## rendered problem display - - - - - - - -
-
- ${phtml} -
-
- - - - - -## - - - -## image input: for clicking on images (see imageinput.html) - - - - - <%block name="js_extra"/> - - - diff --git a/lms/templates/gitupdate.html b/lms/templates/gitupdate.html deleted file mode 100644 index a0cedabeae..0000000000 --- a/lms/templates/gitupdate.html +++ /dev/null @@ -1,32 +0,0 @@ - - -edX gitupdate - - - -
-

edX gitupdate

-
- -

Coursename: ${coursename}

- -% if msg: - - ${msg} - -% else: -

-Do you REALLY want to overwrite all the course.xml + problems + html -files with version from the main git repository? -

- -
- -## - -
-% endif - -

Return to site

- - diff --git a/lms/templates/quickedit.html b/lms/templates/quickedit.html deleted file mode 100644 index bc8e74eb65..0000000000 --- a/lms/templates/quickedit.html +++ /dev/null @@ -1,180 +0,0 @@ -<%namespace name='static' file='static_content.html'/> - - -## ----------------------------------------------------------------------------- -## Template for courseware.views.quickedit -## -## Used for quick-edit link present when viewing capa-format assesment problems. -## ----------------------------------------------------------------------------- - - -## -## - -% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']: - <%static:css group='application'/> -% endif - -% if not settings.MITX_FEATURES['USE_DJANGO_PIPELINE']: -## -% endif - - - - - -% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']: - <%static:js group='application'/> -% endif - -% if not settings.MITX_FEATURES['USE_DJANGO_PIPELINE']: - % for jsfn in [ '/static/%s' % x.replace('.coffee','.js') for x in settings.PIPELINE_JS['application']['source_filenames'] ]: - - % endfor -% endif - -## codemirror - - - -## alternate codemirror -## -## -## - -## image input: for clicking on images (see imageinput.html) - - -## - - - -<%block name="headextra"/> - - - <%include file="mathjax_include.html" /> - - - - - - - -## ----------------------------------------------------------------------------- -## information and i4x PSL code - -
-

QuickEdit

-
-
    -
  • File = ${filename}
  • -
  • ID = ${id}
  • -
- -
- -
- - - -
- -${msg|n} - -## ----------------------------------------------------------------------------- -## rendered problem display - - - -
- - - - - - - -
-
-
- ${phtml} -
-
-
- - - - - -## - - - - - - - - <%block name="js_extra"/> - - - diff --git a/lms/urls.py b/lms/urls.py index b25c4d259e..a203d468e7 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -320,10 +320,6 @@ if settings.COURSEWARE_ENABLED: 'courseware.views.static_tab', name="static_tab"), ) -if settings.QUICKEDIT: - urlpatterns += (url(r'^quickedit/(?P[^/]*)$', 'dogfood.views.quickedit'),) - urlpatterns += (url(r'^dogfood/(?P[^/]*)$', 'dogfood.views.df_capa_problem'),) - if settings.ENABLE_JASMINE: urlpatterns += (url(r'^_jasmine/', include('django_jasmine.urls')),) From e413d16bffb235f418d43a426fcbf9567824c4a8 Mon Sep 17 00:00:00 2001 From: ichuang Date: Wed, 13 Feb 2013 21:25:31 -0500 Subject: [PATCH 25/25] allow "rows" attrib of coderesponse textbox to set box height --- common/lib/capa/capa/templates/codeinput.html | 1 + 1 file changed, 1 insertion(+) diff --git a/common/lib/capa/capa/templates/codeinput.html b/common/lib/capa/capa/templates/codeinput.html index 5c2ff2aca5..eb8cad0d70 100644 --- a/common/lib/capa/capa/templates/codeinput.html +++ b/common/lib/capa/capa/templates/codeinput.html @@ -50,6 +50,7 @@ }, smartIndent: false }); + $("#textbox_${id}").find('.CodeMirror-scroll').height(${int(13.5*eval(rows))}); });