Пример #1
0
    def lms_link_test(self):
        """ Tests get_lms_link_for_item. """
        course_key = SlashSeparatedCourseKey('mitX', '101', 'test')
        location = course_key.make_usage_key('vertical', 'contacting_us')
        link = utils.get_lms_link_for_item(location, False)
        self.assertEquals(
            link,
            "//localhost:8000/courses/mitX/101/test/jump_to/i4x://mitX/101/vertical/contacting_us"
        )

        # test preview
        # for edunext the second parameter is False, its the same test that before
        # link = utils.get_lms_link_for_item(location, True)

        # self.assertEquals(
        #     link,
        #     "//localhost:8000/courses/mitX/101/test/jump_to/i4x://mitX/101/vertical/contacting_us"
        # )

        # now test with the course' location
        location = course_key.make_usage_key('course', 'test')
        link = utils.get_lms_link_for_item(location)
        self.assertEquals(
            link,
            "//localhost:8000/courses/mitX/101/test/jump_to/i4x://mitX/101/course/test"
        )
Пример #2
0
def edit_subsection(request, location):
    # check that we have permissions to edit this item
    course = get_course_for_item(location)
    if not has_access(request.user, course.location):
        raise PermissionDenied()

    item = modulestore().get_item(location, depth=1)

    lms_link = get_lms_link_for_item(
        location, course_id=course.location.course_id)
    preview_link = get_lms_link_for_item(
        location, course_id=course.location.course_id, preview=True)

    # make sure that location references a 'sequential', otherwise return
    # BadRequest
    if item.location.category != 'sequential':
        return HttpResponseBadRequest()

    parent_locs = modulestore().get_parent_locations(location, None)

    # we're for now assuming a single parent
    if len(parent_locs) != 1:
        logging.error(
            'Multiple (or none) parents have been found for {0}'.format(location))

    # this should blow up if we don't find any parents, which would be
    # erroneous
    parent = modulestore().get_item(parent_locs[0])

    # remove all metadata from the generic dictionary that is presented in a
    # more normalized UI

    policy_metadata = dict(
        (field.name, field.read_from(item))
        for field
        in item.fields
        if field.name not in ['display_name', 'start', 'due', 'format'] and field.scope == Scope.settings
    )

    can_view_live = False
    subsection_units = item.get_children()
    for unit in subsection_units:
        state = compute_unit_state(unit)
        if state == UnitState.public or state == UnitState.draft:
            can_view_live = True
            break

    return render_to_response('edit_subsection.html',
                              {'subsection': item,
                               'context_course': course,
                               'create_new_unit_template': Location('i4x', 'edx', 'templates', 'vertical', 'Empty'),
                               'lms_link': lms_link,
                               'preview_link': preview_link,
                               'course_graders': json.dumps(CourseGradingModel.fetch(course.location).graders),
                               'parent_location': course.location,
                               'parent_item': parent,
                               'policy_metadata': policy_metadata,
                               'subsection_units': subsection_units,
                               'can_view_live': can_view_live
                               })
Пример #3
0
 def lms_link_test(self):
     """ Tests get_lms_link_for_item. """
     location = "i4x", "mitX", "101", "vertical", "contacting_us"
     utils.get_course_id = mock.Mock(return_value="mitX/101/test")
     link = utils.get_lms_link_for_item(location, False)
     self.assertEquals(link, "//localhost:8000/courses/mitX/101/test/jump_to/i4x://mitX/101/vertical/contacting_us")
     link = utils.get_lms_link_for_item(location, True)
     self.assertEquals(link, "//preview/courses/mitX/101/test/jump_to/i4x://mitX/101/vertical/contacting_us")
Пример #4
0
 def lms_link_test(self):
     """ Tests get_lms_link_for_item. """
     location = 'i4x', 'mitX', '101', 'vertical', 'contacting_us'
     utils.get_course_id = mock.Mock(return_value="mitX/101/test")
     link = utils.get_lms_link_for_item(location, False)
     self.assertEquals(link, "//localhost:8000/courses/mitX/101/test/jump_to/i4x://mitX/101/vertical/contacting_us")
     link = utils.get_lms_link_for_item(location, True)
     self.assertEquals(
         link,
         "//preview/courses/mitX/101/test/jump_to/i4x://mitX/101/vertical/contacting_us"
     )
Пример #5
0
    def lms_link_test(self):
        """ Tests get_lms_link_for_item. """
        location = "i4x", "mitX", "101", "vertical", "contacting_us"
        link = utils.get_lms_link_for_item(location, False, "mitX/101/test")
        self.assertEquals(link, "//localhost:8000/courses/mitX/101/test/jump_to/i4x://mitX/101/vertical/contacting_us")
        link = utils.get_lms_link_for_item(location, True, "mitX/101/test")
        self.assertEquals(link, "//preview/courses/mitX/101/test/jump_to/i4x://mitX/101/vertical/contacting_us")

        # If no course_id is passed in, it is obtained from the location. This is the case for
        # Studio dashboard.
        location = "i4x", "mitX", "101", "course", "test"
        link = utils.get_lms_link_for_item(location)
        self.assertEquals(link, "//localhost:8000/courses/mitX/101/test/jump_to/i4x://mitX/101/course/test")
Пример #6
0
    def lms_link_test(self):
        """ Tests get_lms_link_for_item. """
        course_key = SlashSeparatedCourseKey("mitX", "101", "test")
        location = course_key.make_usage_key("vertical", "contacting_us")
        link = utils.get_lms_link_for_item(location, False)
        self.assertEquals(link, "//localhost:8000/courses/mitX/101/test/jump_to/i4x://mitX/101/vertical/contacting_us")

        # test preview
        link = utils.get_lms_link_for_item(location, True)
        self.assertEquals(link, "//preview/courses/mitX/101/test/jump_to/i4x://mitX/101/vertical/contacting_us")

        # now test with the course' location
        location = course_key.make_usage_key("course", "test")
        link = utils.get_lms_link_for_item(location)
        self.assertEquals(link, "//localhost:8000/courses/mitX/101/test/jump_to/i4x://mitX/101/course/test")
