def test_get_default_time_display_notz():
    test_time = datetime(1992, 3, 12, 15, 3, 30)
    assert_equals("Mar 12, 1992 at 15:03 UTC",
                  get_default_time_display(test_time))
    assert_equals("Mar 12, 1992 at 15:03 UTC",
                  get_default_time_display(test_time, True))
    assert_equals("Mar 12, 1992 at 15:03",
                  get_default_time_display(test_time, False))
def test_get_default_time_display():
    assert_equals("", get_default_time_display(None))
    test_time = datetime(1992, 3, 12, 15, 3, 30, tzinfo=UTC)
    assert_equals("Mar 12, 1992 at 15:03 UTC",
                  get_default_time_display(test_time))
    assert_equals("Mar 12, 1992 at 15:03 UTC",
                  get_default_time_display(test_time, True))
    assert_equals("Mar 12, 1992 at 15:03",
                  get_default_time_display(test_time, False))
def test_get_default_time_display():
    assert_equals("", date_utils.get_default_time_display(None))
    test_time = time.struct_time((1992, 3, 12, 15, 3, 30, 1, 71, 0))
    assert_equals("Mar 12, 1992 at 15:03 UTC",
                  date_utils.get_default_time_display(test_time))
    assert_equals("Mar 12, 1992 at 15:03 UTC",
                  date_utils.get_default_time_display(test_time, True))
    assert_equals("Mar 12, 1992 at 15:03",
                  date_utils.get_default_time_display(test_time, False))
def test_get_default_time_display_no_tzname():
    assert_equals("", get_default_time_display(None))
    test_time = datetime(1992, 3, 12, 15, 3, 30, tzinfo=NamelessTZ())
    assert_equals("Mar 12, 1992 at 15:03-0300",
                  get_default_time_display(test_time))
    assert_equals("Mar 12, 1992 at 15:03-0300",
                  get_default_time_display(test_time, True))
    assert_equals("Mar 12, 1992 at 15:03",
                  get_default_time_display(test_time, False))
def test_get_default_time_display_notz():
    test_time = datetime(1992, 3, 12, 15, 3, 30)
    assert_equals(
        "Mar 12, 1992 at 15:03 UTC",
        get_default_time_display(test_time))
    assert_equals(
        "Mar 12, 1992 at 15:03 UTC",
        get_default_time_display(test_time, True))
    assert_equals(
        "Mar 12, 1992 at 15:03",
        get_default_time_display(test_time, False))
def test_get_default_time_display():
    assert_equals("", get_default_time_display(None))
    test_time = datetime(1992, 3, 12, 15, 3, 30, tzinfo=UTC)
    assert_equals(
        "Mar 12, 1992 at 15:03 UTC",
        get_default_time_display(test_time))
    assert_equals(
        "Mar 12, 1992 at 15:03 UTC",
        get_default_time_display(test_time, True))
    assert_equals(
        "Mar 12, 1992 at 15:03",
        get_default_time_display(test_time, False))
def test_get_default_time_display_no_tzname():
    assert_equals("", get_default_time_display(None))
    test_time = datetime(1992, 3, 12, 15, 3, 30, tzinfo=NamelessTZ())
    assert_equals(
        "Mar 12, 1992 at 15:03-0300",
        get_default_time_display(test_time))
    assert_equals(
        "Mar 12, 1992 at 15:03-0300",
        get_default_time_display(test_time, True))
    assert_equals(
        "Mar 12, 1992 at 15:03",
        get_default_time_display(test_time, False))
def test_get_default_time_display():
    assert_equals("", date_utils.get_default_time_display(None))
    test_time = time.struct_time((1992, 3, 12, 15, 3, 30, 1, 71, 0))
    assert_equals(
        "Mar 12, 1992 at 15:03 UTC",
        date_utils.get_default_time_display(test_time))
    assert_equals(
        "Mar 12, 1992 at 15:03 UTC",
        date_utils.get_default_time_display(test_time, True))
    assert_equals(
        "Mar 12, 1992 at 15:03",
        date_utils.get_default_time_display(test_time, False))
