def create_module(descriptor): '''creates an XModule instance given a descriptor''' # TODO: We need the request to pass into here. If we could forego that, our arguments # would be simpler with manual_transaction(): field_data_cache = FieldDataCache([descriptor], course.id, student) return get_module_for_descriptor(student, request, descriptor, field_data_cache, course.id)
def get_course_info_section(request, course, section_key): """ This returns the snippet of html to be rendered on the course info page, given the key for the section. Valid keys: - handouts - guest_handouts - updates - guest_updates """ usage_key = course.id.make_usage_key('course_info', section_key) # Use an empty cache field_data_cache = FieldDataCache([], course.id, request.user) info_module = get_module(request.user, request, usage_key, field_data_cache, log_if_not_found=False, wrap_xmodule_display=False, static_asset_path=course.static_asset_path) html = '' if info_module is not None: try: html = info_module.render(STUDENT_VIEW).content except Exception: # pylint: disable=broad-except html = render_to_string('courseware/error-message.html', None) log.exception( u"Error rendering course={course}, section_key={section_key}". format(course=course, section_key=section_key)) return html
def get_course_info_section(request, course, section_key): """ This returns the snippet of html to be rendered on the course info page, given the key for the section. Valid keys: - handouts - guest_handouts - updates - guest_updates """ loc = Location(course.location.tag, course.location.org, course.location.course, 'course_info', section_key) # Use an empty cache field_data_cache = FieldDataCache([], course.id, request.user) info_module = get_module( request.user, request, loc, field_data_cache, course.id, wrap_xmodule_display=False, static_asset_path=course.static_asset_path ) html = '' if info_module is not None: html = info_module.runtime.render(info_module, None, 'student_view').content return html
def setUp(self): super(TestInvalidScopes, self).setUp() self.user = UserFactory.create(username='******') self.field_data_cache = FieldDataCache( [mock_descriptor([mock_field(Scope.user_state, 'a_field')])], course_id, self.user) self.kvs = DjangoKeyValueStore(self.field_data_cache)
def get_course_info_section_module(request, course, section_key): """ This returns the course info module for a given section_key. Valid keys: - handouts - guest_handouts - updates - guest_updates """ usage_key = course.id.make_usage_key('course_info', section_key) # Use an empty cache field_data_cache = FieldDataCache([], course.id, request.user) return get_module( request.user, request, usage_key, field_data_cache, log_if_not_found=False, wrap_xmodule_display=False, static_asset_path=course.static_asset_path, course=course )
def edxnotes_visibility(request, course_id): """ Handle ajax call from "Show notes" checkbox. """ course_key = CourseKey.from_string(course_id) course = get_course_with_access(request.user, "load", course_key) field_data_cache = FieldDataCache([course], course_key, request.user) course_module = get_module_for_descriptor(request.user, request, course, field_data_cache, course_key, course=course) if not is_feature_enabled(course, request.user): raise Http404 try: visibility = json.loads(request.body)["visibility"] course_module.edxnotes_visibility = visibility course_module.save() return JsonResponse(status=200) except (ValueError, KeyError): log.warning( "Could not decode request body as JSON and find a boolean visibility field: '%s'", request.body) return JsonResponseBadRequest()
def inner_get_module(descriptor): """ Delegate to get_module_for_descriptor. """ field_data_cache = FieldDataCache([descriptor], course.id, request.user) return get_module_for_descriptor(request.user, request, descriptor, field_data_cache, course.id)
def get_course_child_content(request, user, course_key, child_descriptor): """ Returns course child content """ field_data_cache = FieldDataCache([child_descriptor], course_key, user) child_content = module_render.get_module_for_descriptor( user, request, child_descriptor, field_data_cache, course_key) return child_content
def get_course_content(request, user, course_key, course_descriptor): # pylint: disable=W0613 """ Returns course content """ field_data_cache = FieldDataCache([course_descriptor], course_key, user) course_content = module_render.get_module_for_descriptor( user, request, course_descriptor, field_data_cache, course_key) return course_content
def _get_course_module(self): """ Returns the course module. """ field_data_cache = FieldDataCache([self.course], self.course.id, self.user) return get_module_for_descriptor(self.user, MagicMock(), self.course, field_data_cache, self.course.id)
def setUp(self): self.user = UserFactory.create(username='******') self.assertEqual( self.user.id, 1) # check our assumption hard-coded in the key functions above. self.field_data_cache = FieldDataCache([mock_descriptor()], course_id, self.user) self.kvs = DjangoKeyValueStore(self.field_data_cache)
def get_module_for_student(student, course, location): """Return the module for the (student, location) using a DummyRequest.""" request = DummyRequest() request.user = student descriptor = modulestore().get_instance(course.id, location, depth=0) field_data_cache = FieldDataCache([descriptor], course.id, student) return get_module(student, request, location, field_data_cache, course.id)
def inner_get_module(descriptor): """ Delegate to get_module_for_descriptor (imported here to avoid circular reference) """ from courseware.module_render import get_module_for_descriptor field_data_cache = FieldDataCache([descriptor], course.id, request.user) return get_module_for_descriptor(request.user, request, descriptor, field_data_cache, course.id)
def get_module_for_student(student, usage_key, request=None): """Return the module for the (student, location) using a DummyRequest.""" if request is None: request = DummyRequest() request.user = student descriptor = modulestore().get_item(usage_key, depth=0) field_data_cache = FieldDataCache([descriptor], usage_key.course_key, student) return get_module(student, request, usage_key, field_data_cache)
def setUp(self): field_storage = self.factory.create() if hasattr(field_storage, 'student'): self.user = field_storage.student else: self.user = UserFactory.create() self.mock_descriptor = mock_descriptor([ mock_field(self.scope, 'existing_field'), mock_field(self.scope, 'other_existing_field')]) self.field_data_cache = FieldDataCache([self.mock_descriptor], course_id, self.user) self.kvs = DjangoKeyValueStore(self.field_data_cache)
def inner_get_module(descriptor): """ Delegate to get_module_for_descriptor """ field_data_cache = FieldDataCache([descriptor], course.id, user) return get_module_for_descriptor(user, _get_mock_request(user), descriptor, field_data_cache, course.id, course=course)
def setUp(self): student_module = StudentModuleFactory( state=json.dumps({ 'a_field': 'a_value', 'b_field': 'b_value' })) self.user = student_module.student self.field_data_cache = FieldDataCache( [mock_descriptor([mock_field(Scope.user_state, 'a_field')])], course_id, self.user) self.kvs = DjangoKeyValueStore(self.field_data_cache)
def test_rebinding_same_user(self, block_type): request = self.request_factory.get('') request.user = self.mock_user course = CourseFactory() descriptor = ItemFactory(category=block_type, parent=course) field_data_cache = FieldDataCache([self.toy_course, descriptor], self.toy_course.id, self.mock_user) render.get_module_for_descriptor(self.mock_user, request, descriptor, field_data_cache, self.toy_course.id) render.get_module_for_descriptor(self.mock_user, request, descriptor, field_data_cache, self.toy_course.id)
def test_changing_position_works(self): # Make a mock FieldDataCache for this course, so we can get the course module mock_field_data_cache = FieldDataCache([self.course], self.course.id, self.student) course = get_module_for_descriptor(self.student, MagicMock(name='request'), self.course, mock_field_data_cache, self.course.id) # Now that we have the course, change the position and save, nothing should explode! course.position = 2 course.save()
def setUp(self): super(TestMissingStudentModule, self).setUp() self.user = UserFactory.create(username='******') self.assertEqual( self.user.id, 1) # check our assumption hard-coded in the key functions above. # The descriptor has no fields, so FDC shouldn't send any queries with self.assertNumQueries(0): self.field_data_cache = FieldDataCache([mock_descriptor()], course_id, self.user) self.kvs = DjangoKeyValueStore(self.field_data_cache)
def create_module(descriptor): '''creates an XModule instance given a descriptor''' with manual_transaction(): field_data_cache = FieldDataCache([descriptor], course.id, student) # don't need tracking/xqueue but we have to pass something return get_module_for_descriptor_internal( student, descriptor, field_data_cache, course.id, track_function=noop_track_function, # dummy xqueue_callback_url_prefix='', # dummy request_token='') # dummy
def setUp(self): student_module = StudentModuleFactory( state=json.dumps({ 'a_field': 'a_value', 'b_field': 'b_value' })) self.user = student_module.student self.assertEqual( self.user.id, 1) # check our assumption hard-coded in the key functions above. self.field_data_cache = FieldDataCache( [mock_descriptor([mock_field(Scope.user_state, 'a_field')])], course_id, self.user) self.kvs = DjangoKeyValueStore(self.field_data_cache)
def mobi_course_action(request, course_id, action): try: course_id_bak = course_id.replace('.', '/') if action in ["updates", "handouts", "structure"]: user = request.user if not user: user = AnonymousUser() course = get_course_with_access(user, course_id_bak, 'load') registered = registered_for_course(course, user) if action == "updates" and registered: # course_updates = get_course_info_section(request, course, action) loc = Location(course.location.tag, course.location.org, course.location.course, 'course_info', action) field_data_cache = FieldDataCache([], course.id, request.user) course_module = get_module( user, request, loc, field_data_cache, course.id, wrap_xmodule_display=False, static_asset_path=course.static_asset_path) return JsonResponse({ 'updates': [ item for item in course_module.items if item["status"] != "deleted" ] }) elif action == "handouts" and registered: course_handouts = get_course_info_section( request, course, action) return JsonResponse({"handouts": course_handouts}) elif action == "structure": url_name = request.get_host( ) + '/m/courses/' + course_id_bak + '/courseware' return JsonResponse( _course_json(course=course, course_id=course.location.course_id, url_name=url_name)) else: raise Exception else: course = get_course_with_access(request.user, course_id_bak, 'see_exists') return JsonResponse(mobi_course_info(request, course)) except: return JsonResponse({"success": False, "errmsg": "access denied!"})
def setUp(self): field_storage = self.factory.create() if hasattr(field_storage, 'student'): self.user = field_storage.student else: self.user = UserFactory.create() self.mock_descriptor = mock_descriptor([ mock_field(self.scope, 'existing_field'), mock_field(self.scope, 'other_existing_field') ]) # Each field is stored as a separate row in the table, # but we can query them in a single query with self.assertNumQueries(1): self.field_data_cache = FieldDataCache([self.mock_descriptor], course_id, self.user) self.kvs = DjangoKeyValueStore(self.field_data_cache)
def _init_field_data_for_block(self, block): """ Initialize the FieldData implementation for the specified XBlock """ if self.user is None: # No user is specified, so we want to throw an error if anything attempts to read/write user-specific fields student_data_store = None elif self.user.is_anonymous: # The user is anonymous. Future work will support saving their state # in a cache or the django session but for now just use a highly # ephemeral dict. student_data_store = KvsFieldData(kvs=DictKeyValueStore()) elif self.system.student_data_mode == XBlockRuntimeSystem.STUDENT_DATA_EPHEMERAL: # We're in an environment like Studio where we want to let the # author test blocks out but not permanently save their state. # This in-memory dict will typically only persist for one # request-response cycle, so we need to soon replace it with a store # that puts the state into a cache or the django session. student_data_store = KvsFieldData(kvs=DictKeyValueStore()) else: # Use database-backed field data (i.e. store user_state in StudentModule) context_key = block.scope_ids.usage_id.context_key if context_key not in self.django_field_data_caches: field_data_cache = FieldDataCache( [block], course_id=context_key, user=self.user, asides=None, read_only=False, ) self.django_field_data_caches[context_key] = field_data_cache else: field_data_cache = self.django_field_data_caches[context_key] field_data_cache.add_descriptors_to_cache([block]) student_data_store = KvsFieldData( kvs=DjangoKeyValueStore(field_data_cache)) return SplitFieldData({ Scope.content: self.system.authored_data_store, Scope.settings: self.system.authored_data_store, Scope.parent: self.system.authored_data_store, Scope.children: self.system.authored_data_store, Scope.user_state_summary: student_data_store, Scope.user_state: student_data_store, Scope.user_info: student_data_store, Scope.preferences: student_data_store, })
def test_event_publishing(self, block_type, mock_track_function): request = self.request_factory.get('') request.user = self.mock_user course = CourseFactory() descriptor = ItemFactory(category=block_type, parent=course) field_data_cache = FieldDataCache([course, descriptor], course.id, self.mock_user) # pylint: disable=no-member block = render.get_module(self.mock_user, request, descriptor.location, field_data_cache) event_type = 'event_type' event = {'event': 'data'} block.runtime.publish(block, event_type, event) mock_track_function.assert_called_once_with(request) mock_track_function.return_value.assert_called_once_with( event_type, event)
def setUp(self): super(TestStudentModuleStorage, self).setUp() student_module = StudentModuleFactory( state=json.dumps({ 'a_field': 'a_value', 'b_field': 'b_value' })) self.user = student_module.student self.assertEqual( self.user.id, 1) # check our assumption hard-coded in the key functions above. # There should be only one query to load a single descriptor with a single user_state field with self.assertNumQueries(1): self.field_data_cache = FieldDataCache( [mock_descriptor([mock_field(Scope.user_state, 'a_field')])], course_id, self.user) self.kvs = DjangoKeyValueStore(self.field_data_cache)
def yield_problems(request, course, student): """ Return an iterator over capa_modules that this student has potentially answered. (all that student has answered will definitely be in the list, but there may be others as well). """ grading_context = course.grading_context descriptor_locations = ( descriptor.location.url() for descriptor in grading_context['all_descriptors']) existing_student_modules = set( StudentModule.objects.filter( module_state_key__in=descriptor_locations).values_list( 'module_state_key', flat=True)) sections_to_list = [] for _, sections in grading_context['graded_sections'].iteritems(): for section in sections: section_descriptor = section['section_descriptor'] # If the student hasn't seen a single problem in the section, skip it. for moduledescriptor in section['xmoduledescriptors']: if moduledescriptor.location.url() in existing_student_modules: sections_to_list.append(section_descriptor) break field_data_cache = FieldDataCache(sections_to_list, course.id, student) for section_descriptor in sections_to_list: section_module = get_module(student, request, section_descriptor.location, field_data_cache, course.id) if section_module is None: # student doesn't have access to this module, or something else # went wrong. # log.debug("couldn't get module for student {0} for section location {1}" # .format(student.username, section_descriptor.location)) continue for problem in yield_module_descendents(section_module): if isinstance(problem, CapaModule): yield problem
def get_course_about_section(course, section_key): """ This returns the snippet of html to be rendered on the course about page, given the key for the section. Valid keys: - overview - title - university - number - short_description - description - key_dates (includes start, end, exams, etc) - video - course_staff_short - course_staff_extended - requirements - syllabus - textbook - faq - more_info - ocw_links """ # Many of these are stored as html files instead of some semantic # markup. This can change without effecting this interface when we find a # good format for defining so many snippets of text/html. # TODO: Remove number, instructors from this list if section_key in ['short_description', 'description', 'key_dates', 'video', 'course_staff_short', 'course_staff_extended', 'requirements', 'syllabus', 'textbook', 'faq', 'more_info', 'number', 'instructors', 'overview', 'effort', 'end_date', 'prerequisites', 'ocw_links']: try: request = get_request_for_thread() loc = course.location.replace(category='about', name=section_key) # Use an empty cache field_data_cache = FieldDataCache([], course.id, request.user) about_module = get_module( request.user, request, loc, field_data_cache, log_if_not_found=False, wrap_xmodule_display=False, static_asset_path=course.static_asset_path ) html = '' if about_module is not None: try: html = about_module.render(STUDENT_VIEW).content except Exception: # pylint: disable=broad-except html = render_to_string('courseware/error-message.html', None) log.exception( u"Error rendering course={course}, section_key={section_key}".format( course=course, section_key=section_key )) return html except ItemNotFoundError: log.warning( u"Missing about section {key} in course {url}".format(key=section_key, url=course.location.to_deprecated_string()) ) return None elif section_key == "title": return course.display_name_with_default elif section_key == "university": return course.display_org_with_default elif section_key == "number": return course.display_number_with_default raise KeyError("Invalid about key " + str(section_key))
def grade(student, request, course, field_data_cache=None, keep_raw_scores=False): """ This grades a student as quickly as possible. It returns the output from the course grader, augmented with the final letter grade. The keys in the output are: course: a CourseDescriptor - grade : A final letter grade. - percent : The final percent for the class (rounded up). - section_breakdown : A breakdown of each section that makes up the grade. (For display) - grade_breakdown : A breakdown of the major components that make up the final grade. (For display) - keep_raw_scores : if True, then value for key 'raw_scores' contains scores for every graded module More information on the format is in the docstring for CourseGrader. """ grading_context = course.grading_context raw_scores = [] if field_data_cache is None: field_data_cache = FieldDataCache(grading_context['all_descriptors'], course.id, student) totaled_scores = {} # This next complicated loop is just to collect the totaled_scores, which is # passed to the grader for section_format, sections in grading_context[ 'graded_sections'].iteritems(): format_scores = [] for section in sections: section_descriptor = section['section_descriptor'] section_name = section_descriptor.display_name_with_default should_grade_section = False # If we haven't seen a single problem in the section, we don't have to grade it at all! We can assume 0% for moduledescriptor in section['xmoduledescriptors']: # some problems have state that is updated independently of interaction # with the LMS, so they need to always be scored. (E.g. foldit.) if moduledescriptor.always_recalculate_grades: should_grade_section = True break # Create a fake key to pull out a StudentModule object from the FieldDataCache key = DjangoKeyValueStore.Key(Scope.user_state, student.id, moduledescriptor.location, None) if field_data_cache.find(key): should_grade_section = True break if should_grade_section: scores = [] def create_module(descriptor): '''creates an XModule instance given a descriptor''' # TODO: We need the request to pass into here. If we could forego that, our arguments # would be simpler return get_module_for_descriptor(student, request, descriptor, field_data_cache, course.id) for module_descriptor in yield_dynamic_descriptor_descendents( section_descriptor, create_module): (correct, total) = get_score(course.id, student, module_descriptor, create_module, field_data_cache) if correct is None and total is None: continue if settings.GENERATE_PROFILE_SCORES: # for debugging! if total > 1: correct = random.randrange(max(total - 2, 1), total + 1) else: correct = total graded = module_descriptor.graded if not total > 0: #We simply cannot grade a problem that is 12/0, because we might need it as a percentage graded = False scores.append( Score(correct, total, graded, module_descriptor.display_name_with_default)) _, graded_total = graders.aggregate_scores( scores, section_name) if keep_raw_scores: raw_scores += scores else: graded_total = Score(0.0, 1.0, True, section_name) #Add the graded total to totaled_scores if graded_total.possible > 0: format_scores.append(graded_total) else: log.exception( "Unable to grade a section with a total possible score of zero. " + str(section_descriptor.location)) totaled_scores[section_format] = format_scores grade_summary = course.grader.grade( totaled_scores, generate_random_scores=settings.GENERATE_PROFILE_SCORES) # We round the grade here, to make sure that the grade is an whole percentage and # doesn't get displayed differently than it gets grades grade_summary['percent'] = round(grade_summary['percent'] * 100 + 0.05) / 100 letter_grade = grade_for_percentage(course.grade_cutoffs, grade_summary['percent']) grade_summary['grade'] = letter_grade grade_summary[ 'totaled_scores'] = totaled_scores # make this available, eg for instructor download & debugging if keep_raw_scores: grade_summary[ 'raw_scores'] = raw_scores # way to get all RAW scores out to instructor # so grader can be double-checked return grade_summary