Пример #7
0
def course_index(request, course_id, branch, version_guid, block):
    """
    Display an editable course overview.

    org, course, name: Attributes of the Location for the item to edit
    """
    location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, usage_id=block)
    # TODO: when converting to split backend, if location does not have a usage_id,
    # we'll need to get the course's root block_id
    if not has_access(request.user, location):
        raise PermissionDenied()


    old_location = loc_mapper().translate_locator_to_location(location)

    lms_link = get_lms_link_for_item(old_location)

    course = modulestore().get_item(old_location, depth=3)
    sections = course.get_children()

    return render_to_response('overview.html', {
        'context_course': course,
        'lms_link': lms_link,
        'sections': sections,
        'course_graders': json.dumps(
            CourseGradingModel.fetch(course.location).graders
        ),
        'parent_location': course.location,
        'new_section_category': 'chapter',
        'new_subsection_category': 'sequential',
        'new_unit_category': 'vertical',
        'category': 'vertical'
    })
Пример #8
0
def course_index(request, course_key):
    """
    Display an editable course overview.

    org, course, name: Attributes of the Location for the item to edit
    """
    course_module = _get_course_module(course_key, request.user, depth=3)
    lms_link = get_lms_link_for_item(course_module.location)
    sections = course_module.get_children()

    try:
        current_action = CourseRerunState.objects.find_first(course_key=course_key, should_display=True)
    except (ItemNotFoundError, CourseActionStateItemNotFoundError):
        current_action = None

    return render_to_response('overview.html', {
        'context_course': course_module,
        'lms_link': lms_link,
        'sections': sections,
        'course_graders': json.dumps(
            CourseGradingModel.fetch(course_key).graders
        ),
        'new_section_category': 'chapter',
        'new_subsection_category': 'sequential',
        'new_unit_category': 'vertical',
        'category': 'vertical',
        'rerun_notification_id': current_action.id if current_action else None,
    })
Пример #9
0
def course_index(request, package_id, branch, version_guid, block):
    """
    Display an editable course overview.

    org, course, name: Attributes of the Location for the item to edit
    """
    locator, course = _get_locator_and_course(
        package_id, branch, version_guid, block, request.user, depth=3
    )
    lms_link = get_lms_link_for_item(course.location)
    sections = course.get_children()

    return render_to_response('overview.html', {
        'context_course': course,
        'lms_link': lms_link,
        'sections': sections,
        'course_graders': json.dumps(
            CourseGradingModel.fetch(locator).graders
        ),
        'parent_locator': locator,
        'new_section_category': 'chapter',
        'new_subsection_category': 'sequential',
        'new_unit_category': 'vertical',
        'category': 'vertical'
    })
Пример #10
0
def experiments_handler(request, course_key_string):
    """
    Displays the experiment list for the current course

    :param request: http request default
    :param course_key_string: slashes:USPx+CS0000+2014_1
    :return: rendered html 


    Mostra a listagem dos experimentos deste curso.

    :param request: http request default
    :param course_key_string: slashes:USPx+CS0000+2014_1
    :return: html renderizado
    """

    usage_key = CourseKey.from_string(course_key_string)
    if not has_course_access(request.user, usage_key):
        raise PermissionDenied()

    course_module = modulestore().get_course(usage_key, depth=3)

    # Lista dos Experimentos
    expList = ExperimentDefinition.objects.filter(userTeacher=request.user, course=course_module.location)
    lms_link = get_lms_link_for_item(course_module.location) # link para o LMS

    return render_to_response('experiment/experimentos.html', {
            'lms_link': lms_link,
            'explist': expList,
            'course_key_string': course_key_string,
            'context_course': course_module # Se não tiver essa variável não carregará o menu
        })
Пример #11
0
def course_index(request, org, course, name):
    """
    Display an editable course overview.

    org, course, name: Attributes of the Location for the item to edit
    """
    location = get_location_and_verify_access(request, org, course, name)

    lms_link = get_lms_link_for_item(location)

    upload_asset_callback_url = reverse('upload_asset', kwargs={
        'org': org,
        'course': course,
        'coursename': name
    })

    course = modulestore().get_item(location, depth=3)
    sections = course.get_children()

    return render_to_response('overview.html', {
        'active_tab': 'courseware',
        'context_course': course,
        'lms_link': lms_link,
        'sections': sections,
        'course_graders': json.dumps(CourseGradingModel.fetch(course.location).graders),
        'parent_location': course.location,
        'new_section_template': Location('i4x', 'edx', 'templates', 'chapter', 'Empty'),
        'new_subsection_template': Location('i4x', 'edx', 'templates', 'sequential', 'Empty'),  # for now they are the same, but the could be different at some point...
        'upload_asset_callback_url': upload_asset_callback_url,
        'create_new_unit_template': Location('i4x', 'edx', 'templates', 'vertical', 'Empty')
    })
def offercourse(request):
    if 'course' in request.GET:
        allcourse = request.GET.getlist('course')
        #return HttpResponse(allcourse)
        for selcourse in allcourse:

            selcourse = str(selcourse)
            organization = (selcourse.split(":")[1]).split('+')[0]
            id_req = selcourse.split("+")[1]
            course_run = selcourse.split("+")[2]
            #id_modifier= organization+"/"+id_req+"/"+course_run
            courses = modulestore('direct').get_courses()
            for course in courses:
                #return  HttpResponse(course.id)
                if str(course.id) == selcourse:
                    #return HttpResponse(course.id)
                    req_course = course
                    break
            #return HttpResponse(course)
            url = get_lms_link_for_item(req_course.location)
            b = OfferedCourse(course_url=url,
                              name=req_course.display_name,
                              course_id=id_req,
                              org=organization,
                              start_date=time.strftime("%Y-%m-%d"))
            b.save()

        return redirect('/rcms/')

    else:
        return redirect('/rcms/3')
Пример #13
0
def course_index(request, package_id, branch, version_guid, block):
    """
    Display an editable course overview.

    org, course, name: Attributes of the Location for the item to edit
    """
    locator, course = _get_locator_and_course(package_id,
                                              branch,
                                              version_guid,
                                              block,
                                              request.user,
                                              depth=3)
    lms_link = get_lms_link_for_item(course.location)
    sections = course.get_children()

    return render_to_response(
        'overview.html', {
            'context_course': course,
            'lms_link': lms_link,
            'sections': sections,
            'course_graders': json.dumps(
                CourseGradingModel.fetch(locator).graders),
            'parent_locator': locator,
            'new_section_category': 'chapter',
            'new_subsection_category': 'sequential',
            'new_unit_category': 'vertical',
            'category': 'vertical'
        })