def render_make_chapter(context,chapter):
    __M_caller = context.caller_stack._push_frame()
    try:
        course_id = context.get('course_id', UNDEFINED)
        show_timezone = context.get('show_timezone', UNDEFINED)
        enumerate = context.get('enumerate', UNDEFINED)
        __M_writer = context.writer()
        # SOURCE LINE 7
        __M_writer(u'\n  <div class="chapter">\n      ')
        # SOURCE LINE 9

        if chapter.get('active'):
            aria_label = _('{chapter}, current chapter').format(chapter=chapter['display_name'])
            active_class = ' class="active"'
        else:
            aria_label = chapter['display_name']
            active_class = ''
              
        
        # SOURCE LINE 16
        __M_writer(u'\n      <h3 ')
        # SOURCE LINE 17
        __M_writer(filters.decode.utf8(active_class))
        __M_writer(u' aria-label="')
        __M_writer(filters.decode.utf8(aria_label))
        __M_writer(u'">\n        <a href="#">\n          ')
        # SOURCE LINE 19
        __M_writer(filters.decode.utf8(chapter['display_name']))
        __M_writer(u'\n        </a>\n      </h3>\n\n    <ul>\n')
        # SOURCE LINE 24
        for i,section in enumerate(chapter['sections']):
            # SOURCE LINE 25
            __M_writer(u'          <li class="')
            __M_writer(filters.decode.utf8('active' if 'active' in section and section['active'] else ''))
            __M_writer(u' ')
            __M_writer(filters.decode.utf8('graded'  if 'graded' in section and section['graded'] else ''))
            __M_writer(u'">\n            <a href="')
            # SOURCE LINE 26
            __M_writer(filters.decode.utf8(reverse('courseware_section', args=[course_id, chapter['url_name'], section['url_name']])))
            __M_writer(u'" class="section_link">\n              <p>')
            # SOURCE LINE 27
            __M_writer(filters.decode.utf8(section['display_name']))
            __M_writer(u' ')
            __M_writer(filters.decode.utf8('<span class="sr">, current section</span>' if 'active' in section and section['active'] else ''))
            __M_writer(u'</p>\n<!--@begin:Hide subtitle-->\n<!--@date:2013-11-11-->              \n              <p class="subtitle" style="display:none;">')
            # SOURCE LINE 30
            __M_writer(filters.decode.utf8(section['format']))
            __M_writer(u' ')
            __M_writer(filters.decode.utf8("due " + get_default_time_display(section['due'], show_timezone) if section.get('due') is not None else ''))
            __M_writer(u'</p>\n<!--@end-->\n            </a>\n          </li>\n')
        # SOURCE LINE 35
        __M_writer(u'    </ul>\n  </div>\n')
        return ''
    finally:
        context.caller_stack._pop_frame()
