Remove system_metadata_fields.
This commit is contained in:
@@ -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'
|
||||
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
|
||||
# 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:
|
||||
if posted_metadata[metadata_key] is None:
|
||||
# remove both from passed in collection as well as the collection read in from the modulestore
|
||||
if metadata_key in module._model_data:
|
||||
del module._model_data[metadata_key]
|
||||
|
||||
@@ -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'
|
||||
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
|
||||
# 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:
|
||||
if posted_metadata[metadata_key] is None:
|
||||
# remove both from passed in collection as well as the collection read in from the modulestore
|
||||
if metadata_key in existing_item._model_data:
|
||||
del existing_item._model_data[metadata_key]
|
||||
|
||||
@@ -14,13 +14,14 @@ class CourseMetadata(object):
|
||||
The objects have no predefined attrs but instead are obj encodings of the
|
||||
editable metadata.
|
||||
'''
|
||||
FILTERED_LIST = XModuleDescriptor.system_metadata_fields + ['start',
|
||||
'end',
|
||||
'enrollment_start',
|
||||
'enrollment_end',
|
||||
'tabs',
|
||||
'graceperiod',
|
||||
'checklists']
|
||||
FILTERED_LIST = ['xml_attributes',
|
||||
'start',
|
||||
'end',
|
||||
'enrollment_start',
|
||||
'enrollment_end',
|
||||
'tabs',
|
||||
'graceperiod',
|
||||
'checklists']
|
||||
|
||||
@classmethod
|
||||
def fetch(cls, course_location):
|
||||
|
||||
@@ -7,10 +7,24 @@
|
||||
% for field_name, field_value in editable_metadata_fields.items():
|
||||
<li>
|
||||
% 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:
|
||||
<label>${field_name}:</label>
|
||||
<input type='text' data-metadata-name='${field_name}' value='${field_value}' size='60' />
|
||||
<label>${field_value['field'].display_name}:</label>
|
||||
<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
|
||||
</li>
|
||||
% endfor
|
||||
|
||||
@@ -13,7 +13,7 @@ from capa.responsetypes import StudentInputError,\
|
||||
ResponseError, LoncapaProblemError
|
||||
from capa.util import convert_files_to_filenames
|
||||
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.exceptions import NotFoundError, ProcessingError
|
||||
from xblock.core import Scope, String, Boolean, Object
|
||||
@@ -62,20 +62,26 @@ class ComplexEncoder(json.JSONEncoder):
|
||||
|
||||
class CapaFields(object):
|
||||
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)
|
||||
due = Date(help="Date that this problem is due by", scope=Scope.settings)
|
||||
graceperiod = Timedelta(help="Amount of time after the due date that submissions will be accepted", scope=Scope.settings)
|
||||
showanswer = String(help="When to show the problem answer to the student", scope=Scope.settings, default="closed")
|
||||
force_save_button = Boolean(help="Whether to force the save button to appear on the page", scope=Scope.settings, default=False)
|
||||
rerandomize = Randomization(help="When to rerandomize the problem", default="always", scope=Scope.settings)
|
||||
max_attempts = StringyInteger(display_name="Maximum Allowed Attempts",
|
||||
help="Maximum number of attempts that a student is allowed", scope=Scope.settings)
|
||||
due = Date(help="Date that this problem is due by", scope=XModuleFields.nonEditableSettingsScope)
|
||||
graceperiod = Timedelta(help="Amount of time after the due date that submissions will be accepted",
|
||||
scope=XModuleFields.nonEditableSettingsScope)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
markdown = String(help="Markdown source of this module", 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=XModuleFields.nonEditableSettingsScope)
|
||||
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):
|
||||
'enable_markdown': self.markdown is not None})
|
||||
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]
|
||||
# TODO (cpennington): Delete this method once all fall 2012 course are being
|
||||
# edited in the cms
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
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.editing_module import MetadataOnlyEditingDescriptor
|
||||
from xblock.core import String, Scope
|
||||
|
||||
|
||||
class DiscussionFields(object):
|
||||
discussion_id = String(scope=Scope.settings)
|
||||
discussion_category = String(scope=Scope.settings)
|
||||
discussion_target = String(scope=Scope.settings)
|
||||
sort_key = String(scope=Scope.settings)
|
||||
discussion_id = String(scope=XModuleFields.nonEditableSettingsScope)
|
||||
discussion_category = String(display_name="Category Name", scope=Scope.settings)
|
||||
discussion_target = String(display_name="Subcategory Name", 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):
|
||||
|
||||
@@ -166,16 +166,6 @@ class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor):
|
||||
elt.set("filename", relname)
|
||||
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):
|
||||
"""
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from .x_module import XModuleDescriptor, DescriptorSystem
|
||||
from .modulestore.inheritance import own_metadata
|
||||
from .x_module import XModuleDescriptor, DescriptorSystem, NonEditableSettingsScope
|
||||
from xblock.core import Scope
|
||||
from xblock.core import XBlock
|
||||
|
||||
|
||||
class MakoDescriptorSystem(DescriptorSystem):
|
||||
@@ -34,20 +35,40 @@ class MakoModuleDescriptor(XModuleDescriptor):
|
||||
"""
|
||||
return {
|
||||
'module': self,
|
||||
'editable_metadata_fields': self.editable_metadata_fields,
|
||||
'editable_metadata_fields': self.editable_metadata_fields
|
||||
}
|
||||
|
||||
def get_html(self):
|
||||
return self.system.render_template(
|
||||
self.mako_template, self.get_context())
|
||||
|
||||
# cdodge: encapsulate a means to expose "editable" metadata fields (i.e. not internal system metadata)
|
||||
@property
|
||||
def editable_metadata_fields(self):
|
||||
fields = {}
|
||||
for field, value in own_metadata(self).items():
|
||||
if field in self.system_metadata_fields:
|
||||
inherited_metadata = getattr(self, '_inherited_metadata', {})
|
||||
metadata = {}
|
||||
for field in self.fields:
|
||||
|
||||
if field.scope != Scope.settings or isinstance(field.scope, NonEditableSettingsScope):
|
||||
continue
|
||||
|
||||
fields[field] = value
|
||||
return fields
|
||||
# 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
|
||||
|
||||
inherited = False
|
||||
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):
|
||||
.format(self.__class__))
|
||||
|
||||
|
||||
class NonEditableSettingsScope(Scope):
|
||||
pass
|
||||
|
||||
|
||||
class XModuleFields(object):
|
||||
display_name = String(
|
||||
display_name="Display Name",
|
||||
help="Display name for this module",
|
||||
scope=Scope.settings,
|
||||
default=None,
|
||||
default=None
|
||||
)
|
||||
nonEditableSettingsScope = NonEditableSettingsScope(user=Scope.settings.user, block=Scope.settings.block)
|
||||
|
||||
|
||||
class XModule(XModuleFields, HTMLSnippet, XBlock):
|
||||
@@ -334,12 +340,6 @@ class XModuleDescriptor(XModuleFields, HTMLSnippet, ResourceTemplates, XBlock):
|
||||
# (like a practice problem).
|
||||
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
|
||||
# be equal
|
||||
equality_attributes = ('_model_data', 'location')
|
||||
|
||||
@@ -6,10 +6,11 @@ import sys
|
||||
from collections import namedtuple
|
||||
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.modulestore import Location
|
||||
from xmodule.modulestore.inheritance import own_metadata
|
||||
from xmodule.x_module import XModuleFields
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -84,7 +85,8 @@ class XmlDescriptor(XModuleDescriptor):
|
||||
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
|
||||
filename_extension = 'xml'
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
# XBlock:
|
||||
# Might change frequently, so put it in local-requirements.txt,
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user