Пример #14
0
def index(request):
    """
    List all courses available to the logged in user
    """
    courses = modulestore('direct').get_items(
        ['i4x', None, None, 'course', None])

    # filter out courses that we don't have access too
    def course_filter(course):
        return (has_access(request.user, course.location)
                and course.location.course != 'templates'
                and course.location.org != '' and course.location.course != ''
                and course.location.name != '')

    courses = filter(course_filter, courses)

    return render_to_response(
        'index.html', {
            'new_course_template':
            Location('i4x', 'edx', 'templates', 'course', 'Empty'),
            'courses': [
                (course.display_name, get_url_reverse('CourseOutline', course),
                 get_lms_link_for_item(course.location,
                                       course_id=course.location.course_id))
                for course in courses
            ],
            'user':
            request.user,
            'disable_course_creation':
            settings.MITX_FEATURES.get('DISABLE_COURSE_CREATION', False)
            and not request.user.is_staff
        })
Пример #15
0
def index(request):
    """
    List all courses available to the logged in user
    """
    courses = modulestore('direct').get_items(
        ['i4x', None, None, 'course', None])

    # filter out courses that we don't have access too
    def course_filter(course):
        return (has_access(request.user, course.location)
                # TODO remove this condition when templates purged from db
                and course.location.course != 'templates' and
                course.location.org != '' and
                course.location.course != '' and course.location.name != '')

    courses = filter(course_filter, courses)

    return render_to_response(
        'index.html', {
            'courses':
            [(course.display_name, get_url_reverse('CourseOutline', course),
              get_lms_link_for_item(course.location,
                                    course_id=course.location.course_id))
             for course in courses],
            'user':
            request.user,
            'request_course_creator_url':
            reverse('request_course_creator'),
            'course_creator_status':
            _get_course_creator_status(request.user),
            'csrf':
            csrf(request)['csrf_token']
        })
Пример #16
0
def index(request):
    """
    List all courses available to the logged in user
    """
    courses = modulestore("direct").get_items(["i4x", None, None, "course", None])

    # filter out courses that we don't have access too
    def course_filter(course):
        return (
            has_access(request.user, course.location)
            # TODO remove this condition when templates purged from db
            and course.location.course != "templates"
            and course.location.org != ""
            and course.location.course != ""
            and course.location.name != ""
        )

    courses = filter(course_filter, courses)

    return render_to_response(
        "index.html",
        {
            "courses": [
                (
                    course.display_name,
                    get_url_reverse("CourseOutline", course),
                    get_lms_link_for_item(course.location, course_id=course.location.course_id),
                )
                for course in courses
            ],
            "user": request.user,
            "disable_course_creation": settings.MITX_FEATURES.get("DISABLE_COURSE_CREATION", False)
            and not request.user.is_staff,
        },
    )
Пример #17
0
def offercourse(request):
	if 'course' in request.GET:
		allcourse = request.GET.getlist('course')
		#return HttpResponse(allcourse)
		for selcourse in allcourse :
			

			selcourse = str(selcourse)
			organization = (selcourse.split(":")[1]).split('+')[0]
			id_req = selcourse.split("+")[1]
			course_run = selcourse.split("+")[2]
			#id_modifier= organization+"/"+id_req+"/"+course_run
			courses = modulestore('direct').get_courses()
			for course in courses:
				#return  HttpResponse(course.id)
				if str(course.id) == selcourse :
					#return HttpResponse(course.id)
					req_course = course
					break
			#return HttpResponse(course)
			url = get_lms_link_for_item(req_course.location)
			b = OfferedCourse(course_url = url, name = req_course.display_name, course_id = id_req, org = organization, start_date = time.strftime("%Y-%m-%d"))
			b.save()


		return redirect('/rcms/')

	else :
		return redirect('/rcms/3')
Пример #18
0
def course_index(request, org, course, name):
    """
    Display an editable course overview.

    org, course, name: Attributes of the Location for the item to edit
    """
    location = get_location_and_verify_access(request, org, course, name)

    lms_link = get_lms_link_for_item(location)

    upload_asset_callback_url = reverse('upload_asset', kwargs={
        'org': org,
        'course': course,
        'coursename': name
    })

    course = modulestore().get_item(location, depth=3)
    sections = course.get_children()

    return render_to_response('overview.html', {
        'context_course': course,
        'lms_link': lms_link,
        'sections': sections,
        'course_graders': json.dumps(
            CourseGradingModel.fetch(course.location).graders
        ),
        'parent_location': course.location,
        'new_section_category': 'chapter',
        'new_subsection_category': 'sequential',
        'upload_asset_callback_url': upload_asset_callback_url,
        'new_unit_category': 'vertical',
        'category': 'vertical'
    })
Пример #19
0
def course_index(request, course_key):
    """
    Display an editable course overview.

    org, course, name: Attributes of the Location for the item to edit
    """
    course_module = _get_course_module(course_key, request.user, depth=3)
    lms_link = get_lms_link_for_item(course_module.location)
    sections = course_module.get_children()

    return render_to_response(
        'overview.html', {
            'context_course':
            course_module,
            'lms_link':
            lms_link,
            'sections':
            sections,
            'course_graders':
            json.dumps(CourseGradingModel.fetch(course_key).graders),
            'new_section_category':
            'chapter',
            'new_subsection_category':
            'sequential',
            'new_unit_category':
            'vertical',
            'category':
            'vertical'
        })
Пример #20
0
def course_index(request, org, course, name):
    """
    Display an editable course overview.

    org, course, name: Attributes of the Location for the item to edit
    """
    location = get_location_and_verify_access(request, org, course, name)

    lms_link = get_lms_link_for_item(location)

    upload_asset_callback_url = reverse('upload_asset', kwargs={
        'org': org,
        'course': course,
        'coursename': name
    })

    course = modulestore().get_item(location, depth=3)
    sections = course.get_children()

    return render_to_response('overview.html', {
        'active_tab': 'courseware',
        'context_course': course,
        'lms_link': lms_link,
        'sections': sections,
        'course_graders': json.dumps(CourseGradingModel.fetch(course.location).graders),
        'parent_location': course.location,
        'new_section_template': Location('i4x', 'edx', 'templates', 'chapter', 'Empty'),
        'new_subsection_template': Location('i4x', 'edx', 'templates', 'sequential', 'Empty'),  # for now they are the same, but the could be different at some point...
        'upload_asset_callback_url': upload_asset_callback_url,
        'create_new_unit_template': Location('i4x', 'edx', 'templates', 'vertical', 'Empty')
    })