Beispiel #10
0
def asset_index(request, org, course, name):
    """
    Display an editable asset library

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

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

    course_module = modulestore().get_item(location)

    course_reference = StaticContent.compute_location(org, course, name)
    assets = contentstore().get_all_content_for_course(course_reference)

    # sort in reverse upload date order
    assets = sorted(assets,
                    key=lambda asset: asset['uploadDate'],
                    reverse=True)

    asset_display = []
    for asset in assets:
        asset_id = asset['_id']
        display_info = {}
        display_info['displayname'] = asset['displayname']
        display_info['uploadDate'] = get_default_time_display(
            asset['uploadDate'].timetuple())

        asset_location = StaticContent.compute_location(
            asset_id['org'], asset_id['course'], asset_id['name'])
        display_info['url'] = StaticContent.get_url_path_from_location(
            asset_location)

        # note, due to the schema change we may not have a 'thumbnail_location'
        # in the result set
        _thumbnail_location = asset.get('thumbnail_location', None)
        thumbnail_location = Location(
            _thumbnail_location) if _thumbnail_location is not None else None
        display_info['thumb_url'] = StaticContent.get_url_path_from_location(
            thumbnail_location) if thumbnail_location is not None else None

        asset_display.append(display_info)

    return render_to_response(
        'asset_index.html', {
            'active_tab': 'assets',
            'context_course': course_module,
            'assets': asset_display,
            'upload_asset_callback_url': upload_asset_callback_url
        })
Beispiel #11
0
def asset_index(request, org, course, name):
    """
    Display an editable asset library

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

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

    course_module = modulestore().get_item(location)

    course_reference = StaticContent.compute_location(org, course, name)
    assets = contentstore().get_all_content_for_course(course_reference)

    # sort in reverse upload date order
    assets = sorted(assets, key=lambda asset: asset['uploadDate'], reverse=True)

    if request.META.get('HTTP_ACCEPT', "").startswith("application/json"):
        return JsonResponse(assets_to_json_dict(assets))

    asset_display = []
    for asset in assets:
        asset_id = asset['_id']
        display_info = {}
        display_info['displayname'] = asset['displayname']
        display_info['uploadDate'] = get_default_time_display(asset['uploadDate'])

        asset_location = StaticContent.compute_location(asset_id['org'], asset_id['course'], asset_id['name'])
        display_info['url'] = StaticContent.get_url_path_from_location(asset_location)
        display_info['portable_url'] = StaticContent.get_static_path_from_location(asset_location)

        # note, due to the schema change we may not have a 'thumbnail_location' in the result set
        _thumbnail_location = asset.get('thumbnail_location', None)
        thumbnail_location = Location(_thumbnail_location) if _thumbnail_location is not None else None
        display_info['thumb_url'] = StaticContent.get_url_path_from_location(thumbnail_location) if thumbnail_location is not None else None

        asset_display.append(display_info)

    return render_to_response('asset_index.html', {
        'context_course': course_module,
        'assets': asset_display,
        'upload_asset_callback_url': upload_asset_callback_url,
        'remove_asset_callback_url': reverse('remove_asset', kwargs={
            'org': org,
            'course': course,
            'name': name
        })
    })
Beispiel #12
0
def _get_asset_json(display_name, date, location, thumbnail_location, locked):
    """
    Helper method for formatting the asset information to send to client.
    """
    asset_url = StaticContent.get_url_path_from_location(location)
    return {
        'display_name': display_name,
        'date_added': get_default_time_display(date),
        'url': asset_url,
        'portable_url': StaticContent.get_static_path_from_location(location),
        'thumbnail': StaticContent.get_url_path_from_location(thumbnail_location) if thumbnail_location is not None else None,
        'locked': locked,
        # Needed for Backbone delete/update.
        'id': asset_url
    }
Beispiel #13
0
def _get_asset_json(display_name, date, location, thumbnail_location, locked):
    """
    Helper method for formatting the asset information to send to client.
    """
    asset_url = StaticContent.get_url_path_from_location(location)
    return {
        'display_name': display_name,
        'date_added': get_default_time_display(date),
        'url': asset_url,
        'portable_url': StaticContent.get_static_path_from_location(location),
        'thumbnail': StaticContent.get_url_path_from_location(thumbnail_location) if thumbnail_location is not None else None,
        'locked': locked,
        # Needed for Backbone delete/update.
        'id': asset_url
    }
