From bd822b9d2fcefb17f88c41c2059aa211879ada6a Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Wed, 13 Feb 2013 14:13:22 -0500 Subject: [PATCH] Fix tests post-merge --- common/djangoapps/student/views.py | 56 +++++++++---------- .../xmodule/combined_open_ended_module.py | 2 +- .../xmodule/combined_open_ended_modulev1.py | 2 +- .../lib/xmodule/xmodule/conditional_module.py | 9 ++- common/lib/xmodule/xmodule/course_module.py | 44 ++++++--------- common/lib/xmodule/xmodule/gst_module.py | 2 +- common/lib/xmodule/xmodule/modulestore/xml.py | 3 + .../xmodule/modulestore/xml_importer.py | 7 +-- .../lib/xmodule/xmodule/open_ended_module.py | 3 +- .../xmodule/xmodule/peer_grading_module.py | 29 ++++------ .../xmodule/xmodule/self_assessment_module.py | 8 +-- .../xmodule/tests/test_course_module.py | 14 ++--- lms/djangoapps/courseware/access.py | 6 +- lms/djangoapps/courseware/courses.py | 2 +- lms/djangoapps/courseware/module_render.py | 10 ++-- lms/djangoapps/courseware/tabs.py | 7 ++- lms/djangoapps/courseware/tests/tests.py | 4 +- lms/djangoapps/courseware/views.py | 6 +- .../controller_query_service.py | 2 +- lms/djangoapps/open_ended_grading/tests.py | 6 +- lms/templates/course.html | 2 +- lms/templates/courseware/progress.html | 4 +- 22 files changed, 107 insertions(+), 121 deletions(-) diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index 9be0aa2efa..a96cb8160b 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -44,9 +44,8 @@ from collections import namedtuple from courseware.courses import get_courses, sort_by_announcement from courseware.access import has_access -from courseware.models import StudentModuleCache from courseware.views import get_module_for_descriptor, jump_to -from courseware.module_render import get_instance_module +from courseware.model_data import ModelDataCache from statsd import statsd @@ -1071,14 +1070,14 @@ def accept_name_change(request): @csrf_exempt def test_center_login(request): - # errors are returned by navigating to the error_url, adding a query parameter named "code" + # errors are returned by navigating to the error_url, adding a query parameter named "code" # which contains the error code describing the exceptional condition. def makeErrorURL(error_url, error_code): log.error("generating error URL with error code {}".format(error_code)) return "{}?code={}".format(error_url, error_code); - + # get provided error URL, which will be used as a known prefix for returning error messages to the - # Pearson shell. + # Pearson shell. error_url = request.POST.get("errorURL") # TODO: check that the parameters have not been tampered with, by comparing the code provided by Pearson @@ -1089,12 +1088,12 @@ def test_center_login(request): # calculate SHA for query string # TODO: figure out how to get the original query string, so we can hash it and compare. - - + + if 'clientCandidateID' not in request.POST: return HttpResponseRedirect(makeErrorURL(error_url, "missingClientCandidateID")); client_candidate_id = request.POST.get("clientCandidateID") - + # TODO: check remaining parameters, and maybe at least log if they're not matching # expected values.... # registration_id = request.POST.get("registrationID") @@ -1108,12 +1107,12 @@ def test_center_login(request): return HttpResponseRedirect(makeErrorURL(error_url, "invalidClientCandidateID")); # find testcenter_registration that matches the provided exam code: - # Note that we could rely in future on either the registrationId or the exam code, - # or possibly both. But for now we know what to do with an ExamSeriesCode, + # Note that we could rely in future on either the registrationId or the exam code, + # or possibly both. But for now we know what to do with an ExamSeriesCode, # while we currently have no record of RegistrationID values at all. if 'vueExamSeriesCode' not in request.POST: - # we are not allowed to make up a new error code, according to Pearson, - # so instead of "missingExamSeriesCode", we use a valid one that is + # we are not allowed to make up a new error code, according to Pearson, + # so instead of "missingExamSeriesCode", we use a valid one that is # inaccurate but at least distinct. (Sigh.) log.error("missing exam series code for cand ID {}".format(client_candidate_id)) return HttpResponseRedirect(makeErrorURL(error_url, "missingPartnerID")); @@ -1127,11 +1126,11 @@ def test_center_login(request): if not registrations: log.error("not able to find exam registration for exam {} and cand ID {}".format(exam_series_code, client_candidate_id)) return HttpResponseRedirect(makeErrorURL(error_url, "noTestsAssigned")); - + # TODO: figure out what to do if there are more than one registrations.... # for now, just take the first... registration = registrations[0] - + course_id = registration.course_id course = course_from_id(course_id) # assume it will be found.... if not course: @@ -1149,19 +1148,19 @@ def test_center_login(request): if not timelimit_descriptor: log.error("cand {} on exam {} for course {}: descriptor not found for location {}".format(client_candidate_id, exam_series_code, course_id, location)) return HttpResponseRedirect(makeErrorURL(error_url, "missingClientProgram")); - - timelimit_module_cache = StudentModuleCache.cache_for_descriptor_descendents(course_id, testcenteruser.user, - timelimit_descriptor, depth=None) - timelimit_module = get_module_for_descriptor(request.user, request, timelimit_descriptor, + + timelimit_module_cache = ModelDataCache.cache_for_descriptor_descendents(course_id, testcenteruser.user, + timelimit_descriptor, depth=None) + timelimit_module = get_module_for_descriptor(request.user, request, timelimit_descriptor, timelimit_module_cache, course_id, position=None) if not timelimit_module.category == 'timelimit': log.error("cand {} on exam {} for course {}: non-timelimit module at location {}".format(client_candidate_id, exam_series_code, course_id, location)) return HttpResponseRedirect(makeErrorURL(error_url, "missingClientProgram")); - + if timelimit_module and timelimit_module.has_ended: log.warning("cand {} on exam {} for course {}: test already over at {}".format(client_candidate_id, exam_series_code, course_id, timelimit_module.ending_at)) return HttpResponseRedirect(makeErrorURL(error_url, "allTestsTaken")); - + # check if we need to provide an accommodation: time_accommodation_mapping = {'ET12ET' : 'ADDHALFTIME', 'ET30MN' : 'ADD30MIN', @@ -1174,27 +1173,24 @@ def test_center_login(request): # special, hard-coded client ID used by Pearson shell for testing: if client_candidate_id == "edX003671291147": time_accommodation_code = 'TESTING' - + if time_accommodation_code: timelimit_module.accommodation_code = time_accommodation_code - instance_module = get_instance_module(course_id, testcenteruser.user, timelimit_module, timelimit_module_cache) - instance_module.state = timelimit_module.get_instance_state() - instance_module.save() log.info("cand {} on exam {} for course {}: receiving accommodation {}".format(client_candidate_id, exam_series_code, course_id, time_accommodation_code)) - + # UGLY HACK!!! - # Login assumes that authentication has occurred, and that there is a + # Login assumes that authentication has occurred, and that there is a # backend annotation on the user object, indicating which backend # against which the user was authenticated. We're authenticating here # against the registration entry, and assuming that the request given # this information is correct, we allow the user to be logged in # without a password. This could all be formalized in a backend object - # that does the above checking. + # that does the above checking. # TODO: (brian) create a backend class to do this. - # testcenteruser.user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__) - testcenteruser.user.backend = "%s.%s" % ("TestcenterAuthenticationModule", "TestcenterAuthenticationClass") + # testcenteruser.user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__) + testcenteruser.user.backend = "%s.%s" % ("TestcenterAuthenticationModule", "TestcenterAuthenticationClass") login(request, testcenteruser.user) - + # And start the test: return jump_to(request, course_id, location) diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index 3e1a622da3..7e583472b8 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -190,7 +190,7 @@ class CombinedOpenEndedDescriptor(XmlDescriptor, EditingDescriptor): } """ - return {'xml_string' : etree.tostring(xml_object), 'metadata' : xml_object.attrib} + return {'xml_string' : etree.tostring(xml_object), 'metadata' : xml_object.attrib}, [] def definition_to_xml(self, resource_fs): diff --git a/common/lib/xmodule/xmodule/combined_open_ended_modulev1.py b/common/lib/xmodule/xmodule/combined_open_ended_modulev1.py index 5775c42ce3..0b5e856e89 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_modulev1.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_modulev1.py @@ -696,7 +696,7 @@ class CombinedOpenEndedV1Descriptor(XmlDescriptor, EditingDescriptor): """Assumes that xml_object has child k""" return xml_object.xpath(k)[0] - return {'task_xml': parse_task('task'), 'prompt': parse('prompt'), 'rubric': parse('rubric')} + return {'task_xml': parse_task('task'), 'prompt': parse('prompt'), 'rubric': parse('rubric')}, [] def definition_to_xml(self, resource_fs): diff --git a/common/lib/xmodule/xmodule/conditional_module.py b/common/lib/xmodule/xmodule/conditional_module.py index 787d355c4a..11d2a58231 100644 --- a/common/lib/xmodule/xmodule/conditional_module.py +++ b/common/lib/xmodule/xmodule/conditional_module.py @@ -4,6 +4,7 @@ import logging from xmodule.x_module import XModule from xmodule.modulestore import Location from xmodule.seq_module import SequenceDescriptor +from xblock.core import String, Scope from pkg_resources import resource_string @@ -34,6 +35,7 @@ class ConditionalModule(XModule): js_module_name = "Conditional" css = {'scss': [resource_string(__name__, 'css/capa/display.scss')]} + condition = String(help="Condition for this module", default='', scope=Scope.settings) def __init__(self, system, location, definition, descriptor, instance_state=None, shared_state=None, **kwargs): """ @@ -44,7 +46,6 @@ class ConditionalModule(XModule): """ XModule.__init__(self, system, location, definition, descriptor, instance_state, shared_state, **kwargs) self.contents = None - self.condition = self.metadata.get('condition', '') self._get_required_modules() children = self.get_display_items() if children: @@ -128,16 +129,18 @@ class ConditionalDescriptor(SequenceDescriptor): stores_state = True has_score = False + required = String(help="List of required xmodule locations, separated by &", default='', scope=Scope.settings) + def __init__(self, *args, **kwargs): super(ConditionalDescriptor, self).__init__(*args, **kwargs) - required_module_list = [tuple(x.split('/', 1)) for x in self.metadata.get('required', '').split('&')] + required_module_list = [tuple(x.split('/', 1)) for x in self.required.split('&')] self.required_module_locations = [] for rm in required_module_list: try: (tag, name) = rm except Exception as err: - msg = "Specification of required module in conditional is broken: %s" % self.metadata.get('required') + msg = "Specification of required module in conditional is broken: %s" % self.required log.warning(msg) self.system.error_tracker(msg) continue diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py index 8935b23a63..ad8dd06ab5 100644 --- a/common/lib/xmodule/xmodule/course_module.py +++ b/common/lib/xmodule/xmodule/course_module.py @@ -169,6 +169,11 @@ class CourseDescriptor(SequenceDescriptor): computed_default=lambda c: {'General': {'id': c.location.html_id()}}, ) testcenter_info = Object(help="Dictionary of Test Center info", scope=Scope.settings) + announcement = Date(help="Date this course is announced", scope=Scope.settings) + cohort_config = Object(help="Dictionary defining cohort configuration", scope=Scope.settings) + is_new = Boolean(help="Whether this course should be flagged as new", scope=Scope.settings) + no_grade = Boolean(help="True if this course isn't graded", default=False, scope=Scope.settings) + disable_progress_graph = Boolean(help="True if this course shouldn't display the progress graph", default=False, scope=Scope.settings) has_children = True info_sidebar_name = String(scope=Scope.settings, default='Course Handouts') @@ -409,27 +414,12 @@ class CourseDescriptor(SequenceDescriptor): def lowest_passing_grade(self): return min(self._grading_policy['GRADE_CUTOFFS'].values()) - @property - def tabs(self): - """ - Return the tabs config, as a python object, or None if not specified. - """ - return self.metadata.get('tabs') - - @tabs.setter - def tabs(self, value): - self.metadata['tabs'] = value - - @property - def show_calculator(self): - return self.metadata.get("show_calculator", None) == "Yes" - @property def is_cohorted(self): """ Return whether the course is cohorted. """ - config = self.metadata.get("cohort_config") + config = self.cohort_config if config is None: return False @@ -440,7 +430,7 @@ class CourseDescriptor(SequenceDescriptor): """ Return list of topic ids defined in course policy. """ - topics = self.metadata.get("discussion_topics", {}) + topics = self.discussion_topics return [d["id"] for d in topics.values()] @@ -451,7 +441,7 @@ class CourseDescriptor(SequenceDescriptor): the empty set. Note that all inline discussions are automatically cohorted based on the course's is_cohorted setting. """ - config = self.metadata.get("cohort_config") + config = self.cohort_config if config is None: return set() @@ -460,13 +450,13 @@ class CourseDescriptor(SequenceDescriptor): @property - def is_new(self): + def is_newish(self): """ - Returns if the course has been flagged as new in the metadata. If + Returns if the course has been flagged as new. If there is no flag, return a heuristic value considering the announcement and the start dates. """ - flag = self.metadata.get('is_new', None) + flag = self.is_new if flag is None: # Use a heuristic if the course has not been flagged announcement, start, now = self._sorting_dates() @@ -512,12 +502,10 @@ class CourseDescriptor(SequenceDescriptor): def to_datetime(timestamp): return datetime(*timestamp[:6]) - def get_date(field): - timetuple = self._try_parse_time(field) - return to_datetime(timetuple) if timetuple else None - - announcement = get_date('announcement') - start = get_date('advertised_start') or to_datetime(self.start) + announcement = self.announcement + if announcement is not None: + announcement = to_datetime(announcement) + start = self.advertised_start or to_datetime(self.start) now = to_datetime(time.gmtime()) return announcement, start, now @@ -719,7 +707,7 @@ class CourseDescriptor(SequenceDescriptor): def get_test_center_exam(self, exam_series_code): exams = [exam for exam in self.test_center_exams if exam.exam_series_code == exam_series_code] return exams[0] if len(exams) == 1 else None - + @property def title(self): return self.display_name diff --git a/common/lib/xmodule/xmodule/gst_module.py b/common/lib/xmodule/xmodule/gst_module.py index ef1be96c84..91a9828c3e 100644 --- a/common/lib/xmodule/xmodule/gst_module.py +++ b/common/lib/xmodule/xmodule/gst_module.py @@ -177,7 +177,7 @@ class GraphicalSliderToolDescriptor(MakoModuleDescriptor, XmlDescriptor): return { 'render': parse('render'), 'configuration': parse('configuration') - } + }, [] def definition_to_xml(self, resource_fs): '''Return an xml element representing this definition.''' diff --git a/common/lib/xmodule/xmodule/modulestore/xml.py b/common/lib/xmodule/xmodule/modulestore/xml.py index d5e48832b9..5675ce1037 100644 --- a/common/lib/xmodule/xmodule/modulestore/xml.py +++ b/common/lib/xmodule/xmodule/modulestore/xml.py @@ -456,6 +456,9 @@ class XMLModuleStore(ModuleStoreBase): def _load_extra_content(self, system, course_descriptor, category, path, course_dir): for filepath in glob.glob(path / '*'): + if not os.path.isfile(filepath): + continue + with open(filepath) as f: try: html = f.read().decode('utf-8') diff --git a/common/lib/xmodule/xmodule/modulestore/xml_importer.py b/common/lib/xmodule/xmodule/modulestore/xml_importer.py index 3f04c4036a..d4251360a9 100644 --- a/common/lib/xmodule/xmodule/modulestore/xml_importer.py +++ b/common/lib/xmodule/xmodule/modulestore/xml_importer.py @@ -199,16 +199,13 @@ def import_from_xml(store, data_dir, course_dirs=None, course_items = [] for course_id in module_store.modules.keys(): - course_data_path = None - course_location = None - # Import course modules first, because importing some of the children requires the course to exist for module in module_store.modules[course_id].itervalues(): if module.category == 'course': import_course_from_xml( store, static_content_store, - course_data_path, + data_dir / module.data_dir, module, target_location_namespace, verbose=verbose @@ -220,7 +217,7 @@ def import_from_xml(store, data_dir, course_dirs=None, import_module_from_xml( store, static_content_store, - course_data_path, + data_dir / module.data_dir, module, target_location_namespace, verbose=verbose diff --git a/common/lib/xmodule/xmodule/open_ended_module.py b/common/lib/xmodule/xmodule/open_ended_module.py index 0ad6a26995..0f297c2681 100644 --- a/common/lib/xmodule/xmodule/open_ended_module.py +++ b/common/lib/xmodule/xmodule/open_ended_module.py @@ -20,7 +20,6 @@ import capa.xqueue_interface as xqueue_interface from pkg_resources import resource_string -from .capa_module import only_one, ComplexEncoder from .editing_module import EditingDescriptor from .html_checker import check_html from progress import Progress @@ -656,7 +655,7 @@ class OpenEndedDescriptor(XmlDescriptor, EditingDescriptor): """Assumes that xml_object has child k""" return xml_object.xpath(k)[0] - return {'oeparam': parse('openendedparam'), } + return {'oeparam': parse('openendedparam')}, [] def definition_to_xml(self, resource_fs): diff --git a/common/lib/xmodule/xmodule/peer_grading_module.py b/common/lib/xmodule/xmodule/peer_grading_module.py index 40ebf97fbe..4315e10a3e 100644 --- a/common/lib/xmodule/xmodule/peer_grading_module.py +++ b/common/lib/xmodule/xmodule/peer_grading_module.py @@ -32,6 +32,7 @@ from .stringify import stringify_children from .x_module import XModule from .xml_module import XmlDescriptor from xmodule.modulestore import Location +from xblock.core import Scope, Object, Integer, Boolean, String from peer_grading_service import peer_grading_service, GradingServiceError @@ -56,32 +57,26 @@ class PeerGradingModule(XModule): css = {'scss': [resource_string(__name__, 'css/combinedopenended/display.scss')]} - def __init__(self, system, location, definition, descriptor, - instance_state=None, shared_state=None, **kwargs): - XModule.__init__(self, system, location, definition, descriptor, - instance_state, shared_state, **kwargs) + student_data_for_location = Object(scope=Scope.student_state) + max_grade = Integer(default=MAX_SCORE, scope=Scope.student_state) + use_for_single_location = Boolean(default=USE_FOR_SINGLE_LOCATION, scope=Scope.settings) + is_graded = Boolean(default=IS_GRADED, scope=Scope.settings) + link_to_location = String(default=LINK_TO_LOCATION, scope=Scope.settings) - # Load instance state - if instance_state is not None: - instance_state = json.loads(instance_state) - else: - instance_state = {} + def __init__(self, *args, **kwargs): + super(PeerGradingModule, self).__init__(*args, **kwargs) #We need to set the location here so the child modules can use it - system.set('location', location) - self.system = system + self.system.set('location', self.location) self.peer_gs = peer_grading_service(self.system) - self.use_for_single_location = self.metadata.get('use_for_single_location', USE_FOR_SINGLE_LOCATION) if isinstance(self.use_for_single_location, basestring): self.use_for_single_location = (self.use_for_single_location in TRUE_DICT) - self.is_graded = self.metadata.get('is_graded', IS_GRADED) if isinstance(self.is_graded, basestring): self.is_graded = (self.is_graded in TRUE_DICT) - self.link_to_location = self.metadata.get('link_to_location', USE_FOR_SINGLE_LOCATION) - if self.use_for_single_location == True: + if self.use_for_single_location: #This will raise an exception if the location is invalid link_to_location_object = Location(self.link_to_location) @@ -89,8 +84,6 @@ class PeerGradingModule(XModule): if not self.ajax_url.endswith("/"): self.ajax_url = self.ajax_url + "/" - self.student_data_for_location = instance_state.get('student_data_for_location', {}) - self.max_grade = instance_state.get('max_grade', MAX_SCORE) if not isinstance(self.max_grade, (int, long)): #This could result in an exception, but not wrapping in a try catch block so it moves up the stack self.max_grade = int(self.max_grade) @@ -521,7 +514,7 @@ class PeerGradingDescriptor(XmlDescriptor, EditingDescriptor): """Assumes that xml_object has child k""" return xml_object.xpath(k)[0] - return {} + return {}, [] def definition_to_xml(self, resource_fs): diff --git a/common/lib/xmodule/xmodule/self_assessment_module.py b/common/lib/xmodule/xmodule/self_assessment_module.py index c1235979b3..f53d543e8e 100644 --- a/common/lib/xmodule/xmodule/self_assessment_module.py +++ b/common/lib/xmodule/xmodule/self_assessment_module.py @@ -58,10 +58,10 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild): # Used for progress / grading. Currently get credit just for # completion (doesn't matter if you self-assessed correct/incorrect). - max_score = Integer(scope=Scope.settings, default=MAX_SCORE) + max_score = Integer(scope=Scope.settings, default=openendedchild.MAX_SCORE) + max_attempts = Integer(scope=Scope.settings, default=openendedchild.MAX_ATTEMPTS) attempts = Integer(scope=Scope.student_state, default=0) - max_attempts = Integer(scope=Scope.settings, default=MAX_ATTEMPTS) rubric = String(scope=Scope.content) prompt = String(scope=Scope.content) submitmessage = String(scope=Scope.content) @@ -318,9 +318,9 @@ class SelfAssessmentDescriptor(XmlDescriptor, EditingDescriptor): # Used for progress / grading. Currently get credit just for # completion (doesn't matter if you self-assessed correct/incorrect). - max_score = Integer(scope=Scope.settings, default=MAX_SCORE) + max_score = Integer(scope=Scope.settings, default=openendedchild.MAX_SCORE) - max_attempts = Integer(scope=Scope.settings, default=MAX_ATTEMPTS) + max_attempts = Integer(scope=Scope.settings, default=openendedchild.MAX_ATTEMPTS) rubric = String(scope=Scope.content) prompt = String(scope=Scope.content) submitmessage = String(scope=Scope.content) diff --git a/common/lib/xmodule/xmodule/tests/test_course_module.py b/common/lib/xmodule/xmodule/tests/test_course_module.py index 712b095696..8de53c3bb2 100644 --- a/common/lib/xmodule/xmodule/tests/test_course_module.py +++ b/common/lib/xmodule/xmodule/tests/test_course_module.py @@ -94,26 +94,26 @@ class IsNewCourseTestCase(unittest.TestCase): @patch('xmodule.course_module.time.gmtime') - def test_is_new(self, gmtime_mock): + def test_is_newish(self, gmtime_mock): gmtime_mock.return_value = NOW descriptor = self.get_dummy_course(start='2012-12-02T12:00', is_new=True) - assert(descriptor.is_new is True) + assert(descriptor.is_newish is True) descriptor = self.get_dummy_course(start='2013-02-02T12:00', is_new=False) assert(descriptor.is_new is False) descriptor = self.get_dummy_course(start='2013-02-02T12:00', is_new=True) - assert(descriptor.is_new is True) + assert(descriptor.is_newish is True) descriptor = self.get_dummy_course(start='2013-01-15T12:00') - assert(descriptor.is_new is True) + assert(descriptor.is_newish is True) descriptor = self.get_dummy_course(start='2013-03-00T12:00') - assert(descriptor.is_new is True) + assert(descriptor.is_newish is True) descriptor = self.get_dummy_course(start='2012-10-15T12:00') - assert(descriptor.is_new is False) + assert(descriptor.is_newish is False) descriptor = self.get_dummy_course(start='2012-12-31T12:00') - assert(descriptor.is_new is True) + assert(descriptor.is_newish is True) diff --git a/lms/djangoapps/courseware/access.py b/lms/djangoapps/courseware/access.py index 6842a9ca42..b2c3691eb7 100644 --- a/lms/djangoapps/courseware/access.py +++ b/lms/djangoapps/courseware/access.py @@ -442,7 +442,7 @@ def _adjust_start_date_for_beta_testers(user, descriptor): NOTE: If testing manually, make sure MITX_FEATURES['DISABLE_START_DATES'] = False in envs/dev.py! """ - if descriptor.days_early_for_beta is None: + if descriptor.lms.days_early_for_beta is None: # bail early if no beta testing is set up return descriptor.lms.start @@ -456,12 +456,12 @@ def _adjust_start_date_for_beta_testers(user, descriptor): # (fun fact: datetime(*a_time_struct[:6]) is the beautiful syntax for # converting time_structs into datetimes) start_as_datetime = datetime(*descriptor.lms.start[:6]) - delta = timedelta(descriptor.days_early_for_beta) + delta = timedelta(descriptor.lms.days_early_for_beta) effective = start_as_datetime - delta # ...and back to time_struct return effective.timetuple() - return descriptor.start + return descriptor.lms.start def _has_instructor_access_to_location(user, location, course_context=None): diff --git a/lms/djangoapps/courseware/courses.py b/lms/djangoapps/courseware/courses.py index 417352a43c..12330865e7 100644 --- a/lms/djangoapps/courseware/courses.py +++ b/lms/djangoapps/courseware/courses.py @@ -89,7 +89,7 @@ def course_image_url(course): """Try to look up the image url for the course. If it's not found, log an error and return the dead link""" if isinstance(modulestore(), XMLModuleStore): - return '/static/' + course.metadata['data_dir'] + "/images/course_image.jpg" + return '/static/' + course.data_dir + "/images/course_image.jpg" else: loc = course.location._replace(tag='c4x', category='asset', name='images_course_image.jpg') path = StaticContent.get_url_path_from_location(loc) diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 3ff3985519..ba2a70371c 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -145,7 +145,7 @@ def get_module(user, request, location, model_data_cache, course_id, location = Location(location) descriptor = modulestore().get_instance(course_id, location, depth=depth) return get_module_for_descriptor(user, request, descriptor, model_data_cache, course_id, - position=position, not_found_ok=not_found_ok, + position=position, wrap_xmodule_display=wrap_xmodule_display, grade_bucket_type=grade_bucket_type) except ItemNotFoundError: @@ -205,14 +205,14 @@ def get_module_for_descriptor(user, request, descriptor, model_data_cache, cours Delegate to get_module. It does an access check, so may return None """ return get_module_for_descriptor(user, request, descriptor, - student_module_cache, course_id, position) + model_data_cache, course_id, position) def xblock_model_data(descriptor): return DbModel( LmsKeyValueStore(descriptor._model_data, model_data_cache), descriptor.module_class, user.id, - LmsUsage(location, location) + LmsUsage(descriptor.location, descriptor.location) ) def publish(event): @@ -260,7 +260,7 @@ def get_module_for_descriptor(user, request, descriptor, model_data_cache, cours # by the replace_static_urls code below replace_urls=partial( static_replace.replace_static_urls, - data_directory=descriptor.metadata.get('data_dir', ''), + data_directory=descriptor.data_dir, course_namespace=descriptor.location._replace(category=None, name=None), ), node_path=settings.NODE_PATH, @@ -282,7 +282,7 @@ def get_module_for_descriptor(user, request, descriptor, model_data_cache, cours log.exception("Error creating module from descriptor {0}".format(descriptor)) # make an ErrorDescriptor -- assuming that the descriptor's system is ok - if has_access(user, location, 'staff', course_id): + if has_access(user, descriptor.location, 'staff', course_id): err_descriptor_class = ErrorDescriptor else: err_descriptor_class = NonStaffErrorDescriptor diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index a47141b183..ad8e90bd1a 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -28,6 +28,7 @@ from xmodule.modulestore.django import modulestore from xmodule.modulestore.xml import XMLModuleStore from xmodule.x_module import XModule from student.models import unique_id_for_user +from courseware.model_data import ModelDataCache from open_ended_grading import open_ended_notifications @@ -321,10 +322,12 @@ def get_static_tab_by_slug(course, tab_slug): return None -def get_static_tab_contents(request, cache, course, tab): +def get_static_tab_contents(request, course, tab): loc = Location(course.location.tag, course.location.org, course.location.course, 'static_tab', tab['url_slug']) - tab_module = get_module(request.user, request, loc, cache, course.id) + model_data_cache = ModelDataCache.cache_for_descriptor_descendents(course.id, + request.user, modulestore().get_instance(course.id, loc), depth=0) + tab_module = get_module(request.user, request, loc, model_data_cache, course.id) logging.debug('course_module = {0}'.format(tab_module)) diff --git a/lms/djangoapps/courseware/tests/tests.py b/lms/djangoapps/courseware/tests/tests.py index 4073af6fb9..db50960800 100644 --- a/lms/djangoapps/courseware/tests/tests.py +++ b/lms/djangoapps/courseware/tests/tests.py @@ -742,11 +742,11 @@ class TestViewAuth(PageLoader): yesterday = time.time() - 24 * 3600 # toy course's hasn't started - self.toy.metadata['start'] = stringify_time(time.gmtime(tomorrow)) + self.toy.lms.start = time.gmtime(tomorrow) self.assertFalse(self.toy.has_started()) # but should be accessible for beta testers - self.toy.days_early_for_beta = 2 + self.toy.lms.days_early_for_beta = 2 # student user shouldn't see it student_user = user(self.student) diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py index c0eb0d186c..0c06649857 100644 --- a/lms/djangoapps/courseware/views.py +++ b/lms/djangoapps/courseware/views.py @@ -443,7 +443,11 @@ def static_tab(request, course_id, tab_slug): if tab is None: raise Http404 - contents = tabs.get_static_tab_contents(request, None, course, tab) + contents = tabs.get_static_tab_contents( + request, + course, + tab + ) if contents is None: raise Http404 diff --git a/lms/djangoapps/open_ended_grading/controller_query_service.py b/lms/djangoapps/open_ended_grading/controller_query_service.py index 83d5617bd2..fbe2f6c006 100644 --- a/lms/djangoapps/open_ended_grading/controller_query_service.py +++ b/lms/djangoapps/open_ended_grading/controller_query_service.py @@ -18,7 +18,7 @@ class ControllerQueryService(GradingService): Interface to staff grading backend. """ def __init__(self, config): - config['system'] = ModuleSystem(None, None, None, render_to_string, None) + config['system'] = ModuleSystem(None, None, None, render_to_string, None, None) super(ControllerQueryService, self).__init__(config) self.check_eta_url = self.url + '/get_submission_eta/' self.is_unique_url = self.url + '/is_name_unique/' diff --git a/lms/djangoapps/open_ended_grading/tests.py b/lms/djangoapps/open_ended_grading/tests.py index ec2fe5ab38..4c18a0d1a7 100644 --- a/lms/djangoapps/open_ended_grading/tests.py +++ b/lms/djangoapps/open_ended_grading/tests.py @@ -143,10 +143,10 @@ class TestPeerGradingService(ct.PageLoader): location = "i4x://edX/toy/peergrading/init" self.mock_service = peer_grading_service.MockPeerGradingService() - self.system = ModuleSystem(location, None, None, render_to_string, None) - self.descriptor = peer_grading_module.PeerGradingDescriptor(self.system) + self.system = ModuleSystem(location, None, None, render_to_string, None, None) + self.descriptor = peer_grading_module.PeerGradingDescriptor(self.system, location, {}) - self.peer_module = peer_grading_module.PeerGradingModule(self.system, location, "", self.descriptor) + self.peer_module = peer_grading_module.PeerGradingModule(self.system, location, self.descriptor, {}) self.peer_module.peer_gs = self.mock_service self.logout() diff --git a/lms/templates/course.html b/lms/templates/course.html index a2eff572e1..f009955df1 100644 --- a/lms/templates/course.html +++ b/lms/templates/course.html @@ -5,7 +5,7 @@ %> <%page args="course" />
- %if course.is_new: + %if course.is_newish: New %endif diff --git a/lms/templates/courseware/progress.html b/lms/templates/courseware/progress.html index 9b52ff2069..9c3df5237c 100644 --- a/lms/templates/courseware/progress.html +++ b/lms/templates/courseware/progress.html @@ -18,7 +18,7 @@ @@ -32,7 +32,7 @@ ${progress_graph.body(grade_summary, course.grade_cutoffs, "grade-detail-graph",

Course Progress

- %if not course.metadata.get('disable_progress_graph',False): + %if not course.disable_progress_graph:
%endif