Commit 8705ff88 by cahrens

Remove system_metadata_fields.

parent cd53dd22
...@@ -75,11 +75,7 @@ def set_module_info(store, location, post_data): ...@@ -75,11 +75,7 @@ def set_module_info(store, location, post_data):
# IMPORTANT NOTE: if the client passed pack 'null' (None) for a piece of metadata that means 'remove it' # IMPORTANT NOTE: if the client passed pack 'null' (None) for a piece of metadata that means 'remove it'
for metadata_key, value in posted_metadata.items(): for metadata_key, value in posted_metadata.items():
# let's strip out any metadata fields from the postback which have been identified as system metadata if posted_metadata[metadata_key] is None:
# and therefore should not be user-editable, so we should accept them back from the client
if metadata_key in module.system_metadata_fields:
del posted_metadata[metadata_key]
elif posted_metadata[metadata_key] is None:
# remove both from passed in collection as well as the collection read in from the modulestore # remove both from passed in collection as well as the collection read in from the modulestore
if metadata_key in module._model_data: if metadata_key in module._model_data:
del module._model_data[metadata_key] del module._model_data[metadata_key]
......
...@@ -687,11 +687,7 @@ def save_item(request): ...@@ -687,11 +687,7 @@ def save_item(request):
# IMPORTANT NOTE: if the client passed pack 'null' (None) for a piece of metadata that means 'remove it' # IMPORTANT NOTE: if the client passed pack 'null' (None) for a piece of metadata that means 'remove it'
for metadata_key, value in posted_metadata.items(): for metadata_key, value in posted_metadata.items():
# let's strip out any metadata fields from the postback which have been identified as system metadata if posted_metadata[metadata_key] is None:
# and therefore should not be user-editable, so we should accept them back from the client
if metadata_key in existing_item.system_metadata_fields:
del posted_metadata[metadata_key]
elif posted_metadata[metadata_key] is None:
# remove both from passed in collection as well as the collection read in from the modulestore # remove both from passed in collection as well as the collection read in from the modulestore
if metadata_key in existing_item._model_data: if metadata_key in existing_item._model_data:
del existing_item._model_data[metadata_key] del existing_item._model_data[metadata_key]
......
...@@ -14,13 +14,14 @@ class CourseMetadata(object): ...@@ -14,13 +14,14 @@ class CourseMetadata(object):
The objects have no predefined attrs but instead are obj encodings of the The objects have no predefined attrs but instead are obj encodings of the
editable metadata. editable metadata.
''' '''
FILTERED_LIST = XModuleDescriptor.system_metadata_fields + ['start', FILTERED_LIST = ['xml_attributes',
'end', 'start',
'enrollment_start', 'end',
'enrollment_end', 'enrollment_start',
'tabs', 'enrollment_end',
'graceperiod', 'tabs',
'checklists'] 'graceperiod',
'checklists']
@classmethod @classmethod
def fetch(cls, course_location): def fetch(cls, course_location):
......
...@@ -7,10 +7,24 @@ ...@@ -7,10 +7,24 @@
% for field_name, field_value in editable_metadata_fields.items(): % for field_name, field_value in editable_metadata_fields.items():
<li> <li>
% if field_name == 'source_code': % if field_name == 'source_code':
<a href="#hls-modal-${hlskey}" style="color:yellow;" id="hls-trig-${hlskey}" >Edit High Level Source</a> % if field_value['is_default'] is False:
<a href="#hls-modal-${hlskey}" style="color:yellow;" id="hls-trig-${hlskey}" >Edit High Level Source</a>
% endif
% else: % else:
<label>${field_name}:</label> <label>${field_value['field'].display_name}:</label>
<input type='text' data-metadata-name='${field_name}' value='${field_value}' size='60' /> <input type='text' data-metadata-name='${field_value["field"].display_name}' value='${field_value["field"].to_json(field_value["value"])}' size='60' />
% if False:
<label>Help: ${field_value['field'].help}</label>
<label>Type: ${type(field_value['field']).__name__}</label>
<label>Inherited: ${field_value['is_inherited']}</label>
<label>Default: ${field_value['is_default']}</label>
% if field_value['field'].values:
<label>Possible values:</label>
% for value in field_value['field'].values:
<label>${value}</label>
% endfor
% endif
% endif
% endif % endif
</li> </li>
% endfor % endfor
......
...@@ -13,7 +13,7 @@ from capa.responsetypes import StudentInputError,\ ...@@ -13,7 +13,7 @@ from capa.responsetypes import StudentInputError,\
ResponseError, LoncapaProblemError ResponseError, LoncapaProblemError
from capa.util import convert_files_to_filenames from capa.util import convert_files_to_filenames
from .progress import Progress from .progress import Progress
from xmodule.x_module import XModule from xmodule.x_module import XModule, XModuleFields
from xmodule.raw_module import RawDescriptor from xmodule.raw_module import RawDescriptor
from xmodule.exceptions import NotFoundError, ProcessingError from xmodule.exceptions import NotFoundError, ProcessingError
from xblock.core import Scope, String, Boolean, Object from xblock.core import Scope, String, Boolean, Object
...@@ -62,20 +62,26 @@ class ComplexEncoder(json.JSONEncoder): ...@@ -62,20 +62,26 @@ class ComplexEncoder(json.JSONEncoder):
class CapaFields(object): class CapaFields(object):
attempts = StringyInteger(help="Number of attempts taken by the student on this problem", default=0, scope=Scope.user_state) attempts = StringyInteger(help="Number of attempts taken by the student on this problem", default=0, scope=Scope.user_state)
max_attempts = StringyInteger(help="Maximum number of attempts that a student is allowed", scope=Scope.settings) max_attempts = StringyInteger(display_name="Maximum Allowed Attempts",
due = Date(help="Date that this problem is due by", scope=Scope.settings) help="Maximum number of attempts that a student is allowed", scope=Scope.settings)
graceperiod = Timedelta(help="Amount of time after the due date that submissions will be accepted", scope=Scope.settings) due = Date(help="Date that this problem is due by", scope=XModuleFields.nonEditableSettingsScope)
showanswer = String(help="When to show the problem answer to the student", scope=Scope.settings, default="closed") graceperiod = Timedelta(help="Amount of time after the due date that submissions will be accepted",
force_save_button = Boolean(help="Whether to force the save button to appear on the page", scope=Scope.settings, default=False) scope=XModuleFields.nonEditableSettingsScope)
rerandomize = Randomization(help="When to rerandomize the problem", default="always", scope=Scope.settings) showanswer = String(display_name="Show Answer",
help="When to show the problem answer to the student", scope=Scope.settings, default="closed",
values=["answered", "always", "attempted", "closed", "never"])
force_save_button = Boolean(help="Whether to force the save button to appear on the page",
scope=XModuleFields.nonEditableSettingsScope, default=False)
rerandomize = Randomization(display_name="Rerandomize", help="When to rerandomize the problem",
default="always", scope=Scope.settings)
data = String(help="XML data for the problem", scope=Scope.content) data = String(help="XML data for the problem", scope=Scope.content)
correct_map = Object(help="Dictionary with the correctness of current student answers", scope=Scope.user_state, default={}) correct_map = Object(help="Dictionary with the correctness of current student answers", scope=Scope.user_state, default={})
input_state = Object(help="Dictionary for maintaining the state of inputtypes", scope=Scope.user_state) input_state = Object(help="Dictionary for maintaining the state of inputtypes", scope=Scope.user_state)
student_answers = Object(help="Dictionary with the current student responses", scope=Scope.user_state) student_answers = Object(help="Dictionary with the current student responses", scope=Scope.user_state)
done = Boolean(help="Whether the student has answered the problem", scope=Scope.user_state) done = Boolean(help="Whether the student has answered the problem", scope=Scope.user_state)
seed = StringyInteger(help="Random seed for this student", scope=Scope.user_state) seed = StringyInteger(help="Random seed for this student", scope=Scope.user_state)
weight = StringyFloat(help="How much to weight this problem by", scope=Scope.settings) weight = StringyFloat(display_name="Problem Weight", help="How much to weight this problem by", scope=Scope.settings)
markdown = String(help="Markdown source of this module", scope=Scope.settings) markdown = String(help="Markdown source of this module", scope=XModuleFields.nonEditableSettingsScope)
source_code = String(help="Source code for LaTeX and Word problems. This feature is not well-supported.", scope=Scope.settings) source_code = String(help="Source code for LaTeX and Word problems. This feature is not well-supported.", scope=Scope.settings)
...@@ -882,16 +888,6 @@ class CapaDescriptor(CapaFields, RawDescriptor): ...@@ -882,16 +888,6 @@ class CapaDescriptor(CapaFields, RawDescriptor):
'enable_markdown': self.markdown is not None}) 'enable_markdown': self.markdown is not None})
return _context return _context
@property
def editable_metadata_fields(self):
"""Remove metadata from the editable fields since it has its own editor"""
subset = super(CapaDescriptor, self).editable_metadata_fields
if 'markdown' in subset:
del subset['markdown']
if 'empty' in subset:
del subset['empty']
return subset
# 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
......
from pkg_resources import resource_string from pkg_resources import resource_string
from xmodule.x_module import XModule from xmodule.x_module import XModule, XModuleFields
from xmodule.raw_module import RawDescriptor from xmodule.raw_module import RawDescriptor
from xmodule.editing_module import MetadataOnlyEditingDescriptor from xmodule.editing_module import MetadataOnlyEditingDescriptor
from xblock.core import String, Scope from xblock.core import String, Scope
class DiscussionFields(object): class DiscussionFields(object):
discussion_id = String(scope=Scope.settings) discussion_id = String(scope=XModuleFields.nonEditableSettingsScope)
discussion_category = String(scope=Scope.settings) discussion_category = String(display_name="Category Name", scope=Scope.settings)
discussion_target = String(scope=Scope.settings) discussion_target = String(display_name="Subcategory Name", scope=Scope.settings)
sort_key = String(scope=Scope.settings) # We may choose to enable this in the future, but while Kevin is investigating....
sort_key = String(scope=XModuleFields.nonEditableSettingsScope)
class DiscussionModule(DiscussionFields, XModule): class DiscussionModule(DiscussionFields, XModule):
......
...@@ -166,16 +166,6 @@ class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor): ...@@ -166,16 +166,6 @@ class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor):
elt.set("filename", relname) elt.set("filename", relname)
return elt return elt
@property
def editable_metadata_fields(self):
"""Remove any metadata from the editable fields which have their own editor or shouldn't be edited by user."""
subset = super(HtmlDescriptor, self).editable_metadata_fields
if 'empty' in subset:
del subset['empty']
return subset
class AboutDescriptor(HtmlDescriptor): class AboutDescriptor(HtmlDescriptor):
""" """
......
from .x_module import XModuleDescriptor, DescriptorSystem from .x_module import XModuleDescriptor, DescriptorSystem, NonEditableSettingsScope
from .modulestore.inheritance import own_metadata from xblock.core import Scope
from xblock.core import XBlock
class MakoDescriptorSystem(DescriptorSystem): class MakoDescriptorSystem(DescriptorSystem):
...@@ -34,20 +35,40 @@ class MakoModuleDescriptor(XModuleDescriptor): ...@@ -34,20 +35,40 @@ class MakoModuleDescriptor(XModuleDescriptor):
""" """
return { return {
'module': self, 'module': self,
'editable_metadata_fields': self.editable_metadata_fields, 'editable_metadata_fields': self.editable_metadata_fields
} }
def get_html(self): def get_html(self):
return self.system.render_template( return self.system.render_template(
self.mako_template, self.get_context()) self.mako_template, self.get_context())
# cdodge: encapsulate a means to expose "editable" metadata fields (i.e. not internal system metadata)
@property @property
def editable_metadata_fields(self): def editable_metadata_fields(self):
fields = {} inherited_metadata = getattr(self, '_inherited_metadata', {})
for field, value in own_metadata(self).items(): metadata = {}
if field in self.system_metadata_fields: for field in self.fields:
if field.scope != Scope.settings or isinstance(field.scope, NonEditableSettingsScope):
continue
# We are not allowing editing of xblock tag and name fields at this time (for any component).
if field == XBlock.tags or field == XBlock.name:
continue continue
fields[field] = value inherited = False
return fields default = False
value = getattr(self, field.name)
if field.name in self._model_data:
default = False
if field.name in inherited_metadata and self._model_data.get(field.name) == inherited_metadata.get(
field.name):
inherited = True
else:
default = True
metadata[field.name] = {'field' : field,
'value': value,
'is_inherited': inherited,
'is_default': default }
return metadata
...@@ -78,12 +78,18 @@ class HTMLSnippet(object): ...@@ -78,12 +78,18 @@ class HTMLSnippet(object):
.format(self.__class__)) .format(self.__class__))
class NonEditableSettingsScope(Scope):
pass
class XModuleFields(object): class XModuleFields(object):
display_name = String( display_name = String(
display_name="Display Name",
help="Display name for this module", help="Display name for this module",
scope=Scope.settings, scope=Scope.settings,
default=None, default=None
) )
nonEditableSettingsScope = NonEditableSettingsScope(user=Scope.settings.user, block=Scope.settings.block)
class XModule(XModuleFields, HTMLSnippet, XBlock): class XModule(XModuleFields, HTMLSnippet, XBlock):
...@@ -334,12 +340,6 @@ class XModuleDescriptor(XModuleFields, HTMLSnippet, ResourceTemplates, XBlock): ...@@ -334,12 +340,6 @@ class XModuleDescriptor(XModuleFields, HTMLSnippet, ResourceTemplates, XBlock):
# (like a practice problem). # (like a practice problem).
has_score = False has_score = False
# cdodge: this is a list of metadata names which are 'system' metadata
# and should not be edited by an end-user
system_metadata_fields = ['data_dir', 'published_date', 'published_by', 'is_draft',
'discussion_id', 'xml_attributes']
# A list of descriptor attributes that must be equal for the descriptors to # A list of descriptor attributes that must be equal for the descriptors to
# be equal # be equal
equality_attributes = ('_model_data', 'location') equality_attributes = ('_model_data', 'location')
......
...@@ -6,10 +6,11 @@ import sys ...@@ -6,10 +6,11 @@ import sys
from collections import namedtuple from collections import namedtuple
from lxml import etree from lxml import etree
from xblock.core import Object, Scope from xblock.core import Object
from xmodule.x_module import (XModuleDescriptor, policy_key) from xmodule.x_module import (XModuleDescriptor, policy_key)
from xmodule.modulestore import Location from xmodule.modulestore import Location
from xmodule.modulestore.inheritance import own_metadata from xmodule.modulestore.inheritance import own_metadata
from xmodule.x_module import XModuleFields
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -84,7 +85,8 @@ class XmlDescriptor(XModuleDescriptor): ...@@ -84,7 +85,8 @@ class XmlDescriptor(XModuleDescriptor):
Mixin class for standardized parsing of from xml Mixin class for standardized parsing of from xml
""" """
xml_attributes = Object(help="Map of unhandled xml attributes, used only for storage between import and export", default={}, scope=Scope.settings) xml_attributes = Object(help="Map of unhandled xml attributes, used only for storage between import and export",
default={}, scope=XModuleFields.nonEditableSettingsScope)
# Extension to append to filename paths # Extension to append to filename paths
filename_extension = 'xml' filename_extension = 'xml'
......
...@@ -6,4 +6,4 @@ ...@@ -6,4 +6,4 @@
# XBlock: # XBlock:
# Might change frequently, so put it in local-requirements.txt, # Might change frequently, so put it in local-requirements.txt,
# but conceptually is an external package, so it is in a separate repo. # but conceptually is an external package, so it is in a separate repo.
-e git+https://github.com/edx/XBlock.git@2e0770ff#egg=XBlock -e git+https://github.com/edx/XBlock.git@49181a1b#egg=XBlock
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