Beispiel #14
0
def asset_index(request, org, course, name):
    """
    Display an editable asset library

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

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

    course_module = modulestore().get_item(location)

    course_reference = StaticContent.compute_location(org, course, name)
    assets = contentstore().get_all_content_for_course(course_reference)

    # sort in reverse upload date order
    assets = sorted(assets, key=lambda asset: asset["uploadDate"], reverse=True)

    asset_display = []
    for asset in assets:
        asset_id = asset["_id"]
        display_info = {}
        display_info["displayname"] = asset["displayname"]
        display_info["uploadDate"] = get_default_time_display(asset["uploadDate"].timetuple())

        asset_location = StaticContent.compute_location(asset_id["org"], asset_id["course"], asset_id["name"])
        display_info["url"] = StaticContent.get_url_path_from_location(asset_location)

        # note, due to the schema change we may not have a 'thumbnail_location' in the result set
        _thumbnail_location = asset.get("thumbnail_location", None)
        thumbnail_location = Location(_thumbnail_location) if _thumbnail_location is not None else None
        display_info["thumb_url"] = (
            StaticContent.get_url_path_from_location(thumbnail_location) if thumbnail_location is not None else None
        )

        asset_display.append(display_info)

    return render_to_response(
        "asset_index.html",
        {
            "active_tab": "assets",
            "context_course": course_module,
            "assets": asset_display,
            "upload_asset_callback_url": upload_asset_callback_url,
        },
    )
Beispiel #15
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
    })
Beispiel #16
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,
        })
Beispiel #17
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
    )

    # Note that the unit_state (draft, public, private) does not match up with the published value
    # passed to translate_location. The two concepts are different at this point.
    unit_locator = loc_mapper().translate_location(
        course.location.course_id, Location(location), False, True
    )

    component_templates = defaultdict(list)
    for category in COMPONENT_TYPES:
        component_class = load_mixed_class(category)
        # add the default template
        # TODO: Once mixins are defined per-application, rather than per-runtime,
        # this should use a cms mixed-in class. (cpennington)
        if hasattr(component_class, 'display_name'):
            display_name = component_class.display_name.default or 'Blank'
        else:
            display_name = 'Blank'
        component_templates[category].append((
            display_name,
            category,
            False,  # No defaults have markdown (hardcoded current default)
            None  # no boilerplate for overrides
        ))
        # add boilerplates
        if hasattr(component_class, 'templates'):
            for template in component_class.templates():
                filter_templates = getattr(component_class, 'filter_templates', None)
                if not filter_templates or filter_templates(template, course):
                    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 = load_mixed_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! %s",
            course_advanced_keys
        )

    components = [
        [
            component.location.url(),
            loc_mapper().translate_location(
                course.location.course_id, component.location, False, True
            )
        ]
        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
    )

    return render_to_response('unit.html', {
        'context_course': course,
        'unit': item,
        # Still needed for creating a draft.
        'unit_location': location,
        'unit_locator': unit_locator,
        '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.start)
            if containing_subsection.start is not None else None
        ),
        'section': containing_section,
        'new_unit_category': 'vertical',
        'unit_state': compute_unit_state(item),
        'published_date': (
            get_default_time_display(item.published_date)
            if item.published_date is not None else None
        ),
    })
Beispiel #18
0
 def registration_end_date_text(self):
     return date_utils.get_default_time_display(
         self.registration_end_date)
Beispiel #19
0
 def registration_end_date_text(self):
     return date_utils.get_default_time_display(self.registration_end_date)
Beispiel #20
0
def upload_asset(request, org, course, coursename):
    """
    cdodge: this method allows for POST uploading of files into the course asset library, which will
    be supported by GridFS in MongoDB.
    """
    if request.method != "POST":
        # (cdodge) @todo: Is there a way to do a - say - 'raise Http400'?
        return HttpResponseBadRequest()

    # construct a location from the passed in path
    location = get_location_and_verify_access(request, org, course, coursename)

    # Does the course actually exist?!? Get anything from it to prove its existance

    try:
        modulestore().get_item(location)
    except:
        # no return it as a Bad Request response
        logging.error("Could not find course" + location)
        return HttpResponseBadRequest()

    # compute a 'filename' which is similar to the location formatting, we're using the 'filename'
    # nomenclature since we're using a FileSystem paradigm here. We're just imposing
    # the Location string formatting expectations to keep things a bit more consistent

    filename = request.FILES["file"].name
    mime_type = request.FILES["file"].content_type
    filedata = request.FILES["file"].read()

    content_loc = StaticContent.compute_location(org, course, filename)
    content = StaticContent(content_loc, filename, mime_type, filedata)

    # first let's see if a thumbnail can be created
    (thumbnail_content, thumbnail_location) = contentstore().generate_thumbnail(content)

    # delete cached thumbnail even if one couldn't be created this time (else the old thumbnail will continue to show)
    del_cached_content(thumbnail_location)
    # now store thumbnail location only if we could create it
    if thumbnail_content is not None:
        content.thumbnail_location = thumbnail_location

    # then commit the content
    contentstore().save(content)
    del_cached_content(content.location)

    # readback the saved content - we need the database timestamp
    readback = contentstore().find(content.location)

    response_payload = {
        "displayname": content.name,
        "uploadDate": get_default_time_display(readback.last_modified_at.timetuple()),
        "url": StaticContent.get_url_path_from_location(content.location),
        "thumb_url": StaticContent.get_url_path_from_location(thumbnail_location)
        if thumbnail_content is not None
        else None,
        "msg": "Upload completed",
    }

    response = HttpResponse(json.dumps(response_payload))
    response["asset_url"] = StaticContent.get_url_path_from_location(content.location)
    return response
Beispiel #21
0
def unit_handler(request,
                 tag=None,
                 course_id=None,
                 branch=None,
                 version_guid=None,
                 block=None):
    """
    The restful handler for unit-specific requests.

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

        component_templates = defaultdict(list)
        for category in COMPONENT_TYPES:
            component_class = _load_mixed_class(category)
            # add the default template
            # TODO: Once mixins are defined per-application, rather than per-runtime,
            # this should use a cms mixed-in class. (cpennington)
            if hasattr(component_class, 'display_name'):
                display_name = component_class.display_name.default or 'Blank'
            else:
                display_name = 'Blank'
            component_templates[category].append((
                display_name,
                category,
                False,  # No defaults have markdown (hardcoded current default)
                None  # no boilerplate for overrides
            ))
            # add boilerplates
            if hasattr(component_class, 'templates'):
                for template in component_class.templates():
                    filter_templates = getattr(component_class,
                                               'filter_templates', None)
                    if not filter_templates or filter_templates(
                            template, course):
                        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 = _load_mixed_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! %s",
                      course_advanced_keys)

        components = [
            loc_mapper().translate_location(course.location.course_id,
                                            component.location, False, True)
            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(
            old_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.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)

        return render_to_response(
            'unit.html', {
                'context_course':
                course,
                'unit':
                item,
                'unit_locator':
                locator,
                '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.start)
                 if containing_subsection.start is not None else None),
                'section':
                containing_section,
                'new_unit_category':
                'vertical',
                'unit_state':
                compute_unit_state(item),
                'published_date':
                (get_default_time_display(item.published_date)
                 if item.published_date is not None else None),
            })
    else:
        return HttpResponseBadRequest("Only supports html requests")
