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 })
def cache_metadata(obj, obj_type, location, course, modulestore): from contentstore.utils import get_lms_link_for_item from contentstore.utils import compute_unit_state, UnitState params = {} params['course'] = str(course.location) params['start'] = obj.start params['due'] = obj.due params['url'] = get_lms_link_for_item(location,course_id = course.location.course_id, preview=False) params['state'] = str(compute_unit_state(obj)) params['obj_type'] = obj_type params['title'] = obj.display_name if obj_type == 'video': params['video_url'] = str((obj.get_context())['transcripts_basic_tab_metadata']['video_url']['value']) # first see if exists already try: cache = XModule_Metadata_Cache.objects.get(url=params['url']) for attr, value in params.iteritems(): setattr(cache, attr, value) except XModule_Metadata_Cache.DoesNotExist: cache = XModule_Metadata_Cache(**params) cache.posted = False cache.save() return
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, })
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 course_locator = loc_mapper().translate_location( course.location.course_id, course.location, False, True ) locator = loc_mapper().translate_location( course.location.course_id, item.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 } )
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 ), })
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_unit_state(unit) if state == UnitState.public or state == UnitState.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")
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) xblocks = item.get_children() locators = [ loc_mapper().translate_location(course.location.course_id, xblock.location, False, True) for xblock in xblocks ] # 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 = get_parent_xblock(item) containing_section = get_parent_xblock(containing_subsection) # 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 = ( u"//{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, "locators": locators, "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")
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 %', location ) # this should blow up if we don't find any parents, which would be erroneous parent = modulestore().get_item(parent_locs[0]) sections = modulestore().get_item(course.location, depth=3).get_children() #for section in sections: # print section.display_name_with_default # subsections = section.get_children() # for subsection in subsections: # print subsection.display_name_with_default # 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', 'unlock_term'] and field.scope == Scope.settings ) #item.unlock_term = '{"disjunctions":[]}' term = json.loads(item.unlock_term) # updating if term has links to already not existed sections for disjunction in term["disjunctions"]: for conjunction in disjunction["conjunctions"]: if not is_section_exist(conjunction["source_section_id"], sections): disjunction["conjunctions"].remove(conjunction) item.unlock_term = json.dumps(term) 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, 'sections': sections, 'can_view_live': can_view_live })
def subsection_handler(request, tag=None, course_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(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() 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_locs = modulestore().get_parent_locations(old_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', unicode(locator) ) # 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 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")
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 {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, "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, }, )
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, }, )
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, })
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 })
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 } )
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_locs = modulestore().get_parent_locations(old_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', unicode(locator)) # 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 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")
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 = ( u'//{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")