def _import_module(module): module.location = module.location._replace(revision='draft') # make sure our parent has us in its list of children # this is to make sure private only verticals show up in the list of children since # they would have been filtered out from the non-draft store export if module.location.category == 'vertical': non_draft_location = module.location._replace(revision=None) sequential_url = module.xml_attributes['parent_sequential_url'] index = int(module.xml_attributes['index_in_children_list']) seq_location = Location(sequential_url) # IMPORTANT: Be sure to update the sequential in the NEW namespace seq_location = seq_location._replace(org=target_location_namespace.org, course=target_location_namespace.course ) sequential = store.get_item(seq_location, depth=0) if non_draft_location.url() not in sequential.children: sequential.children.insert(index, non_draft_location.url()) store.update_children(sequential.location, sequential.children) import_module(module, draft_store, course_data_path, static_content_store, source_location_namespace, target_location_namespace, allow_not_found=True) for child in module.get_children(): _import_module(child)
def _clone_modules(modulestore, modules, dest_location): for module in modules: original_loc = Location(module.location) if original_loc.category != 'course': module.location = module.location._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course) else: # on the course module we also have to update the module name module.location = module.location._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course, name=dest_location.name) print "Cloning module {0} to {1}....".format(original_loc, module.location) # NOTE: usage of the the internal module.xblock_kvs._data does not include any 'default' values for the fields modulestore.update_item(module.location, module.xblock_kvs._data) # repoint children if module.has_children: new_children = [] for child_loc_url in module.children: child_loc = Location(child_loc_url) child_loc = child_loc._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course ) new_children.append(child_loc.url()) modulestore.update_children(module.location, new_children) # save metadata modulestore.update_metadata(module.location, own_metadata(module))
def _import_module(module): module.location = module.location._replace(revision='draft') # make sure our parent has us in its list of children # this is to make sure private only verticals show up in the list of children since # they would have been filtered out from the non-draft store export if module.location.category == 'vertical': module.location = module.location._replace(revision=None) sequential_url = module.xml_attributes['parent_sequential_url'] index = int(module.xml_attributes['index_in_children_list']) seq_location = Location(sequential_url) # IMPORTANT: Be sure to update the sequential in the NEW namespace seq_location = seq_location._replace(org=target_location_namespace.org, course=target_location_namespace.course ) sequential = store.get_item(seq_location) if module.location.url() not in sequential.children: sequential.children.insert(index, module.location.url()) store.update_children(sequential.location, sequential.children) del module.xml_attributes['parent_sequential_url'] del module.xml_attributes['index_in_children_list'] import_module(module, draft_store, course_data_path, static_content_store, allow_not_found=True) for child in module.get_children(): _import_module(child)
def remap_namespace(module, target_location_namespace): if target_location_namespace is None: return module # This looks a bit wonky as we need to also change the 'name' of the # imported course to be what the caller passed in if module.location.category != 'course': module.location = module.location._replace( tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course ) else: original_location = module.location # # module is a course module # module.location = module.location._replace( tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course, name=target_location_namespace.name ) # There is more re-namespacing work we have to do when # importing course modules # remap pdf_textbook urls for entry in module.pdf_textbooks: for chapter in entry.get('chapters', []): if StaticContent.is_c4x_path(chapter.get('url', '')): chapter['url'] = StaticContent.renamespace_c4x_path( chapter['url'], target_location_namespace ) # if there is a wiki_slug which is the same as the original location # (aka default value), then remap that so the wiki doesn't point to # the old Wiki. if module.wiki_slug == original_location.course: module.wiki_slug = target_location_namespace.course module.save() # then remap children pointers since they too will be re-namespaced if hasattr(module, 'children'): children_locs = module.children if children_locs is not None and children_locs != []: new_locs = [] for child in children_locs: child_loc = Location(child) new_child_loc = child_loc._replace( tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course ) new_locs.append(new_child_loc.url()) module.children = new_locs return module
def _clone_modules(modulestore, modules, source_location, dest_location): for module in modules: original_loc = Location(module.location) if original_loc.category != "course": module.location = module.location._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course ) else: # on the course module we also have to update the module name module.location = module.location._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course, name=dest_location.name ) print "Cloning module {0} to {1}....".format(original_loc, module.location) if "data" in module.fields and module.fields["data"].is_set_on(module) and isinstance(module.data, basestring): module.data = rewrite_nonportable_content_links( source_location.course_id, dest_location.course_id, module.data ) # repoint children if module.has_children: new_children = [] for child_loc_url in module.children: child_loc = Location(child_loc_url) child_loc = child_loc._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course ) new_children.append(child_loc.url()) module.children = new_children modulestore.update_item(module, "**replace_user**")
def import_module_from_xml(modulestore, static_content_store, course_data_path, module, target_location_namespace=None, verbose=False): # remap module to the new namespace if target_location_namespace is not None: # This looks a bit wonky as we need to also change the 'name' of the imported course to be what # the caller passed in if module.location.category != 'course': module.location = module.location._replace(tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course) else: module.location = module.location._replace(tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course, name=target_location_namespace.name) # then remap children pointers since they too will be re-namespaced if module.has_children: children_locs = module.children new_locs = [] for child in children_locs: child_loc = Location(child) new_child_loc = child_loc._replace(tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course) new_locs.append(new_child_loc.url()) module.children = new_locs if hasattr(module, 'data'): modulestore.update_item(module.location, module.data) if module.has_children: modulestore.update_children(module.location, module.children) modulestore.update_metadata(module.location, own_metadata(module))
def remap_namespace(module, target_location_namespace): if target_location_namespace is None: return module # This looks a bit wonky as we need to also change the 'name' of the imported course to be what # the caller passed in if module.location.category != 'course': module.location = module.location._replace(tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course) else: module.location = module.location._replace(tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course, name=target_location_namespace.name) # then remap children pointers since they too will be re-namespaced if hasattr(module, 'children'): children_locs = module.children if children_locs is not None and children_locs != []: new_locs = [] for child in children_locs: child_loc = Location(child) new_child_loc = child_loc._replace(tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course) new_locs.append(new_child_loc.url()) module.children = new_locs return module
def clone_item(request): parent_location = Location(request.POST['parent_location']) template = Location(request.POST['template']) display_name = request.POST.get('display_name') if not has_access(request.user, parent_location): raise PermissionDenied() parent = get_modulestore(template).get_item(parent_location) dest_location = parent_location._replace( category=template.category, name=uuid4().hex) new_item = get_modulestore(template).clone_item(template, dest_location) # replace the display name with an optional parameter passed in from the # caller if display_name is not None: new_item.display_name = display_name get_modulestore(template).update_metadata( new_item.location.url(), own_metadata(new_item)) if new_item.location.category not in DETACHED_CATEGORIES: get_modulestore(parent.location).update_children( parent_location, parent.children + [new_item.location.url()]) return HttpResponse(json.dumps({'id': dest_location.url()}))
def clone_item(request): parent_location = Location(request.POST['parent_location']) template = Location(request.POST['template']) display_name = request.POST.get('display_name') if not has_access(request.user, parent_location): raise PermissionDenied() parent = get_modulestore(template).get_item(parent_location) dest_location = parent_location._replace(category=template.category, name=uuid4().hex) new_item = get_modulestore(template).clone_item(template, dest_location) # replace the display name with an optional parameter passed in from the # caller if display_name is not None: new_item.display_name = display_name get_modulestore(template).update_metadata(new_item.location.url(), own_metadata(new_item)) if new_item.location.category not in DETACHED_CATEGORIES: get_modulestore(parent.location).update_children( parent_location, parent.children + [new_item.location.url()]) return HttpResponse(json.dumps({'id': dest_location.url()}))
def remap_namespace(module, target_location_namespace): if target_location_namespace is None: return module # This looks a bit wonky as we need to also change the 'name' of the imported course to be what # the caller passed in if module.location.category != 'course': module.location = module.location._replace( tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course) else: module.location = module.location._replace( tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course, name=target_location_namespace.name) # then remap children pointers since they too will be re-namespaced if hasattr(module, 'children'): children_locs = module.children if children_locs is not None and children_locs != []: new_locs = [] for child in children_locs: child_loc = Location(child) new_child_loc = child_loc._replace( tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course) new_locs.append(new_child_loc.url()) module.children = new_locs return module
def create_new_course(request): if settings.MITX_FEATURES.get('DISABLE_COURSE_CREATION', False) and not request.user.is_staff: raise PermissionDenied() # This logic is repeated in xmodule/modulestore/tests/factories.py # so if you change anything here, you need to also change it there. # TODO: write a test that creates two courses, one with the factory and # the other with this method, then compare them to make sure they are # equivalent. template = Location(request.POST['template']) org = request.POST.get('org') number = request.POST.get('number') display_name = request.POST.get('display_name') try: dest_location = Location('i4x', org, number, 'course', Location.clean(display_name)) except InvalidLocationError as error: return HttpResponse(json.dumps({'ErrMsg': "Unable to create course '" + display_name + "'.\n\n" + error.message})) # see if the course already exists existing_course = None try: existing_course = modulestore('direct').get_item(dest_location) except ItemNotFoundError: pass if existing_course is not None: return HttpResponse(json.dumps({'ErrMsg': 'There is already a course defined with this name.'})) course_search_location = ['i4x', dest_location.org, dest_location.course, 'course', None] courses = modulestore().get_items(course_search_location) if len(courses) > 0: return HttpResponse(json.dumps({'ErrMsg': 'There is already a course defined with the same organization and course number.'})) new_course = modulestore('direct').clone_item(template, dest_location) # clone a default 'about' module as well about_template_location = Location(['i4x', 'edx', 'templates', 'about', 'overview']) dest_about_location = dest_location._replace(category='about', name='overview') modulestore('direct').clone_item(about_template_location, dest_about_location) if display_name is not None: new_course.display_name = display_name # set a default start date to now new_course.start = datetime.datetime.now(UTC()) initialize_course_tabs(new_course) create_all_course_groups(request.user, new_course.location) # seed the forums seed_permissions_roles(new_course.location.course_id) return HttpResponse(json.dumps({'id': new_course.location.url()}))
def import_module_from_xml(modulestore, static_content_store, course_data_path, module, target_location_namespace=None, verbose=False): # remap module to the new namespace if target_location_namespace is not None: # This looks a bit wonky as we need to also change the 'name' of the imported course to be what # the caller passed in if module.location.category != 'course': module.location = module.location._replace( tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course) else: module.location = module.location._replace( tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course, name=target_location_namespace.name) # then remap children pointers since they too will be re-namespaced if module.has_children: children_locs = module.children new_locs = [] for child in children_locs: child_loc = Location(child) new_child_loc = child_loc._replace( tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course) new_locs.append(new_child_loc.url()) module.children = new_locs if hasattr(module, 'data'): # cdodge: now go through any link references to '/static/' and make sure we've imported # it as a StaticContent asset try: remap_dict = {} # use the rewrite_links as a utility means to enumerate through all links # in the module data. We use that to load that reference into our asset store # IMPORTANT: There appears to be a bug in lxml.rewrite_link which makes us not be able to # do the rewrites natively in that code. # For example, what I'm seeing is <img src='foo.jpg' /> -> <img src='bar.jpg'> # Note the dropped element closing tag. This causes the LMS to fail when rendering modules - that's # no good, so we have to do this kludge if isinstance(module.data, str) or isinstance(module.data, unicode): # some module 'data' fields are non strings which blows up the link traversal code lxml_rewrite_links(module.data, lambda link: verify_content_links( module, course_data_path, static_content_store, link, remap_dict)) for key in remap_dict.keys(): module.data = module.data.replace(key, remap_dict[key]) except Exception: logging.exception( "failed to rewrite links on {0}. Continuing...".format(module.location)) modulestore.update_item(module.location, module.data) if module.has_children: modulestore.update_children(module.location, module.children) modulestore.update_metadata(module.location, own_metadata(module))
def remap_namespace(module, target_location_namespace): if target_location_namespace is None: return module # This looks a bit wonky as we need to also change the 'name' of the imported course to be what # the caller passed in if module.location.category != 'course': module.location = module.location._replace( tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course ) else: original_location = module.location # # module is a course module # module.location = module.location._replace( tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course, name=target_location_namespace.name ) # # There is more re-namespacing work we have to do when importing course modules # # remap pdf_textbook urls for entry in module.pdf_textbooks: for chapter in entry.get('chapters', []): if StaticContent.is_c4x_path(chapter.get('url', '')): chapter['url'] = StaticContent.renamespace_c4x_path(chapter['url'], target_location_namespace) # if there is a wiki_slug which is the same as the original location (aka default value), # then remap that so the wiki doesn't point to the old Wiki. if module.wiki_slug == original_location.course: module.wiki_slug = target_location_namespace.course module.save() # then remap children pointers since they too will be re-namespaced if hasattr(module, 'children'): children_locs = module.children if children_locs is not None and children_locs != []: new_locs = [] for child in children_locs: child_loc = Location(child) new_child_loc = child_loc._replace( tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course ) new_locs.append(new_child_loc.url()) module.children = new_locs return module
def _clone_modules(modulestore, modules, source_location, dest_location): for module in modules: original_loc = Location(module.location) if original_loc.category != 'course': new_location = module.location._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course ) module.scope_ids = module.scope_ids._replace( def_id=new_location, usage_id=new_location ) else: # on the course module we also have to update the module name new_location = module.location._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course, name=dest_location.name ) module.scope_ids = module.scope_ids._replace( def_id=new_location, usage_id=new_location ) print "Cloning module {0} to {1}....".format(original_loc, module.location) # NOTE: usage of the the internal module.xblock_kvs._data does not include any 'default' values for the fields data = module.xblock_kvs._data if isinstance(data, basestring): data = rewrite_nonportable_content_links( source_location.course_id, dest_location.course_id, data) modulestore.update_item(module.location, data) # repoint children if module.has_children: new_children = [] for child_loc_url in module.children: child_loc = Location(child_loc_url) child_loc = child_loc._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course ) new_children.append(child_loc.url()) modulestore.update_children(module.location, new_children) # save metadata modulestore.update_metadata(module.location, own_metadata(module))
def _clone_modules(modulestore, modules, source_location, dest_location): for module in modules: original_loc = Location(module.location) if original_loc.category != 'course': new_location = module.location._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course) module.scope_ids = module.scope_ids._replace(def_id=new_location, usage_id=new_location) else: # on the course module we also have to update the module name new_location = module.location._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course, name=dest_location.name) module.scope_ids = module.scope_ids._replace(def_id=new_location, usage_id=new_location) print "Cloning module {0} to {1}....".format(original_loc, module.location) # NOTE: usage of the the internal module.xblock_kvs._data does not include any 'default' values for the fields data = module.xblock_kvs._data if isinstance(data, basestring): data = rewrite_nonportable_content_links(source_location.course_id, dest_location.course_id, data) modulestore.update_item(module.location, data) # repoint children if module.has_children: new_children = [] for child_loc_url in module.children: child_loc = Location(child_loc_url) child_loc = child_loc._replace(tag=dest_location.tag, org=dest_location.org, course=dest_location.course) new_children.append(child_loc.url()) modulestore.update_children(module.location, new_children) # save metadata modulestore.update_metadata(module.location, own_metadata(module))
def fetch(cls, course_location): """ Fetch the course details for the given course from persistence and return a CourseDetails model. """ if not isinstance(course_location, Location): course_location = Location(course_location) course = cls(course_location) descriptor = get_modulestore(course_location).get_item(course_location) course.start_date = descriptor.start course.end_date = descriptor.end course.enrollment_start = descriptor.enrollment_start course.enrollment_end = descriptor.enrollment_end temploc = course_location._replace(category='about', name='syllabus') try: course.syllabus = get_modulestore(temploc).get_item(temploc).data except ItemNotFoundError: pass temploc = temploc._replace(name='overview') try: course.overview = get_modulestore(temploc).get_item(temploc).data except ItemNotFoundError: pass temploc = temploc._replace(name='effort') try: course.effort = get_modulestore(temploc).get_item(temploc).data except ItemNotFoundError: pass temploc = temploc._replace(name='video') try: raw_video = get_modulestore(temploc).get_item(temploc).data course.intro_video = CourseDetails.parse_video_tag(raw_video) except ItemNotFoundError: pass return course
def _clone_modules(modulestore, modules, source_location, dest_location): for module in modules: original_loc = Location(module.location) if original_loc.category != 'course': module.location = module.location._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course ) else: # on the course module we also have to update the module name module.location = module.location._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course, name=dest_location.name ) print "Cloning module {0} to {1}....".format(original_loc, module.location) if 'data' in module.fields and module.fields['data'].is_set_on(module) and isinstance(module.data, basestring): module.data = rewrite_nonportable_content_links( source_location.course_id, dest_location.course_id, module.data ) # repoint children if module.has_children: new_children = [] for child_loc_url in module.children: child_loc = Location(child_loc_url) child_loc = child_loc._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course ) new_children.append(child_loc.url()) module.children = new_children modulestore.update_item(module, '**replace_user**')
def clone_course(modulestore, contentstore, source_location, dest_location, delete_original=False): # first check to see if the modulestore is Mongo backed if not isinstance(modulestore, MongoModuleStore): raise Exception("Expected a MongoModuleStore in the runtime. Aborting....") # check to see if the dest_location exists as an empty course # we need an empty course because the app layers manage the permissions and users if not modulestore.has_item(dest_location): raise Exception("An empty course at {0} must have already been created. Aborting...".format(dest_location)) # verify that the dest_location really is an empty course, which means only one with an optional 'overview' dest_modules = modulestore.get_items([dest_location.tag, dest_location.org, dest_location.course, None, None, None]) basically_empty = True for module in dest_modules: if module.location.category == 'course' or (module.location.category == 'about' and module.location.name == 'overview'): continue basically_empty = False break if not basically_empty: raise Exception("Course at destination {0} is not an empty course. You can only clone into an empty course. Aborting...".format(dest_location)) # check to see if the source course is actually there if not modulestore.has_item(source_location): raise Exception("Cannot find a course at {0}. Aborting".format(source_location)) # Get all modules under this namespace which is (tag, org, course) tuple modules = modulestore.get_items([source_location.tag, source_location.org, source_location.course, None, None, None]) for module in modules: original_loc = Location(module.location) if original_loc.category != 'course': module.location = module.location._replace(tag=dest_location.tag, org=dest_location.org, course=dest_location.course) else: # on the course module we also have to update the module name module.location = module.location._replace(tag=dest_location.tag, org=dest_location.org, course=dest_location.course, name=dest_location.name) print "Cloning module {0} to {1}....".format(original_loc, module.location) modulestore.update_item(module.location, module._model_data._kvs._data) # repoint children if module.has_children: new_children = [] for child_loc_url in module.children: child_loc = Location(child_loc_url) child_loc = child_loc._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course ) new_children.append(child_loc.url()) modulestore.update_children(module.location, new_children) # save metadata modulestore.update_metadata(module.location, module._model_data._kvs._metadata) # now iterate through all of the assets and clone them # first the thumbnails thumbs = contentstore.get_all_content_thumbnails_for_course(source_location) for thumb in thumbs: thumb_loc = Location(thumb["_id"]) content = contentstore.find(thumb_loc) content.location = content.location._replace(org=dest_location.org, course=dest_location.course) print "Cloning thumbnail {0} to {1}".format(thumb_loc, content.location) contentstore.save(content) # now iterate through all of the assets, also updating the thumbnail pointer assets = contentstore.get_all_content_for_course(source_location) for asset in assets: asset_loc = Location(asset["_id"]) content = contentstore.find(asset_loc) content.location = content.location._replace(org=dest_location.org, course=dest_location.course) # be sure to update the pointer to the thumbnail if content.thumbnail_location is not None: content.thumbnail_location = content.thumbnail_location._replace(org=dest_location.org, course=dest_location.course) print "Cloning asset {0} to {1}".format(asset_loc, content.location) contentstore.save(content) return True
def clone_course(modulestore, contentstore, source_location, dest_location, delete_original=False): # first check to see if the modulestore is Mongo backed if not isinstance(modulestore, MongoModuleStore): raise Exception( "Expected a MongoModuleStore in the runtime. Aborting....") # check to see if the dest_location exists as an empty course # we need an empty course because the app layers manage the permissions and users if not modulestore.has_item(dest_location): raise Exception( "An empty course at {0} must have already been created. Aborting..." .format(dest_location)) # verify that the dest_location really is an empty course, which means only one with an optional 'overview' dest_modules = modulestore.get_items([ dest_location.tag, dest_location.org, dest_location.course, None, None, None ]) basically_empty = True for module in dest_modules: if module.location.category == 'course' or ( module.location.category == 'about' and module.location.name == 'overview'): continue basically_empty = False break if not basically_empty: raise Exception( "Course at destination {0} is not an empty course. You can only clone into an empty course. Aborting..." .format(dest_location)) # check to see if the source course is actually there if not modulestore.has_item(source_location): raise Exception( "Cannot find a course at {0}. Aborting".format(source_location)) # Get all modules under this namespace which is (tag, org, course) tuple modules = modulestore.get_items([ source_location.tag, source_location.org, source_location.course, None, None, None ]) for module in modules: original_loc = Location(module.location) if original_loc.category != 'course': module.location = module.location._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course) else: # on the course module we also have to update the module name module.location = module.location._replace( tag=dest_location.tag, org=dest_location.org, course=dest_location.course, name=dest_location.name) print "Cloning module {0} to {1}....".format(original_loc, module.location) modulestore.update_item(module.location, module._model_data._kvs._data) # repoint children if module.has_children: new_children = [] for child_loc_url in module.children: child_loc = Location(child_loc_url) child_loc = child_loc._replace(tag=dest_location.tag, org=dest_location.org, course=dest_location.course) new_children.append(child_loc.url()) modulestore.update_children(module.location, new_children) # save metadata modulestore.update_metadata(module.location, module._model_data._kvs._metadata) # now iterate through all of the assets and clone them # first the thumbnails thumbs = contentstore.get_all_content_thumbnails_for_course( source_location) for thumb in thumbs: thumb_loc = Location(thumb["_id"]) content = contentstore.find(thumb_loc) content.location = content.location._replace( org=dest_location.org, course=dest_location.course) print "Cloning thumbnail {0} to {1}".format(thumb_loc, content.location) contentstore.save(content) # now iterate through all of the assets, also updating the thumbnail pointer assets = contentstore.get_all_content_for_course(source_location) for asset in assets: asset_loc = Location(asset["_id"]) content = contentstore.find(asset_loc) content.location = content.location._replace( org=dest_location.org, course=dest_location.course) # be sure to update the pointer to the thumbnail if content.thumbnail_location is not None: content.thumbnail_location = content.thumbnail_location._replace( org=dest_location.org, course=dest_location.course) print "Cloning asset {0} to {1}".format(asset_loc, content.location) contentstore.save(content) return True
def update_from_json(cls, jsondict): """ Decode the json into CourseDetails and save any changed attrs to the db """ # TODO make it an error for this to be undefined & for it to not be retrievable from modulestore course_location = jsondict['course_location'] # Will probably want to cache the inflight courses because every blur generates an update descriptor = get_modulestore(course_location).get_item(course_location) dirty = False # In the descriptor's setter, the date is converted to JSON using Date's to_json method. # Calling to_json on something that is already JSON doesn't work. Since reaching directly # into the model is nasty, convert the JSON Date to a Python date, which is what the # setter expects as input. date = Date() if 'start_date' in jsondict: converted = date.from_json(jsondict['start_date']) else: converted = None if converted != descriptor.start: dirty = True descriptor.start = converted if 'end_date' in jsondict: converted = date.from_json(jsondict['end_date']) else: converted = None if converted != descriptor.end: dirty = True descriptor.end = converted if 'enrollment_start' in jsondict: converted = date.from_json(jsondict['enrollment_start']) else: converted = None if converted != descriptor.enrollment_start: dirty = True descriptor.enrollment_start = converted if 'enrollment_end' in jsondict: converted = date.from_json(jsondict['enrollment_end']) else: converted = None if converted != descriptor.enrollment_end: dirty = True descriptor.enrollment_end = converted if dirty: get_modulestore(course_location).update_metadata( course_location, own_metadata(descriptor)) # NOTE: below auto writes to the db w/o verifying that any of the fields actually changed # to make faster, could compare against db or could have client send over a list of which fields changed. temploc = Location(course_location)._replace(category='about', name='syllabus') update_item(temploc, jsondict['syllabus']) temploc = temploc._replace(name='overview') update_item(temploc, jsondict['overview']) temploc = temploc._replace(name='effort') update_item(temploc, jsondict['effort']) temploc = temploc._replace(name='video') recomposed_video_tag = CourseDetails.recompose_video_tag( jsondict['intro_video']) update_item(temploc, recomposed_video_tag) # Could just generate and return a course obj w/o doing any db reads, but I put the reads in as a means to confirm # it persisted correctly return CourseDetails.fetch(course_location)
def location(attr): parent = Location(attr.parent_location) dest_name = attr.display_name.replace( " ", "_") if attr.display_name is not None else uuid4().hex return parent._replace(category=attr.category, name=dest_name)
def location(attr): parent = Location(attr.parent_location) dest_name = attr.display_name.replace(" ", "_") if attr.display_name is not None else uuid4().hex return parent._replace(category=attr.category, name=dest_name)
def import_module_from_xml(modulestore, static_content_store, course_data_path, module, target_location_namespace=None, verbose=False): # remap module to the new namespace if target_location_namespace is not None: # This looks a bit wonky as we need to also change the 'name' of the imported course to be what # the caller passed in if module.location.category != 'course': module.location = module.location._replace( tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course) else: module.location = module.location._replace( tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course, name=target_location_namespace.name) # then remap children pointers since they too will be re-namespaced if module.has_children: children_locs = module.children new_locs = [] for child in children_locs: child_loc = Location(child) new_child_loc = child_loc._replace( tag=target_location_namespace.tag, org=target_location_namespace.org, course=target_location_namespace.course) new_locs.append(new_child_loc.url()) module.children = new_locs if hasattr(module, 'data'): # cdodge: now go through any link references to '/static/' and make sure we've imported # it as a StaticContent asset try: remap_dict = {} # use the rewrite_links as a utility means to enumerate through all links # in the module data. We use that to load that reference into our asset store # IMPORTANT: There appears to be a bug in lxml.rewrite_link which makes us not be able to # do the rewrites natively in that code. # For example, what I'm seeing is <img src='foo.jpg' /> -> <img src='bar.jpg'> # Note the dropped element closing tag. This causes the LMS to fail when rendering modules - that's # no good, so we have to do this kludge if isinstance(module.data, str) or isinstance( module.data, unicode ): # some module 'data' fields are non strings which blows up the link traversal code lxml_rewrite_links( module.data, lambda link: verify_content_links( module, course_data_path, static_content_store, link, remap_dict)) for key in remap_dict.keys(): module.data = module.data.replace(key, remap_dict[key]) except Exception: logging.exception( "failed to rewrite links on {0}. Continuing...".format( module.location)) modulestore.update_item(module.location, module.data) if module.has_children: modulestore.update_children(module.location, module.children) modulestore.update_metadata(module.location, own_metadata(module))
def update_from_json(cls, jsondict): """ Decode the json into CourseDetails and save any changed attrs to the db """ # TODO make it an error for this to be undefined & for it to not be retrievable from modulestore course_location = jsondict['course_location'] # Will probably want to cache the inflight courses because every blur generates an update descriptor = get_modulestore(course_location).get_item(course_location) dirty = False # In the descriptor's setter, the date is converted to JSON using Date's to_json method. # Calling to_json on something that is already JSON doesn't work. Since reaching directly # into the model is nasty, convert the JSON Date to a Python date, which is what the # setter expects as input. date = Date() if 'start_date' in jsondict: converted = date.from_json(jsondict['start_date']) else: converted = None if converted != descriptor.start: dirty = True descriptor.start = converted if 'end_date' in jsondict: converted = date.from_json(jsondict['end_date']) else: converted = None if converted != descriptor.end: dirty = True descriptor.end = converted if 'enrollment_start' in jsondict: converted = date.from_json(jsondict['enrollment_start']) else: converted = None if converted != descriptor.enrollment_start: dirty = True descriptor.enrollment_start = converted if 'enrollment_end' in jsondict: converted = date.from_json(jsondict['enrollment_end']) else: converted = None if converted != descriptor.enrollment_end: dirty = True descriptor.enrollment_end = converted if dirty: get_modulestore(course_location).update_metadata(course_location, own_metadata(descriptor)) # NOTE: below auto writes to the db w/o verifying that any of the fields actually changed # to make faster, could compare against db or could have client send over a list of which fields changed. temploc = Location(course_location)._replace(category='about', name='syllabus') update_item(temploc, jsondict['syllabus']) temploc = temploc._replace(name='overview') update_item(temploc, jsondict['overview']) temploc = temploc._replace(name='effort') update_item(temploc, jsondict['effort']) temploc = temploc._replace(name='video') recomposed_video_tag = CourseDetails.recompose_video_tag(jsondict['intro_video']) update_item(temploc, recomposed_video_tag) # Could just generate and return a course obj w/o doing any db reads, but I put the reads in as a means to confirm # it persisted correctly return CourseDetails.fetch(course_location)