Beispiel #22
0
def upload_asset(request, org, course, coursename):
    '''
    This method allows for POST uploading of files into the course asset
    library, which will be supported by GridFS in MongoDB.
    '''
    # construct a location from the passed in path
    location = get_location_and_verify_access(request, org, course, coursename)

    # Does the course actually exist?!? Get anything from it to prove its
    # existence
    try:
        modulestore().get_item(location)
    except:
        # no return it as a Bad Request response
        logging.error('Could not find course' + location)
        return HttpResponseBadRequest()

    if 'file' not in request.FILES:
        return HttpResponseBadRequest()

    # compute a 'filename' which is similar to the location formatting, we're
    # using the 'filename' nomenclature since we're using a FileSystem paradigm
    # here. We're just imposing the Location string formatting expectations to
    # keep things a bit more consistent
    upload_file = request.FILES['file']
    filename = upload_file.name
    mime_type = upload_file.content_type

    content_loc = StaticContent.compute_location(org, course, filename)

    chunked = upload_file.multiple_chunks()
    sc_partial = partial(StaticContent, content_loc, filename, mime_type)
    if chunked:
        content = sc_partial(upload_file.chunks())
        tempfile_path = upload_file.temporary_file_path()
    else:
        content = sc_partial(upload_file.read())
        tempfile_path = None

    thumbnail_content = None
    thumbnail_location = None

    # first let's see if a thumbnail can be created
    (thumbnail_content, thumbnail_location) = contentstore().generate_thumbnail(
            content,
            tempfile_path=tempfile_path
    )

    # delete cached thumbnail even if one couldn't be created this time (else
    # the old thumbnail will continue to show)
    del_cached_content(thumbnail_location)
    # now store thumbnail location only if we could create it
    if thumbnail_content is not None:
        content.thumbnail_location = thumbnail_location

    # then commit the content
    contentstore().save(content)
    del_cached_content(content.location)

    # readback the saved content - we need the database timestamp
    readback = contentstore().find(content.location)

    response_payload = {
            'displayname': content.name,
            'uploadDate': get_default_time_display(readback.last_modified_at),
            'url': StaticContent.get_url_path_from_location(content.location),
            'portable_url': StaticContent.get_static_path_from_location(content.location),
            'thumb_url': StaticContent.get_url_path_from_location(thumbnail_location)
                if thumbnail_content is not None else None,
            'msg': 'Upload completed'
    }

    response = JsonResponse(response_payload)
    return response