Пример #21
0
def course_index(request, course_id, branch, version_guid, block):
    """
    Display an editable course overview.

    org, course, name: Attributes of the Location for the item to edit
    """
    location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, usage_id=block)
    # TODO: when converting to split backend, if location does not have a usage_id,
    # we'll need to get the course's root block_id
    if not has_access(request.user, location):
        raise PermissionDenied()


    old_location = loc_mapper().translate_locator_to_location(location)

    lms_link = get_lms_link_for_item(old_location)

    course = modulestore().get_item(old_location, depth=3)
    sections = course.get_children()

    return render_to_response('overview.html', {
        'context_course': course,
        'lms_link': lms_link,
        'sections': sections,
        'course_graders': json.dumps(
            CourseGradingModel.fetch(course.location).graders
        ),
        'parent_location': course.location,
        'new_section_category': 'chapter',
        'new_subsection_category': 'sequential',
        'new_unit_category': 'vertical',
        'category': 'vertical'
    })
Пример #22
0
def course_index(request, org, course, name):
    """
    Display an editable course overview.

    org, course, name: Attributes of the Location for the item to edit
    """
    location = get_location_and_verify_access(request, org, course, name)

    lms_link = get_lms_link_for_item(location)

    upload_asset_callback_url = reverse("upload_asset", kwargs={"org": org, "course": course, "coursename": name})

    course = modulestore().get_item(location, depth=3)
    sections = course.get_children()

    return render_to_response(
        "overview.html",
        {
            "context_course": course,
            "lms_link": lms_link,
            "sections": sections,
            "course_graders": json.dumps(CourseGradingModel.fetch(course.location).graders),
            "parent_location": course.location,
            "new_section_category": "chapter",
            "new_subsection_category": "sequential",
            "upload_asset_callback_url": upload_asset_callback_url,
            "new_unit_category": "vertical",
            "category": "vertical",
        },
    )
Пример #23
0
def index(request):
    """
    List all courses available to the logged in user
    """
    courses = modulestore('direct').get_items(['i4x', None, None, 'course', None])

    # filter out courses that we don't have access too
    def course_filter(course):
        return (has_access(request.user, course.location)
                # TODO remove this condition when templates purged from db
                and course.location.course != 'templates'
                and course.location.org != ''
                and course.location.course != ''
                and course.location.name != '')
    courses = filter(course_filter, courses)

    return render_to_response('index.html', {
        'courses': [(course.display_name,
                    get_url_reverse('CourseOutline', course),
                    get_lms_link_for_item(course.location, course_id=course.location.course_id))
                    for course in courses],
        'user': request.user,
        'request_course_creator_url': reverse('request_course_creator'),
        'course_creator_status': _get_course_creator_status(request.user),
        'csrf': csrf(request)['csrf_token']
    })
Пример #24
0
def subsection_handler(request, usage_key_string):
    """
    The restful handler for subsection-specific requests.

    GET
        html: return html page for editing a subsection
        json: not currently supported
    """
    if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'):
        usage_key = UsageKey.from_string(usage_key_string)
        try:
            course, item, lms_link = _get_item_in_course(request, usage_key)
        except ItemNotFoundError:
            return HttpResponseBadRequest()

        preview_link = get_lms_link_for_item(item.location, preview=True)

        # make sure that location references a 'sequential', otherwise return
        # BadRequest
        if item.location.category != 'sequential':
            return HttpResponseBadRequest()

        parent = get_parent_xblock(item)

        # remove all metadata from the generic dictionary that is presented in a
        # more normalized UI. We only want to display the XBlocks fields, not
        # the fields from any mixins that have been added
        fields = getattr(item, 'unmixed_class', item.__class__).fields

        policy_metadata = dict(
            (field.name, field.read_from(item))
            for field
            in fields.values()
            if field.name not in ['display_name', 'start', 'due', 'format'] and field.scope == Scope.settings
        )

        can_view_live = False
        subsection_units = item.get_children()
        can_view_live = any([modulestore().has_published_version(unit) for unit in subsection_units])

        return render_to_response(
            'edit_subsection.html',
            {
                'subsection': item,
                'context_course': course,
                'new_unit_category': 'vertical',
                'lms_link': lms_link,
                'preview_link': preview_link,
                'course_graders': json.dumps(CourseGradingModel.fetch(item.location.course_key).graders),
                'parent_item': parent,
                'locator': item.location,
                'policy_metadata': policy_metadata,
                'subsection_units': subsection_units,
                'can_view_live': can_view_live
            }
        )
    else:
        return HttpResponseBadRequest("Only supports html requests")
def delete_metadata(location, course, modulestore):
    from contentstore.utils import get_lms_link_for_item
    obj_url = get_lms_link_for_item(location,course_id = course.location.course_id, preview=False)
    try:
        existing_item = XModule_Metadata_Cache.objects.get(url=obj_url)
        existing_item.state = 'deleted'
        existing_item.save()
    except XModule_Metadata_Cache.DoesNotExist:
        pass
Пример #26
0
    def lms_link_test(self):
        """ Tests get_lms_link_for_item. """
        course_key = CourseLocator('mitX', '101', 'test')
        location = course_key.make_usage_key('vertical', 'contacting_us')
        link = utils.get_lms_link_for_item(location, False)
        self.assertEquals(link, "//localhost:8000/courses/course-v1:mitX+101+test/jump_to/block-v1:mitX+101+test+type@vertical+block@contacting_us")

        # test preview
        link = utils.get_lms_link_for_item(location, True)
        self.assertEquals(
            link,
            "//preview.localhost/courses/course-v1:mitX+101+test/jump_to/block-v1:mitX+101+test+type@vertical+block@contacting_us"
        )

        # now test with the course' location
        location = course_key.make_usage_key('course', 'test')
        link = utils.get_lms_link_for_item(location)
        self.assertEquals(link, "//localhost:8000/courses/course-v1:mitX+101+test/jump_to/block-v1:mitX+101+test+type@course+block@test")
Пример #27
0
 def format_course_for_view(course):
     """
     return tuple of the data which the view requires for each course
     """
     return (course.display_name,
             reverse_course_url('course_handler', course.id),
             get_lms_link_for_item(course.location),
             course.display_org_with_default,
             course.display_number_with_default, course.location.name)
