def _verify_masquerade_for_group(self, group): """ Verify that the masquerade works for the specified group id. """ # Send the request to set the masquerade request_json = { "role": "student", "user_partition_id": self.user_partition.id, "group_id": group.id if group is not None else None } request = self._create_mock_json_request( self.test_user, data=request_json, session=self.session ) response = handle_ajax(request, unicode(self.course.id)) # pylint has issues analyzing this class (maybe due to circular imports?) self.assertEquals(response.status_code, 200) # pylint: disable=no-member # Now setup the masquerade for the test user setup_masquerade(request, self.course.id, True) scheme = self.user_partition.scheme self.assertEqual( scheme.get_group_for_user(self.course.id, self.test_user, self.user_partition), group )
def get_module_by_usage_id(request, course_id, usage_id, disable_staff_debug_info=False, course=None): """ Gets a module instance based on its `usage_id` in a course, for a given request/user Returns (instance, tracking_context) """ user = request.user try: course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id) usage_key = course_id.make_usage_key_from_deprecated_string(unquote_slashes(usage_id)) except InvalidKeyError: raise Http404("Invalid location") try: descriptor = modulestore().get_item(usage_key) descriptor_orig_usage_key, descriptor_orig_version = modulestore().get_block_original_usage(usage_key) except ItemNotFoundError: log.warn( "Invalid location for course id {course_id}: {usage_key}".format( course_id=usage_key.course_key, usage_key=usage_key ) ) raise Http404 tracking_context = { 'module': { 'display_name': descriptor.display_name_with_default, 'usage_key': unicode(descriptor.location), } } # For blocks that are inherited from a content library, we add some additional metadata: if descriptor_orig_usage_key is not None: tracking_context['module']['original_usage_key'] = unicode(descriptor_orig_usage_key) tracking_context['module']['original_usage_version'] = unicode(descriptor_orig_version) field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course_id, user, descriptor ) setup_masquerade(request, course_id, has_access(user, 'staff', descriptor, course_id)) instance = get_module_for_descriptor( user, request, descriptor, field_data_cache, usage_key.course_key, disable_staff_debug_info=disable_staff_debug_info, course=course ) if instance is None: # Either permissions just changed, or someone is trying to be clever # and load something they shouldn't have access to. log.debug("No module %s for user %s -- access denied?", usage_key, user) raise Http404 return (instance, tracking_context)
def masquerade_as_group_member(user, course, partition_id, group_id): """ Installs a masquerade for the specified user and course, to enable the user to masquerade as belonging to the specific partition/group combination. Arguments: user (User): a user. course (CourseDescriptor): a course. partition_id (int): the integer partition id, referring to partitions already configured in the course. group_id (int); the integer group id, within the specified partition. Returns: the status code for the AJAX response to update the user's masquerade for the specified course. """ request = _create_mock_json_request(user, data={ "role": "student", "user_partition_id": partition_id, "group_id": group_id }) response = handle_ajax(request, unicode(course.id)) setup_masquerade(request, course.id, True) return response.status_code
def _verify_masquerade_for_group(self, group): """ Verify that the masquerade works for the specified group id. """ # Send the request to set the masquerade request_json = { "role": "student", } if group and self.user_partition: request_json['user_partition_id'] = self.user_partition.id request_json['group_id'] = group.id request = self._create_mock_json_request( self.test_user, body=json.dumps(request_json), session=self.session ) handle_ajax(request, unicode(self.course.id)) # Now setup the masquerade for the test user setup_masquerade(request, self.test_user, True) scheme = self.user_partition.scheme # pylint: disable=no-member self.assertEqual( scheme.get_group_for_user(self.course.id, self.test_user, self.user_partition), group )
def get_module_for_descriptor(user, request, descriptor, field_data_cache, course_id, position=None, wrap_xmodule_display=True, grade_bucket_type=None, static_asset_path=''): """ Implements get_module, extracting out the request-specific functionality. See get_module() docstring for further details. """ # allow course staff to masquerade as student if has_access(user, descriptor, 'staff', course_id): setup_masquerade(request, True) track_function = make_track_function(request) xqueue_callback_url_prefix = get_xqueue_callback_url_prefix(request) return get_module_for_descriptor_internal( user, descriptor, field_data_cache, course_id, track_function, xqueue_callback_url_prefix, position, wrap_xmodule_display, grade_bucket_type, static_asset_path)
def get_module_for_descriptor( user, request, descriptor, field_data_cache, course_id, position=None, wrap_xmodule_display=True, grade_bucket_type=None, static_asset_path="", ): """ Implements get_module, extracting out the request-specific functionality. See get_module() docstring for further details. """ # allow course staff to masquerade as student if has_access(user, descriptor, "staff", course_id): setup_masquerade(request, True) track_function = make_track_function(request) xqueue_callback_url_prefix = get_xqueue_callback_url_prefix(request) return get_module_for_descriptor_internal( user, descriptor, field_data_cache, course_id, track_function, xqueue_callback_url_prefix, position, wrap_xmodule_display, grade_bucket_type, static_asset_path, )
def get_module_for_descriptor(user, request, descriptor, field_data_cache, course_id, position=None, wrap_xmodule_display=True, grade_bucket_type=None, static_asset_path=''): """ Implements get_module, extracting out the request-specific functionality. See get_module() docstring for further details. """ # allow course staff to masquerade as student if has_access(user, 'staff', descriptor, course_id): setup_masquerade(request, True) track_function = make_track_function(request) xqueue_callback_url_prefix = get_xqueue_callback_url_prefix(request) user_location = getattr(request, 'session', {}).get('country_code') return get_module_for_descriptor_internal( user=user, descriptor=descriptor, field_data_cache=field_data_cache, course_id=course_id, track_function=track_function, xqueue_callback_url_prefix=xqueue_callback_url_prefix, position=position, wrap_xmodule_display=wrap_xmodule_display, grade_bucket_type=grade_bucket_type, static_asset_path=static_asset_path, user_location=user_location, request_token=request_token(request), )
def initialize(self, **kwargs): if 'request' in kwargs and kwargs['request'] and kwargs['course_id']: request = kwargs['request'] try: course_key = CourseKey.from_string(kwargs['course_id']) except InvalidKeyError: course_key = SlashSeparatedCourseKey.from_deprecated_string(kwargs['course_id']) staff_access = bool(has_access(request.user, 'staff', course_key)) setup_masquerade(request, course_key, staff_access)
def initialize(self, **kwargs): if 'request' in kwargs and kwargs['request'] and kwargs['course_id']: request = kwargs['request'] try: course_key = CourseKey.from_string(kwargs['course_id']) except InvalidKeyError: course_key = SlashSeparatedCourseKey.from_deprecated_string(kwargs['course_id']) staff_access = has_access(request.user, 'staff', course_key) setup_masquerade(request, course_key, staff_access)
def get_module_by_usage_id(request, course_id, usage_id): """ Gets a module instance based on its `usage_id` in a course, for a given request/user Returns (instance, tracking_context) """ user = request.user try: course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id) usage_key = course_id.make_usage_key_from_deprecated_string( unquote_slashes(usage_id)) except InvalidKeyError: raise Http404("Invalid location") try: descriptor = modulestore().get_item(usage_key) descriptor_orig_usage_key, descriptor_orig_version = modulestore( ).get_block_original_usage(usage_key) except ItemNotFoundError: log.warn( "Invalid location for course id {course_id}: {usage_key}".format( course_id=usage_key.course_key, usage_key=usage_key)) raise Http404 tracking_context = { 'module': { 'display_name': descriptor.display_name_with_default, 'usage_key': unicode(descriptor.location), } } # For blocks that are inherited from a content library, we add some additional metadata: if descriptor_orig_usage_key is not None: tracking_context['module']['original_usage_key'] = unicode( descriptor_orig_usage_key) tracking_context['module']['original_usage_version'] = unicode( descriptor_orig_version) field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course_id, user, descriptor) setup_masquerade(request, course_id, has_access(user, 'staff', descriptor, course_id)) instance = get_module(user, request, usage_key, field_data_cache, grade_bucket_type='ajax') if instance is None: # Either permissions just changed, or someone is trying to be clever # and load something they shouldn't have access to. log.debug("No module %s for user %s -- access denied?", usage_key, user) raise Http404 return (instance, tracking_context)
def course_info(request, course_id): """ Display the course's info.html, or 404 if there is no such course. Assumes the course_id is in a valid format. """ course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course = get_course_with_access(request.user, "load", course_key) staff_access = has_access(request.user, "staff", course) masq = setup_masquerade(request, staff_access) # allow staff to toggle masquerade on info page reverifications = fetch_reverify_banner_info(request, course_key) studio_url = get_studio_url(course_key, "course_info") context = { "request": request, "course_id": course_key.to_deprecated_string(), "cache": None, "course": course, "staff_access": staff_access, "masquerade": masq, "studio_url": studio_url, "reverifications": reverifications, } return render_to_response("courseware/info.html", context)
def render_to_fragment(self, request, course_id, **kwargs): if(not _has_page_access(request.user, course_id)): raise Http404() course_key = CourseKey.from_string(course_id) course = get_course_with_access(request.user, "load", course_key) # masquerade and student required for preview_menu (admin) staff_access = bool(has_access(request.user, 'staff', course)) can_masquerade = request.user.has_perm(MASQUERADE_AS_STUDENT, course) masquerade, student = setup_masquerade(request, course_key, staff_access, reset_masquerade_data=True) prefetch_related_objects([student], 'groups') if request.user.id != student.id: course = get_course_with_access(student, 'load', course_key, check_if_enrolled=True) context = { "course": course, "student_id": student.id, "supports_preview_menu": True, "staff_access": staff_access, "can_masquerade": can_masquerade, "masquerade": masquerade, 'studio_url': get_studio_url(course, 'settings/grading'), "DEV_URL": configuration_helpers.get_value('EOL_PROGRESS_TAB_DEV_URL', settings.EOL_PROGRESS_TAB_DEV_URL) } html = render_to_string('eol_progress_tab/eol_progress_tab_fragment.html', context) fragment = Fragment(html) return fragment
def course_info(request, course_id): """ Display the course's info.html, or 404 if there is no such course. Assumes the course_id is in a valid format. """ course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course = get_course_with_access(request.user, 'load', course_key) staff_access = has_access(request.user, 'staff', course) masq = setup_masquerade(request, staff_access) # allow staff to toggle masquerade on info page reverifications = fetch_reverify_banner_info(request, course_key) studio_url = get_studio_url(course_key, 'course_info') context = { 'request': request, 'course_id': course_key.to_deprecated_string(), 'cache': None, 'course': course, 'staff_access': staff_access, 'masquerade': masq, 'studio_url': studio_url, 'reverifications': reverifications, } return render_to_response('courseware/info.html', context)
def course_info(request, course_id): """ Display the course's info.html, or 404 if there is no such course. Assumes the course_id is in a valid format. """ course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course = get_course_with_access(request.user, 'load', course_key) staff_access = has_access(request.user, 'staff', course) masq = setup_masquerade( request, staff_access) # allow staff to toggle masquerade on info page reverifications = fetch_reverify_banner_info(request, course_key) studio_url = get_studio_url(course_key, 'course_info') context = { 'request': request, 'course_id': course_key.to_deprecated_string(), 'cache': None, 'course': course, 'staff_access': staff_access, 'masquerade': masq, 'studio_url': studio_url, 'reverifications': reverifications, } return render_to_response('courseware/info.html', context)
def get_module_by_usage_id(request, course_id, usage_id, disable_staff_debug_info=False, course=None): """ Gets a module instance based on its `usage_id` in a course, for a given request/user Returns (instance, tracking_context) """ user = request.user try: course_id = CourseKey.from_string(course_id) usage_key = UsageKey.from_string(unquote_slashes(usage_id)).map_into_course(course_id) except InvalidKeyError: raise Http404("Invalid location") try: descriptor = modulestore().get_item(usage_key) descriptor_orig_usage_key, descriptor_orig_version = modulestore().get_block_original_usage(usage_key) except ItemNotFoundError: log.warn( "Invalid location for course id %s: %s", usage_key.course_key, usage_key ) raise Http404 tracking_context = { 'module': { 'display_name': descriptor.display_name_with_default_escaped, 'usage_key': unicode(descriptor.location), } } # For blocks that are inherited from a content library, we add some additional metadata: if descriptor_orig_usage_key is not None: tracking_context['module']['original_usage_key'] = unicode(descriptor_orig_usage_key) tracking_context['module']['original_usage_version'] = unicode(descriptor_orig_version) unused_masquerade, user = setup_masquerade(request, course_id, has_access(user, 'staff', descriptor, course_id)) field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course_id, user, descriptor, read_only=CrawlersConfig.is_crawler(request), ) instance = get_module_for_descriptor( user, request, descriptor, field_data_cache, usage_key.course_key, disable_staff_debug_info=disable_staff_debug_info, course=course ) if instance is None: # Either permissions just changed, or someone is trying to be clever # and load something they shouldn't have access to. log.debug("No module %s for user %s -- access denied?", usage_key, user) raise Http404 return (instance, tracking_context)
def _verify_masquerade_for_group(self, group): """ Verify that the masquerade works for the specified group id. """ # Send the request to set the masquerade request_json = { "role": "student", "user_partition_id": self.user_partition.id, "group_id": group.id if group is not None else None, } request = self._create_mock_json_request(self.test_user, body=json.dumps(request_json), session=self.session) handle_ajax(request, unicode(self.course.id)) # Now setup the masquerade for the test user setup_masquerade(request, self.test_user, True) scheme = self.user_partition.scheme self.assertEqual(scheme.get_group_for_user(self.course.id, self.test_user, self.user_partition), group)
def mobi_directory(request, course_id): user = User.objects.prefetch_related("groups").get(id=request.user.id) request.user = user # keep just one instance of User course = get_course_with_access(user, course_id, 'load', depth=2) staff_access = has_access(user, course, 'staff') registered = registered_for_course(course, user) if not registered: # TODO (vshnayder): do course instructors need to be registered to see course? log.debug(u'User %s tried to view course %s but is not enrolled', user, course.location.url()) return redirect(reverse('about_course', args=[course.id])) masq = setup_masquerade(request, staff_access) try: field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course.id, user, course, depth=2) course_module = get_module_for_descriptor(user, request, course, field_data_cache, course.id) if course_module is None: log.warning(u'If you see this, something went wrong: if we got this' u' far, should have gotten a course module for this user') return redirect(reverse('about_course', args=[course.id])) context = { 'csrf': csrf(request)['csrf_token'], 'accordion': mobi_render_accordion(request, course), 'COURSE_TITLE': course.display_name_with_default, 'course': course, 'init': '', 'fragment': Fragment(), 'staff_access': staff_access, 'masquerade': masq, 'xqa_server': settings.FEATURES.get('USE_XQA_SERVER', 'http://*****:*****@content-qa.mitx.mit.edu/xqa'), 'reverifications': fetch_reverify_banner_info(request, course_id), } result = render_to_response('wechat/mobi_directory.html', context) except Exception as e: if isinstance(e, Http404): # let it propagate raise # In production, don't want to let a 500 out for any reason if settings.DEBUG: raise else: log.exception("Error in index view: user={user}, course={course},".format( user=user, course=course,)) try: result = render_to_response('courseware/courseware-error.html', {'staff_access': staff_access, 'course': course}) except: # Let the exception propagate, relying on global config to at # at least return a nice error message log.exception("Error while rendering courseware-error page") raise return result
def course_info(request, course_id): """ Display the course's info.html, or 404 if there is no such course. Assumes the course_id is in a valid format. """ course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) with modulestore().bulk_operations(course_key): course = get_course_with_access(request.user, 'load', course_key) # check to see if there is a required survey that must be taken before # the user can access the course. if request.user.is_authenticated() and survey.utils.must_answer_survey( course, request.user): return redirect(reverse('course_survey', args=[unicode(course.id)])) staff_access = has_access(request.user, 'staff', course) masq = setup_masquerade( request, staff_access) # allow staff to toggle masquerade on info page reverifications = fetch_reverify_banner_info(request, course_key) studio_url = get_studio_url(course, 'course_info') # link to where the student should go to enroll in the course: # about page if there is not marketing site, SITE_NAME if there is url_to_enroll = reverse(course_about, args=[course_id]) if settings.FEATURES.get('ENABLE_MKTG_SITE'): url_to_enroll = marketing_link('COURSES') show_enroll_banner = request.user.is_authenticated( ) and not CourseEnrollment.is_enrolled(request.user, course.id) context = { 'request': request, 'course_id': course_key.to_deprecated_string(), 'cache': None, 'course': course, 'staff_access': staff_access, 'masquerade': masq, 'studio_url': studio_url, 'reverifications': reverifications, 'show_enroll_banner': show_enroll_banner, 'url_to_enroll': url_to_enroll, } now = datetime.now(UTC()) effective_start = _adjust_start_date_for_beta_testers( request.user, course, course_key) if staff_access and now < effective_start: # Disable student view button if user is staff and # course is not yet visible to students. context['disable_student_access'] = True return render_to_response('courseware/info.html', context)
def piazza_discussion(request, course_id): ''' Shows the page under the Discussion tab with an iframe containing Piazza ''' # Create a new tool configuration config = ToolConfig(title = 'Piazza', launch_url = LTI_LAUNCH_URL) # Create tool consumer using LTI! consumer = ToolConsumer(LTI_CONSUMER_KEY, LTI_CONSUMER_SECRET) consumer.set_config(config) #retrieve user and course models user = User.objects.prefetch_related("groups").get(id=request.user.id) userProfile = UserProfile.objects.get(user_id=user.id) course = course_from_id(course_id) #check for permissions to determine what role to pass to Piazza.com through piazza_role = '' if user.groups.filter(name=('instructor_'+course_id)).count() != 0 or request.user.is_staff: piazza_role = 'Instructor' elif user.groups.filter(name=('staff_'+course_id)).count() != 0: piazza_role = 'Staff' else: piazza_role = 'Learner' # Set some launch data from: http://www.imsglobal.org/LTI/v1p1pd/ltiIMGv1p1pd.html#_Toc309649684 consumer.resource_link_id = course_id consumer.lis_person_contact_email_primary = user.email consumer.lis_person_name_full = str(userProfile.name) hash = hashlib.md5() hash.update(str(userProfile.user_id)) consumer.user_id = hash.hexdigest() #TODO: check if user is is_staff, student, professor, or staff and set the role appropriately consumer.roles = piazza_role consumer.context_id = course_id consumer.context_title = course.display_name_with_default consumer.context_label = course.number.replace('_', ' ') consumer.tool_consumer_instance_guid = 'lms.cvn.columbia.edu' consumer.tool_consumer_instance_description = 'Columbia University' launch_data = consumer.generate_launch_data() launch_url = consumer.launch_url course = get_course_with_access(request.user, course_id, 'load') staff_access = has_access(request.user, course, 'staff') masq = setup_masquerade(request, staff_access) # allow staff to toggle masquerade on info page return render_to_response('courseware/piazza_discussion.html', {'request': request, 'course_id': course_id, 'cache': None, 'course': course, 'staff_access': staff_access, 'masquerade': masq, 'launch_url':launch_url, 'launch_data':launch_data})
def test_group_masquerade(self): """ Tests that a staff member can masquerade as being in a particular group. """ # Verify that there is no masquerading group initially group_id, user_partition_id = get_masquerading_group_info(self.test_user, self.course.id) self.assertIsNone(group_id) self.assertIsNone(user_partition_id) # Install a masquerading group request = self._create_mock_json_request( self.test_user, body='{"role": "student", "user_partition_id": 0, "group_id": 1}' ) handle_ajax(request, unicode(self.course.id)) setup_masquerade(request, self.test_user, True) # Verify that the masquerading group is returned group_id, user_partition_id = get_masquerading_group_info(self.test_user, self.course.id) self.assertEqual(group_id, 1) self.assertEqual(user_partition_id, 0)
def course_info(request, course_id): """ Display the course's info.html, or 404 if there is no such course. Assumes the course_id is in a valid format. """ course = get_course_with_access(request.user, course_id, 'load') staff_access = has_access(request.user, course, 'staff') masq = setup_masquerade(request, staff_access) # allow staff to toggle masquerade on info page return render_to_response('courseware/info.html', {'request': request, 'course_id': course_id, 'cache': None, 'course': course, 'staff_access': staff_access, 'masquerade': masq})
def _verify_masquerade_for_group(self, group): """ Verify that the masquerade works for the specified group id. """ # Send the request to set the masquerade request_json = { "role": "student", "user_partition_id": self.user_partition.id, "group_id": group.id if group is not None else None } request = self._create_mock_json_request(self.test_user, body=json.dumps(request_json), session=self.session) handle_ajax(request, unicode(self.course.id)) # Now setup the masquerade for the test user setup_masquerade(request, self.test_user, True) scheme = self.user_partition.scheme # pylint: disable=no-member self.assertEqual( scheme.get_group_for_user(self.course.id, self.test_user, self.user_partition), group)
def course_info(request, course_id): """ Display the course's info.html, or 404 if there is no such course. Assumes the course_id is in a valid format. """ course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) with modulestore().bulk_operations(course_key): course = get_course_with_access(request.user, "load", course_key) # check to see if there is a required survey that must be taken before # the user can access the course. if request.user.is_authenticated() and survey.utils.must_answer_survey(course, request.user): return redirect(reverse("course_survey", args=[unicode(course.id)])) staff_access = has_access(request.user, "staff", course) masquerade = setup_masquerade(request, course_key, staff_access) # allow staff to masquerade on the info page reverifications = fetch_reverify_banner_info(request, course_key) studio_url = get_studio_url(course, "course_info") # link to where the student should go to enroll in the course: # about page if there is not marketing site, SITE_NAME if there is url_to_enroll = reverse(course_about, args=[course_id]) if settings.FEATURES.get("ENABLE_MKTG_SITE"): url_to_enroll = marketing_link("COURSES") show_enroll_banner = request.user.is_authenticated() and not CourseEnrollment.is_enrolled( request.user, course.id ) context = { "request": request, "course_id": course_key.to_deprecated_string(), "cache": None, "course": course, "staff_access": staff_access, "masquerade": masquerade, "studio_url": studio_url, "reverifications": reverifications, "show_enroll_banner": show_enroll_banner, "url_to_enroll": url_to_enroll, } now = datetime.now(UTC()) effective_start = _adjust_start_date_for_beta_testers(request.user, course, course_key) if staff_access and now < effective_start: # Disable student view button if user is staff and # course is not yet visible to students. context["disable_student_access"] = True return render_to_response("courseware/info.html", context)
def _setup_masquerade_for_effective_user(self): """ Setup the masquerade information to allow the request to be processed for the requested effective user. """ self.real_user = self.request.user self.masquerade, self.effective_user = setup_masquerade( self.request, self.course_key, self.is_staff, reset_masquerade_data=True) # Set the user in the request to the effective user. self.request.user = self.effective_user
def _verify_masquerade_for_group(self, group): """ Verify that the masquerade works for the specified group id. """ # Send the request to set the masquerade request_json = { "role": "student", "user_partition_id": self.user_partition.id, "group_id": group.id if group is not None else None } request = self._create_mock_json_request(self.test_user, data=request_json, session=self.session) response = handle_ajax(request, unicode(self.course.id)) # pylint has issues analyzing this class (maybe due to circular imports?) self.assertEquals(response.status_code, 200) # pylint: disable=no-member # Now setup the masquerade for the test user setup_masquerade(request, self.course.id, True) scheme = self.user_partition.scheme self.assertEqual( scheme.get_group_for_user(self.course.id, self.test_user, self.user_partition), group)
def masquerade_as_group_member(user, course, partition_id, group_id): """ Installs a masquerade for the specified user and course, to enable the user to masquerade as belonging to the specific partition/group combination. Arguments: user (User): a user. course (CourseDescriptor): a course. partition_id (int): the integer partition id, referring to partitions already configured in the course. group_id (int); the integer group id, within the specified partition. Returns: the status code for the AJAX response to update the user's masquerade for the specified course. """ request = _create_mock_json_request( user, data={"role": "student", "user_partition_id": partition_id, "group_id": group_id} ) response = handle_ajax(request, unicode(course.id)) setup_masquerade(request, course.id, True) return response.status_code
def _get_context(request, course_id): """ Return all course/student/user data """ course_key = CourseKey.from_string(course_id) course = get_course_with_access(request.user, "load", course_key) # Get general info of course grade_cutoff, avg_grade, min_grade, max_grade = _get_course_info( course, course_key) # masquerade and student required for preview_menu (admin) staff_access = bool(has_access(request.user, 'staff', course)) masquerade, student = setup_masquerade(request, course_key, staff_access, reset_masquerade_data=True) prefetch_related_objects([student], 'groups') if request.user.id != student.id: # refetch the course as the assumed student course = get_course_with_access(student, 'load', course_key, check_if_enrolled=True) course_grade = CourseGradeFactory().read(student, course) # Student grades courseware_summary = list(course_grade.chapter_grades.values()) course_expiration_fragment = generate_course_expired_fragment( student, course) context = { "course": course, "avg_grade": avg_grade, "min_grade": min_grade, "max_grade": max_grade, "grade_cutoff": grade_cutoff, "supports_preview_menu": True, "staff_access": staff_access, "masquerade": masquerade, "student": student, "courseware_summary": courseware_summary, "grade_summary": course_grade.summary, "course_expiration_fragment": course_expiration_fragment, "grade_percent_scaled": grade_percent_scaled, "get_section_visibility": get_section_visibility, "get_feedback": get_feedback, "update_url": reverse('feedback_post_update'), "set_visibility_url": reverse('feedback_post_set_visibility'), } return context
def course_info(request, course_id): """ Display the course's info.html, or 404 if there is no such course. Assumes the course_id is in a valid format. """ course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) with modulestore().bulk_operations(course_key): course = get_course_with_access(request.user, 'load', course_key) staff_access = has_access(request.user, 'staff', course) masq = setup_masquerade(request, staff_access) # allow staff to toggle masquerade on info page reverifications = fetch_reverify_banner_info(request, course_key) studio_url = get_studio_url(course, 'course_info') # link to where the student should go to enroll in the course: # about page if there is not marketing site, SITE_NAME if there is url_to_enroll = reverse(course_about, args=[course_id]) if settings.FEATURES.get('ENABLE_MKTG_SITE'): url_to_enroll = marketing_link('COURSES') show_enroll_banner = request.user.is_authenticated() and not CourseEnrollment.is_enrolled(request.user, course.id) context = { 'request': request, 'course_id': course_key.to_deprecated_string(), 'cache': None, 'course': course, 'staff_access': staff_access, 'masquerade': masq, 'studio_url': studio_url, 'reverifications': reverifications, 'show_enroll_banner': show_enroll_banner, 'url_to_enroll': url_to_enroll, } now = datetime.now(UTC()) effective_start = _adjust_start_date_for_beta_testers(request.user, course, course_key) if staff_access and now < effective_start: # Disable student view button if user is staff and # course is not yet visible to students. context['disable_student_access'] = True return render_to_response('courseware/info.html', context)
def course_info(request, course_id): """ Display the course's info.html, or 404 if there is no such course. Assumes the course_id is in a valid format. """ course = get_course_with_access(request.user, course_id, "load") staff_access = has_access(request.user, course, "staff") masq = setup_masquerade(request, staff_access) # allow staff to toggle masquerade on info page return render_to_response( "courseware/info.html", { "request": request, "course_id": course_id, "cache": None, "course": course, "staff_access": staff_access, "masquerade": masq, }, )
def course_info(request, course_id): """ Display the course's info.html, or 404 if there is no such course. Assumes the course_id is in a valid format. """ course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course = get_course_with_access(request.user, 'load', course_key) staff_access = has_access(request.user, 'staff', course) masq = setup_masquerade( request, staff_access) # allow staff to toggle masquerade on info page reverifications = fetch_reverify_banner_info(request, course_key) studio_url = get_studio_url(course, 'course_info') # link to where the student should go to enroll in the course: # about page if there is not marketing site, SITE_NAME if there is url_to_enroll = reverse(course_about, args=[course_id]) if settings.FEATURES.get('ENABLE_MKTG_SITE'): url_to_enroll = marketing_link('COURSES') show_enroll_banner = request.user.is_authenticated( ) and not CourseEnrollment.is_enrolled(request.user, course.id) context = { 'request': request, 'course_id': course_key.to_deprecated_string(), 'cache': None, 'course': course, 'staff_access': staff_access, 'masquerade': masq, 'studio_url': studio_url, 'reverifications': reverifications, 'show_enroll_banner': show_enroll_banner, 'url_to_enroll': url_to_enroll, } return render_to_response('courseware/info.html', context)
def course_info(request, course_id): """ Display the course's info.html, or 404 if there is no such course. Assumes the course_id is in a valid format. """ course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course = get_course_with_access(request.user, 'load', course_key) staff_access = has_access(request.user, 'staff', course) masq = setup_masquerade(request, staff_access) # allow staff to toggle masquerade on info page reverifications = fetch_reverify_banner_info(request, course_key) studio_url = get_studio_url(course, 'course_info') # link to where the student should go to enroll in the course: # about page if there is not marketing site, SITE_NAME if there is url_to_enroll = reverse(course_about, args=[course_id]) if settings.FEATURES.get('ENABLE_MKTG_SITE'): url_to_enroll = marketing_link('COURSES') show_enroll_banner = request.user.is_authenticated() and not CourseEnrollment.is_enrolled(request.user, course.id) context = { 'request': request, 'course_id': course_key.to_deprecated_string(), 'cache': None, 'course': course, 'staff_access': staff_access, 'masquerade': masq, 'studio_url': studio_url, 'reverifications': reverifications, 'show_enroll_banner': show_enroll_banner, 'url_to_enroll': url_to_enroll, } return render_to_response('courseware/info.html', context)
def _invoke_xblock_handler(request, course_id, usage_id, handler, suffix, user): """ Invoke an XBlock handler, either authenticated or not. Arguments: request (HttpRequest): the current request course_id (str): A string of the form org/course/run usage_id (str): A string of the form i4x://org/course/category/name@revision handler (str): The name of the handler to invoke suffix (str): The suffix to pass to the handler when invoked user (User): The currently logged in user """ try: course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id) usage_key = course_id.make_usage_key_from_deprecated_string( unquote_slashes(usage_id)) except InvalidKeyError: raise Http404("Invalid location") # Check submitted files files = request.FILES or {} error_msg = _check_files_limits(files) if error_msg: return HttpResponse(json.dumps({'success': error_msg})) try: descriptor = modulestore().get_item(usage_key) descriptor_orig_usage_key, descriptor_orig_version = modulestore( ).get_block_original_usage(usage_key) except ItemNotFoundError: log.warn( "Invalid location for course id {course_id}: {usage_key}".format( course_id=usage_key.course_key, usage_key=usage_key)) raise Http404 tracking_context_name = 'module_callback_handler' tracking_context = { 'module': { 'display_name': descriptor.display_name_with_default, 'usage_key': unicode(descriptor.location), } } # For blocks that are inherited from a content library, we add some additional metadata: if descriptor_orig_usage_key is not None: tracking_context['module']['original_usage_key'] = unicode( descriptor_orig_usage_key) tracking_context['module']['original_usage_version'] = unicode( descriptor_orig_version) field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course_id, user, descriptor) setup_masquerade(request, course_id, has_access(user, 'staff', descriptor, course_id)) instance = get_module(user, request, usage_key, field_data_cache, grade_bucket_type='ajax') if instance is None: # Either permissions just changed, or someone is trying to be clever # and load something they shouldn't have access to. log.debug("No module %s for user %s -- access denied?", usage_key, user) raise Http404 req = django_to_webob_request(request) try: with tracker.get_tracker().context(tracking_context_name, tracking_context): resp = instance.handle(handler, req, suffix) except NoSuchHandlerError: log.exception("XBlock %s attempted to access missing handler %r", instance, handler) raise Http404 # If we can't find the module, respond with a 404 except NotFoundError: log.exception("Module indicating to user that request doesn't exist") raise Http404 # For XModule-specific errors, we log the error and respond with an error message except ProcessingError as err: log.warning("Module encountered an error while processing AJAX call", exc_info=True) return JsonResponse(object={'success': err.args[0]}, status=200) # If any other error occurred, re-raise it to trigger a 500 response except Exception: log.exception("error executing xblock handler") raise return webob_to_django_response(resp)
def get_module_for_descriptor(user, request, descriptor, model_data_cache, course_id, position=None, wrap_xmodule_display=True, grade_bucket_type=None): """ Actually implement get_module. See docstring there for details. """ # allow course staff to masquerade as student if has_access(user, descriptor, 'staff', course_id): setup_masquerade(request, True) # Short circuit--if the user shouldn't have access, bail without doing any work if not has_access(user, descriptor, 'load', course_id): return None # Setup system context for module instance ajax_url = reverse( 'modx_dispatch', kwargs=dict(course_id=course_id, location=descriptor.location.url(), dispatch=''), ) # Intended use is as {ajax_url}/{dispatch_command}, so get rid of the trailing slash. ajax_url = ajax_url.rstrip('/') def make_xqueue_callback(dispatch='score_update'): # Fully qualified callback URL for external queueing system xqueue_callback_url = '{proto}://{host}'.format( host=request.get_host(), proto=request.META.get('HTTP_X_FORWARDED_PROTO', 'https' if request.is_secure() else 'http')) xqueue_callback_url = settings.XQUEUE_INTERFACE.get( 'callback_url', xqueue_callback_url) # allow override xqueue_callback_url += reverse( 'xqueue_callback', kwargs=dict(course_id=course_id, userid=str(user.id), id=descriptor.location.url(), dispatch=dispatch), ) return xqueue_callback_url # Default queuename is course-specific and is derived from the course that # contains the current module. # TODO: Queuename should be derived from 'course_settings.json' of each course xqueue_default_queuename = descriptor.location.org + '-' + descriptor.location.course xqueue = { 'interface': xqueue_interface, 'construct_callback': make_xqueue_callback, 'default_queuename': xqueue_default_queuename.replace(' ', '_'), 'waittime': settings.XQUEUE_WAITTIME_BETWEEN_REQUESTS } #This is a hacky way to pass settings to the combined open ended xmodule #It needs an S3 interface to upload images to S3 #It needs the open ended grading interface in order to get peer grading to be done #this first checks to see if the descriptor is the correct one, and only sends settings if it is #Get descriptor metadata fields indicating needs for various settings needs_open_ended_interface = getattr(descriptor, "needs_open_ended_interface", False) needs_s3_interface = getattr(descriptor, "needs_s3_interface", False) #Initialize interfaces to None open_ended_grading_interface = None s3_interface = None #Create interfaces if needed if needs_open_ended_interface: open_ended_grading_interface = settings.OPEN_ENDED_GRADING_INTERFACE open_ended_grading_interface[ 'mock_peer_grading'] = settings.MOCK_PEER_GRADING open_ended_grading_interface[ 'mock_staff_grading'] = settings.MOCK_STAFF_GRADING if needs_s3_interface: s3_interface = { 'access_key': getattr(settings, 'AWS_ACCESS_KEY_ID', ''), 'secret_access_key': getattr(settings, 'AWS_SECRET_ACCESS_KEY', ''), 'storage_bucket_name': getattr(settings, 'AWS_STORAGE_BUCKET_NAME', 'openended') } def inner_get_module(descriptor): """ Delegate to get_module. It does an access check, so may return None """ return get_module_for_descriptor(user, request, descriptor, model_data_cache, course_id, position) def xblock_model_data(descriptor): return DbModel( LmsKeyValueStore(descriptor._model_data, model_data_cache), descriptor.module_class, user.id, LmsUsage(descriptor.location, descriptor.location)) def publish(event): if event.get('event_name') != 'grade': return student_module, created = StudentModule.objects.get_or_create( course_id=course_id, student=user, module_type=descriptor.location.category, module_state_key=descriptor.location.url(), defaults={'state': '{}'}, ) student_module.grade = event.get('value') student_module.max_grade = event.get('max_value') student_module.save() #Bin score into range and increment stats score_bucket = get_score_bucket(student_module.grade, student_module.max_grade) org, course_num, run = course_id.split("/") tags = [ "org:{0}".format(org), "course:{0}".format(course_num), "run:{0}".format(run), "score_bucket:{0}".format(score_bucket) ] if grade_bucket_type is not None: tags.append('type:%s' % grade_bucket_type) statsd.increment("lms.courseware.question_answered", tags=tags) def can_execute_unsafe_code(): # To decide if we can run unsafe code, we check the course id against # a list of regexes configured on the server. for regex in settings.COURSES_WITH_UNSAFE_CODE: if re.match(regex, course_id): return True return False # TODO (cpennington): When modules are shared between courses, the static # prefix is going to have to be specific to the module, not the directory # that the xml was loaded from system = ModuleSystem( track_function=make_track_function(request), render_template=render_to_string, ajax_url=ajax_url, xqueue=xqueue, # TODO (cpennington): Figure out how to share info between systems filestore=descriptor.system.resources_fs, get_module=inner_get_module, user=user, # TODO (cpennington): This should be removed when all html from # a module is coming through get_html and is therefore covered # by the replace_static_urls code below replace_urls=partial( static_replace.replace_static_urls, data_directory=getattr(descriptor, 'data_dir', None), course_namespace=descriptor.location._replace(category=None, name=None), ), node_path=settings.NODE_PATH, xblock_model_data=xblock_model_data, publish=publish, anonymous_student_id=unique_id_for_user(user), course_id=course_id, open_ended_grading_interface=open_ended_grading_interface, s3_interface=s3_interface, cache=cache, can_execute_unsafe_code=can_execute_unsafe_code, ) # pass position specified in URL to module through ModuleSystem system.set('position', position) system.set('DEBUG', settings.DEBUG) if settings.MITX_FEATURES.get('ENABLE_PSYCHOMETRICS'): system.set( 'psychometrics_handler', # set callback for updating PsychometricsData make_psychometrics_data_update_handler(course_id, user, descriptor.location.url())) try: module = descriptor.xmodule(system) except: log.exception( "Error creating module from descriptor {0}".format(descriptor)) # make an ErrorDescriptor -- assuming that the descriptor's system is ok if has_access(user, descriptor.location, 'staff', course_id): err_descriptor_class = ErrorDescriptor else: err_descriptor_class = NonStaffErrorDescriptor err_descriptor = err_descriptor_class.from_xml( str(descriptor), descriptor.system, org=descriptor.location.org, course=descriptor.location.course, error_msg=exc_info_to_str(sys.exc_info())) # Make an error module return err_descriptor.xmodule(system) system.set('user_is_staff', has_access(user, descriptor.location, 'staff', course_id)) _get_html = module.get_html if wrap_xmodule_display == True: _get_html = wrap_xmodule(module.get_html, module, 'xmodule_display.html') module.get_html = replace_static_urls( _get_html, getattr(descriptor, 'data_dir', None), course_namespace=module.location._replace(category=None, name=None)) # Allow URLs of the form '/course/' refer to the root of multicourse directory # hierarchy of this course module.get_html = replace_course_urls(module.get_html, course_id) if settings.MITX_FEATURES.get('DISPLAY_HISTOGRAMS_TO_STAFF'): if has_access(user, module, 'staff', course_id): module.get_html = add_histogram(module.get_html, module, user) return module
def _index_bulk_op(request, course_key, chapter, section, position): """ Render the index page for the specified course. """ user = request.user course = get_course_with_access(user, 'load', course_key, depth=2) staff_access = has_access(user, 'staff', course) registered = registered_for_course(course, user) if not registered: # TODO (vshnayder): do course instructors need to be registered to see course? log.debug(u'User %s tried to view course %s but is not enrolled', user, course.location.to_deprecated_string()) return redirect(reverse('about_course', args=[course_key.to_deprecated_string()])) # see if all pre-requisites (as per the milestones app feature) have been fulfilled # Note that if the pre-requisite feature flag has been turned off (default) then this check will # always pass if not has_access(user, 'view_courseware_with_prerequisites', course): # prerequisites have not been fulfilled therefore redirect to the Dashboard log.info( u'User %d tried to view course %s ' u'without fulfilling prerequisites', user.id, unicode(course.id)) return redirect(reverse('dashboard')) # check to see if there is a required survey that must be taken before # the user can access the course. if survey.utils.must_answer_survey(course, user): return redirect(reverse('course_survey', args=[unicode(course.id)])) masquerade = setup_masquerade(request, course_key, staff_access) try: field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course_key, user, course, depth=2) course_module = get_module_for_descriptor(user, request, course, field_data_cache, course_key) if course_module is None: log.warning(u'If you see this, something went wrong: if we got this' u' far, should have gotten a course module for this user') return redirect(reverse('about_course', args=[course_key.to_deprecated_string()])) studio_url = get_studio_url(course, 'course') context = { 'csrf': csrf(request)['csrf_token'], 'accordion': render_accordion(request, course, chapter, section, field_data_cache), 'COURSE_TITLE': course.display_name_with_default, 'course': course, 'init': '', 'fragment': Fragment(), 'staff_access': staff_access, 'studio_url': studio_url, 'masquerade': masquerade, 'xqa_server': settings.FEATURES.get('USE_XQA_SERVER', 'http://*****:*****@content-qa.mitx.mit.edu/xqa'), 'reverifications': fetch_reverify_banner_info(request, course_key), } now = datetime.now(UTC()) effective_start = _adjust_start_date_for_beta_testers(user, course, course_key) if staff_access and now < effective_start: # Disable student view button if user is staff and # course is not yet visible to students. context['disable_student_access'] = True has_content = course.has_children_at_depth(CONTENT_DEPTH) if not has_content: # Show empty courseware for a course with no units return render_to_response('courseware/courseware.html', context) elif chapter is None: # passing CONTENT_DEPTH avoids returning 404 for a course with an # empty first section and a second section with content return redirect_to_course_position(course_module, CONTENT_DEPTH) # Only show the chat if it's enabled by the course and in the # settings. show_chat = course.show_chat and settings.FEATURES['ENABLE_CHAT'] if show_chat: context['chat'] = chat_settings(course, user) # If we couldn't load the chat settings, then don't show # the widget in the courseware. if context['chat'] is None: show_chat = False context['show_chat'] = show_chat chapter_descriptor = course.get_child_by(lambda m: m.location.name == chapter) if chapter_descriptor is not None: save_child_position(course_module, chapter) else: raise Http404('No chapter descriptor found with name {}'.format(chapter)) chapter_module = course_module.get_child_by(lambda m: m.location.name == chapter) if chapter_module is None: # User may be trying to access a chapter that isn't live yet if masquerade and masquerade.role == 'student': # if staff is masquerading as student be kinder, don't 404 log.debug('staff masquerading as student: no chapter %s', chapter) return redirect(reverse('courseware', args=[course.id.to_deprecated_string()])) raise Http404 if section is not None: section_descriptor = chapter_descriptor.get_child_by(lambda m: m.location.name == section) if section_descriptor is None: # Specifically asked-for section doesn't exist if masquerade and masquerade.role == 'student': # don't 404 if staff is masquerading as student log.debug('staff masquerading as student: no section %s', section) return redirect(reverse('courseware', args=[course.id.to_deprecated_string()])) raise Http404 ## Allow chromeless operation if section_descriptor.chrome: chrome = [s.strip() for s in section_descriptor.chrome.lower().split(",")] if 'accordion' not in chrome: context['disable_accordion'] = True if 'tabs' not in chrome: context['disable_tabs'] = True if section_descriptor.default_tab: context['default_tab'] = section_descriptor.default_tab # cdodge: this looks silly, but let's refetch the section_descriptor with depth=None # which will prefetch the children more efficiently than doing a recursive load section_descriptor = modulestore().get_item(section_descriptor.location, depth=None) # Load all descendants of the section, because we're going to display its # html, which in general will need all of its children section_field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course_key, user, section_descriptor, depth=None, asides=XBlockAsidesConfig.possible_asides() ) # Verify that position a string is in fact an int if position is not None: try: int(position) except ValueError: raise Http404("Position {} is not an integer!".format(position)) section_module = get_module_for_descriptor( request.user, request, section_descriptor, section_field_data_cache, course_key, position ) if section_module is None: # User may be trying to be clever and access something # they don't have access to. raise Http404 # Save where we are in the chapter save_child_position(chapter_module, section) context['fragment'] = section_module.render(STUDENT_VIEW) context['section_title'] = section_descriptor.display_name_with_default else: # section is none, so display a message studio_url = get_studio_url(course, 'course') prev_section = get_current_child(chapter_module) if prev_section is None: # Something went wrong -- perhaps this chapter has no sections visible to the user. # Clearing out the last-visited state and showing "first-time" view by redirecting # to courseware. course_module.position = None course_module.save() return redirect(reverse('courseware', args=[course.id.to_deprecated_string()])) prev_section_url = reverse('courseware_section', kwargs={ 'course_id': course_key.to_deprecated_string(), 'chapter': chapter_descriptor.url_name, 'section': prev_section.url_name }) context['fragment'] = Fragment(content=render_to_string( 'courseware/welcome-back.html', { 'course': course, 'studio_url': studio_url, 'chapter_module': chapter_module, 'prev_section': prev_section, 'prev_section_url': prev_section_url } )) result = render_to_response('courseware/courseware.html', context) except Exception as e: # Doesn't bar Unicode characters from URL, but if Unicode characters do # cause an error it is a graceful failure. if isinstance(e, UnicodeEncodeError): raise Http404("URL contains Unicode characters") if isinstance(e, Http404): # let it propagate raise # In production, don't want to let a 500 out for any reason if settings.DEBUG: raise else: log.exception( u"Error in index view: user={user}, course={course}, chapter={chapter}" u" section={section} position={position}".format( user=user, course=course, chapter=chapter, section=section, position=position )) try: result = render_to_response('courseware/courseware-error.html', { 'staff_access': staff_access, 'course': course }) except: # Let the exception propagate, relying on global config to at # at least return a nice error message log.exception("Error while rendering courseware-error page") raise return result
def index(request, course_id): # Palette color_not = '#CCCCCC' color_fail = '#e41a1c' color_ok = '#F2F20D' color_prof = '#4daf4a' problem_activity='#377eb8' video_activity='#ff7f00' video_repetition='#fdbf6f' course_activity='#984ea3' graded_time='#88419d' ungraded_time='#8c6bb1' chapter_time='#8c96c6' play_event='#1b9e77' pause_event='#d95f02' seek_from_event='#7570b3' seek_to_event='#e7298a' change_speed_event='#66a61e' morning_time='#C9C96C' afternoon_time ='#7F7160' night_time ='#50587C' # Request data course_key = get_course_key(course_id) course = get_course_module(course_key) #course2= get_course_by_id(SlashSeparatedCourseKey.from_deprecated_string(course_id)) #user = request.user #Codigo Jose A. Gascon staff_access = has_access(request.user, 'staff', course).has_access#Codigo Jose A. Gascon instructor_access = has_access(request.user, 'instructor', course).has_access#Codigo Jose A. Gascon #Codigo Jose A. Gascon masq, user = setup_masquerade(request, course_key,staff_access, reset_masquerade_data=True) # allow staff to toggle masquerade on info page user = request.user studio_url = get_studio_url(course, 'course_info') #reverifications = fetch_reverify_banner_info(request, course_key) #course = get_course_with_access(request.user, action='load', course_key=course_key, depth=None, check_if_enrolled=False) #user = User.objects.get(request.user.email) # Proficiency and pass limit pass_limit = get_course_grade_cutoff(course) proficiency_limit = (1 - pass_limit) / 2 + pass_limit usernames_in = [] for student in CourseEnrollment.objects.users_enrolled_in(course_key):#Codigo Jose A. Gascon, se cambia la forma de llamar al metode users_enrolled_in usernames_in.append(student.username.encode('utf-8')) # Data for visualization in JSON user_for_charts = '#average' if (staff_access or instructor_access) else user kwargs = { 'qualifiers': {'category': 'video', }, } # This returns video descriptors in the order they appear on the course video_descriptors = videos_problems_in(course)[0] #WARNINIG #video_durations = get_info_videos_descriptors(video_descriptors)[2] #video_names, video_module_keys, video_durations = get_info_videos_descriptors(video_descriptors) # NO SE USAN LAS OTRAS VARIABLES video_names, video_module_keys, video_durations =get_DB_infovideos(course_key) video_names_sorted = video_names video_ids_sort = video_names_sorted #course_name = get_course_by_id(course_key, depth=None) names_students=[] only_students = [] students_names = get_course_students(course_key) print students_names for student in students_names: staff_access_user = has_access(student, 'staff', course).has_access instructor_access_user = has_access(student, 'instructor', course).has_access if not (staff_access_user or instructor_access_user): names_students.append(student.username.encode('utf-8')) only_students.append(student) video_ids_str = [] course_video_names = [] problem_ids_str=[] for descriptor in video_descriptors: video_ids_str.append((course_key.make_usage_key('video', descriptor.location.name))._to_string()) course_video_names.append(unicodedata.normalize('NFKD', descriptor.display_name_with_default).encode('ASCII', 'ignore')) if len(video_descriptors) > 0: first_video_id = course_key.make_usage_key('video', video_descriptors[0].location.name) # Video progress visualization. Video percentage seen total and non-overlapped. video_names, avg_video_time, video_percentages = get_video_time_watched(user_for_charts, course_key) if avg_video_time != []: all_video_time_percent = map(truediv, avg_video_time, video_durations) all_video_time_percent = [int(round(x*100,0)) for x in all_video_time_percent] else: all_video_time_percent = avg_video_time column_headers = ['Video', 'Different video time', 'Total video time'] # Codigo Javier Orcoyen video_prog_json = ready_for_arraytodatatable(column_headers, video_names, video_percentages, all_video_time_percent) video_names, all_video_time = get_module_consumption(user_for_charts, course_key, 'video') # Time spent on every video resource column_headers = ['Video', 'Time watched'] video_distrib_json = ready_for_arraytodatatable(column_headers, video_names, all_video_time) # Video events dispersion within video length scatter_array = get_video_events_info(user_for_charts, first_video_id) # Repetitions per video intervals user_for_vid_intervals = '#class_total_times' if user_for_charts == '#average' else user_for_charts video_intervals_array = get_user_video_intervals(user_for_vid_intervals, first_video_id) # Case no videos in course else: video_names = None video_prog_json = json.dumps(None) video_distrib_json = json.dumps(None) scatter_array = json.dumps(None) video_intervals_array = json.dumps(None) # Time spent on every problem resource # Codigo Javier Orcoyen problem_names, time_x_problem = get_module_consumption(user_for_charts, course_key, 'problem') column_headers = ['Problem', 'Time on problem'] problem_distrib_json = ready_for_arraytodatatable(column_headers, problem_names, time_x_problem) print 'USER' print user problems_in = videos_problems_in(course)[1] problem_names_sorted = [x.display_name_with_default.encode('utf-8') for x in problems_in] orden=[] orden.append(i for i, x in enumerate(problem_names_sorted)) problem_ids_str=list(problem_names_sorted) for n in range(len(problem_names_sorted)): problem_names_sorted[n]= unicodedata.normalize('NFKD', unicode(problem_names_sorted[n],'utf-8')).encode('ASCII', 'ignore') problem_ids_str[n]= unicodedata.normalize('NFKD', unicode(problem_ids_str[n],'utf-8')).encode('ASCII', 'ignore') user_val=1 # Daily time spent on video and/or problem resources video_days, video_daily_time = get_daily_consumption(user_for_charts, course_key, 'video') problem_days, problem_daily_time = get_daily_consumption(user_for_charts, course_key, 'problem') vid_and_prob_daily_time = join_video_problem_time(video_days, video_daily_time, problem_days, problem_daily_time) #Analytics visualizations if staff_access or instructor_access: # Instructor access std_sort = get_DB_sort_course_homework(course_key) # Chapter time cs, st = get_DB_course_spent_time(course_key, student_id=ALL_STUDENTS) students_spent_time = chapter_time_to_js(cs, st) students_grades = get_DB_student_grades(course_key, student_id=ALL_STUDENTS) cs, sa = course_accesses = get_DB_course_section_accesses(course_key, student_id=ALL_STUDENTS) students_course_accesses = course_accesses_to_js(cs, sa) #students_prob_vid_progress = get_DB_course_video_problem_progress(course_key, student_id=ALL_STUDENTS)# C. J. A. Gascon ERROR students_time_schedule = get_DB_time_schedule(course_key, student_id=ALL_STUDENTS) else: # Sort homework # Chapter time std_sort = None cs, st = get_DB_course_spent_time(course_key, user.id) students_spent_time = chapter_time_to_js(cs, st) students_grades = get_DB_student_grades(course_key, user.id) cs, sa = course_accesses = get_DB_course_section_accesses(course_key, user.id) students_course_accesses = course_accesses_to_js(cs, sa) students_time_schedule = get_DB_time_schedule(course_key, user.id) #students_prob_vid_progress = get_DB_course_video_problem_progress(course_key, user.id) #C. J. A. Gascon ERROR context = {'course': course, 'request': request, 'user': user, 'user_id': user.id, 'staff_access': staff_access, 'instructor_access': instructor_access, 'masquerade': masq, 'studio_url': studio_url, #'reverifications': reverifications, 'course_id': course_id, 'students': students_to_js(only_students), 'visualizations_id': VISUALIZATIONS_ID, 'std_grades_dump': dumps(students_grades), 'sort_std_dump': dumps(std_sort), 'time_dump': dumps(students_spent_time), 'accesses_dump': dumps(students_course_accesses), 'std_time_schedule_dumb': dumps(students_time_schedule), #'vid_prob_prog_dump': dumps(students_prob_vid_progress), #C. J. A. Gascon ERROR 'pass_limit': pass_limit, 'prof_limit': proficiency_limit, 'usernames_in' : usernames_in, 'video_names' : course_video_names, 'video_ids' : video_ids_str, 'video_prog_json' : video_prog_json, 'video_distrib_json' : video_distrib_json, 'problem_distrib_json' : problem_distrib_json, 'video_intervals_array' : video_intervals_array, 'vid_and_prob_daily_time' : vid_and_prob_daily_time, 'scatter_array' : scatter_array, 'problem_names' : problem_names, 'problem_ids' : problem_ids_str, 'color_not' : color_not, 'color_ok' : color_ok, 'color_prof' : color_prof, 'color_fail' : color_fail, 'problem_activity' : problem_activity, 'video_activity' : video_activity, 'course_activity' : course_activity, 'video_repetition' : video_repetition, 'graded_time' : graded_time, 'ungraded_time' : ungraded_time, 'chapter_time' : chapter_time, 'user_for_charts' : user_for_charts, 'video_ids_sort' : video_ids_sort, 'video_names_sorted' : video_names_sorted, 'problem_names_sorted' : problem_names_sorted, 'play_event' : play_event, 'pause_event' : pause_event, 'seek_from_event' : seek_from_event, 'seek_to_event' : seek_to_event, 'change_speed_event' : change_speed_event, 'morning_time' : morning_time, 'afternoon_time' : afternoon_time, 'night_time' : night_time, 'names_students' : names_students, 'user_val' : user_val,} return render_to_response('learning_analytics/learning_analytics.html', context)
def initialize(self, **kwargs): if 'request' in kwargs and kwargs['request'] and kwargs['course_id']: request = kwargs['request'] course_key = CourseKey.from_string(kwargs['course_id']) staff_access = bool(has_access(request.user, 'staff', course_key)) setup_masquerade(request, course_key, staff_access)
def index(request, course_id, chapter=None, section=None, position=None): """ Displays courseware accordion and associated content. If course, chapter, and section are all specified, renders the page, or returns an error if they are invalid. If section is not specified, displays the accordion opened to the right chapter. If neither chapter or section are specified, redirects to user's most recent chapter, or the first chapter if this is the user's first visit. Arguments: - request : HTTP request - course_id : course id (str: ORG/course/URL_NAME) - chapter : chapter url_name (str) - section : section url_name (str) - position : position in module, eg of <sequential> module (str) Returns: - HTTPresponse """ user = User.objects.prefetch_related("groups").get(id=request.user.id) request.user = user # keep just one instance of User course = get_course_with_access(user, course_id, "load", depth=2) staff_access = has_access(user, course, "staff") registered = registered_for_course(course, user) if not registered: # TODO (vshnayder): do course instructors need to be registered to see course? log.debug("User %s tried to view course %s but is not enrolled" % (user, course.location.url())) return redirect(reverse("about_course", args=[course.id])) masq = setup_masquerade(request, staff_access) try: field_data_cache = FieldDataCache.cache_for_descriptor_descendents(course.id, user, course, depth=2) course_module = get_module_for_descriptor(user, request, course, field_data_cache, course.id) if course_module is None: log.warning( "If you see this, something went wrong: if we got this" " far, should have gotten a course module for this user" ) return redirect(reverse("about_course", args=[course.id])) if chapter is None: return redirect_to_course_position(course_module) context = { "csrf": csrf(request)["csrf_token"], "accordion": render_accordion(request, course, chapter, section, field_data_cache), "COURSE_TITLE": course.display_name_with_default, "course": course, "init": "", "fragment": Fragment(), "staff_access": staff_access, "masquerade": masq, "xqa_server": settings.FEATURES.get("USE_XQA_SERVER", "http://*****:*****@content-qa.mitx.mit.edu/xqa"), } # Only show the chat if it's enabled by the course and in the # settings. show_chat = course.show_chat and settings.FEATURES["ENABLE_CHAT"] if show_chat: context["chat"] = chat_settings(course, user) # If we couldn't load the chat settings, then don't show # the widget in the courseware. if context["chat"] is None: show_chat = False context["show_chat"] = show_chat chapter_descriptor = course.get_child_by(lambda m: m.url_name == chapter) if chapter_descriptor is not None: save_child_position(course_module, chapter) else: raise Http404("No chapter descriptor found with name {}".format(chapter)) chapter_module = course_module.get_child_by(lambda m: m.url_name == chapter) if chapter_module is None: # User may be trying to access a chapter that isn't live yet if masq == "student": # if staff is masquerading as student be kinder, don't 404 log.debug("staff masq as student: no chapter %s" % chapter) return redirect(reverse("courseware", args=[course.id])) raise Http404 if section is not None: section_descriptor = chapter_descriptor.get_child_by(lambda m: m.url_name == section) if section_descriptor is None: # Specifically asked-for section doesn't exist if masq == "student": # if staff is masquerading as student be kinder, don't 404 log.debug("staff masq as student: no section %s" % section) return redirect(reverse("courseware", args=[course.id])) raise Http404 # cdodge: this looks silly, but let's refetch the section_descriptor with depth=None # which will prefetch the children more efficiently than doing a recursive load section_descriptor = modulestore().get_instance(course.id, section_descriptor.location, depth=None) # Load all descendants of the section, because we're going to display its # html, which in general will need all of its children section_field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course_id, user, section_descriptor, depth=None ) section_module = get_module_for_descriptor( request.user, request, section_descriptor, section_field_data_cache, course_id, position ) if section_module is None: # User may be trying to be clever and access something # they don't have access to. raise Http404 # Save where we are in the chapter save_child_position(chapter_module, section) context["fragment"] = section_module.render("student_view") else: # section is none, so display a message prev_section = get_current_child(chapter_module) if prev_section is None: # Something went wrong -- perhaps this chapter has no sections visible to the user raise Http404 prev_section_url = reverse( "courseware_section", kwargs={ "course_id": course_id, "chapter": chapter_descriptor.url_name, "section": prev_section.url_name, }, ) context["fragment"] = Fragment( content=render_to_string( "courseware/welcome-back.html", { "course": course, "chapter_module": chapter_module, "prev_section": prev_section, "prev_section_url": prev_section_url, }, ) ) result = render_to_response("courseware/courseware.html", context) except Exception as e: if isinstance(e, Http404): # let it propagate raise # In production, don't want to let a 500 out for any reason if settings.DEBUG: raise else: log.exception( "Error in index view: user={user}, course={course}," " chapter={chapter} section={section}" "position={position}".format( user=user, course=course, chapter=chapter, section=section, position=position ) ) try: result = render_to_response( "courseware/courseware-error.html", {"staff_access": staff_access, "course": course} ) except: # Let the exception propagate, relying on global config to at # at least return a nice error message log.exception("Error while rendering courseware-error page") raise return result
def _invoke_xblock_handler(request, course_id, usage_id, handler, suffix, user): """ Invoke an XBlock handler, either authenticated or not. Arguments: request (HttpRequest): the current request course_id (str): A string of the form org/course/run usage_id (str): A string of the form i4x://org/course/category/name@revision handler (str): The name of the handler to invoke suffix (str): The suffix to pass to the handler when invoked user (User): The currently logged in user """ try: course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id) usage_key = course_id.make_usage_key_from_deprecated_string(unquote_slashes(usage_id)) except InvalidKeyError: raise Http404("Invalid location") # Check submitted files files = request.FILES or {} error_msg = _check_files_limits(files) if error_msg: return HttpResponse(json.dumps({"success": error_msg})) try: descriptor = modulestore().get_item(usage_key) descriptor_orig_usage_key, descriptor_orig_version = modulestore().get_block_original_usage(usage_key) except ItemNotFoundError: log.warn( "Invalid location for course id {course_id}: {usage_key}".format( course_id=usage_key.course_key, usage_key=usage_key ) ) raise Http404 tracking_context_name = "module_callback_handler" tracking_context = { "module": {"display_name": descriptor.display_name_with_default, "usage_key": unicode(descriptor.location)} } # For blocks that are inherited from a content library, we add some additional metadata: if descriptor_orig_usage_key is not None: tracking_context["module"]["original_usage_key"] = unicode(descriptor_orig_usage_key) tracking_context["module"]["original_usage_version"] = unicode(descriptor_orig_version) field_data_cache = FieldDataCache.cache_for_descriptor_descendents(course_id, user, descriptor) setup_masquerade(request, course_id, has_access(user, "staff", descriptor, course_id)) instance = get_module(user, request, usage_key, field_data_cache, grade_bucket_type="ajax") if instance is None: # Either permissions just changed, or someone is trying to be clever # and load something they shouldn't have access to. log.debug("No module %s for user %s -- access denied?", usage_key, user) raise Http404 req = django_to_webob_request(request) try: with tracker.get_tracker().context(tracking_context_name, tracking_context): resp = instance.handle(handler, req, suffix) except NoSuchHandlerError: log.exception("XBlock %s attempted to access missing handler %r", instance, handler) raise Http404 # If we can't find the module, respond with a 404 except NotFoundError: log.exception("Module indicating to user that request doesn't exist") raise Http404 # For XModule-specific errors, we log the error and respond with an error message except ProcessingError as err: log.warning("Module encountered an error while processing AJAX call", exc_info=True) return JsonResponse(object={"success": err.args[0]}, status=200) # If any other error occurred, re-raise it to trigger a 500 response except Exception: log.exception("error executing xblock handler") raise return webob_to_django_response(resp)
def mobi_directory(request, course_id): user = User.objects.prefetch_related("groups").get(id=request.user.id) request.user = user # keep just one instance of User course = get_course_with_access(user, course_id, 'load', depth=2) staff_access = has_access(user, course, 'staff') registered = registered_for_course(course, user) motoc = mobi_toc_for_course(user, request, course) show_list = list() for toc in motoc: videolist = toc['show_url'][0] show_list.append(videolist) if not registered: # TODO (vshnayder): do course instructors need to be registered to see course? log.debug(u'User %s tried to view course %s but is not enrolled', user, course.location.url()) return redirect(reverse('about_course', args=[course.id])) masq = setup_masquerade(request, staff_access) try: field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course.id, user, course, depth=2) course_module = get_module_for_descriptor(user, request, course, field_data_cache, course.id) if course_module is None: log.warning(u'If you see this, something went wrong: if we got this' u' far, should have gotten a course module for this user') return redirect(reverse('about_course', args=[course.id])) context = { 'csrf': csrf(request)['csrf_token'], 'accordion': mobi_render_accordion(request, course), 'COURSE_TITLE': course.display_name_with_default, 'course': course, 'init': '', 'fragment': Fragment(), 'staff_access': staff_access, 'masquerade': masq, 'xqa_server': settings.FEATURES.get('USE_XQA_SERVER', 'http://*****:*****@content-qa.mitx.mit.edu/xqa'), 'reverifications': fetch_reverify_banner_info(request, course_id), 'show_url': show_list[0], } result = render_to_response('wechat/mobi_directory.html', context) except Exception as e: if isinstance(e, Http404): # let it propagate raise # In production, don't want to let a 500 out for any reason if settings.DEBUG: raise else: log.exception("Error in index view: user={user}, course={course},".format( user=user, course=course,)) try: result = render_to_response('courseware/courseware-error.html', {'staff_access': staff_access, 'course': course}) except: # Let the exception propagate, relying on global config to at # at least return a nice error message log.exception("Error while rendering courseware-error page") raise return result
def index(request, course_id): # Request data course_key = get_course_key(course_id) course = get_course_module(course_key) user = request.user staff_access = has_access(request.user, 'staff', course) instructor_access = has_access(request.user, 'instructor', course) masq = setup_masquerade( request, staff_access) # allow staff to toggle masquerade on info page studio_url = get_studio_url(course, 'course_info') reverifications = fetch_reverify_banner_info(request, course_key) #course = get_course_with_access(request.user, action='load', course_key=course_key, depth=None, check_if_enrolled=False) # Proficiency and pass limit pass_limit = get_course_grade_cutoff(course) proficiency_limit = (1 - pass_limit) / 2 + pass_limit usernames_in = [] for student in CourseEnrollment.users_enrolled_in(course_key): usernames_in.append(student.username.encode('utf-8')) # Data for visualization in JSON user_for_charts = '#average' if (staff_access or instructor_access) else user kwargs = { 'qualifiers': { 'category': 'video', }, } # This returns video descriptors in the order they appear on the course video_descriptors = videos_problems_in(course)[0] video_durations = get_info_videos_descriptors(video_descriptors)[2] video_ids_str = [] course_video_names = [] for descriptor in video_descriptors: video_ids_str.append( (course_key.make_usage_key('video', descriptor.location.name))._to_string()) course_video_names.append(descriptor.display_name_with_default) if len(video_descriptors) > 0: first_video_id = course_key.make_usage_key( 'video', video_descriptors[0].location.name) # Video progress visualization. Video percentage seen total and non-overlapped. video_names, avg_video_time, video_percentages = get_module_consumption( user_for_charts, course_key, 'video', 'video_progress') if avg_video_time != []: all_video_time_percent = map(truediv, avg_video_time, video_durations) all_video_time_percent = [ int(round(x * 100, 0)) for x in all_video_time_percent ] else: all_video_time_percent = avg_video_time column_headers = ['Video', 'Different video time', 'Total video time'] video_prog_json = ready_for_arraytodatatable(column_headers, video_names, video_percentages, all_video_time_percent) video_names, all_video_time = get_module_consumption( user_for_charts, course_key, 'video', 'total_time_vid_prob')[0:2] # Time spent on every video resource column_headers = ['Video', 'Time watched'] video_distrib_json = ready_for_arraytodatatable( column_headers, video_names, all_video_time) # Video events dispersion within video length scatter_array = get_video_events_info(user_for_charts, first_video_id) # Repetitions per video intervals user_for_vid_intervals = '#class_total_times' if user_for_charts == '#average' else user_for_charts video_intervals_array = get_user_video_intervals( user_for_vid_intervals, first_video_id) # Case no videos in course else: video_names = None video_prog_json = simplejson.dumps(None) video_distrib_json = simplejson.dumps(None) scatter_array = simplejson.dumps(None) video_intervals_array = simplejson.dumps(None) # Time spent on every problem resource problem_names, time_x_problem = get_module_consumption( user_for_charts, course_key, 'problem', 'total_time_vid_prob')[0:2] column_headers = ['Problem', 'Time on problem'] problem_distrib_json = ready_for_arraytodatatable(column_headers, problem_names, time_x_problem) # Daily time spent on video and/or problem resources video_days, video_daily_time = get_daily_consumption( user_for_charts, course_key, 'video') problem_days, problem_daily_time = get_daily_consumption( user_for_charts, course_key, 'problem') vid_and_prob_daily_time = join_video_problem_time(video_days, video_daily_time, problem_days, problem_daily_time) #Analytics visualizations if staff_access or instructor_access: # Instructor access std_sort = get_DB_sort_course_homework(course_key) # Chapter time cs, st = get_DB_course_spent_time(course_key, student_id=ALL_STUDENTS) students_spent_time = chapter_time_to_js(cs, st) students_grades = get_DB_student_grades(course_key, student_id=ALL_STUDENTS) cs, sa = course_accesses = get_DB_course_section_accesses( course_key, student_id=ALL_STUDENTS) students_course_accesses = course_accesses_to_js(cs, sa) students_prob_vid_progress = get_DB_course_video_problem_progress( course_key, student_id=ALL_STUDENTS) students_time_schedule = get_DB_time_schedule(course_key, student_id=ALL_STUDENTS) else: # Sort homework # Chapter time std_sort = None cs, st = get_DB_course_spent_time(course_key, user.id) students_spent_time = chapter_time_to_js(cs, st) students_grades = get_DB_student_grades(course_key, user.id) cs, sa = course_accesses = get_DB_course_section_accesses( course_key, user.id) students_course_accesses = course_accesses_to_js(cs, sa) students_time_schedule = get_DB_time_schedule(course_key, user.id) students_prob_vid_progress = get_DB_course_video_problem_progress( course_key, user.id) context = { 'course': course, 'request': request, 'user': user, 'user_id': user.id, 'staff_access': staff_access, 'instructor_access': instructor_access, 'masquerade': masq, 'studio_url': studio_url, 'reverifications': reverifications, 'course_id': course_id, 'students': students_to_js(get_course_students(course_key)), 'visualizations_id': VISUALIZATIONS_ID, 'std_grades_dump': dumps(students_grades), 'sort_std_dump': dumps(std_sort), 'time_dump': dumps(students_spent_time), 'accesses_dump': dumps(students_course_accesses), 'std_time_schedule_dumb': dumps(students_time_schedule), 'vid_prob_prog_dump': dumps(students_prob_vid_progress), 'pass_limit': pass_limit, 'prof_limit': proficiency_limit, 'usernames_in': usernames_in, 'video_names': course_video_names, 'video_ids': video_ids_str, 'video_prog_json': video_prog_json, 'video_distrib_json': video_distrib_json, 'problem_distrib_json': problem_distrib_json, 'video_intervals_array': video_intervals_array, 'vid_and_prob_daily_time': vid_and_prob_daily_time, 'scatter_array': scatter_array, } return render_to_response('learning_analytics/learning_analytics.html', context)
def index(request, course_id, chapter=None, section=None, position=None): """ Displays courseware accordion and associated content. If course, chapter, and section are all specified, renders the page, or returns an error if they are invalid. If section is not specified, displays the accordion opened to the right chapter. If neither chapter or section are specified, redirects to user's most recent chapter, or the first chapter if this is the user's first visit. Arguments: - request : HTTP request - course_id : course id (str: ORG/course/URL_NAME) - chapter : chapter url_name (str) - section : section url_name (str) - position : position in module, eg of <sequential> module (str) Returns: - HTTPresponse """ course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) user = User.objects.prefetch_related("groups").get(id=request.user.id) request.user = user # keep just one instance of User course = get_course_with_access(user, 'load', course_key, depth=2) staff_access = has_access(user, 'staff', course) registered = registered_for_course(course, user) if not registered: # TODO (vshnayder): do course instructors need to be registered to see course? log.debug(u'User %s tried to view course %s but is not enrolled', user, course.location.to_deprecated_string()) return redirect(reverse('about_course', args=[course_key.to_deprecated_string()])) masq = setup_masquerade(request, staff_access) try: field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course_key, user, course, depth=2) course_module = get_module_for_descriptor(user, request, course, field_data_cache, course_key) if course_module is None: log.warning(u'If you see this, something went wrong: if we got this' u' far, should have gotten a course module for this user') return redirect(reverse('about_course', args=[course_key.to_deprecated_string()])) studio_url = get_studio_url(course_key, 'course') context = { 'csrf': csrf(request)['csrf_token'], 'accordion': render_accordion(request, course, chapter, section, field_data_cache), 'COURSE_TITLE': course.display_name_with_default, 'course': course, 'init': '', 'fragment': Fragment(), 'staff_access': staff_access, 'studio_url': studio_url, 'masquerade': masq, 'xqa_server': settings.FEATURES.get('USE_XQA_SERVER', 'http://*****:*****@content-qa.mitx.mit.edu/xqa'), 'reverifications': fetch_reverify_banner_info(request, course_key), } has_content = course.has_children_at_depth(CONTENT_DEPTH) if not has_content: # Show empty courseware for a course with no units return render_to_response('courseware/courseware.html', context) elif chapter is None: # passing CONTENT_DEPTH avoids returning 404 for a course with an # empty first section and a second section with content return redirect_to_course_position(course_module, CONTENT_DEPTH) # Only show the chat if it's enabled by the course and in the # settings. show_chat = course.show_chat and settings.FEATURES['ENABLE_CHAT'] if show_chat: context['chat'] = chat_settings(course, user) # If we couldn't load the chat settings, then don't show # the widget in the courseware. if context['chat'] is None: show_chat = False context['show_chat'] = show_chat chapter_descriptor = course.get_child_by(lambda m: m.location.name == chapter) if chapter_descriptor is not None: save_child_position(course_module, chapter) else: raise Http404('No chapter descriptor found with name {}'.format(chapter)) chapter_module = course_module.get_child_by(lambda m: m.location.name == chapter) if chapter_module is None: # User may be trying to access a chapter that isn't live yet if masq == 'student': # if staff is masquerading as student be kinder, don't 404 log.debug('staff masq as student: no chapter %s' % chapter) return redirect(reverse('courseware', args=[course.id.to_deprecated_string()])) raise Http404 if section is not None: section_descriptor = chapter_descriptor.get_child_by(lambda m: m.location.name == section) if section_descriptor is None: # Specifically asked-for section doesn't exist if masq == 'student': # if staff is masquerading as student be kinder, don't 404 log.debug('staff masq as student: no section %s' % section) return redirect(reverse('courseware', args=[course.id.to_deprecated_string()])) raise Http404 ## Allow chromeless operation if section_descriptor.chrome: chrome = [s.strip() for s in section_descriptor.chrome.lower().split(",")] if 'accordion' not in chrome: context['disable_accordion'] = True if 'tabs' not in chrome: context['disable_tabs'] = True if section_descriptor.default_tab: context['default_tab'] = section_descriptor.default_tab # cdodge: this looks silly, but let's refetch the section_descriptor with depth=None # which will prefetch the children more efficiently than doing a recursive load section_descriptor = modulestore().get_item(section_descriptor.location, depth=None) # Load all descendants of the section, because we're going to display its # html, which in general will need all of its children section_field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course_key, user, section_descriptor, depth=None) # Verify that position a string is in fact an int if position is not None: try: int(position) except ValueError: raise Http404("Position {} is not an integer!".format(position)) section_module = get_module_for_descriptor( request.user, request, section_descriptor, section_field_data_cache, course_key, position ) if section_module is None: # User may be trying to be clever and access something # they don't have access to. raise Http404 # Save where we are in the chapter save_child_position(chapter_module, section) context['fragment'] = section_module.render(STUDENT_VIEW) context['section_title'] = section_descriptor.display_name_with_default else: # section is none, so display a message studio_url = get_studio_url(course_key, 'course') prev_section = get_current_child(chapter_module) if prev_section is None: # Something went wrong -- perhaps this chapter has no sections visible to the user raise Http404 prev_section_url = reverse('courseware_section', kwargs={ 'course_id': course_key.to_deprecated_string(), 'chapter': chapter_descriptor.url_name, 'section': prev_section.url_name }) context['fragment'] = Fragment(content=render_to_string( 'courseware/welcome-back.html', { 'course': course, 'studio_url': studio_url, 'chapter_module': chapter_module, 'prev_section': prev_section, 'prev_section_url': prev_section_url } )) result = render_to_response('courseware/courseware.html', context) except Exception as e: # Doesn't bar Unicode characters from URL, but if Unicode characters do # cause an error it is a graceful failure. if isinstance(e, UnicodeEncodeError): raise Http404("URL contains Unicode characters") if isinstance(e, Http404): # let it propagate raise # In production, don't want to let a 500 out for any reason if settings.DEBUG: raise else: log.exception( u"Error in index view: user={user}, course={course}, chapter={chapter}" u" section={section} position={position}".format( user=user, course=course, chapter=chapter, section=section, position=position )) try: result = render_to_response('courseware/courseware-error.html', { 'staff_access': staff_access, 'course': course }) except: # Let the exception propagate, relying on global config to at # at least return a nice error message log.exception("Error while rendering courseware-error page") raise return result
def index(request, course_id): # Request data course_key = get_course_key(course_id) course = get_course_module(course_key) user = request.user staff_access = has_access(request.user, 'staff', course) instructor_access = has_access(request.user, 'instructor', course) masq = setup_masquerade(request, staff_access) # allow staff to toggle masquerade on info page studio_url = get_studio_url(course, 'course_info') reverifications = fetch_reverify_banner_info(request, course_key) #course = get_course_with_access(request.user, action='load', course_key=course_key, depth=None, check_if_enrolled=False) # Proficiency and pass limit pass_limit = get_course_grade_cutoff(course) proficiency_limit = (1 - pass_limit) / 2 + pass_limit usernames_in = [] for student in CourseEnrollment.users_enrolled_in(course_key): usernames_in.append(student.username.encode('utf-8')) # Data for visualization in JSON user_for_charts = '#average' if (staff_access or instructor_access) else user kwargs = { 'qualifiers': {'category': 'video', }, } # This returns video descriptors in the order they appear on the course video_descriptors = videos_problems_in(course)[0] video_durations = get_info_videos_descriptors(video_descriptors)[2] video_ids_str = [] course_video_names = [] for descriptor in video_descriptors: video_ids_str.append((course_key.make_usage_key('video', descriptor.location.name))._to_string()) course_video_names.append(descriptor.display_name_with_default) if len(video_descriptors) > 0: first_video_id = course_key.make_usage_key('video', video_descriptors[0].location.name) # Video progress visualization. Video percentage seen total and non-overlapped. video_names, avg_video_time, video_percentages = get_module_consumption(user_for_charts, course_key, 'video', 'video_progress') if avg_video_time != []: all_video_time_percent = map(truediv, avg_video_time, video_durations) all_video_time_percent = [int(round(x*100,0)) for x in all_video_time_percent] else: all_video_time_percent = avg_video_time column_headers = ['Video', 'Different video time', 'Total video time'] video_prog_json = ready_for_arraytodatatable(column_headers, video_names, video_percentages, all_video_time_percent) video_names, all_video_time = get_module_consumption(user_for_charts, course_key, 'video', 'total_time_vid_prob')[0:2] # Time spent on every video resource column_headers = ['Video', 'Time watched'] video_distrib_json = ready_for_arraytodatatable(column_headers, video_names, all_video_time) # Video events dispersion within video length scatter_array = get_video_events_info(user_for_charts, first_video_id) # Repetitions per video intervals user_for_vid_intervals = '#class_total_times' if user_for_charts == '#average' else user_for_charts video_intervals_array = get_user_video_intervals(user_for_vid_intervals, first_video_id) # Case no videos in course else: video_names = None video_prog_json = simplejson.dumps(None) video_distrib_json = simplejson.dumps(None) scatter_array = simplejson.dumps(None) video_intervals_array = simplejson.dumps(None) # Time spent on every problem resource problem_names, time_x_problem = get_module_consumption(user_for_charts, course_key, 'problem', 'total_time_vid_prob')[0:2] column_headers = ['Problem', 'Time on problem'] problem_distrib_json = ready_for_arraytodatatable(column_headers, problem_names, time_x_problem) # Daily time spent on video and/or problem resources video_days, video_daily_time = get_daily_consumption(user_for_charts, course_key, 'video') problem_days, problem_daily_time = get_daily_consumption(user_for_charts, course_key, 'problem') vid_and_prob_daily_time = join_video_problem_time(video_days, video_daily_time, problem_days, problem_daily_time) #Analytics visualizations if staff_access or instructor_access: # Instructor access std_sort = get_DB_sort_course_homework(course_key) # Chapter time cs, st = get_DB_course_spent_time(course_key, student_id=ALL_STUDENTS) students_spent_time = chapter_time_to_js(cs, st) students_grades = get_DB_student_grades(course_key, student_id=ALL_STUDENTS) cs, sa = course_accesses = get_DB_course_section_accesses(course_key, student_id=ALL_STUDENTS) students_course_accesses = course_accesses_to_js(cs, sa) students_prob_vid_progress = get_DB_course_video_problem_progress(course_key, student_id=ALL_STUDENTS) students_time_schedule = get_DB_time_schedule(course_key, student_id=ALL_STUDENTS) else: # Sort homework # Chapter time std_sort = None cs, st = get_DB_course_spent_time(course_key, user.id) students_spent_time = chapter_time_to_js(cs, st) students_grades = get_DB_student_grades(course_key, user.id) cs, sa = course_accesses = get_DB_course_section_accesses(course_key, user.id) students_course_accesses = course_accesses_to_js(cs, sa) students_time_schedule = get_DB_time_schedule(course_key, user.id) students_prob_vid_progress = get_DB_course_video_problem_progress(course_key, user.id) context = {'course': course, 'request': request, 'user': user, 'user_id': user.id, 'staff_access': staff_access, 'instructor_access': instructor_access, 'masquerade': masq, 'studio_url': studio_url, 'reverifications': reverifications, 'course_id': course_id, 'students': students_to_js(get_course_students(course_key)), 'visualizations_id': VISUALIZATIONS_ID, 'std_grades_dump': dumps(students_grades), 'sort_std_dump': dumps(std_sort), 'time_dump': dumps(students_spent_time), 'accesses_dump': dumps(students_course_accesses), 'std_time_schedule_dumb': dumps(students_time_schedule), 'vid_prob_prog_dump': dumps(students_prob_vid_progress), 'pass_limit': pass_limit, 'prof_limit': proficiency_limit, 'usernames_in' : usernames_in, 'video_names' : course_video_names, 'video_ids' : video_ids_str, 'video_prog_json' : video_prog_json, 'video_distrib_json' : video_distrib_json, 'problem_distrib_json' : problem_distrib_json, 'video_intervals_array' : video_intervals_array, 'vid_and_prob_daily_time' : vid_and_prob_daily_time, 'scatter_array' : scatter_array, } return render_to_response('learning_analytics/learning_analytics.html', context)
def piazza_discussion(request, course_id): ''' Shows the page under the Discussion tab with an iframe containing Piazza ''' # Create a new tool configuration config = ToolConfig(title='Piazza', launch_url=LTI_LAUNCH_URL) # Create tool consumer using LTI! consumer = ToolConsumer(LTI_CONSUMER_KEY, LTI_CONSUMER_SECRET) consumer.set_config(config) #retrieve user and course models user = User.objects.prefetch_related("groups").get(id=request.user.id) userProfile = UserProfile.objects.get(user_id=user.id) course = course_from_id(course_id) #check for permissions to determine what role to pass to Piazza.com through piazza_role = '' if user.groups.filter(name=( 'instructor_' + course_id)).count() != 0 or request.user.is_staff: piazza_role = 'Instructor' elif user.groups.filter(name=('staff_' + course_id)).count() != 0: piazza_role = 'Staff' else: piazza_role = 'Learner' # Set some launch data from: http://www.imsglobal.org/LTI/v1p1pd/ltiIMGv1p1pd.html#_Toc309649684 consumer.resource_link_id = course_id consumer.lis_person_contact_email_primary = user.email consumer.lis_person_name_full = str(userProfile.name) hash = hashlib.md5() hash.update(str(userProfile.user_id)) consumer.user_id = hash.hexdigest() #TODO: check if user is is_staff, student, professor, or staff and set the role appropriately consumer.roles = piazza_role consumer.context_id = course_id consumer.context_title = course.display_name_with_default consumer.context_label = course.number.replace('_', ' ') consumer.tool_consumer_instance_guid = 'lms.cvn.columbia.edu' consumer.tool_consumer_instance_description = 'Columbia University' launch_data = consumer.generate_launch_data() launch_url = consumer.launch_url course = get_course_with_access(request.user, course_id, 'load') staff_access = has_access(request.user, course, 'staff') masq = setup_masquerade( request, staff_access) # allow staff to toggle masquerade on info page return render_to_response( 'courseware/piazza_discussion.html', { 'request': request, 'course_id': course_id, 'cache': None, 'course': course, 'staff_access': staff_access, 'masquerade': masq, 'launch_url': launch_url, 'launch_data': launch_data })
def index(request, course_id, chapter=None, section=None, position=None): """ Displays courseware accordion and associated content. If course, chapter, and section are all specified, renders the page, or returns an error if they are invalid. If section is not specified, displays the accordion opened to the right chapter. If neither chapter or section are specified, redirects to user's most recent chapter, or the first chapter if this is the user's first visit. Arguments: - request : HTTP request - course_id : course id (str: ORG/course/URL_NAME) - chapter : chapter url_name (str) - section : section url_name (str) - position : position in module, eg of <sequential> module (str) Returns: - HTTPresponse """ course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) user = User.objects.prefetch_related("groups").get(id=request.user.id) request.user = user # keep just one instance of User course = get_course_with_access(user, 'load', course_key, depth=2) staff_access = has_access(user, 'staff', course) registered = registered_for_course(course, user) if not registered: # TODO (vshnayder): do course instructors need to be registered to see course? log.debug(u'User %s tried to view course %s but is not enrolled', user, course.location.to_deprecated_string()) return redirect( reverse('about_course', args=[course_key.to_deprecated_string()])) masq = setup_masquerade(request, staff_access) try: field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course_key, user, course, depth=2) course_module = get_module_for_descriptor(user, request, course, field_data_cache, course_key) if course_module is None: log.warning( u'If you see this, something went wrong: if we got this' u' far, should have gotten a course module for this user') return redirect( reverse('about_course', args=[course_key.to_deprecated_string()])) studio_url = get_studio_url(course_key, 'course') context = { 'csrf': csrf(request)['csrf_token'], 'accordion': render_accordion(request, course, chapter, section, field_data_cache), 'COURSE_TITLE': course.display_name_with_default, 'course': course, 'init': '', 'fragment': Fragment(), 'staff_access': staff_access, 'studio_url': studio_url, 'masquerade': masq, 'xqa_server': settings.FEATURES.get( 'USE_XQA_SERVER', 'http://*****:*****@content-qa.mitx.mit.edu/xqa'), 'reverifications': fetch_reverify_banner_info(request, course_key), } has_content = course.has_children_at_depth(CONTENT_DEPTH) if not has_content: # Show empty courseware for a course with no units return render_to_response('courseware/courseware.html', context) elif chapter is None: # passing CONTENT_DEPTH avoids returning 404 for a course with an # empty first section and a second section with content return redirect_to_course_position(course_module, CONTENT_DEPTH) # Only show the chat if it's enabled by the course and in the # settings. show_chat = course.show_chat and settings.FEATURES['ENABLE_CHAT'] if show_chat: context['chat'] = chat_settings(course, user) # If we couldn't load the chat settings, then don't show # the widget in the courseware. if context['chat'] is None: show_chat = False context['show_chat'] = show_chat chapter_descriptor = course.get_child_by( lambda m: m.location.name == chapter) if chapter_descriptor is not None: save_child_position(course_module, chapter) else: raise Http404( 'No chapter descriptor found with name {}'.format(chapter)) chapter_module = course_module.get_child_by( lambda m: m.location.name == chapter) if chapter_module is None: # User may be trying to access a chapter that isn't live yet if masq == 'student': # if staff is masquerading as student be kinder, don't 404 log.debug('staff masq as student: no chapter %s' % chapter) return redirect( reverse('courseware', args=[course.id.to_deprecated_string()])) raise Http404 if section is not None: section_descriptor = chapter_descriptor.get_child_by( lambda m: m.location.name == section) if section_descriptor is None: # Specifically asked-for section doesn't exist if masq == 'student': # if staff is masquerading as student be kinder, don't 404 log.debug('staff masq as student: no section %s' % section) return redirect( reverse('courseware', args=[course.id.to_deprecated_string()])) raise Http404 ## Allow chromeless operation if section_descriptor.chrome: chrome = [ s.strip() for s in section_descriptor.chrome.lower().split(",") ] if 'accordion' not in chrome: context['disable_accordion'] = True if 'tabs' not in chrome: context['disable_tabs'] = True if section_descriptor.default_tab: context['default_tab'] = section_descriptor.default_tab # cdodge: this looks silly, but let's refetch the section_descriptor with depth=None # which will prefetch the children more efficiently than doing a recursive load section_descriptor = modulestore().get_item( section_descriptor.location, depth=None) # Load all descendants of the section, because we're going to display its # html, which in general will need all of its children section_field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course_key, user, section_descriptor, depth=None) # Verify that position a string is in fact an int if position is not None: try: int(position) except ValueError: raise Http404( "Position {} is not an integer!".format(position)) section_module = get_module_for_descriptor( request.user, request, section_descriptor, section_field_data_cache, course_key, position) if section_module is None: # User may be trying to be clever and access something # they don't have access to. raise Http404 # Save where we are in the chapter save_child_position(chapter_module, section) context['fragment'] = section_module.render(STUDENT_VIEW) context[ 'section_title'] = section_descriptor.display_name_with_default else: # section is none, so display a message studio_url = get_studio_url(course_key, 'course') prev_section = get_current_child(chapter_module) if prev_section is None: # Something went wrong -- perhaps this chapter has no sections visible to the user raise Http404 prev_section_url = reverse('courseware_section', kwargs={ 'course_id': course_key.to_deprecated_string(), 'chapter': chapter_descriptor.url_name, 'section': prev_section.url_name }) context['fragment'] = Fragment(content=render_to_string( 'courseware/welcome-back.html', { 'course': course, 'studio_url': studio_url, 'chapter_module': chapter_module, 'prev_section': prev_section, 'prev_section_url': prev_section_url })) result = render_to_response('courseware/courseware.html', context) except Exception as e: # Doesn't bar Unicode characters from URL, but if Unicode characters do # cause an error it is a graceful failure. if isinstance(e, UnicodeEncodeError): raise Http404("URL contains Unicode characters") if isinstance(e, Http404): # let it propagate raise # In production, don't want to let a 500 out for any reason if settings.DEBUG: raise else: log.exception( u"Error in index view: user={user}, course={course}, chapter={chapter}" u" section={section} position={position}".format( user=user, course=course, chapter=chapter, section=section, position=position)) try: result = render_to_response('courseware/courseware-error.html', { 'staff_access': staff_access, 'course': course }) except: # Let the exception propagate, relying on global config to at # at least return a nice error message log.exception("Error while rendering courseware-error page") raise return result
def index(request, course_id, chapter=None, section=None, position=None): """ Displays courseware accordion and associated content. If course, chapter, and section are all specified, renders the page, or returns an error if they are invalid. If section is not specified, displays the accordion opened to the right chapter. If neither chapter or section are specified, redirects to user's most recent chapter, or the first chapter if this is the user's first visit. Arguments: - request : HTTP request - course_id : course id (str: ORG/course/URL_NAME) - chapter : chapter url_name (str) - section : section url_name (str) - position : position in module, eg of <sequential> module (str) Returns: - HTTPresponse """ user = User.objects.prefetch_related("groups").get(id=request.user.id) request.user = user # keep just one instance of User course = get_course_with_access(user, course_id, 'load', depth=2) staff_access = has_access(user, course, 'staff') registered = registered_for_course(course, user) if not registered: # TODO (vshnayder): do course instructors need to be registered to see course? log.debug('User %s tried to view course %s but is not enrolled' % (user, course.location.url())) return redirect(reverse('about_course', args=[course.id])) masq = setup_masquerade(request, staff_access) try: model_data_cache = ModelDataCache.cache_for_descriptor_descendents( course.id, user, course, depth=2) course_module = get_module_for_descriptor(user, request, course, model_data_cache, course.id) if course_module is None: log.warning( 'If you see this, something went wrong: if we got this' ' far, should have gotten a course module for this user') return redirect(reverse('about_course', args=[course.id])) if chapter is None: return redirect_to_course_position(course_module) context = { 'csrf': csrf(request)['csrf_token'], 'accordion': render_accordion(request, course, chapter, section, model_data_cache), 'COURSE_TITLE': course.display_name_with_default, 'course': course, 'init': '', 'content': '', 'staff_access': staff_access, 'masquerade': masq, 'xqa_server': settings.MITX_FEATURES.get( 'USE_XQA_SERVER', 'http://*****:*****@content-qa.mitx.mit.edu/xqa') } # Only show the chat if it's enabled by the course and in the # settings. show_chat = course.show_chat and settings.MITX_FEATURES['ENABLE_CHAT'] if show_chat: context['chat'] = chat_settings(course, user) # If we couldn't load the chat settings, then don't show # the widget in the courseware. if context['chat'] is None: show_chat = False context['show_chat'] = show_chat chapter_descriptor = course.get_child_by( lambda m: m.url_name == chapter) if chapter_descriptor is not None: save_child_position(course_module, chapter) else: raise Http404( 'No chapter descriptor found with name {}'.format(chapter)) chapter_module = course_module.get_child_by( lambda m: m.url_name == chapter) if chapter_module is None: # User may be trying to access a chapter that isn't live yet if masq == 'student': # if staff is masquerading as student be kinder, don't 404 log.debug('staff masq as student: no chapter %s' % chapter) return redirect(reverse('courseware', args=[course.id])) raise Http404 if section is not None: section_descriptor = chapter_descriptor.get_child_by( lambda m: m.url_name == section) if section_descriptor is None: # Specifically asked-for section doesn't exist if masq == 'student': # if staff is masquerading as student be kinder, don't 404 log.debug('staff masq as student: no section %s' % section) return redirect(reverse('courseware', args=[course.id])) raise Http404 # cdodge: this looks silly, but let's refetch the section_descriptor with depth=None # which will prefetch the children more efficiently than doing a recursive load section_descriptor = modulestore().get_instance( course.id, section_descriptor.location, depth=None) # Load all descendants of the section, because we're going to display its # html, which in general will need all of its children section_model_data_cache = ModelDataCache.cache_for_descriptor_descendents( course_id, user, section_descriptor, depth=None) section_module = get_module(request.user, request, section_descriptor.location, section_model_data_cache, course_id, position, depth=None) if section_module is None: # User may be trying to be clever and access something # they don't have access to. raise Http404 # Save where we are in the chapter save_child_position(chapter_module, section) # check here if this section *is* a timed module. if section_module.category == 'timelimit': timer_context = update_timelimit_module( user, course_id, student_module_cache, section_descriptor, section_module) if 'timer_expiration_duration' in timer_context: context.update(timer_context) else: # if there is no expiration defined, then we know the timer has expired: return HttpResponseRedirect( timer_context['time_expired_redirect_url']) else: # check here if this page is within a course that has an active timed module running. If so, then # add in the appropriate timer information to the rendering context: context.update( check_for_active_timelimit_module(request, course_id, course)) context['content'] = section_module.runtime.render( section_module, None, 'student_view').content else: # section is none, so display a message prev_section = get_current_child(chapter_module) if prev_section is None: # Something went wrong -- perhaps this chapter has no sections visible to the user raise Http404 prev_section_url = reverse('courseware_section', kwargs={ 'course_id': course_id, 'chapter': chapter_descriptor.url_name, 'section': prev_section.url_name }) context['content'] = render_to_string( 'courseware/welcome-back.html', { 'course': course, 'chapter_module': chapter_module, 'prev_section': prev_section, 'prev_section_url': prev_section_url }) result = render_to_response('courseware/courseware.html', context) except Exception as e: if isinstance(e, Http404): # let it propagate raise # In production, don't want to let a 500 out for any reason if settings.DEBUG: raise else: log.exception("Error in index view: user={user}, course={course}," " chapter={chapter} section={section}" "position={position}".format(user=user, course=course, chapter=chapter, section=section, position=position)) try: result = render_to_response('courseware/courseware-error.html', { 'staff_access': staff_access, 'course': course }) except: # Let the exception propagate, relying on global config to at # at least return a nice error message log.exception("Error while rendering courseware-error page") raise return result
def mobi_index(request, course_id, chapter=None, section=None, position=None): user = User.objects.prefetch_related("groups").get(id=request.user.id) request.user = user # keep just one instance of User course = get_course_with_access(user, course_id, 'load', depth=2) staff_access = has_access(user, course, 'staff') registered = registered_for_course(course, user) if not registered: # TODO (vshnayder): do course instructors need to be registered to see course? log.debug(u'User %s tried to view course %s but is not enrolled', user, course.location.url()) return redirect(reverse('about_course', args=[course.id])) masq = setup_masquerade(request, staff_access) try: field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course.id, user, course, depth=2) course_module = get_module_for_descriptor(user, request, course, field_data_cache, course.id) if course_module is None: log.warning(u'If you see this, something went wrong: if we got this' u' far, should have gotten a course module for this user') return redirect(reverse('about_course', args=[course.id])) if chapter is None: return redirect_to_course_position(course_module) context = { 'csrf': csrf(request)['csrf_token'], 'accordion': render_accordion(request, course, chapter, section, field_data_cache), 'COURSE_TITLE': course.display_name_with_default, 'course': course, 'init': '', 'fragment': Fragment(), 'staff_access': staff_access, 'masquerade': masq, 'xqa_server': settings.FEATURES.get('USE_XQA_SERVER', 'http://*****:*****@content-qa.mitx.mit.edu/xqa'), 'reverifications': fetch_reverify_banner_info(request, course_id), } # Only show the chat if it's enabled by the course and in the # settings. show_chat = course.show_chat and settings.FEATURES['ENABLE_CHAT'] if show_chat: context['chat'] = chat_settings(course, user) # If we couldn't load the chat settings, then don't show # the widget in the courseware. if context['chat'] is None: show_chat = False context['show_chat'] = show_chat chapter_descriptor = course.get_child_by(lambda m: m.url_name == chapter) if chapter_descriptor is not None: save_child_position(course_module, chapter) else: raise Http404('No chapter descriptor found with name {}'.format(chapter)) chapter_module = course_module.get_child_by(lambda m: m.url_name == chapter) if chapter_module is None: # User may be trying to access a chapter that isn't live yet if masq=='student': # if staff is masquerading as student be kinder, don't 404 log.debug('staff masq as student: no chapter %s' % chapter) return redirect(reverse('courseware', args=[course.id])) raise Http404 if section is not None: section_descriptor = chapter_descriptor.get_child_by(lambda m: m.url_name == section) if section_descriptor is None: # Specifically asked-for section doesn't exist if masq=='student': # if staff is masquerading as student be kinder, don't 404 log.debug('staff masq as student: no section %s' % section) return redirect(reverse('courseware', args=[course.id])) raise Http404 # cdodge: this looks silly, but let's refetch the section_descriptor with depth=None # which will prefetch the children more efficiently than doing a recursive load section_descriptor = modulestore().get_instance(course.id, section_descriptor.location, depth=None) # Load all descendants of the section, because we're going to display its # html, which in general will need all of its children section_field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course_id, user, section_descriptor, depth=None) section_module = get_module_for_descriptor(request.user, request, section_descriptor, section_field_data_cache, course_id, position ) if section_module is None: # User may be trying to be clever and access something # they don't have access to. raise Http404 # Save where we are in the chapter save_child_position(chapter_module, section) context['fragment'] = section_module.render('mobi_student_view') context['section_title'] = section_descriptor.display_name_with_default else: # section is none, so display a message prev_section = get_current_child(chapter_module) if prev_section is None: # Something went wrong -- perhaps this chapter has no sections visible to the user raise Http404 prev_section_url = reverse('courseware_section', kwargs={'course_id': course_id, 'chapter': chapter_descriptor.url_name, 'section': prev_section.url_name}) context['fragment'] = Fragment(content=render_to_string( 'courseware/welcome-back.html', { 'course': course, 'chapter_module': chapter_module, 'prev_section': prev_section, 'prev_section_url': prev_section_url } )) result = render_to_response('wechat/mobi_courseware.html', context) except Exception as e: if isinstance(e, Http404): # let it propagate raise # In production, don't want to let a 500 out for any reason if settings.DEBUG: raise else: log.exception("Error in index view: user={user}, course={course}," " chapter={chapter} section={section}" "position={position}".format( user=user, course=course, chapter=chapter, section=section, position=position )) try: result = render_to_response('courseware/courseware-error.html', {'staff_access': staff_access, 'course': course}) except: # Let the exception propagate, relying on global config to at # at least return a nice error message log.exception("Error while rendering courseware-error page") raise return result
def index(request, course_id, chapter=None, section=None, position=None): """ Displays courseware accordion and associated content. If course, chapter, and section are all specified, renders the page, or returns an error if they are invalid. If section is not specified, displays the accordion opened to the right chapter. If neither chapter or section are specified, redirects to user's most recent chapter, or the first chapter if this is the user's first visit. Arguments: - request : HTTP request - course_id : course id (str: ORG/course/URL_NAME) - chapter : chapter url_name (str) - section : section url_name (str) - position : position in module, eg of <sequential> module (str) Returns: - HTTPresponse """ user = User.objects.prefetch_related("groups").get(id=request.user.id) request.user = user # keep just one instance of User course = get_course_with_access(user, course_id, 'load', depth=2) staff_access = has_access(user, course, 'staff') registered = registered_for_course(course, user) if not registered: # TODO (vshnayder): do course instructors need to be registered to see course? log.debug('User %s tried to view course %s but is not enrolled' % (user, course.location.url())) return redirect(reverse('about_course', args=[course.id])) masq = setup_masquerade(request, staff_access) try: field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course.id, user, course, depth=2) course_module = get_module_for_descriptor(user, request, course, field_data_cache, course.id) if course_module is None: log.warning('If you see this, something went wrong: if we got this' ' far, should have gotten a course module for this user') return redirect(reverse('about_course', args=[course.id])) if chapter is None: return redirect_to_course_position(course_module) context = { 'csrf': csrf(request)['csrf_token'], 'accordion': render_accordion(request, course, chapter, section, field_data_cache), 'COURSE_TITLE': course.display_name_with_default, 'course': course, 'init': '', 'content': '', 'staff_access': staff_access, 'masquerade': masq, 'xqa_server': settings.MITX_FEATURES.get('USE_XQA_SERVER', 'http://*****:*****@content-qa.mitx.mit.edu/xqa'), #@begin:Inform the template that it is in homepage #@date:2013-11-02 'is_index':'True' #@end } # Only show the chat if it's enabled by the course and in the # settings. show_chat = course.show_chat and settings.MITX_FEATURES['ENABLE_CHAT'] if show_chat: context['chat'] = chat_settings(course, user) # If we couldn't load the chat settings, then don't show # the widget in the courseware. if context['chat'] is None: show_chat = False context['show_chat'] = show_chat chapter_descriptor = course.get_child_by(lambda m: m.url_name == chapter) if chapter_descriptor is not None: save_child_position(course_module, chapter) else: raise Http404('No chapter descriptor found with name {}'.format(chapter)) chapter_module = course_module.get_child_by(lambda m: m.url_name == chapter) if chapter_module is None: # User may be trying to access a chapter that isn't live yet if masq=='student': # if staff is masquerading as student be kinder, don't 404 log.debug('staff masq as student: no chapter %s' % chapter) return redirect(reverse('courseware', args=[course.id])) raise Http404 if section is not None: section_descriptor = chapter_descriptor.get_child_by(lambda m: m.url_name == section) if section_descriptor is None: # Specifically asked-for section doesn't exist if masq=='student': # if staff is masquerading as student be kinder, don't 404 log.debug('staff masq as student: no section %s' % section) return redirect(reverse('courseware', args=[course.id])) raise Http404 # cdodge: this looks silly, but let's refetch the section_descriptor with depth=None # which will prefetch the children more efficiently than doing a recursive load section_descriptor = modulestore().get_instance(course.id, section_descriptor.location, depth=None) # Load all descendants of the section, because we're going to display its # html, which in general will need all of its children section_field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course_id, user, section_descriptor, depth=None) section_module = get_module(request.user, request, section_descriptor.location, section_field_data_cache, course_id, position, depth=None) if section_module is None: # User may be trying to be clever and access something # they don't have access to. raise Http404 # Save where we are in the chapter save_child_position(chapter_module, section) # check here if this section *is* a timed module. if section_module.category == 'timelimit': timer_context = update_timelimit_module(user, course_id, student_module_cache, section_descriptor, section_module) if 'timer_expiration_duration' in timer_context: context.update(timer_context) else: # if there is no expiration defined, then we know the timer has expired: return HttpResponseRedirect(timer_context['time_expired_redirect_url']) else: # check here if this page is within a course that has an active timed module running. If so, then # add in the appropriate timer information to the rendering context: context.update(check_for_active_timelimit_module(request, course_id, course)) context['content'] = section_module.runtime.render(section_module, None, 'student_view').content else: # section is none, so display a message prev_section = get_current_child(chapter_module) if prev_section is None: # Something went wrong -- perhaps this chapter has no sections visible to the user raise Http404 prev_section_url = reverse('courseware_section', kwargs={'course_id': course_id, 'chapter': chapter_descriptor.url_name, 'section': prev_section.url_name}) context['content'] = render_to_string('courseware/welcome-back.html', {'course': course, 'chapter_module': chapter_module, 'prev_section': prev_section, 'prev_section_url': prev_section_url}) result = render_to_response('courseware/courseware.html', context) except Exception as e: if isinstance(e, Http404): # let it propagate raise # In production, don't want to let a 500 out for any reason if settings.DEBUG: raise else: log.exception("Error in index view: user={user}, course={course}," " chapter={chapter} section={section}" "position={position}".format( user=user, course=course, chapter=chapter, section=section, position=position )) try: result = render_to_response('courseware/courseware-error.html', {'staff_access': staff_access, 'course': course}) except: # Let the exception propagate, relying on global config to at # at least return a nice error message log.exception("Error while rendering courseware-error page") raise return result
def index(request, course_id, chapter=None, section=None, position=None): """ Displays courseware accordion and associated content. If course, chapter, and section are all specified, renders the page, or returns an error if they are invalid. If section is not specified, displays the accordion opened to the right chapter. If neither chapter or section are specified, redirects to user's most recent chapter, or the first chapter if this is the user's first visit. Arguments: - request : HTTP request - course_id : course id (str: ORG/course/URL_NAME) - chapter : chapter url_name (str) - section : section url_name (str) - position : position in module, eg of <sequential> module (str) Returns: - HTTPresponse """ user = User.objects.prefetch_related("groups").get(id=request.user.id) request.user = user # keep just one instance of User # Если пользователь не активен - отправляем на главную страницу if not user.is_active and not user.profile.is_demo: return redirect('/') try: course = get_course_with_access(user, course_id, 'load', depth=2) except: return redirect('/') # Если курс помечен, как непубликуемый в LMS - отправляем на главную страницу if not course.show_in_lms: return redirect('/') staff_access = has_access(user, course, 'staff') registered = registered_for_course(course, user) if not registered: # TODO (vshnayder): do course instructors need to be registered to see course? log.debug('User %s tried to view course %s but is not enrolled' % (user, course.location.url())) return redirect(reverse('about_course', args=[course.id])) masq = setup_masquerade(request, staff_access) try: field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course.id, user, course, depth=2) course_module = get_module_for_descriptor(user, request, course, field_data_cache, course.id) if course_module is None: log.warning('If you see this, something went wrong: if we got this' ' far, should have gotten a course module for this user') return redirect(reverse('about_course', args=[course.id])) if chapter is None: return redirect_to_course_position(course_module) context = { 'csrf': csrf(request)['csrf_token'], 'accordion': render_accordion(request, course, chapter, section, field_data_cache), 'COURSE_TITLE': course.display_name_with_default, 'course': course, 'init': '', 'fragment': Fragment(), 'staff_access': staff_access, 'masquerade': masq, 'xqa_server': settings.FEATURES.get('USE_XQA_SERVER', 'http://*****:*****@content-qa.mitx.mit.edu/xqa') } # Only show the chat if it's enabled by the course and in the # settings. show_chat = course.show_chat and settings.FEATURES['ENABLE_CHAT'] if show_chat: context['chat'] = chat_settings(course, user) # If we couldn't load the chat settings, then don't show # the widget in the courseware. if context['chat'] is None: show_chat = False context['show_chat'] = show_chat chapter_descriptor = course.get_child_by(lambda m: m.url_name == chapter) if chapter_descriptor is not None: save_child_position(course_module, chapter) else: raise Http404('No chapter descriptor found with name {}'.format(chapter)) chapter_module = course_module.get_child_by(lambda m: m.url_name == chapter) if chapter_module is None: # User may be trying to access a chapter that isn't live yet if masq=='student': # if staff is masquerading as student be kinder, don't 404 log.debug('staff masq as student: no chapter %s' % chapter) return redirect(reverse('courseware', args=[course.id])) raise Http404 if section is not None: section_descriptor = chapter_descriptor.get_child_by(lambda m: m.url_name == section) if section_descriptor is None: # Specifically asked-for section doesn't exist if masq=='student': # if staff is masquerading as student be kinder, don't 404 log.debug('staff masq as student: no section %s' % section) return redirect(reverse('courseware', args=[course.id])) raise Http404 # cdodge: this looks silly, but let's refetch the section_descriptor with depth=None # which will prefetch the children more efficiently than doing a recursive load section_descriptor = modulestore().get_instance(course.id, section_descriptor.location, depth=None) # Load all descendants of the section, because we're going to display its # html, which in general will need all of its children section_field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course_id, user, section_descriptor, depth=None) section_module = get_module_for_descriptor(request.user, request, section_descriptor, section_field_data_cache, course_id, position ) if section_module is None: # User may be trying to be clever and access something # they don't have access to. raise Http404 # model_data_cache_for_check = ModelDataCache.cache_for_descriptor_descendents(course_id, user, course, depth=None) courseware_summary = grades.progress_summary(user, request, course) is_section_unlocked = grades.return_section_by_id(section_module.url_name, courseware_summary)['unlocked'] #Контент раздела закрыт для демопользователя is_demo = UserProfile.objects.get(user=request.user).is_demo if is_demo and not section_module.available_for_demo: is_section_unlocked = False # Save where we are in the chapter save_child_position(chapter_module, section) context['fragment'] = section_module.render('student_view', context) else: # section is none, so display a message prev_section = get_current_child(chapter_module) if prev_section is None: # Something went wrong -- perhaps this chapter has no sections visible to the user raise Http404 prev_section_url = reverse('courseware_section', kwargs={'course_id': course_id, 'chapter': chapter_descriptor.url_name, 'section': prev_section.url_name}) context['fragment'] = Fragment(content=render_to_string( 'courseware/welcome-back.html', { 'course': course, 'chapter_module': chapter_module, 'prev_section': prev_section, 'prev_section_url': prev_section_url } )) result = render_to_response('courseware/courseware.html', context) except Exception as e: if isinstance(e, Http404): # let it propagate raise # In production, don't want to let a 500 out for any reason if settings.DEBUG: raise else: log.exception("Error in index view: user={user}, course={course}," " chapter={chapter} section={section}" "position={position}".format( user=user, course=course, chapter=chapter, section=section, position=position )) try: result = render_to_response('courseware/courseware-error.html', {'staff_access': staff_access, 'course': course}) except: # Let the exception propagate, relying on global config to at # at least return a nice error message log.exception("Error while rendering courseware-error page") raise return result
def get_module_for_descriptor( user, request, descriptor, model_data_cache, course_id, position=None, wrap_xmodule_display=True, grade_bucket_type=None): """ Actually implement get_module. See docstring there for details. """ # allow course staff to masquerade as student if has_access(user, descriptor, 'staff', course_id): setup_masquerade(request, True) # Short circuit--if the user shouldn't have access, bail without doing any # work if not has_access(user, descriptor, 'load', course_id): return None # Setup system context for module instance ajax_url = reverse('modx_dispatch', kwargs=dict(course_id=course_id, location=descriptor.location.url(), dispatch=''), ) # Intended use is as {ajax_url}/{dispatch_command}, so get rid of the # trailing slash. ajax_url = ajax_url.rstrip('/') def make_xqueue_callback(dispatch='score_update'): # Fully qualified callback URL for external queueing system xqueue_callback_url = '{proto}://{host}'.format( host=request.get_host(), proto=request.META.get( 'HTTP_X_FORWARDED_PROTO', 'https' if request.is_secure() else 'http') ) xqueue_callback_url = settings.XQUEUE_INTERFACE.get( 'callback_url', xqueue_callback_url) # allow override xqueue_callback_url += reverse('xqueue_callback', kwargs=dict(course_id=course_id, userid=str(user.id), id=descriptor.location.url( ), dispatch=dispatch), ) return xqueue_callback_url # Default queuename is course-specific and is derived from the course that # contains the current module. # TODO: Queuename should be derived from 'course_settings.json' of each # course xqueue_default_queuename = descriptor.location.org + \ '-' + descriptor.location.course xqueue = {'interface': xqueue_interface, 'construct_callback': make_xqueue_callback, 'default_queuename': xqueue_default_queuename.replace(' ', '_'), 'waittime': settings.XQUEUE_WAITTIME_BETWEEN_REQUESTS } # This is a hacky way to pass settings to the combined open ended xmodule # It needs an S3 interface to upload images to S3 # It needs the open ended grading interface in order to get peer grading to be done # this first checks to see if the descriptor is the correct one, and only # sends settings if it is # Get descriptor metadata fields indicating needs for various settings needs_open_ended_interface = getattr( descriptor, "needs_open_ended_interface", False) needs_s3_interface = getattr(descriptor, "needs_s3_interface", False) # Initialize interfaces to None open_ended_grading_interface = None s3_interface = None # Create interfaces if needed if needs_open_ended_interface: open_ended_grading_interface = settings.OPEN_ENDED_GRADING_INTERFACE open_ended_grading_interface[ 'mock_peer_grading'] = settings.MOCK_PEER_GRADING open_ended_grading_interface[ 'mock_staff_grading'] = settings.MOCK_STAFF_GRADING if needs_s3_interface: s3_interface = { 'access_key': getattr(settings, 'AWS_ACCESS_KEY_ID', ''), 'secret_access_key': getattr(settings, 'AWS_SECRET_ACCESS_KEY', ''), 'storage_bucket_name': getattr(settings, 'AWS_STORAGE_BUCKET_NAME', 'openended') } def inner_get_module(descriptor): """ Delegate to get_module. It does an access check, so may return None """ return get_module_for_descriptor(user, request, descriptor, model_data_cache, course_id, position) def xblock_model_data(descriptor): return DbModel( LmsKeyValueStore(descriptor._model_data, model_data_cache), descriptor.module_class, user.id, LmsUsage(descriptor.location, descriptor.location) ) def publish(event): if event.get('event_name') != 'grade': return student_module, created = StudentModule.objects.get_or_create( course_id=course_id, student=user, module_type=descriptor.location.category, module_state_key=descriptor.location.url(), defaults={'state': '{}'}, ) student_module.grade = event.get('value') student_module.max_grade = event.get('max_value') student_module.save() # Bin score into range and increment stats score_bucket = get_score_bucket( student_module.grade, student_module.max_grade) org, course_num, run = course_id.split("/") tags = ["org:{0}".format(org), "course:{0}".format(course_num), "run:{0}".format(run), "score_bucket:{0}".format(score_bucket)] if grade_bucket_type is not None: tags.append('type:%s' % grade_bucket_type) statsd.increment("lms.courseware.question_answered", tags=tags) def can_execute_unsafe_code(): # To decide if we can run unsafe code, we check the course id against # a list of regexes configured on the server. for regex in settings.COURSES_WITH_UNSAFE_CODE: if re.match(regex, course_id): return True return False # TODO (cpennington): When modules are shared between courses, the static # prefix is going to have to be specific to the module, not the directory # that the xml was loaded from system = ModuleSystem(track_function=make_track_function(request), render_template=render_to_string, ajax_url=ajax_url, xqueue=xqueue, # TODO (cpennington): Figure out how to share info # between systems filestore=descriptor.system.resources_fs, get_module=inner_get_module, user=user, # TODO (cpennington): This should be removed when all html from # a module is coming through get_html and is therefore covered # by the replace_static_urls code below replace_urls=partial( static_replace.replace_static_urls, data_directory=getattr( descriptor, 'data_dir', None), course_namespace=descriptor.location._replace( category=None, name=None), ), node_path=settings.NODE_PATH, xblock_model_data=xblock_model_data, publish=publish, anonymous_student_id=unique_id_for_user(user), course_id=course_id, open_ended_grading_interface=open_ended_grading_interface, s3_interface=s3_interface, cache=cache, can_execute_unsafe_code=can_execute_unsafe_code, ) # pass position specified in URL to module through ModuleSystem system.set('position', position) system.set('DEBUG', settings.DEBUG) if settings.MITX_FEATURES.get('ENABLE_PSYCHOMETRICS'): system.set('psychometrics_handler', # set callback for updating PsychometricsData make_psychometrics_data_update_handler(course_id, user, descriptor.location.url())) try: module = descriptor.xmodule(system) except: log.exception( "Error creating module from descriptor {0}".format(descriptor)) # make an ErrorDescriptor -- assuming that the descriptor's system is # ok if has_access(user, descriptor.location, 'staff', course_id): err_descriptor_class = ErrorDescriptor else: err_descriptor_class = NonStaffErrorDescriptor err_descriptor = err_descriptor_class.from_xml( str(descriptor), descriptor.system, org=descriptor.location.org, course=descriptor.location.course, error_msg=exc_info_to_str(sys.exc_info()) ) # Make an error module return err_descriptor.xmodule(system) system.set('user_is_staff', has_access( user, descriptor.location, 'staff', course_id)) _get_html = module.get_html if wrap_xmodule_display: _get_html = wrap_xmodule( module.get_html, module, 'xmodule_display.html') module.get_html = replace_static_urls( _get_html, getattr(descriptor, 'data_dir', None), course_namespace=module.location._replace(category=None, name=None)) # Allow URLs of the form '/course/' refer to the root of multicourse directory # hierarchy of this course module.get_html = replace_course_urls(module.get_html, course_id) if settings.MITX_FEATURES.get('DISPLAY_HISTOGRAMS_TO_STAFF'): if has_access(user, module, 'staff', course_id): module.get_html = add_histogram(module.get_html, module, user) return module
def index(request, course_id): # Palette color_not = '#CCCCCC' color_fail = '#e41a1c' color_ok = '#F2F20D' color_prof = '#4daf4a' problem_activity='#377eb8' video_activity='#ff7f00' video_repetition='#fdbf6f' course_activity='#984ea3' graded_time='#88419d' ungraded_time='#8c6bb1' chapter_time='#8c96c6' play_event='#1b9e77' pause_event='#d95f02' seek_from_event='#7570b3' seek_to_event='#e7298a' change_speed_event='#66a61e' morning_time='#C9C96C' afternoon_time ='#7F7160' night_time ='#50587C' # Request data course_key = get_course_key(course_id) course = get_course_module(course_key) #course2= get_course_by_id(SlashSeparatedCourseKey.from_deprecated_string(course_id)) #user = request.user #Codigo Jose A. Gascon staff_access = has_access(request.user, 'staff', course).has_access#Codigo Jose A. Gascon instructor_access = has_access(request.user, 'instructor', course).has_access#Codigo Jose A. Gascon #Codigo Jose A. Gascon masq, user = setup_masquerade(request, course_key,staff_access, reset_masquerade_data=True) # allow staff to toggle masquerade on info page user = request.user studio_url = get_studio_url(course, 'course_info') #reverifications = fetch_reverify_banner_info(request, course_key) #course = get_course_with_access(request.user, action='load', course_key=course_key, depth=None, check_if_enrolled=False) #user = User.objects.get(request.user.email) # Proficiency and pass limit pass_limit = get_course_grade_cutoff(course) proficiency_limit = (1 - pass_limit) / 2 + pass_limit usernames_in = [] for student in CourseEnrollment.objects.users_enrolled_in(course_key):#Codigo Jose A. Gascon, se cambia la forma de llamar al metode users_enrolled_in usernames_in.append(student.username.encode('utf-8')) # Data for visualization in JSON user_for_charts = '#average' if (staff_access or instructor_access) else user kwargs = { 'qualifiers': {'category': 'video', }, } # This returns video descriptors in the order they appear on the course video_descriptors = videos_problems_in(course)[0] #WARNINIG #video_durations = get_info_videos_descriptors(video_descriptors)[2] #video_names, video_module_keys, video_durations = get_info_videos_descriptors(video_descriptors) # NO SE USAN LAS OTRAS VARIABLES video_names, video_module_keys, video_durations =get_DB_infovideos() video_names_sorted = video_names video_ids_sort = video_names_sorted #course_name = get_course_by_id(course_key, depth=None) names_students=[] only_students = [] students_names = get_course_students(course_key) print students_names for student in students_names: staff_access_user = has_access(student, 'staff', course).has_access instructor_access_user = has_access(student, 'instructor', course).has_access if not (staff_access_user or instructor_access_user): names_students.append(student.username.encode('utf-8')) only_students.append(student) video_ids_str = [] course_video_names = [] problem_ids_str=[] for descriptor in video_descriptors: video_ids_str.append((course_key.make_usage_key('video', descriptor.location.name))._to_string()) course_video_names.append(descriptor.display_name_with_default) if len(video_descriptors) > 0: first_video_id = course_key.make_usage_key('video', video_descriptors[0].location.name) # Video progress visualization. Video percentage seen total and non-overlapped. video_names, avg_video_time, video_percentages = get_video_time_watched(user_for_charts, course_key) if avg_video_time != []: all_video_time_percent = map(truediv, avg_video_time, video_durations) all_video_time_percent = [int(round(x*100,0)) for x in all_video_time_percent] else: all_video_time_percent = avg_video_time column_headers = ['Video', 'Different video time', 'Total video time'] # Codigo Javier Orcoyen video_prog_json = ready_for_arraytodatatable(column_headers, video_names, video_percentages, all_video_time_percent) video_names, all_video_time = get_module_consumption(user_for_charts, course_key, 'video') # Time spent on every video resource column_headers = ['Video', 'Time watched'] video_distrib_json = ready_for_arraytodatatable(column_headers, video_names, all_video_time) # Video events dispersion within video length scatter_array = get_video_events_info(user_for_charts, first_video_id) # Repetitions per video intervals user_for_vid_intervals = '#class_total_times' if user_for_charts == '#average' else user_for_charts video_intervals_array = get_user_video_intervals(user_for_vid_intervals, first_video_id) # Case no videos in course else: video_names = None video_prog_json = json.dumps(None) video_distrib_json = json.dumps(None) scatter_array = json.dumps(None) video_intervals_array = json.dumps(None) # Time spent on every problem resource # Codigo Javier Orcoyen problem_names, time_x_problem = get_module_consumption(user_for_charts, course_key, 'problem') column_headers = ['Problem', 'Time on problem'] problem_distrib_json = ready_for_arraytodatatable(column_headers, problem_names, time_x_problem) print 'USER' print user problems_in = videos_problems_in(course)[1] problem_names_sorted = [x.display_name_with_default.encode('utf-8') for x in problems_in] orden=[] orden.append(i for i, x in enumerate(problem_names_sorted)) problem_ids_str=problem_names_sorted # Daily time spent on video and/or problem resources video_days, video_daily_time = get_daily_consumption(user_for_charts, course_key, 'video') problem_days, problem_daily_time = get_daily_consumption(user_for_charts, course_key, 'problem') vid_and_prob_daily_time = join_video_problem_time(video_days, video_daily_time, problem_days, problem_daily_time) #Analytics visualizations if staff_access or instructor_access: # Instructor access std_sort = get_DB_sort_course_homework(course_key) # Chapter time cs, st = get_DB_course_spent_time(course_key, student_id=ALL_STUDENTS) students_spent_time = chapter_time_to_js(cs, st) students_grades = get_DB_student_grades(course_key, student_id=ALL_STUDENTS) cs, sa = course_accesses = get_DB_course_section_accesses(course_key, student_id=ALL_STUDENTS) students_course_accesses = course_accesses_to_js(cs, sa) #students_prob_vid_progress = get_DB_course_video_problem_progress(course_key, student_id=ALL_STUDENTS)# C. J. A. Gascon ERROR students_time_schedule = get_DB_time_schedule(course_key, student_id=ALL_STUDENTS) else: # Sort homework # Chapter time std_sort = None cs, st = get_DB_course_spent_time(course_key, user.id) students_spent_time = chapter_time_to_js(cs, st) students_grades = get_DB_student_grades(course_key, user.id) cs, sa = course_accesses = get_DB_course_section_accesses(course_key, user.id) students_course_accesses = course_accesses_to_js(cs, sa) students_time_schedule = get_DB_time_schedule(course_key, user.id) #students_prob_vid_progress = get_DB_course_video_problem_progress(course_key, user.id) #C. J. A. Gascon ERROR context = {'course': course, 'request': request, 'user': user, 'user_id': user.id, 'staff_access': staff_access, 'instructor_access': instructor_access, 'masquerade': masq, 'studio_url': studio_url, #'reverifications': reverifications, 'course_id': course_id, 'students': students_to_js(only_students), 'visualizations_id': VISUALIZATIONS_ID, 'std_grades_dump': dumps(students_grades), 'sort_std_dump': dumps(std_sort), 'time_dump': dumps(students_spent_time), 'accesses_dump': dumps(students_course_accesses), 'std_time_schedule_dumb': dumps(students_time_schedule), #'vid_prob_prog_dump': dumps(students_prob_vid_progress), #C. J. A. Gascon ERROR 'pass_limit': pass_limit, 'prof_limit': proficiency_limit, 'usernames_in' : usernames_in, 'video_names' : course_video_names, 'video_ids' : video_ids_str, 'video_prog_json' : video_prog_json, 'video_distrib_json' : video_distrib_json, 'problem_distrib_json' : problem_distrib_json, 'video_intervals_array' : video_intervals_array, 'vid_and_prob_daily_time' : vid_and_prob_daily_time, 'scatter_array' : scatter_array, 'problem_names' : problem_names, 'problem_ids' : problem_ids_str, 'color_not' : color_not, 'color_ok' : color_ok, 'color_prof' : color_prof, 'color_fail' : color_fail, 'problem_activity' : problem_activity, 'video_activity' : video_activity, 'course_activity' : course_activity, 'video_repetition' : video_repetition, 'graded_time' : graded_time, 'ungraded_time' : ungraded_time, 'chapter_time' : chapter_time, 'user_for_charts' : user_for_charts, 'video_ids_sort' : video_ids_sort, 'video_names_sorted' : video_names_sorted, 'problem_names_sorted' : problem_names_sorted, 'play_event' : play_event, 'pause_event' : pause_event, 'seek_from_event' : seek_from_event, 'seek_to_event' : seek_to_event, 'change_speed_event' : change_speed_event, 'morning_time' : morning_time, 'afternoon_time' : afternoon_time, 'night_time' : night_time, 'names_students' : names_students,} return render_to_response('learning_analytics/learning_analytics.html', context)