Beispiel #23
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! {0}".format(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,
        },
    )
Beispiel #24
0
def unit_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
    """
    The restful handler for unit-specific requests.

    GET
        html: return html page for editing a unit
        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()

        component_templates = defaultdict(list)
        for category in COMPONENT_TYPES:
            component_class = _load_mixed_class(category)
            # add the default template
            # TODO: Once mixins are defined per-application, rather than per-runtime,
            # this should use a cms mixed-in class. (cpennington)
            if hasattr(component_class, 'display_name'):
                display_name = component_class.display_name.default or 'Blank'
            else:
                display_name = 'Blank'
            component_templates[category].append((
                display_name,
                category,
                False,  # No defaults have markdown (hardcoded current default)
                None  # no boilerplate for overrides
            ))
            # add boilerplates
            if hasattr(component_class, 'templates'):
                for template in component_class.templates():
                    filter_templates = getattr(component_class, 'filter_templates', None)
                    if not filter_templates or filter_templates(template, course):
                        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 = _load_mixed_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! %s",
                course_advanced_keys
            )

        components = [
            loc_mapper().translate_location(
                course.location.course_id, component.location, False, True
            )
            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(old_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.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
        )

        return render_to_response('unit.html', {
            'context_course': course,
            'unit': item,
            'unit_locator': locator,
            '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.start)
                if containing_subsection.start is not None else None
            ),
            'section': containing_section,
            'new_unit_category': 'vertical',
            'unit_state': compute_unit_state(item),
            'published_date': (
                get_default_time_display(item.published_date)
                if item.published_date is not None else None
            ),
        })
    else:
        return HttpResponseBadRequest("Only supports html requests")
Beispiel #25
0
def upload_asset(request, org, course, coursename):
    '''
    This method allows for POST uploading of files into the course asset
    library, which will be supported by GridFS in MongoDB.
    '''
    # construct a location from the passed in path
    location = get_location_and_verify_access(request, org, course, coursename)

    # Does the course actually exist?!? Get anything from it to prove its
    # existence
    try:
        modulestore().get_item(location)
    except:
        # no return it as a Bad Request response
        logging.error('Could not find course' + location)
        return HttpResponseBadRequest()

    if 'files[]' not in request.FILES:
        return HttpResponseBadRequest()

    # compute a 'filename' which is similar to the location formatting, we're
    # using the 'filename' nomenclature since we're using a FileSystem paradigm
    # here. We're just imposing the Location string formatting expectations to
    # keep things a bit more consistent
    upload_file = request.FILES['files[]']
    filename = upload_file.name
    mime_type = upload_file.content_type

    content_loc = StaticContent.compute_location(org, course, filename)

    chunked = upload_file.multiple_chunks()
    sc_partial = partial(StaticContent, content_loc, filename, mime_type)
    if chunked:
        content = sc_partial(upload_file.chunks())
        tempfile_path = upload_file.temporary_file_path()
    else:
        content = sc_partial(upload_file.read())
        tempfile_path = None

    thumbnail_content = None
    thumbnail_location = None

    # first let's see if a thumbnail can be created
    (thumbnail_content, thumbnail_location) = contentstore().generate_thumbnail(
            content,
            tempfile_path=tempfile_path
    )

    # delete cached thumbnail even if one couldn't be created this time (else
    # the old thumbnail will continue to show)
    del_cached_content(thumbnail_location)
    # now store thumbnail location only if we could create it
    if thumbnail_content is not None:
        content.thumbnail_location = thumbnail_location

    # then commit the content
    contentstore().save(content)
    del_cached_content(content.location)

    # readback the saved content - we need the database timestamp
    readback = contentstore().find(content.location)

    response_payload = {
            'displayname': content.name,
            'uploadDate': get_default_time_display(readback.last_modified_at),
            'url': StaticContent.get_url_path_from_location(content.location),
            'portable_url': StaticContent.get_static_path_from_location(content.location),
            'thumb_url': StaticContent.get_url_path_from_location(thumbnail_location)
                if thumbnail_content is not None else None,
            'msg': 'Upload completed'
    }

    response = JsonResponse(response_payload)
    return response
Beispiel #26
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
    """
    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(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,
    })