Пример #28
0
    def lms_link_test(self):
        """ Tests get_lms_link_for_item. """
        location = Location('i4x', 'mitX', '101', 'vertical', 'contacting_us')
        link = utils.get_lms_link_for_item(location, False, "mitX/101/test")
        self.assertEquals(link, "//localhost:8000/courses/mitX/101/test/jump_to/i4x://mitX/101/vertical/contacting_us")
        link = utils.get_lms_link_for_item(location, True, "mitX/101/test")
        self.assertEquals(
            link,
            "//preview/courses/mitX/101/test/jump_to/i4x://mitX/101/vertical/contacting_us"
        )

        # If no course_id is passed in, it is obtained from the location. This is the case for
        # Studio dashboard.
        location = Location('i4x', 'mitX', '101', 'course', 'test')
        link = utils.get_lms_link_for_item(location)
        self.assertEquals(
            link,
            "//localhost:8000/courses/mitX/101/test/jump_to/i4x://mitX/101/course/test"
        )
Пример #29
0
 def format_course_for_view(course):
     return (course.display_name,
             reverse("course_index",
                     kwargs={
                         'org': course.location.org,
                         'course': course.location.course,
                         'name': course.location.name,
                     }), get_lms_link_for_item(course.location),
             course.display_org_with_default,
             course.display_number_with_default, course.location.name)
Пример #30
0
def _get_item_in_course(request, usage_key):
    """
    Helper method for getting the old location, containing course,
    item, lms_link, and preview_lms_link for a given locator.

    Verifies that the caller has permission to access this item.
    """
    # usage_key's course_key may have an empty run property
    usage_key = usage_key.replace(course_key=modulestore().fill_in_run(usage_key.course_key))

    course_key = usage_key.course_key

    if not has_course_author_access(request.user, course_key):
        raise PermissionDenied()

    course = modulestore().get_course(course_key)
    item = modulestore().get_item(usage_key, depth=1)
    lms_link = get_lms_link_for_item(item.location)
    preview_lms_link = get_lms_link_for_item(item.location, preview=True)

    return course, item, lms_link, preview_lms_link
Пример #31
0
def _get_item_in_course(request, usage_key):
    """
    Helper method for getting the old location, containing course,
    item, lms_link, and preview_lms_link for a given locator.

    Verifies that the caller has permission to access this item.
    """
    # usage_key's course_key may have an empty run property
    usage_key = usage_key.replace(course_key=modulestore().fill_in_run(usage_key.course_key))

    course_key = usage_key.course_key

    if not has_course_author_access(request.user, course_key):
        raise PermissionDenied()

    course = modulestore().get_course(course_key)
    item = modulestore().get_item(usage_key, depth=1)
    lms_link = get_lms_link_for_item(item.location)
    preview_lms_link = get_lms_link_for_item(item.location, preview=True)

    return course, item, lms_link, preview_lms_link
Пример #32
0
    def lms_link_test(self):
        """ Tests get_lms_link_for_item. """
        course_key = CourseLocator('mitX', '101', 'test')
        location = course_key.make_usage_key('vertical', 'contacting_us')
        link = utils.get_lms_link_for_item(location, False)
        self.assertEquals(link, "//localhost:8000/courses/course-v1:mitX+101+test/jump_to/block-v1:mitX+101+test+type"
                                "@vertical+block@contacting_us")

        # test preview
        link = utils.get_lms_link_for_item(location, True)
        self.assertEquals(
            link,
            "//preview.localhost/courses/course-v1:mitX+101+test/jump_to/block-v1:mitX+101+test+type@vertical+block"
            "@contacting_us "
        )

        # now test with the course' location
        location = course_key.make_usage_key('course', 'test')
        link = utils.get_lms_link_for_item(location)
        self.assertEquals(link, "//localhost:8000/courses/course-v1:mitX+101+test/jump_to/block-v1:mitX+101+test+type"
                                "@course+block@test")
Пример #33
0
 def format_course_for_view(course):
     """
     return tuple of the data which the view requires for each course
     """
     return (
         course.display_name,
         reverse_course_url('course_handler', course.id),
         get_lms_link_for_item(course.location),
         course.display_org_with_default,
         course.display_number_with_default,
         course.location.name
     )
Пример #34
0
 def format_course_for_view(course):
     return (
         course.display_name,
         reverse("course_index", kwargs={
             'org': course.location.org,
             'course': course.location.course,
             'name': course.location.name,
         }),
         get_lms_link_for_item(
             course.location,
             course_id=course.location.course_id,
         ),
     )
Пример #35
0
    def lms_link_test(self):
        """ Tests get_lms_link_for_item. """
        location = 'i4x', 'mitX', '101', 'vertical', 'contacting_us'
        link = utils.get_lms_link_for_item(location, False, "mitX/101/test")
        self.assertEquals(link, "//localhost:8111/courses/mitX/101/test/jump_to/i4x://mitX/101/vertical/contacting_us")
        link = utils.get_lms_link_for_item(location, True, "mitX/101/test")
        self.assertEquals(
            link,
            "//preview/courses/mitX/101/test/jump_to/i4x://mitX/101/vertical/contacting_us"
        )

        # If no course_id is passed in, it is obtained from the location. This is the case for
        # Studio dashboard.
        location = 'i4x', 'mitX', '101', 'course', 'test'
        link = utils.get_lms_link_for_item(location)
        self.assertEquals(
            link,
#@begin:Change lms port to 8111 and the code
#@date:2013-11-02        
            "//localhost:8111/courses/mitX/101/test/jump_to/i4x://mitX/101/course/test"
#@end
        )
Пример #36
0
 def format_course_for_view(course):
     # published = false b/c studio manipulates draft versions not b/c the course isn't pub'd
     course_loc = loc_mapper().translate_location(course.location.course_id,
                                                  course.location,
                                                  published=False,
                                                  add_entry_if_missing=True)
     return (
         course.display_name,
         # note, couldn't get django reverse to work; so, wrote workaround
         course_loc.url_reverse('course/', ''),
         get_lms_link_for_item(course.location),
         course.display_org_with_default,
         course.display_number_with_default,
         course.location.name)
Пример #37
0
def format_course_for_view(course):
    """
    Return a dict of the data which the view requires for each course
    """
    return {
        'display_name': course.display_name,
        'course_key': unicode(course.location.course_key),
        'url': reverse_course_url('course_handler', course.id),
        'lms_link': get_lms_link_for_item(course.location),
        'rerun_link': _get_rerun_link_for_item(course.id),
        'org': course.display_org_with_default,
        'number': course.display_number_with_default,
        'run': course.location.run
    }
Пример #38
0
 def format_course_for_view(course):
     # published = false b/c studio manipulates draft versions not b/c the course isn't pub'd
     course_url = loc_mapper().translate_location(
         course.location.course_id, course.location, published=False, add_entry_if_missing=True
     )
     return (
         course.display_name,
         reverse("contentstore.views.course_handler", kwargs={'course_url': course_url}),
         get_lms_link_for_item(
             course.location
         ),
         course.display_org_with_default,
         course.display_number_with_default,
         course.location.name
     )
