Commit 7e224f58 by Calen Pennington

Convert a bunch more references from metadata to fields

parent 57b3ceba
...@@ -670,6 +670,11 @@ class CapaDescriptor(RawDescriptor): ...@@ -670,6 +670,11 @@ class CapaDescriptor(RawDescriptor):
# actually use type and points? # actually use type and points?
metadata_attributes = RawDescriptor.metadata_attributes + ('type', 'points') metadata_attributes = RawDescriptor.metadata_attributes + ('type', 'points')
# The capa format specifies that what we call max_attempts in the code
# is the attribute `attempts`. This will do that conversion
metadata_translations = dict(RawDescriptor.metadata_translations)
metadata_translations['attempts'] = 'max_attempts'
# VS[compat] # VS[compat]
# TODO (cpennington): Delete this method once all fall 2012 course are being # TODO (cpennington): Delete this method once all fall 2012 course are being
# edited in the cms # edited in the cms
......
...@@ -33,6 +33,9 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -33,6 +33,9 @@ class CourseDescriptor(SequenceDescriptor):
show_calculator = Boolean(help="Whether to show the calculator in this course", default=False, scope=Scope.settings) show_calculator = Boolean(help="Whether to show the calculator in this course", default=False, scope=Scope.settings)
start = Date(help="Start time when this module is visible", scope=Scope.settings) start = Date(help="Start time when this module is visible", scope=Scope.settings)
display_name = String(help="Display name for this module", scope=Scope.settings) display_name = String(help="Display name for this module", scope=Scope.settings)
tabs = List(help="List of tabs to enable in this course", scope=Scope.settings)
end_of_course_survey_url = String(help="Url for the end-of-course survey", scope=Scope.settings)
discussion_blackouts = List(help="List of pairs of start/end dates for discussion blackouts", scope=Scope.settings, default=[])
has_children = True has_children = True
info_sidebar_name = String(scope=Scope.settings, default='Course Handouts') info_sidebar_name = String(scope=Scope.settings, default='Course Handouts')
...@@ -128,7 +131,7 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -128,7 +131,7 @@ class CourseDescriptor(SequenceDescriptor):
if self.start is None: if self.start is None:
msg = "Course loaded without a valid start date. id = %s" % self.id msg = "Course loaded without a valid start date. id = %s" % self.id
# hack it -- start in 1970 # hack it -- start in 1970
self.metadata['start'] = stringify_time(time.gmtime(0)) self.lms.start = time.gmtime(0)
log.critical(msg) log.critical(msg)
system.error_tracker(msg) system.error_tracker(msg)
...@@ -198,8 +201,6 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -198,8 +201,6 @@ class CourseDescriptor(SequenceDescriptor):
grading_policy['GRADER'] = grader_from_conf(grading_policy['GRADER']) grading_policy['GRADER'] = grader_from_conf(grading_policy['GRADER'])
self._grading_policy = grading_policy self._grading_policy = grading_policy
@classmethod @classmethod
def read_grading_policy(cls, paths, system): def read_grading_policy(cls, paths, system):
"""Load a grading policy from the specified paths, in order, if it exists.""" """Load a grading policy from the specified paths, in order, if it exists."""
...@@ -221,14 +222,13 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -221,14 +222,13 @@ class CourseDescriptor(SequenceDescriptor):
return policy_str return policy_str
@classmethod @classmethod
def from_xml(cls, xml_data, system, org=None, course=None): def from_xml(cls, xml_data, system, org=None, course=None):
instance = super(CourseDescriptor, cls).from_xml(xml_data, system, org, course) instance = super(CourseDescriptor, cls).from_xml(xml_data, system, org, course)
# bleh, have to parse the XML here to just pull out the url_name attribute # bleh, have to parse the XML here to just pull out the url_name attribute
course_file = StringIO(xml_data) course_file = StringIO(xml_data)
xml_obj = etree.parse(course_file,parser=edx_xml_parser).getroot() xml_obj = etree.parse(course_file, parser=edx_xml_parser).getroot()
policy_dir = None policy_dir = None
url_name = xml_obj.get('url_name', xml_obj.get('slug')) url_name = xml_obj.get('url_name', xml_obj.get('slug'))
...@@ -241,7 +241,7 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -241,7 +241,7 @@ class CourseDescriptor(SequenceDescriptor):
paths = [policy_dir + '/grading_policy.json'] + paths paths = [policy_dir + '/grading_policy.json'] + paths
policy = json.loads(cls.read_grading_policy(paths, system)) policy = json.loads(cls.read_grading_policy(paths, system))
# cdodge: import the grading policy information that is on disk and put into the # cdodge: import the grading policy information that is on disk and put into the
# descriptor 'definition' bucket as a dictionary so that it is persisted in the DB # descriptor 'definition' bucket as a dictionary so that it is persisted in the DB
instance.grading_policy = policy instance.grading_policy = policy
...@@ -250,7 +250,6 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -250,7 +250,6 @@ class CourseDescriptor(SequenceDescriptor):
instance.set_grading_policy(policy) instance.set_grading_policy(policy)
return instance return instance
@classmethod @classmethod
def definition_from_xml(cls, xml_object, system): def definition_from_xml(cls, xml_object, system):
...@@ -334,17 +333,6 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -334,17 +333,6 @@ class CourseDescriptor(SequenceDescriptor):
self.definition['data'].setdefault('grading_policy',{})['GRADE_CUTOFFS'] = value self.definition['data'].setdefault('grading_policy',{})['GRADE_CUTOFFS'] = value
@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
@lazyproperty @lazyproperty
def grading_context(self): def grading_context(self):
""" """
...@@ -383,14 +371,14 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -383,14 +371,14 @@ class CourseDescriptor(SequenceDescriptor):
for c in self.get_children(): for c in self.get_children():
sections = [] sections = []
for s in c.get_children(): for s in c.get_children():
if s.metadata.get('graded', False): if s.lms.graded:
xmoduledescriptors = list(yield_descriptor_descendents(s)) xmoduledescriptors = list(yield_descriptor_descendents(s))
xmoduledescriptors.append(s) xmoduledescriptors.append(s)
# The xmoduledescriptors included here are only the ones that have scores. # The xmoduledescriptors included here are only the ones that have scores.
section_description = { 'section_descriptor' : s, 'xmoduledescriptors' : filter(lambda child: child.has_score, xmoduledescriptors) } section_description = { 'section_descriptor' : s, 'xmoduledescriptors' : filter(lambda child: child.has_score, xmoduledescriptors) }
section_format = s.metadata.get('format', "") section_format = s.lms.format
graded_sections[ section_format ] = graded_sections.get( section_format, [] ) + [section_description] graded_sections[ section_format ] = graded_sections.get( section_format, [] ) + [section_description]
all_descriptors.extend(xmoduledescriptors) all_descriptors.extend(xmoduledescriptors)
...@@ -447,7 +435,7 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -447,7 +435,7 @@ class CourseDescriptor(SequenceDescriptor):
try: try:
blackout_periods = [(parse_time(start), parse_time(end)) blackout_periods = [(parse_time(start), parse_time(end))
for start, end for start, end
in self.metadata.get('discussion_blackouts', [])] in self.discussion_blackouts]
now = time.gmtime() now = time.gmtime()
for start, end in blackout_periods: for start, end in blackout_periods:
if start <= now <= end: if start <= now <= end:
...@@ -457,17 +445,6 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -457,17 +445,6 @@ class CourseDescriptor(SequenceDescriptor):
return True return True
@property
def end_of_course_survey_url(self):
"""
Pull from policy. Once we have our own survey module set up, can change this to point to an automatically
created survey for each class.
Returns None if no url specified.
"""
return self.metadata.get('end_of_course_survey_url')
@property @property
def title(self): def title(self):
return self.display_name return self.display_name
......
...@@ -12,6 +12,10 @@ class DiscussionModule(XModule): ...@@ -12,6 +12,10 @@ class DiscussionModule(XModule):
} }
js_module_name = "InlineDiscussion" js_module_name = "InlineDiscussion"
discussion_id = String(scope=Scope.settings)
discussion_category = String(scope=Scope.settings)
discussion_target = String(scope=Scope.settings)
data = String(help="XML definition of inline discussion", scope=Scope.content) data = String(help="XML definition of inline discussion", scope=Scope.content)
def get_html(self): def get_html(self):
...@@ -31,3 +35,10 @@ class DiscussionModule(XModule): ...@@ -31,3 +35,10 @@ class DiscussionModule(XModule):
class DiscussionDescriptor(RawDescriptor): class DiscussionDescriptor(RawDescriptor):
module_class = DiscussionModule module_class = DiscussionModule
template_dir_name = "discussion" template_dir_name = "discussion"
# The discussion XML format uses `id` and `for` attributes,
# but these would overload other module attributes, so we prefix them
# for actual use in the code
metadata_translations = dict(RawDescriptor.metadata_translations)
metadata_translations['id'] = 'discussion_id'
metadata_translations['for'] = 'discussion_target'
...@@ -430,10 +430,10 @@ class XMLModuleStore(ModuleStoreBase): ...@@ -430,10 +430,10 @@ class XMLModuleStore(ModuleStoreBase):
NOTE: This means that there is no such thing as lazy loading at the NOTE: This means that there is no such thing as lazy loading at the
moment--this accesses all the children.""" moment--this accesses all the children."""
for child in descriptor.get_children(): for child in descriptor.get_children():
inherit_metadata(child, descriptor.metadata) inherit_metadata(child, descriptor._model_data)
compute_inherited_metadata(child) compute_inherited_metadata(child)
def inherit_metadata(descriptor, metadata): def inherit_metadata(descriptor, model_data):
""" """
Updates this module with metadata inherited from a containing module. Updates this module with metadata inherited from a containing module.
Only metadata specified in self.inheritable_metadata will Only metadata specified in self.inheritable_metadata will
...@@ -441,11 +441,10 @@ class XMLModuleStore(ModuleStoreBase): ...@@ -441,11 +441,10 @@ class XMLModuleStore(ModuleStoreBase):
""" """
# Set all inheritable metadata from kwargs that are # Set all inheritable metadata from kwargs that are
# in self.inheritable_metadata and aren't already set in metadata # in self.inheritable_metadata and aren't already set in metadata
for attr in self.inheritable_metadata: for attr in descriptor.inheritable_metadata:
if attr not in self.metadata and attr in metadata: if attr not in descriptor._model_data and attr in model_data:
self._inherited_metadata.add(attr) descriptor._inherited_metadata.add(attr)
self.metadata[attr] = metadata[attr] descriptor._model_data[attr] = model_data[attr]
compute_inherited_metadata(course_descriptor) compute_inherited_metadata(course_descriptor)
...@@ -485,7 +484,7 @@ class XMLModuleStore(ModuleStoreBase): ...@@ -485,7 +484,7 @@ class XMLModuleStore(ModuleStoreBase):
if category == "static_tab": if category == "static_tab":
for tab in course_descriptor.tabs or []: for tab in course_descriptor.tabs or []:
if tab.get('url_slug') == slug: if tab.get('url_slug') == slug:
module.display_name = tab['name'] module.lms.display_name = tab['name']
module.data_dir = course_dir module.data_dir = course_dir
self.modules[course_descriptor.id][module.location] = module self.modules[course_descriptor.id][module.location] = module
except Exception, e: except Exception, e:
......
...@@ -155,7 +155,7 @@ def _has_access_course_desc(user, course, action): ...@@ -155,7 +155,7 @@ def _has_access_course_desc(user, course, action):
if settings.MITX_FEATURES.get('ACCESS_REQUIRE_STAFF_FOR_COURSE'): if settings.MITX_FEATURES.get('ACCESS_REQUIRE_STAFF_FOR_COURSE'):
# if this feature is on, only allow courses that have ispublic set to be # if this feature is on, only allow courses that have ispublic set to be
# seen by non-staff # seen by non-staff
if course.metadata.get('ispublic'): if course.lms.ispublic:
debug("Allow: ACCESS_REQUIRE_STAFF_FOR_COURSE and ispublic") debug("Allow: ACCESS_REQUIRE_STAFF_FOR_COURSE and ispublic")
return True return True
return _has_staff_access_to_descriptor(user, course) return _has_staff_access_to_descriptor(user, course)
......
...@@ -179,12 +179,12 @@ def grade(student, request, course, student_module_cache=None, keep_raw_scores=F ...@@ -179,12 +179,12 @@ def grade(student, request, course, student_module_cache=None, keep_raw_scores=F
else: else:
correct = total correct = total
graded = module_descriptor.metadata.get("graded", False) graded = module_descriptor.lms.graded
if not total > 0: if not total > 0:
#We simply cannot grade a problem that is 12/0, because we might need it as a percentage #We simply cannot grade a problem that is 12/0, because we might need it as a percentage
graded = False graded = False
scores.append(Score(correct, total, graded, module_descriptor.metadata.get('display_name'))) scores.append(Score(correct, total, graded, module_descriptor.lms.display_name))
section_total, graded_total = graders.aggregate_scores(scores, section_name) section_total, graded_total = graders.aggregate_scores(scores, section_name)
if keep_raw_scores: if keep_raw_scores:
...@@ -288,7 +288,7 @@ def progress_summary(student, request, course, student_module_cache): ...@@ -288,7 +288,7 @@ def progress_summary(student, request, course, student_module_cache):
continue continue
# Same for sections # Same for sections
graded = section_module.metadata.get('graded', False) graded = section_module.lms.graded
scores = [] scores = []
module_creator = lambda descriptor : section_module.system.get_module(descriptor.location) module_creator = lambda descriptor : section_module.system.get_module(descriptor.location)
...@@ -301,20 +301,20 @@ def progress_summary(student, request, course, student_module_cache): ...@@ -301,20 +301,20 @@ def progress_summary(student, request, course, student_module_cache):
continue continue
scores.append(Score(correct, total, graded, scores.append(Score(correct, total, graded,
module_descriptor.metadata.get('display_name'))) module_descriptor.lms.display_name))
scores.reverse() scores.reverse()
section_total, graded_total = graders.aggregate_scores( section_total, graded_total = graders.aggregate_scores(
scores, section_module.metadata.get('display_name')) scores, section_module.lms.display_name)
format = section_module.metadata.get('format', "") format = section_module.lms.format
sections.append({ sections.append({
'display_name': section_module.display_name, 'display_name': section_module.display_name,
'url_name': section_module.url_name, 'url_name': section_module.url_name,
'scores': scores, 'scores': scores,
'section_total': section_total, 'section_total': section_total,
'format': format, 'format': format,
'due': section_module.metadata.get("due", ""), 'due': section_module.due,
'graded': graded, 'graded': graded,
}) })
......
...@@ -488,8 +488,8 @@ class TestViewAuth(PageLoader): ...@@ -488,8 +488,8 @@ class TestViewAuth(PageLoader):
# Make courses start in the future # Make courses start in the future
tomorrow = time.time() + 24*3600 tomorrow = time.time() + 24*3600
self.toy.metadata['start'] = stringify_time(time.gmtime(tomorrow)) self.toy.lms.start = time.gmtime(tomorrow)
self.full.metadata['start'] = stringify_time(time.gmtime(tomorrow)) self.full.lms.start = time.gmtime(tomorrow)
self.assertFalse(self.toy.has_started()) self.assertFalse(self.toy.has_started())
self.assertFalse(self.full.has_started()) self.assertFalse(self.full.has_started())
......
...@@ -142,9 +142,9 @@ def initialize_discussion_info(course): ...@@ -142,9 +142,9 @@ def initialize_discussion_info(course):
for location, module in all_modules.items(): for location, module in all_modules.items():
if location.category == 'discussion': if location.category == 'discussion':
id = module.metadata['id'] id = module.discussion_id
category = module.metadata['discussion_category'] category = module.discussion_category
title = module.metadata['for'] title = module.discussion_target
sort_key = module.metadata.get('sort_key', title) sort_key = module.metadata.get('sort_key', title)
category = " / ".join([x.strip() for x in category.split("/")]) category = " / ".join([x.strip() for x in category.split("/")])
last_category = category.split("/")[-1] last_category = category.split("/")[-1]
......
...@@ -15,7 +15,7 @@ class LmsNamespace(Namespace): ...@@ -15,7 +15,7 @@ class LmsNamespace(Namespace):
format = String( format = String(
help="What format this module is in (used for deciding which " help="What format this module is in (used for deciding which "
"grader to apply, and what to show in the TOC)", "grader to apply, and what to show in the TOC)",
scope=Scope.settings scope=Scope.settings,
) )
display_name = String( display_name = String(
...@@ -29,3 +29,4 @@ class LmsNamespace(Namespace): ...@@ -29,3 +29,4 @@ class LmsNamespace(Namespace):
source_file = String(help="DO NOT USE", scope=Scope.settings) source_file = String(help="DO NOT USE", scope=Scope.settings)
giturl = String(help="DO NOT USE", scope=Scope.settings, default='https://github.com/MITx') giturl = String(help="DO NOT USE", scope=Scope.settings, default='https://github.com/MITx')
xqa_key = String(help="DO NOT USE", scope=Scope.settings) xqa_key = String(help="DO NOT USE", scope=Scope.settings)
ispublic = Boolean(help="Whether this course is open to the public, or only to admins", scope=Scope.settings)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment