Esempio n. 1
0
                    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)
Esempio n. 2
0
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)
Esempio n. 4
0
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
Esempio n. 5
0
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**")
Esempio n. 6
0
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
Esempio n. 8
0
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()}))
Esempio n. 9
0
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()}))
Esempio n. 10
0
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
Esempio n. 11
0
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()}))
Esempio n. 12
0
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()}))
Esempio n. 13
0
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))
Esempio n. 14
0
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
Esempio n. 15
0
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))
Esempio n. 16
0
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))
Esempio n. 17
0
    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
Esempio n. 18
0
    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
Esempio n. 19
0
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**')
Esempio n. 20
0
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
Esempio n. 21
0
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
Esempio n. 22
0
    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)
Esempio n. 23
0
 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)
Esempio n. 24
0
 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)
Esempio n. 25
0
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))
Esempio n. 26
0
    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)