Пример #39
0
 def format_course_for_view(course):
     return (
         course.display_name,
         reverse("course_index", kwargs={
             'org': course.location.org,
             'course': course.location.course,
             'name': course.location.name,
         }),
         get_lms_link_for_item(
             course.location
         ),
         course.display_org_with_default,
         course.display_number_with_default,
         course.location.name
     )
Пример #40
0
 def format_course_for_view(course):
     # published = false b/c studio manipulates draft versions not b/c the course isn't pub'd
     course_loc = loc_mapper().translate_location(
         course.location.course_id, course.location, published=False, add_entry_if_missing=True
     )
     return (
         course.display_name,
         # note, couldn't get django reverse to work; so, wrote workaround
         course_loc.url_reverse('course/', ''),
         get_lms_link_for_item(
             course.location
         ),
         course.display_org_with_default,
         course.display_number_with_default,
         course.location.name
     )
Пример #41
0
def _get_item_in_course(request, locator):
    """
    Helper method for getting the old location, containing course,
    item, and lms_link for a given locator.

    Verifies that the caller has permission to access this item.
    """
    if not has_course_access(request.user, locator):
        raise PermissionDenied()

    old_location = loc_mapper().translate_locator_to_location(locator)
    course_location = loc_mapper().translate_locator_to_location(locator, True)
    course = modulestore().get_item(course_location)
    item = modulestore().get_item(old_location, depth=1)
    lms_link = get_lms_link_for_item(old_location, course_id=course.location.course_id)

    return old_location, course, item, lms_link
Пример #42
0
def _get_item_in_course(request, usage_key):
    """
    Helper method for getting the old location, containing course,
    item, and lms_link for a given locator.

    Verifies that the caller has permission to access this item.
    """
    course_key = usage_key.course_key

    if not has_course_access(request.user, course_key):
        raise PermissionDenied()

    course = modulestore().get_course(course_key)
    item = get_modulestore(usage_key).get_item(usage_key, depth=1)
    lms_link = get_lms_link_for_item(usage_key)

    return course, item, lms_link
Пример #43
0
def _get_item_in_course(request, locator):
    """
    Helper method for getting the old location, containing course,
    item, and lms_link for a given locator.

    Verifies that the caller has permission to access this item.
    """
    if not has_course_access(request.user, locator):
        raise PermissionDenied()

    old_location = loc_mapper().translate_locator_to_location(locator)
    course_location = loc_mapper().translate_locator_to_location(locator, True)
    course = modulestore().get_item(course_location)
    item = modulestore().get_item(old_location, depth=1)
    lms_link = get_lms_link_for_item(old_location, course_id=course.location.course_id)

    return old_location, course, item, lms_link
Пример #44
0
def _get_item_in_course(request, usage_key):
    """
    Helper method for getting the old location, containing course,
    item, and lms_link for a given locator.

    Verifies that the caller has permission to access this item.
    """
    course_key = usage_key.course_key

    if not has_course_access(request.user, course_key):
        raise PermissionDenied()

    course = modulestore().get_course(course_key)
    item = get_modulestore(usage_key).get_item(usage_key, depth=1)
    lms_link = get_lms_link_for_item(usage_key)

    return course, item, lms_link
Пример #45
0
    def student_view(self, context=None):
        user_allowed = False
        user_state = {}
        message = ""
        lti_parameters = {}
        fragment = Fragment()
        context.update(self._get_context_for_template())
        child_fragments = self.runtime.render_children(block=self, view_name='student_view', context=context)
        context.update({"child_fragments": child_fragments})
        if self._is_studio():  # studio view
            context["lms_link"] = get_lms_link_for_item(self.location) if get_lms_link_for_item else ""
            fragment.add_content(self._render_template('static/html/studio.html', context))
        else:  # Student view
            if self.launch_url and self._get_exam_id():
                try:
                    lti_consumer = LtiConsumer(self)
                    lti_parameters = lti_consumer.get_signed_lti_parameters()
                    exam_id = self._get_exam_id()
                    user_state = self.get_proctorexam_user_state(
                        self._get_exam_id(),
                        lti_parameters
                    )
                    context["user_state"] = user_state
                except LtiError:
                    message = _("Proctor Exam xblock configuration is incomplete, LTI passport is invalid")
            else:
                message = _("Proctor Exam xblock configuration is incomplete, exam URL is missing")

            if user_state and "student" in user_state and (user_state["student"].get("status") == "exam_started"):
                # User have completed Proctor Exam indentification process,
                # we show him exam content
                html = self._render_template('static/html/sequence.html', context)
                fragment.add_content(html)
                fragment.add_frags_resources(child_fragments)
            else:
                if self._allowed_verified():
                    # User have to complete Proctor Exam indentification process
                    context.update({'lti_parameters': lti_parameters, "message": message})
                    html = self._render_template("static/html/student.html", context)
                else:
                    html = self._render_template("static/html/honor.html", context)
                fragment.add_content(html)
                fragment.add_css(self.resource_string('static/css/student.css'))

        return fragment
Пример #46
0
 def format_course_for_view(course):
     return (
         course.display_name,
         reverse("course_index", kwargs={
             'org': course.location.org,
             'course': course.location.course,
             'name': course.location.name,
         }),
         #@begin:lms link
         #@data:2014-01-02
         get_lms_link_for_item(
             course.location,
             request=request
         ),
         #@end
         course.display_org_with_default,
         course.display_number_with_default,
         course.location.name
     )
Пример #47
0
 def format_course_for_view(course):
     """
     return tuple of the data which the view requires for each course
     """
     # published = false b/c studio manipulates draft versions not b/c the course isn't pub'd
     course_loc = loc_mapper().translate_location(
         course.location.course_id, course.location, published=False, add_entry_if_missing=True
     )
     return (
         course.display_name,
         # note, couldn't get django reverse to work; so, wrote workaround
         course_loc.url_reverse('course/', ''),
         get_lms_link_for_item(course.location),
         course.display_org_with_default,
         course.display_number_with_default,
         course.location.name,
         course.available_for_demo,
         course.show_in_lms,
         course.has_dynamic_graph,
     )
Пример #48
0
def course_index(request, course_key):
    """
    Display an editable course overview.

    org, course, name: Attributes of the Location for the item to edit
    """
    course_module = _get_course_module(course_key, request.user, depth=3)
    lms_link = get_lms_link_for_item(course_module.location)
    sections = course_module.get_children()

    return render_to_response('overview.html', {
        'context_course': course_module,
        'lms_link': lms_link,
        'sections': sections,
        'course_graders': json.dumps(
            CourseGradingModel.fetch(course_key).graders
        ),
        'new_section_category': 'chapter',
        'new_subsection_category': 'sequential',
        'new_unit_category': 'vertical',
        'category': 'vertical'
    })
Пример #49
0
def edit_unit(request, location):
    """
    Display an editing page for the specified module.

    Expects a GET request with the parameter 'id'.

    id: A Location URL
    """
    try:
        course = get_course_for_item(location)
    except InvalidLocationError:
        return HttpResponseBadRequest()

    if not has_access(request.user, course.location):
        raise PermissionDenied()

    try:
        item = modulestore().get_item(location, depth=1)
    except ItemNotFoundError:
        return HttpResponseBadRequest()

    lms_link = get_lms_link_for_item(item.location,
                                     course_id=course.location.course_id)

    component_templates = defaultdict(list)

    # Check if there are any advanced modules specified in the course policy. These modules
    # should be specified as a list of strings, where the strings are the names of the modules
    # in ADVANCED_COMPONENT_TYPES that should be enabled for the course.
    course_advanced_keys = course.advanced_modules

    # Set component types according to course policy file
    component_types = list(COMPONENT_TYPES)
    if isinstance(course_advanced_keys, list):
        course_advanced_keys = [
            c for c in course_advanced_keys if c in ADVANCED_COMPONENT_TYPES
        ]
        if len(course_advanced_keys) > 0:
            component_types.append(ADVANCED_COMPONENT_CATEGORY)
    else:
        log.error("Improper format for course advanced keys! {0}".format(
            course_advanced_keys))

    templates = modulestore().get_items(Location('i4x', 'edx', 'templates'))
    for template in templates:
        category = template.location.category

        if category in course_advanced_keys:
            category = ADVANCED_COMPONENT_CATEGORY

        if category in component_types:
            # This is a hack to create categories for different xmodules
            component_templates[category].append(
                (template.display_name_with_default, template.location.url(),
                 hasattr(template, 'markdown')
                 and template.markdown is not None))

    components = [
        component.location.url() for component in item.get_children()
    ]

    # TODO (cpennington): If we share units between courses,
    # this will need to change to check permissions correctly so as
    # to pick the correct parent subsection

    containing_subsection_locs = modulestore().get_parent_locations(
        location, None)
    containing_subsection = modulestore().get_item(
        containing_subsection_locs[0])

    containing_section_locs = modulestore().get_parent_locations(
        containing_subsection.location, None)
    containing_section = modulestore().get_item(containing_section_locs[0])

    # cdodge hack. We're having trouble previewing drafts via jump_to redirect
    # so let's generate the link url here

    # need to figure out where this item is in the list of children as the preview will need this
    index = 1
    for child in containing_subsection.get_children():
        if child.location == item.location:
            break
        index = index + 1

    preview_lms_base = settings.MITX_FEATURES.get('PREVIEW_LMS_BASE')

    preview_lms_link = '//{preview_lms_base}/courses/{org}/{course}/{course_name}/courseware/{section}/{subsection}/{index}'.format(
        preview_lms_base=preview_lms_base,
        lms_base=settings.LMS_BASE,
        org=course.location.org,
        course=course.location.course,
        course_name=course.location.name,
        section=containing_section.location.name,
        subsection=containing_subsection.location.name,
        index=index)

    unit_state = compute_unit_state(item)

    return render_to_response(
        'unit.html', {
            'context_course':
            course,
            'active_tab':
            'courseware',
            'unit':
            item,
            'unit_location':
            location,
            'components':
            components,
            'component_templates':
            component_templates,
            'draft_preview_link':
            preview_lms_link,
            'published_preview_link':
            lms_link,
            'subsection':
            containing_subsection,
            'release_date':
            get_default_time_display(containing_subsection.lms.start)
            if containing_subsection.lms.start is not None else None,
            'section':
            containing_section,
            'create_new_unit_template':
            Location('i4x', 'edx', 'templates', 'vertical', 'Empty'),
            'unit_state':
            unit_state,
            'published_date':
            item.cms.published_date.strftime('%B %d, %Y')
            if item.cms.published_date is not None else None,
        })
Пример #50
0
def subsection_handler(request,
                       tag=None,
                       package_id=None,
                       branch=None,
                       version_guid=None,
                       block=None):
    """
    The restful handler for subsection-specific requests.

    GET
        html: return html page for editing a subsection
        json: not currently supported
    """
    if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'):
        locator = BlockUsageLocator(package_id=package_id,
                                    branch=branch,
                                    version_guid=version_guid,
                                    block_id=block)
        try:
            old_location, course, item, lms_link = _get_item_in_course(
                request, locator)
        except ItemNotFoundError:
            return HttpResponseBadRequest()

        preview_link = get_lms_link_for_item(
            old_location, course_id=course.location.course_id, preview=True)

        # make sure that location references a 'sequential', otherwise return
        # BadRequest
        if item.location.category != 'sequential':
            return HttpResponseBadRequest()

        parent = get_parent_xblock(item)

        # remove all metadata from the generic dictionary that is presented in a
        # more normalized UI. We only want to display the XBlocks fields, not
        # the fields from any mixins that have been added
        fields = getattr(item, 'unmixed_class', item.__class__).fields

        policy_metadata = dict(
            (field.name, field.read_from(item)) for field in fields.values()
            if field.name not in ['display_name', 'start', 'due', 'format']
            and field.scope == Scope.settings)

        can_view_live = False
        subsection_units = item.get_children()
        for unit in subsection_units:
            state = compute_publish_state(unit)
            if state in (PublishState.public, PublishState.draft):
                can_view_live = True
                break

        course_locator = loc_mapper().translate_location(
            course.location.course_id, course.location, False, True)

        return render_to_response(
            'edit_subsection.html', {
                'subsection':
                item,
                'context_course':
                course,
                'new_unit_category':
                'vertical',
                'lms_link':
                lms_link,
                'preview_link':
                preview_link,
                'course_graders':
                json.dumps(CourseGradingModel.fetch(course_locator).graders),
                'parent_item':
                parent,
                'locator':
                locator,
                'policy_metadata':
                policy_metadata,
                'subsection_units':
                subsection_units,
                'can_view_live':
                can_view_live
            })
    else:
        return HttpResponseBadRequest("Only supports html requests")