Beispiel #27
0
def upload_asset(request, org, course, coursename):
    '''
    cdodge: this method allows for POST uploading of files into the course asset library, which will
    be supported by GridFS in MongoDB.
    '''
    if request.method != 'POST':
        # (cdodge) @todo: Is there a way to do a - say - 'raise Http400'?
        return HttpResponseBadRequest()

    # construct a location from the passed in path
    location = get_location_and_verify_access(request, org, course, coursename)

    # Does the course actually exist?!? Get anything from it to prove its existance

    try:
        modulestore().get_item(location)
    except:
        # no return it as a Bad Request response
        logging.error('Could not find course' + location)
        return HttpResponseBadRequest()

    if 'file' not in request.FILES:
        return HttpResponseBadRequest()

    # compute a 'filename' which is similar to the location formatting, we're using the 'filename'
    # nomenclature since we're using a FileSystem paradigm here. We're just imposing
    # the Location string formatting expectations to keep things a bit more consistent

    filename = request.FILES['file'].name
    mime_type = request.FILES['file'].content_type
    filedata = request.FILES['file'].read()

    content_loc = StaticContent.compute_location(org, course, filename)
    content = StaticContent(content_loc, filename, mime_type, filedata)

    # first let's see if a thumbnail can be created
    (thumbnail_content,
     thumbnail_location) = contentstore().generate_thumbnail(content)

    # delete cached thumbnail even if one couldn't be created this time (else the old thumbnail will continue to show)
    del_cached_content(thumbnail_location)
    # now store thumbnail location only if we could create it
    if thumbnail_content is not None:
        content.thumbnail_location = thumbnail_location

    # then commit the content
    contentstore().save(content)
    del_cached_content(content.location)

    # readback the saved content - we need the database timestamp
    readback = contentstore().find(content.location)

    response_payload = {
        'displayname':
        content.name,
        'uploadDate':
        get_default_time_display(readback.last_modified_at),
        'url':
        StaticContent.get_url_path_from_location(content.location),
        'thumb_url':
        StaticContent.get_url_path_from_location(thumbnail_location)
        if thumbnail_content is not None else None,
        'msg':
        'Upload completed'
    }

    response = HttpResponse(json.dumps(response_payload))
    response['asset_url'] = StaticContent.get_url_path_from_location(
        content.location)
    return response