Commit 260dc84f by Christina Roberts

Merge pull request #1854 from MITx/fix/cdodge/violation-fixes

violation fixes
parents c0b32caa 3ca2bf46
...@@ -97,8 +97,7 @@ def update_course_updates(location, update, passed_id=None): ...@@ -97,8 +97,7 @@ def update_course_updates(location, update, passed_id=None):
if (len(new_html_parsed) == 1): if (len(new_html_parsed) == 1):
content = new_html_parsed[0].tail content = new_html_parsed[0].tail
else: else:
content = "\n".join([html.tostring(ele) content = "\n".join([html.tostring(ele) for ele in new_html_parsed[1:]])
for ele in new_html_parsed[1:]])
return {"id": passed_id, return {"id": passed_id,
"date": update['date'], "date": update['date'],
......
from static_replace import replace_static_urls from static_replace import replace_static_urls
from xmodule.modulestore.exceptions import ItemNotFoundError from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule.modulestore import Location from xmodule.modulestore import Location
from django.http import Http404
def get_module_info(store, location, parent_location=None, rewrite_static_links=False): def get_module_info(store, location, parent_location=None, rewrite_static_links=False):
......
import logging
from django.conf import settings from django.conf import settings
from xmodule.modulestore import Location from xmodule.modulestore import Location
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
...@@ -9,7 +8,7 @@ import copy ...@@ -9,7 +8,7 @@ import copy
DIRECT_ONLY_CATEGORIES = ['course', 'chapter', 'sequential', 'about', 'static_tab', 'course_info'] DIRECT_ONLY_CATEGORIES = ['course', 'chapter', 'sequential', 'about', 'static_tab', 'course_info']
#In order to instantiate an open ended tab automatically, need to have this data #In order to instantiate an open ended tab automatically, need to have this data
OPEN_ENDED_PANEL = {"name" : "Open Ended Panel", "type" : "open_ended"} OPEN_ENDED_PANEL = {"name": "Open Ended Panel", "type": "open_ended"}
def get_modulestore(location): def get_modulestore(location):
...@@ -87,8 +86,7 @@ def get_lms_link_for_item(location, preview=False, course_id=None): ...@@ -87,8 +86,7 @@ def get_lms_link_for_item(location, preview=False, course_id=None):
if settings.LMS_BASE is not None: if settings.LMS_BASE is not None:
if preview: if preview:
lms_base = settings.MITX_FEATURES.get('PREVIEW_LMS_BASE', lms_base = settings.MITX_FEATURES.get('PREVIEW_LMS_BASE', 'preview.' + settings.LMS_BASE)
'preview.' + settings.LMS_BASE)
else: else:
lms_base = settings.LMS_BASE lms_base = settings.LMS_BASE
...@@ -193,6 +191,7 @@ class CoursePageNames: ...@@ -193,6 +191,7 @@ class CoursePageNames:
CourseOutline = "course_index" CourseOutline = "course_index"
Checklists = "checklists" Checklists = "checklists"
def add_open_ended_panel_tab(course): def add_open_ended_panel_tab(course):
""" """
Used to add the open ended panel tab to a course if it does not exist. Used to add the open ended panel tab to a course if it does not exist.
...@@ -209,6 +208,7 @@ def add_open_ended_panel_tab(course): ...@@ -209,6 +208,7 @@ def add_open_ended_panel_tab(course):
changed = True changed = True
return changed, course_tabs return changed, course_tabs
def remove_open_ended_panel_tab(course): def remove_open_ended_panel_tab(course):
""" """
Used to remove the open ended panel tab from a course if it exists. Used to remove the open ended panel tab from a course if it exists.
...@@ -221,6 +221,6 @@ def remove_open_ended_panel_tab(course): ...@@ -221,6 +221,6 @@ def remove_open_ended_panel_tab(course):
#Check to see if open ended panel is defined in the course #Check to see if open ended panel is defined in the course
if OPEN_ENDED_PANEL in course_tabs: if OPEN_ENDED_PANEL in course_tabs:
#Add panel to the tabs if it is not defined #Add panel to the tabs if it is not defined
course_tabs = [ct for ct in course_tabs if ct!=OPEN_ENDED_PANEL] course_tabs = [ct for ct in course_tabs if ct != OPEN_ENDED_PANEL]
changed = True changed = True
return changed, course_tabs return changed, course_tabs
...@@ -14,9 +14,6 @@ from tempfile import mkdtemp ...@@ -14,9 +14,6 @@ from tempfile import mkdtemp
from django.core.servers.basehttp import FileWrapper from django.core.servers.basehttp import FileWrapper
from django.core.files.temp import NamedTemporaryFile from django.core.files.temp import NamedTemporaryFile
# to install PIL on MacOSX: 'easy_install http://dist.repoze.org/PIL-1.1.6.tar.gz'
from PIL import Image
from django.http import HttpResponse, Http404, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseServerError from django.http import HttpResponse, Http404, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseServerError
from django.http import HttpResponseNotFound from django.http import HttpResponseNotFound
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
...@@ -244,8 +241,7 @@ def edit_subsection(request, location): ...@@ -244,8 +241,7 @@ def edit_subsection(request, location):
(field.name, field.read_from(item)) (field.name, field.read_from(item))
for field for field
in item.fields in item.fields
if field.name not in ['display_name', 'start', 'due', 'format'] and if field.name not in ['display_name', 'start', 'due', 'format'] and field.scope == Scope.settings
field.scope == Scope.settings
) )
can_view_live = False can_view_live = False
...@@ -623,7 +619,6 @@ def delete_item(request): ...@@ -623,7 +619,6 @@ def delete_item(request):
store = get_modulestore(item_loc) store = get_modulestore(item_loc)
# @TODO: this probably leaves draft items dangling. My preferance would be for the semantic to be # @TODO: this probably leaves draft items dangling. My preferance would be for the semantic to be
# if item.location.revision=None, then delete both draft and published version # if item.location.revision=None, then delete both draft and published version
# if caller wants to only delete the draft than the caller should put item.location.revision='draft' # if caller wants to only delete the draft than the caller should put item.location.revision='draft'
...@@ -665,7 +660,7 @@ def save_item(request): ...@@ -665,7 +660,7 @@ def save_item(request):
if not has_access(request.user, item_location): if not has_access(request.user, item_location):
raise PermissionDenied() raise PermissionDenied()
store = get_modulestore(Location(item_location)); store = get_modulestore(Location(item_location))
if request.POST.get('data') is not None: if request.POST.get('data') is not None:
data = request.POST['data'] data = request.POST['data']
...@@ -800,7 +795,7 @@ def upload_asset(request, org, course, coursename): ...@@ -800,7 +795,7 @@ def upload_asset(request, org, course, coursename):
# Does the course actually exist?!? Get anything from it to prove its existance # Does the course actually exist?!? Get anything from it to prove its existance
try: try:
item = modulestore().get_item(location) modulestore().get_item(location)
except: except:
# no return it as a Bad Request response # no return it as a Bad Request response
logging.error('Could not find course' + location) logging.error('Could not find course' + location)
...@@ -844,14 +839,12 @@ def upload_asset(request, org, course, coursename): ...@@ -844,14 +839,12 @@ def upload_asset(request, org, course, coursename):
response['asset_url'] = StaticContent.get_url_path_from_location(content.location) response['asset_url'] = StaticContent.get_url_path_from_location(content.location)
return response return response
'''
This view will return all CMS users who are editors for the specified course
'''
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
def manage_users(request, location): def manage_users(request, location):
'''
This view will return all CMS users who are editors for the specified course
'''
# check that logged in user has permissions to this item # check that logged in user has permissions to this item
if not has_access(request.user, location, role=INSTRUCTOR_ROLE_NAME) and not has_access(request.user, location, role=STAFF_ROLE_NAME): if not has_access(request.user, location, role=INSTRUCTOR_ROLE_NAME) and not has_access(request.user, location, role=STAFF_ROLE_NAME):
raise PermissionDenied() raise PermissionDenied()
...@@ -878,14 +871,14 @@ def create_json_response(errmsg=None): ...@@ -878,14 +871,14 @@ def create_json_response(errmsg=None):
return resp return resp
'''
This POST-back view will add a user - specified by email - to the list of editors for
the specified course
'''
@expect_json @expect_json
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
def add_user(request, location): def add_user(request, location):
'''
This POST-back view will add a user - specified by email - to the list of editors for
the specified course
'''
email = request.POST["email"] email = request.POST["email"]
if email == '': if email == '':
...@@ -911,14 +904,15 @@ def add_user(request, location): ...@@ -911,14 +904,15 @@ def add_user(request, location):
return create_json_response() return create_json_response()
'''
This POST-back view will remove a user - specified by email - from the list of editors for
the specified course
'''
@expect_json @expect_json
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
def remove_user(request, location): def remove_user(request, location):
'''
This POST-back view will remove a user - specified by email - from the list of editors for
the specified course
'''
email = request.POST["email"] email = request.POST["email"]
# check that logged in user has admin permissions on this course # check that logged in user has admin permissions on this course
...@@ -999,7 +993,6 @@ def reorder_static_tabs(request): ...@@ -999,7 +993,6 @@ def reorder_static_tabs(request):
else: else:
reordered_tabs.append(tab) reordered_tabs.append(tab)
# OK, re-assemble the static tabs in the new order # OK, re-assemble the static tabs in the new order
course.tabs = reordered_tabs course.tabs = reordered_tabs
modulestore('direct').update_metadata(course.location, own_metadata(course)) modulestore('direct').update_metadata(course.location, own_metadata(course))
...@@ -1011,7 +1004,6 @@ def reorder_static_tabs(request): ...@@ -1011,7 +1004,6 @@ def reorder_static_tabs(request):
def edit_tabs(request, org, course, coursename): def edit_tabs(request, org, course, coursename):
location = ['i4x', org, course, 'course', coursename] location = ['i4x', org, course, 'course', coursename]
course_item = modulestore().get_item(location) course_item = modulestore().get_item(location)
static_tabs_loc = Location('i4x', org, course, 'static_tab', None)
# check that logged in user has permissions to this item # check that logged in user has permissions to this item
if not has_access(request.user, location): if not has_access(request.user, location):
...@@ -1184,7 +1176,7 @@ def course_config_graders_page(request, org, course, name): ...@@ -1184,7 +1176,7 @@ def course_config_graders_page(request, org, course, name):
return render_to_response('settings_graders.html', { return render_to_response('settings_graders.html', {
'context_course': course_module, 'context_course': course_module,
'course_location' : location, 'course_location': location,
'course_details': json.dumps(course_details, cls=CourseSettingsEncoder) 'course_details': json.dumps(course_details, cls=CourseSettingsEncoder)
}) })
...@@ -1203,8 +1195,8 @@ def course_config_advanced_page(request, org, course, name): ...@@ -1203,8 +1195,8 @@ def course_config_advanced_page(request, org, course, name):
return render_to_response('settings_advanced.html', { return render_to_response('settings_advanced.html', {
'context_course': course_module, 'context_course': course_module,
'course_location' : location, 'course_location': location,
'advanced_dict' : json.dumps(CourseMetadata.fetch(location)), 'advanced_dict': json.dumps(CourseMetadata.fetch(location)),
}) })
...@@ -1225,7 +1217,8 @@ def course_settings_updates(request, org, course, name, section): ...@@ -1225,7 +1217,8 @@ def course_settings_updates(request, org, course, name, section):
manager = CourseDetails manager = CourseDetails
elif section == 'grading': elif section == 'grading':
manager = CourseGradingModel manager = CourseGradingModel
else: return else:
return
if request.method == 'GET': if request.method == 'GET':
# Cannot just do a get w/o knowing the course name :-( # Cannot just do a get w/o knowing the course name :-(
...@@ -1320,6 +1313,7 @@ def course_advanced_updates(request, org, course, name): ...@@ -1320,6 +1313,7 @@ def course_advanced_updates(request, org, course, name):
response_json = json.dumps(CourseMetadata.update_from_json(location, request_body, filter_tabs=filter_tabs)) response_json = json.dumps(CourseMetadata.update_from_json(location, request_body, filter_tabs=filter_tabs))
return HttpResponse(response_json, mimetype="application/json") return HttpResponse(response_json, mimetype="application/json")
@ensure_csrf_cookie @ensure_csrf_cookie
@login_required @login_required
def get_checklists(request, org, course, name): def get_checklists(request, org, course, name):
...@@ -1433,7 +1427,6 @@ def asset_index(request, org, course, name): ...@@ -1433,7 +1427,6 @@ def asset_index(request, org, course, name):
# sort in reverse upload date order # sort in reverse upload date order
assets = sorted(assets, key=lambda asset: asset['uploadDate'], reverse=True) assets = sorted(assets, key=lambda asset: asset['uploadDate'], reverse=True)
thumbnails = contentstore().get_all_content_thumbnails_for_course(course_reference)
asset_display = [] asset_display = []
for asset in assets: for asset in assets:
id = asset['_id'] id = asset['_id']
...@@ -1586,8 +1579,10 @@ def import_course(request, org, course, name): ...@@ -1586,8 +1579,10 @@ def import_course(request, org, course, name):
shutil.move(r / fname, course_dir) shutil.move(r / fname, course_dir)
module_store, course_items = import_from_xml(modulestore('direct'), settings.GITHUB_REPO_ROOT, module_store, course_items = import_from_xml(modulestore('direct'), settings.GITHUB_REPO_ROOT,
[course_subdir], load_error_modules=False, static_content_store=contentstore(), [course_subdir], load_error_modules=False,
target_location_namespace=Location(location), draft_store=modulestore()) static_content_store=contentstore(),
target_location_namespace=Location(location),
draft_store=modulestore())
# we can blow this away when we're done importing. # we can blow this away when we're done importing.
shutil.rmtree(course_dir) shutil.rmtree(course_dir)
......
...@@ -174,7 +174,6 @@ class CourseDetails(object): ...@@ -174,7 +174,6 @@ class CourseDetails(object):
return result return result
# TODO move to a more general util? Is there a better way to do the isinstance model check? # TODO move to a more general util? Is there a better way to do the isinstance model check?
class CourseSettingsEncoder(json.JSONEncoder): class CourseSettingsEncoder(json.JSONEncoder):
def default(self, obj): def default(self, obj):
......
...@@ -45,8 +45,7 @@ class CourseGradingModel(object): ...@@ -45,8 +45,7 @@ class CourseGradingModel(object):
# return empty model # return empty model
else: else:
return { return {"id": index,
"id": index,
"type": "", "type": "",
"min_count": 0, "min_count": 0,
"drop_count": 0, "drop_count": 0,
...@@ -95,7 +94,6 @@ class CourseGradingModel(object): ...@@ -95,7 +94,6 @@ class CourseGradingModel(object):
return CourseGradingModel.fetch(course_location) return CourseGradingModel.fetch(course_location)
@staticmethod @staticmethod
def update_grader_from_json(course_location, grader): def update_grader_from_json(course_location, grader):
""" """
...@@ -137,7 +135,6 @@ class CourseGradingModel(object): ...@@ -137,7 +135,6 @@ class CourseGradingModel(object):
return cutoffs return cutoffs
@staticmethod @staticmethod
def update_grace_period_from_json(course_location, graceperiodjson): def update_grace_period_from_json(course_location, graceperiodjson):
""" """
...@@ -210,8 +207,7 @@ class CourseGradingModel(object): ...@@ -210,8 +207,7 @@ class CourseGradingModel(object):
location = Location(location) location = Location(location)
descriptor = get_modulestore(location).get_item(location) descriptor = get_modulestore(location).get_item(location)
return { return {"graderType": descriptor.lms.format if descriptor.lms.format is not None else 'Not Graded',
"graderType": descriptor.lms.format if descriptor.lms.format is not None else 'Not Graded',
"location": location, "location": location,
"id": 99 # just an arbitrary value to "id": 99 # just an arbitrary value to
} }
...@@ -231,7 +227,6 @@ class CourseGradingModel(object): ...@@ -231,7 +227,6 @@ class CourseGradingModel(object):
get_modulestore(location).update_metadata(location, descriptor._model_data._kvs._metadata) get_modulestore(location).update_metadata(location, descriptor._model_data._kvs._metadata)
@staticmethod @staticmethod
def convert_set_grace_period(descriptor): def convert_set_grace_period(descriptor):
# 5 hours 59 minutes 59 seconds => converted to iso format # 5 hours 59 minutes 59 seconds => converted to iso format
...@@ -262,8 +257,7 @@ class CourseGradingModel(object): ...@@ -262,8 +257,7 @@ class CourseGradingModel(object):
@staticmethod @staticmethod
def parse_grader(json_grader): def parse_grader(json_grader):
# manual to clear out kruft # manual to clear out kruft
result = { result = {"type": json_grader["type"],
"type": json_grader["type"],
"min_count": int(json_grader.get('min_count', 0)), "min_count": int(json_grader.get('min_count', 0)),
"drop_count": int(json_grader.get('drop_count', 0)), "drop_count": int(json_grader.get('drop_count', 0)),
"short_label": json_grader.get('short_label', None), "short_label": json_grader.get('short_label', None),
......
...@@ -6,6 +6,7 @@ from xblock.core import Scope ...@@ -6,6 +6,7 @@ from xblock.core import Scope
from xmodule.course_module import CourseDescriptor from xmodule.course_module import CourseDescriptor
import copy import copy
class CourseMetadata(object): class CourseMetadata(object):
''' '''
For CRUD operations on metadata fields which do not have specific editors For CRUD operations on metadata fields which do not have specific editors
...@@ -13,8 +14,13 @@ class CourseMetadata(object): ...@@ -13,8 +14,13 @@ 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', 'end', FILTERED_LIST = XModuleDescriptor.system_metadata_fields + ['start',
'enrollment_start', 'enrollment_end', 'tabs', 'graceperiod', 'checklists'] 'end',
'enrollment_start',
'enrollment_end',
'tabs',
'graceperiod',
'checklists']
@classmethod @classmethod
def fetch(cls, course_location): def fetch(cls, course_location):
......
...@@ -6,7 +6,7 @@ from xmodule.x_module import XModule ...@@ -6,7 +6,7 @@ from xmodule.x_module import XModule
from xmodule.raw_module import RawDescriptor from xmodule.raw_module import RawDescriptor
from xmodule.xml_module import XmlDescriptor from xmodule.xml_module import XmlDescriptor
from xmodule.exceptions import InvalidDefinitionError from xmodule.exceptions import InvalidDefinitionError
from xblock.core import String, Scope, Object, BlockScope from xblock.core import String, Scope, Object
DEFAULT = "_DEFAULT_GROUP" DEFAULT = "_DEFAULT_GROUP"
......
import logging import logging
from lxml import etree from lxml import etree
from pkg_resources import resource_string, resource_listdir from pkg_resources import resource_string
from xmodule.x_module import XModule from xmodule.x_module import XModule
from xmodule.raw_module import RawDescriptor from xmodule.raw_module import RawDescriptor
from xmodule.contentstore.content import StaticContent
from xblock.core import Scope, String from xblock.core import Scope, String
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -25,7 +24,6 @@ class AnnotatableModule(AnnotatableFields, XModule): ...@@ -25,7 +24,6 @@ class AnnotatableModule(AnnotatableFields, XModule):
css = {'scss': [resource_string(__name__, 'css/annotatable/display.scss')]} css = {'scss': [resource_string(__name__, 'css/annotatable/display.scss')]}
icon_class = 'annotatable' icon_class = 'annotatable'
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
XModule.__init__(self, *args, **kwargs) XModule.__init__(self, *args, **kwargs)
......
...@@ -219,5 +219,5 @@ class CombinedOpenEndedDescriptor(CombinedOpenEndedFields, RawDescriptor): ...@@ -219,5 +219,5 @@ class CombinedOpenEndedDescriptor(CombinedOpenEndedFields, RawDescriptor):
stores_state = True stores_state = True
has_score = True has_score = True
always_recalculate_grades=True always_recalculate_grades = True
template_dir_name = "combinedopenended" template_dir_name = "combinedopenended"
...@@ -10,7 +10,7 @@ from pkg_resources import resource_string ...@@ -10,7 +10,7 @@ from pkg_resources import resource_string
from xmodule.x_module import XModule from xmodule.x_module import XModule
from xmodule.modulestore import Location from xmodule.modulestore import Location
from xmodule.seq_module import SequenceDescriptor from xmodule.seq_module import SequenceDescriptor
from xblock.core import String, Scope, List from xblock.core import Scope, List
from xmodule.modulestore.exceptions import ItemNotFoundError from xmodule.modulestore.exceptions import ItemNotFoundError
...@@ -60,7 +60,6 @@ class ConditionalModule(ConditionalFields, XModule): ...@@ -60,7 +60,6 @@ class ConditionalModule(ConditionalFields, XModule):
js = {'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee'), js = {'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee'),
resource_string(__name__, 'js/src/conditional/display.coffee'), resource_string(__name__, 'js/src/conditional/display.coffee'),
resource_string(__name__, 'js/src/collapsible.coffee'), resource_string(__name__, 'js/src/collapsible.coffee'),
]} ]}
js_module_name = "Conditional" js_module_name = "Conditional"
...@@ -82,8 +81,7 @@ class ConditionalModule(ConditionalFields, XModule): ...@@ -82,8 +81,7 @@ class ConditionalModule(ConditionalFields, XModule):
xml_value = self.descriptor.xml_attributes.get(xml_attr) xml_value = self.descriptor.xml_attributes.get(xml_attr)
if xml_value: if xml_value:
return xml_value, attr_name return xml_value, attr_name
raise Exception('Error in conditional module: unknown condition "%s"' raise Exception('Error in conditional module: unknown condition "%s"' % xml_attr)
% xml_attr)
def is_condition_satisfied(self): def is_condition_satisfied(self):
self.required_modules = [self.system.get_module(descriptor) for self.required_modules = [self.system.get_module(descriptor) for
...@@ -163,7 +161,6 @@ class ConditionalDescriptor(ConditionalFields, SequenceDescriptor): ...@@ -163,7 +161,6 @@ class ConditionalDescriptor(ConditionalFields, SequenceDescriptor):
stores_state = True stores_state = True
has_score = False has_score = False
@staticmethod @staticmethod
def parse_sources(xml_element, system, return_descriptor=False): def parse_sources(xml_element, system, return_descriptor=False):
"""Parse xml_element 'sources' attr and: """Parse xml_element 'sources' attr and:
......
...@@ -9,6 +9,7 @@ import StringIO ...@@ -9,6 +9,7 @@ import StringIO
from xmodule.modulestore import Location from xmodule.modulestore import Location
from .django import contentstore from .django import contentstore
# to install PIL on MacOSX: 'easy_install http://dist.repoze.org/PIL-1.1.6.tar.gz'
from PIL import Image from PIL import Image
...@@ -61,6 +62,7 @@ class StaticContent(object): ...@@ -61,6 +62,7 @@ class StaticContent(object):
return {'tag': location.tag, 'org': location.org, 'course': location.course, return {'tag': location.tag, 'org': location.org, 'course': location.course,
'category': location.category, 'name': location.name, 'category': location.category, 'name': location.name,
'revision': location.revision} 'revision': location.revision}
@staticmethod @staticmethod
def get_location_from_path(path): def get_location_from_path(path):
# remove leading / character if it is there one # remove leading / character if it is there one
...@@ -79,8 +81,6 @@ class StaticContent(object): ...@@ -79,8 +81,6 @@ class StaticContent(object):
return StaticContent.get_url_path_from_location(loc) return StaticContent.get_url_path_from_location(loc)
class ContentStore(object): class ContentStore(object):
''' '''
Abstraction for all ContentStore providers (e.g. MongoDB) Abstraction for all ContentStore providers (e.g. MongoDB)
......
from __future__ import absolute_import from __future__ import absolute_import
from importlib import import_module from importlib import import_module
from os import environ
from django.conf import settings from django.conf import settings
......
...@@ -6,7 +6,6 @@ from gridfs.errors import NoFile ...@@ -6,7 +6,6 @@ from gridfs.errors import NoFile
from xmodule.modulestore.mongo import location_to_query, Location from xmodule.modulestore.mongo import location_to_query, Location
from xmodule.contentstore.content import XASSET_LOCATION_TAG from xmodule.contentstore.content import XASSET_LOCATION_TAG
import sys
import logging import logging
from .content import StaticContent, ContentStore from .content import StaticContent, ContentStore
...@@ -26,7 +25,6 @@ class MongoContentStore(ContentStore): ...@@ -26,7 +25,6 @@ class MongoContentStore(ContentStore):
self.fs = gridfs.GridFS(_db) self.fs = gridfs.GridFS(_db)
self.fs_files = _db["fs.files"] # the underlying collection GridFS uses self.fs_files = _db["fs.files"] # the underlying collection GridFS uses
def save(self, content): def save(self, content):
id = content.get_id() id = content.get_id()
...@@ -34,7 +32,8 @@ class MongoContentStore(ContentStore): ...@@ -34,7 +32,8 @@ class MongoContentStore(ContentStore):
self.delete(id) self.delete(id)
with self.fs.new_file(_id=id, filename=content.get_url_path(), content_type=content.content_type, with self.fs.new_file(_id=id, filename=content.get_url_path(), content_type=content.content_type,
displayname=content.name, thumbnail_location=content.thumbnail_location, import_path=content.import_path) as fp: displayname=content.name, thumbnail_location=content.thumbnail_location,
import_path=content.import_path) as fp:
fp.write(content.data) fp.write(content.data)
...@@ -49,7 +48,8 @@ class MongoContentStore(ContentStore): ...@@ -49,7 +48,8 @@ class MongoContentStore(ContentStore):
try: try:
with self.fs.get(id) as fp: with self.fs.get(id) as fp:
return StaticContent(location, fp.displayname, fp.content_type, fp.read(), return StaticContent(location, fp.displayname, fp.content_type, fp.read(),
fp.uploadDate, thumbnail_location=fp.thumbnail_location if hasattr(fp, 'thumbnail_location') else None, fp.uploadDate,
thumbnail_location=fp.thumbnail_location if hasattr(fp, 'thumbnail_location') else None,
import_path=fp.import_path if hasattr(fp, 'import_path') else None) import_path=fp.import_path if hasattr(fp, 'import_path') else None)
except NoFile: except NoFile:
raise NotFoundError() raise NotFoundError()
......
...@@ -211,7 +211,6 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): ...@@ -211,7 +211,6 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
template_dir_name = 'course' template_dir_name = 'course'
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(CourseDescriptor, self).__init__(*args, **kwargs) super(CourseDescriptor, self).__init__(*args, **kwargs)
...@@ -421,7 +420,6 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): ...@@ -421,7 +420,6 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
policy['GRADE_CUTOFFS'] = value policy['GRADE_CUTOFFS'] = value
self.grading_policy = policy self.grading_policy = policy
@property @property
def lowest_passing_grade(self): def lowest_passing_grade(self):
return min(self._grading_policy['GRADE_CUTOFFS'].values()) return min(self._grading_policy['GRADE_CUTOFFS'].values())
...@@ -460,7 +458,6 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): ...@@ -460,7 +458,6 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
else: else:
return self.cohort_config.get("auto_cohort_groups", []) return self.cohort_config.get("auto_cohort_groups", [])
@property @property
def top_level_discussion_topic_ids(self): def top_level_discussion_topic_ids(self):
""" """
...@@ -469,7 +466,6 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): ...@@ -469,7 +466,6 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
topics = self.discussion_topics topics = self.discussion_topics
return [d["id"] for d in topics.values()] return [d["id"] for d in topics.values()]
@property @property
def cohorted_discussions(self): def cohorted_discussions(self):
""" """
...@@ -483,8 +479,6 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): ...@@ -483,8 +479,6 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
return set(config.get("cohorted_discussions", [])) return set(config.get("cohorted_discussions", []))
@property @property
def is_newish(self): def is_newish(self):
""" """
...@@ -585,7 +579,6 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): ...@@ -585,7 +579,6 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
yield module_descriptor yield module_descriptor
for c in self.get_children(): for c in self.get_children():
sections = []
for s in c.get_children(): for s in c.get_children():
if s.lms.graded: if s.lms.graded:
xmoduledescriptors = list(yield_descriptor_descendents(s)) xmoduledescriptors = list(yield_descriptor_descendents(s))
...@@ -603,7 +596,6 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): ...@@ -603,7 +596,6 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
return {'graded_sections': graded_sections, return {'graded_sections': graded_sections,
'all_descriptors': all_descriptors, } 'all_descriptors': all_descriptors, }
@staticmethod @staticmethod
def make_id(org, course, url_name): def make_id(org, course, url_name):
return '/'.join([org, course, url_name]) return '/'.join([org, course, url_name])
......
from lxml import etree from pkg_resources import resource_string
from pkg_resources import resource_string, resource_listdir
from xmodule.x_module import XModule from xmodule.x_module import XModule
from xmodule.raw_module import RawDescriptor from xmodule.raw_module import RawDescriptor
...@@ -21,7 +20,6 @@ class DiscussionModule(DiscussionFields, XModule): ...@@ -21,7 +20,6 @@ class DiscussionModule(DiscussionFields, XModule):
} }
js_module_name = "InlineDiscussion" js_module_name = "InlineDiscussion"
def get_html(self): def get_html(self):
context = { context = {
'discussion_id': self.discussion_id, 'discussion_id': self.discussion_id,
......
class InvalidDefinitionError(Exception): class InvalidDefinitionError(Exception):
pass pass
class NotFoundError(Exception): class NotFoundError(Exception):
pass pass
class ProcessingError(Exception): class ProcessingError(Exception):
''' '''
An error occurred while processing a request to the XModule. An error occurred while processing a request to the XModule.
......
...@@ -51,6 +51,8 @@ class Date(ModelType): ...@@ -51,6 +51,8 @@ class Date(ModelType):
TIMEDELTA_REGEX = re.compile(r'^((?P<days>\d+?) day(?:s?))?(\s)?((?P<hours>\d+?) hour(?:s?))?(\s)?((?P<minutes>\d+?) minute(?:s)?)?(\s)?((?P<seconds>\d+?) second(?:s)?)?$') TIMEDELTA_REGEX = re.compile(r'^((?P<days>\d+?) day(?:s?))?(\s)?((?P<hours>\d+?) hour(?:s?))?(\s)?((?P<minutes>\d+?) minute(?:s)?)?(\s)?((?P<seconds>\d+?) second(?:s)?)?$')
class Timedelta(ModelType): class Timedelta(ModelType):
def from_json(self, time_str): def from_json(self, time_str):
""" """
......
...@@ -149,7 +149,6 @@ class FolditModule(FolditFields, XModule): ...@@ -149,7 +149,6 @@ class FolditModule(FolditFields, XModule):
return 1 return 1
class FolditDescriptor(FolditFields, XmlDescriptor, EditingDescriptor): class FolditDescriptor(FolditFields, XmlDescriptor, EditingDescriptor):
""" """
Module for adding Foldit problems to courses Module for adding Foldit problems to courses
......
...@@ -6,7 +6,6 @@ Passes settings.MODULESTORE as kwargs to MongoModuleStore ...@@ -6,7 +6,6 @@ Passes settings.MODULESTORE as kwargs to MongoModuleStore
from __future__ import absolute_import from __future__ import absolute_import
from importlib import import_module from importlib import import_module
from os import environ
from django.conf import settings from django.conf import settings
......
...@@ -12,6 +12,7 @@ INHERITABLE_METADATA = ( ...@@ -12,6 +12,7 @@ INHERITABLE_METADATA = (
'giturl' # for git edit link 'giturl' # for git edit link
) )
def compute_inherited_metadata(descriptor): def compute_inherited_metadata(descriptor):
"""Given a descriptor, traverse all of its descendants and do metadata """Given a descriptor, traverse all of its descendants and do metadata
inheritance. Should be called on a CourseDescriptor after importing a inheritance. Should be called on a CourseDescriptor after importing a
......
...@@ -7,7 +7,6 @@ from collections import namedtuple ...@@ -7,7 +7,6 @@ from collections import namedtuple
from fs.osfs import OSFS from fs.osfs import OSFS
from itertools import repeat from itertools import repeat
from path import path from path import path
from datetime import datetime
from operator import attrgetter from operator import attrgetter
from uuid import uuid4 from uuid import uuid4
...@@ -31,11 +30,13 @@ log = logging.getLogger(__name__) ...@@ -31,11 +30,13 @@ log = logging.getLogger(__name__)
# there is only one revision for each item. Once we start versioning inside the CMS, # there is only one revision for each item. Once we start versioning inside the CMS,
# that assumption will have to change # that assumption will have to change
def get_course_id_no_run(location): def get_course_id_no_run(location):
''' '''
''' '''
return "/".join([location.org, location.course]) return "/".join([location.org, location.course])
class MongoKeyValueStore(KeyValueStore): class MongoKeyValueStore(KeyValueStore):
""" """
A KeyValueStore that maps keyed data access to one of the 3 data areas A KeyValueStore that maps keyed data access to one of the 3 data areas
...@@ -130,8 +131,8 @@ class CachingDescriptorSystem(MakoDescriptorSystem): ...@@ -130,8 +131,8 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
render_template: a function for rendering templates, as per render_template: a function for rendering templates, as per
MakoDescriptorSystem MakoDescriptorSystem
""" """
super(CachingDescriptorSystem, self).__init__( super(CachingDescriptorSystem, self).__init__(self.load_item, resources_fs,
self.load_item, resources_fs, error_tracker, render_template) error_tracker, render_template)
self.modulestore = modulestore self.modulestore = modulestore
self.module_data = module_data self.module_data = module_data
self.default_class = default_class self.default_class = default_class
...@@ -140,7 +141,6 @@ class CachingDescriptorSystem(MakoDescriptorSystem): ...@@ -140,7 +141,6 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
self.course_id = None self.course_id = None
self.cached_metadata = cached_metadata self.cached_metadata = cached_metadata
def load_item(self, location): def load_item(self, location):
""" """
Return an XModule instance for the specified location Return an XModule instance for the specified location
...@@ -468,7 +468,7 @@ class MongoModuleStore(ModuleStoreBase): ...@@ -468,7 +468,7 @@ class MongoModuleStore(ModuleStoreBase):
# if we are loading a course object, if we're not prefetching children (depth != 0) then don't # if we are loading a course object, if we're not prefetching children (depth != 0) then don't
# bother with the metadata inheritance # bother with the metadata inheritance
return [self._load_item(item, data_cache, return [self._load_item(item, data_cache,
apply_cached_metadata=(item['location']['category']!='course' or depth !=0)) for item in items] apply_cached_metadata=(item['location']['category'] != 'course' or depth != 0)) for item in items]
def get_courses(self): def get_courses(self):
''' '''
...@@ -710,10 +710,9 @@ class MongoModuleStore(ModuleStoreBase): ...@@ -710,10 +710,9 @@ class MongoModuleStore(ModuleStoreBase):
course.tabs = [tab for tab in existing_tabs if tab.get('url_slug') != location.name] course.tabs = [tab for tab in existing_tabs if tab.get('url_slug') != location.name]
self.update_metadata(course.location, own_metadata(course)) self.update_metadata(course.location, own_metadata(course))
self.collection.remove({'_id': Location(location).dict()},
# Must include this to avoid the django debug toolbar (which defines the deprecated "safe=False") # Must include this to avoid the django debug toolbar (which defines the deprecated "safe=False")
# from overriding our default value set in the init method. # from overriding our default value set in the init method.
safe=self.collection.safe) self.collection.remove({'_id': Location(location).dict()}, safe=self.collection.safe)
# recompute (and update) the metadata inheritance tree which is cached # recompute (and update) the metadata inheritance tree which is cached
self.refresh_cached_metadata_inheritance_tree(Location(location)) self.refresh_cached_metadata_inheritance_tree(Location(location))
self.fire_updated_modulestore_signal(get_course_id_no_run(Location(location)), Location(location)) self.fire_updated_modulestore_signal(get_course_id_no_run(Location(location)), Location(location))
......
...@@ -3,7 +3,7 @@ from itertools import repeat ...@@ -3,7 +3,7 @@ from itertools import repeat
from xmodule.course_module import CourseDescriptor from xmodule.course_module import CourseDescriptor
from .exceptions import (ItemNotFoundError, NoPathToItem) from .exceptions import (ItemNotFoundError, NoPathToItem)
from . import ModuleStore, Location from . import Location
def path_to_location(modulestore, course_id, location): def path_to_location(modulestore, course_id, location):
......
import logging
from xmodule.contentstore.content import StaticContent from xmodule.contentstore.content import StaticContent
from xmodule.modulestore import Location from xmodule.modulestore import Location
from xmodule.modulestore.mongo import MongoModuleStore from xmodule.modulestore.mongo import MongoModuleStore
...@@ -94,7 +93,7 @@ def clone_course(modulestore, contentstore, source_location, dest_location, dele ...@@ -94,7 +93,7 @@ def clone_course(modulestore, contentstore, source_location, dest_location, dele
return True return True
def delete_course(modulestore, contentstore, source_location, commit = False): def delete_course(modulestore, contentstore, source_location, commit=False):
# first check to see if the modulestore is Mongo backed # first check to see if the modulestore is Mongo backed
if not isinstance(modulestore, MongoModuleStore): if not isinstance(modulestore, MongoModuleStore):
raise Exception("Expected a MongoModuleStore in the runtime. Aborting....") raise Exception("Expected a MongoModuleStore in the runtime. Aborting....")
......
...@@ -169,7 +169,6 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem): ...@@ -169,7 +169,6 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem):
# Didn't load properly. Fall back on loading as an error # Didn't load properly. Fall back on loading as an error
# descriptor. This should never error due to formatting. # descriptor. This should never error due to formatting.
msg = "Error loading from xml. " + str(err)[:200] msg = "Error loading from xml. " + str(err)[:200]
log.warning(msg) log.warning(msg)
# Normally, we don't want lots of exception traces in our logs from common # Normally, we don't want lots of exception traces in our logs from common
...@@ -376,10 +375,10 @@ class XMLModuleStore(ModuleStoreBase): ...@@ -376,10 +375,10 @@ class XMLModuleStore(ModuleStoreBase):
if course is None: if course is None:
msg = ("No 'course' attribute set for course in {dir}." msg = ("No 'course' attribute set for course in {dir}."
" Using default '{default}'".format( " Using default '{default}'".format(dir=course_dir,
dir=course_dir,
default=course_dir default=course_dir
)) )
)
log.warning(msg) log.warning(msg)
tracker(msg) tracker(msg)
course = course_dir course = course_dir
...@@ -445,7 +444,6 @@ class XMLModuleStore(ModuleStoreBase): ...@@ -445,7 +444,6 @@ class XMLModuleStore(ModuleStoreBase):
log.debug('========> Done with course import from {0}'.format(course_dir)) log.debug('========> Done with course import from {0}'.format(course_dir))
return course_descriptor return course_descriptor
def load_extra_content(self, system, course_descriptor, category, base_dir, course_dir, url_name): def load_extra_content(self, system, course_descriptor, category, base_dir, course_dir, url_name):
self._load_extra_content(system, course_descriptor, category, base_dir, course_dir) self._load_extra_content(system, course_descriptor, category, base_dir, course_dir)
...@@ -453,7 +451,6 @@ class XMLModuleStore(ModuleStoreBase): ...@@ -453,7 +451,6 @@ class XMLModuleStore(ModuleStoreBase):
if os.path.isdir(base_dir / url_name): if os.path.isdir(base_dir / url_name):
self._load_extra_content(system, course_descriptor, category, base_dir / url_name, course_dir) self._load_extra_content(system, course_descriptor, category, base_dir / url_name, course_dir)
def _load_extra_content(self, system, course_descriptor, category, path, course_dir): def _load_extra_content(self, system, course_descriptor, category, path, course_dir):
for filepath in glob.glob(path / '*'): for filepath in glob.glob(path / '*'):
...@@ -480,7 +477,6 @@ class XMLModuleStore(ModuleStoreBase): ...@@ -480,7 +477,6 @@ class XMLModuleStore(ModuleStoreBase):
logging.exception("Failed to load {0}. Skipping... Exception: {1}".format(filepath, str(e))) logging.exception("Failed to load {0}. Skipping... Exception: {1}".format(filepath, str(e)))
system.error_tracker("ERROR: " + str(e)) system.error_tracker("ERROR: " + str(e))
def get_instance(self, course_id, location, depth=0): def get_instance(self, course_id, location, depth=0):
""" """
Returns an XModuleDescriptor instance for the item at Returns an XModuleDescriptor instance for the item at
...@@ -542,7 +538,6 @@ class XMLModuleStore(ModuleStoreBase): ...@@ -542,7 +538,6 @@ class XMLModuleStore(ModuleStoreBase):
return items return items
def get_courses(self, depth=0): def get_courses(self, depth=0):
""" """
Returns a list of course descriptors. If there were errors on loading, Returns a list of course descriptors. If there were errors on loading,
...@@ -567,7 +562,6 @@ class XMLModuleStore(ModuleStoreBase): ...@@ -567,7 +562,6 @@ class XMLModuleStore(ModuleStoreBase):
""" """
raise NotImplementedError("XMLModuleStores are read-only") raise NotImplementedError("XMLModuleStores are read-only")
def update_children(self, location, children): def update_children(self, location, children):
""" """
Set the children for the item specified by the location to Set the children for the item specified by the location to
...@@ -578,7 +572,6 @@ class XMLModuleStore(ModuleStoreBase): ...@@ -578,7 +572,6 @@ class XMLModuleStore(ModuleStoreBase):
""" """
raise NotImplementedError("XMLModuleStores are read-only") raise NotImplementedError("XMLModuleStores are read-only")
def update_metadata(self, location, metadata): def update_metadata(self, location, metadata):
""" """
Set the metadata for the item specified by the location to Set the metadata for the item specified by the location to
......
...@@ -28,6 +28,7 @@ def lazyproperty(fn): ...@@ -28,6 +28,7 @@ def lazyproperty(fn):
""" """
attr_name = '_lazy_' + fn.__name__ attr_name = '_lazy_' + fn.__name__
@property @property
def _lazyprop(self): def _lazyprop(self):
if not hasattr(self, attr_name): if not hasattr(self, attr_name):
......
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