def _fulfill_content_milestones(user, course_key, content_key): """ Internal helper to handle milestone fulfillments for the specified content module """ # Fulfillment Use Case: Entrance Exam # If this module is part of an entrance exam, we'll need to see if the student # has reached the point at which they can collect the associated milestone if milestones_helpers.is_entrance_exams_enabled(): course = modulestore().get_course(course_key) content = modulestore().get_item(content_key) entrance_exam_enabled = getattr(course, 'entrance_exam_enabled', False) in_entrance_exam = getattr(content, 'in_entrance_exam', False) if entrance_exam_enabled and in_entrance_exam: # We don't have access to the true request object in this context, but we can use a mock request = RequestFactory().request() request.user = user exam_pct = get_entrance_exam_score(request, course) if exam_pct >= course.entrance_exam_minimum_score_pct: exam_key = UsageKey.from_string(course.entrance_exam_id) relationship_types = milestones_helpers.get_milestone_relationship_types() content_milestones = milestones_helpers.get_course_content_milestones( course_key, exam_key, relationship=relationship_types['FULFILLS'] ) # Add each milestone to the user's set... user = {'id': request.user.id} for milestone in content_milestones: milestones_helpers.add_user_milestone(user, milestone)
def evaluate_entrance_exam(course_grade, user): """ Evaluates any entrance exam milestone relationships attached to the given course. If the course_grade meets the minimum score required, the dependent milestones will be marked fulfilled for the user. """ course = course_grade.course if milestones_helpers.is_entrance_exams_enabled() and getattr( course, 'entrance_exam_enabled', False): if get_entrance_exam_content(user, course): exam_chapter_key = get_entrance_exam_usage_key(course) exam_score_ratio = get_entrance_exam_score_ratio( course_grade, exam_chapter_key) if exam_score_ratio >= course.entrance_exam_minimum_score_pct: relationship_types = milestones_helpers.get_milestone_relationship_types( ) content_milestones = milestones_helpers.get_course_content_milestones( course.id, exam_chapter_key, relationship=relationship_types['FULFILLS']) # Mark each entrance exam dependent milestone as fulfilled by the user. for milestone in content_milestones: milestones_helpers.add_user_milestone({'id': user.id}, milestone)
def _filter_entrance_exam_grader(graders): """ If the entrance exams feature is enabled we need to hide away the grader from views/controls like the 'Grade as' dropdown that allows a course author to select the grader type for a given section of a course """ if is_entrance_exams_enabled(): graders = [grader for grader in graders if grader.get('type') != u'Entrance Exam'] return graders
def course_has_entrance_exam(course): """ Checks to see if a course is properly configured for an entrance exam """ if not is_entrance_exams_enabled(): return False if not course.entrance_exam_enabled: return False if not course.entrance_exam_id: return False return True
def course_has_entrance_exam(course): """ Checks to see if a course is properly configured for an entrance exam """ if not is_entrance_exams_enabled(): return False if not course.entrance_exam_enabled: return False if not course.entrance_exam_id: return False return True
def evaluate_entrance_exam(course_grade, user): """ Evaluates any entrance exam milestone relationships attached to the given course. If the course_grade meets the minimum score required, the dependent milestones will be marked fulfilled for the user. """ course = course_grade.course_data.course if milestones_helpers.is_entrance_exams_enabled() and getattr(course, 'entrance_exam_enabled', False): if get_entrance_exam_content(user, course): exam_chapter_key = get_entrance_exam_usage_key(course) exam_score_ratio = get_entrance_exam_score_ratio(course_grade, exam_chapter_key) if exam_score_ratio >= course.entrance_exam_minimum_score_pct: relationship_types = milestones_helpers.get_milestone_relationship_types() content_milestones = milestones_helpers.get_course_content_milestones( course.id, exam_chapter_key, relationship=relationship_types['FULFILLS'] ) # Mark each entrance exam dependent milestone as fulfilled by the user. for milestone in content_milestones: milestones_helpers.add_user_milestone({'id': user.id}, milestone)
def create_xblock(parent_locator, user, category, display_name, boilerplate=None, is_entrance_exam=False): """ Performs the actual grunt work of creating items/xblocks -- knows nothing about requests, views, etc. """ store = modulestore() usage_key = usage_key_with_run(parent_locator) with store.bulk_operations(usage_key.course_key): parent = store.get_item(usage_key) dest_usage_key = usage_key.replace(category=category, name=uuid4().hex) # get the metadata, display_name, and definition from the caller metadata = {} data = None template_id = boilerplate if template_id: clz = parent.runtime.load_block_type(category) if clz is not None: template = clz.get_template(template_id) if template is not None: metadata = template.get('metadata', {}) data = template.get('data') if display_name is not None: metadata['display_name'] = display_name # We should use the 'fields' kwarg for newer module settings/values (vs. metadata or data) fields = {} # Entrance Exams: Chapter module positioning child_position = None if is_entrance_exams_enabled(): if category == 'chapter' and is_entrance_exam: fields['is_entrance_exam'] = is_entrance_exam fields['in_entrance_exam'] = True # Inherited metadata, all children will have it child_position = 0 # TODO need to fix components that are sending definition_data as strings, instead of as dicts # For now, migrate them into dicts here. if isinstance(data, basestring): data = {'data': data} created_block = store.create_child( user.id, usage_key, dest_usage_key.block_type, block_id=dest_usage_key.block_id, fields=fields, definition_data=data, metadata=metadata, runtime=parent.runtime, position=child_position, ) # Entrance Exams: Grader assignment if is_entrance_exams_enabled(): course_key = usage_key.course_key course = store.get_course(course_key) if hasattr(course, 'entrance_exam_enabled') and course.entrance_exam_enabled: if category == 'sequential' and parent_locator == course.entrance_exam_id: # Clean up any pre-existing entrance exam graders remove_entrance_exam_graders(course_key, user) grader = { "type": GRADER_TYPES['ENTRANCE_EXAM'], "min_count": 0, "drop_count": 0, "short_label": "Entrance", "weight": 0 } grading_model = CourseGradingModel.update_grader_from_json( course.id, grader, user ) CourseGradingModel.update_section_grader_type( created_block, grading_model['type'], user ) # VS[compat] cdodge: This is a hack because static_tabs also have references from the course module, so # if we add one then we need to also add it to the policy information (i.e. metadata) # we should remove this once we can break this reference from the course to static tabs if category == 'static_tab': dog_stats_api.increment( DEPRECATION_VSCOMPAT_EVENT, tags=( "location:create_xblock_static_tab", u"course:{}".format(unicode(dest_usage_key.course_key)), ) ) display_name = display_name or _("Empty") # Prevent name being None course = store.get_course(dest_usage_key.course_key) course.tabs.append( StaticTab( name=display_name, url_slug=dest_usage_key.name, ) ) store.update_item(course, user.id) return created_block
def create_xblock(parent_locator, user, category, display_name, boilerplate=None, is_entrance_exam=False): """ Performs the actual grunt work of creating items/xblocks -- knows nothing about requests, views, etc. """ store = modulestore() usage_key = usage_key_with_run(parent_locator) with store.bulk_operations(usage_key.course_key): parent = store.get_item(usage_key) dest_usage_key = usage_key.replace(category=category, name=uuid4().hex) # get the metadata, display_name, and definition from the caller metadata = {} data = None template_id = boilerplate if template_id: clz = parent.runtime.load_block_type(category) if clz is not None: template = clz.get_template(template_id) if template is not None: metadata = template.get('metadata', {}) data = template.get('data') if display_name is not None: metadata['display_name'] = display_name # We should use the 'fields' kwarg for newer module settings/values (vs. metadata or data) fields = {} # Entrance Exams: Chapter module positioning child_position = None if is_entrance_exams_enabled(): if category == 'chapter' and is_entrance_exam: fields['is_entrance_exam'] = is_entrance_exam fields[ 'in_entrance_exam'] = True # Inherited metadata, all children will have it child_position = 0 # TODO need to fix components that are sending definition_data as strings, instead of as dicts # For now, migrate them into dicts here. if isinstance(data, basestring): data = {'data': data} created_block = store.create_child( user.id, usage_key, dest_usage_key.block_type, block_id=dest_usage_key.block_id, fields=fields, definition_data=data, metadata=metadata, runtime=parent.runtime, position=child_position, ) # Entrance Exams: Grader assignment if is_entrance_exams_enabled(): course_key = usage_key.course_key course = store.get_course(course_key) if hasattr( course, 'entrance_exam_enabled') and course.entrance_exam_enabled: if category == 'sequential' and parent_locator == course.entrance_exam_id: # Clean up any pre-existing entrance exam graders remove_entrance_exam_graders(course_key, user) grader = { "type": GRADER_TYPES['ENTRANCE_EXAM'], "min_count": 0, "drop_count": 0, "short_label": "Entrance", "weight": 0 } grading_model = CourseGradingModel.update_grader_from_json( course.id, grader, user) CourseGradingModel.update_section_grader_type( created_block, grading_model['type'], user) # VS[compat] cdodge: This is a hack because static_tabs also have references from the course module, so # if we add one then we need to also add it to the policy information (i.e. metadata) # we should remove this once we can break this reference from the course to static tabs if category == 'static_tab': dog_stats_api.increment( DEPRECATION_VSCOMPAT_EVENT, tags=( "location:create_xblock_static_tab", u"course:{}".format(unicode(dest_usage_key.course_key)), )) display_name = display_name or _( "Empty") # Prevent name being None course = store.get_course(dest_usage_key.course_key) course.tabs.append( StaticTab( name=display_name, url_slug=dest_usage_key.block_id, )) store.update_item(course, user.id) return created_block