Пример #51
0
def edit_subsection(request, location):
    "Edit the subsection of a course"
    # check that we have permissions to edit this item
    try:
        course = get_course_for_item(location)
    except InvalidLocationError:
        return HttpResponseBadRequest()

    if not has_access(request.user, course.location):
        raise PermissionDenied()

    try:
        item = modulestore().get_item(location, depth=1)
    except ItemNotFoundError:
        return HttpResponseBadRequest()

    lms_link = get_lms_link_for_item(
            location, course_id=course.location.course_id
    )
    preview_link = get_lms_link_for_item(
            location, course_id=course.location.course_id, preview=True
    )

    # make sure that location references a 'sequential', otherwise return
    # BadRequest
    if item.location.category != 'sequential':
        return HttpResponseBadRequest()

    parent_locs = modulestore().get_parent_locations(location, None)

    # we're for now assuming a single parent
    if len(parent_locs) != 1:
        logging.error(
                'Multiple (or none) parents have been found for %s',
                location
        )

    # this should blow up if we don't find any parents, which would be erroneous
    parent = modulestore().get_item(parent_locs[0])

    # remove all metadata from the generic dictionary that is presented in a
    # more normalized UI. We only want to display the XBlocks fields, not
    # the fields from any mixins that have been added
    fields = getattr(item, 'unmixed_class', item.__class__).fields

    policy_metadata = dict(
        (field.name, field.read_from(item))
        for field
        in fields.values()
        if field.name not in ['display_name', 'start', 'due', 'format']
            and field.scope == Scope.settings
    )

    can_view_live = False
    subsection_units = item.get_children()
    for unit in subsection_units:
        state = compute_unit_state(unit)
        if state == UnitState.public or state == UnitState.draft:
            can_view_live = True
            break

    return render_to_response(
        'edit_subsection.html',
        {
           'subsection': item,
           'context_course': course,
           'new_unit_category': 'vertical',
           'lms_link': lms_link,
           'preview_link': preview_link,
           'course_graders': json.dumps(CourseGradingModel.fetch(course.location).graders),
           'parent_location': course.location,
           'parent_item': parent,
           'policy_metadata': policy_metadata,
           'subsection_units': subsection_units,
           'can_view_live': can_view_live
        }
    )
Пример #52
0
def edit_unit(request, location):
    """
    Display an editing page for the specified module.

    Expects a GET request with the parameter `id`.

    id: A Location URL
    """
    try:
        course = get_course_for_item(location)
    except InvalidLocationError:
        return HttpResponseBadRequest()

    if not has_access(request.user, course.location):
        raise PermissionDenied()

    try:
        item = modulestore().get_item(location, depth=1)
    except ItemNotFoundError:
        return HttpResponseBadRequest()
    lms_link = get_lms_link_for_item(
            item.location,
            course_id=course.location.course_id
    )

    component_templates = defaultdict(list)
    for category in COMPONENT_TYPES:
        component_class = XModuleDescriptor.load_class(category)
        # add the default template
        component_templates[category].append((
            component_class.display_name.default or 'Blank',
            category,
            False,  # No defaults have markdown (hardcoded current default)
            None  # no boilerplate for overrides
        ))
        # add boilerplates
        for template in component_class.templates():
            component_templates[category].append((
                template['metadata'].get('display_name'),
                category,
                template['metadata'].get('markdown') is not None,
                template.get('template_id')
            ))

    # Check if there are any advanced modules specified in the course policy.
    # These modules should be specified as a list of strings, where the strings
    # are the names of the modules in ADVANCED_COMPONENT_TYPES that should be
    # enabled for the course.
    course_advanced_keys = course.advanced_modules

    # Set component types according to course policy file
    if isinstance(course_advanced_keys, list):
        for category in course_advanced_keys:
            if category in ADVANCED_COMPONENT_TYPES:
                # Do I need to allow for boilerplates or just defaults on the
                # class? i.e., can an advanced have more than one entry in the
                # menu? one for default and others for prefilled boilerplates?
                try:
                    component_class = XModuleDescriptor.load_class(category)

                    component_templates['advanced'].append((
                        component_class.display_name.default or category,
                        category,
                        False,
                        None  # don't override default data
                        ))
                except PluginMissingError:
                    # dhm: I got this once but it can happen any time the
                    # course author configures an advanced component which does
                    # not exist on the server. This code here merely
                    # prevents any authors from trying to instantiate the
                    # non-existent component type by not showing it in the menu
                    pass
    else:
        log.error(
            "Improper format for course advanced keys! %",
            course_advanced_keys
        )

    components = [
        component.location.url()
        for component
        in item.get_children()
    ]

    # TODO (cpennington): If we share units between courses,
    # this will need to change to check permissions correctly so as
    # to pick the correct parent subsection

    containing_subsection_locs = modulestore().get_parent_locations(
            location, None
    )
    containing_subsection = modulestore().get_item(containing_subsection_locs[0])
    containing_section_locs = modulestore().get_parent_locations(
            containing_subsection.location, None
    )
    containing_section = modulestore().get_item(containing_section_locs[0])

    # cdodge hack. We're having trouble previewing drafts via jump_to redirect
    # so let's generate the link url here

    # need to figure out where this item is in the list of children as the
    # preview will need this
    index = 1
    for child in containing_subsection.get_children():
        if child.location == item.location:
            break
        index = index + 1

    preview_lms_base = settings.MITX_FEATURES.get('PREVIEW_LMS_BASE')

    preview_lms_link = (
            '//{preview_lms_base}/courses/{org}/{course}/'
            '{course_name}/courseware/{section}/{subsection}/{index}'
        ).format(
            preview_lms_base=preview_lms_base,
            lms_base=settings.LMS_BASE,
            org=course.location.org,
            course=course.location.course,
            course_name=course.location.name,
            section=containing_section.location.name,
            subsection=containing_subsection.location.name,
            index=index
        )

    unit_state = compute_unit_state(item)

    return render_to_response('unit.html', {
        'context_course': course,
        'unit': item,
        'unit_location': location,
        'components': components,
        'component_templates': component_templates,
        'draft_preview_link': preview_lms_link,
        'published_preview_link': lms_link,
        'subsection': containing_subsection,
        'release_date': get_default_time_display(containing_subsection.lms.start)
            if containing_subsection.lms.start is not None else None,
        'section': containing_section,
        'new_unit_category': 'vertical',
        'unit_state': unit_state,
        'published_date': get_default_time_display(item.cms.published_date)
            if item.cms.published_date is not None else None
    })