def instrument_course_progress_render(
            self, course_width, enable_ccx, view_as_ccx,
            sql_queries, mongo_reads,
    ):
        """
        Renders the progress page, instrumenting Mongo reads and SQL queries.
        """
        course_key = self.setup_course(course_width, enable_ccx, view_as_ccx)

        # Switch to published-only mode to simulate the LMS
        with self.settings(MODULESTORE_BRANCH='published-only'):
            # Clear all caches before measuring
            for cache in settings.CACHES:
                caches[cache].clear()

            # Refill the metadata inheritance cache
            get_course_in_cache(course_key)

            # We clear the request cache to simulate a new request in the LMS.
            RequestCache.clear_request_cache()

            # Reset the list of provider classes, so that our django settings changes
            # can actually take affect.
            OverrideFieldData.provider_classes = None

            with self.assertNumQueries(sql_queries, using='default', table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
                with self.assertNumQueries(0, using='student_module_history'):
                    with self.assertMongoCallCount(mongo_reads):
                        with self.assertXBlockInstantiations(1):
                            self.grade_course(course_key)
    def instrument_course_progress_render(
        self,
        course_width,
        enable_ccx,
        view_as_ccx,
        sql_queries,
        mongo_reads,
    ):
        """
        Renders the progress page, instrumenting Mongo reads and SQL queries.
        """
        course_key = self.setup_course(course_width, enable_ccx, view_as_ccx)

        # Switch to published-only mode to simulate the LMS
        with self.settings(MODULESTORE_BRANCH='published-only'):
            # Clear all caches before measuring
            for cache in settings.CACHES:
                caches[cache].clear()

            # Refill the metadata inheritance cache
            get_course_in_cache(course_key)

            # We clear the request cache to simulate a new request in the LMS.
            RequestCache.clear_request_cache()

            # Reset the list of provider classes, so that our django settings changes
            # can actually take affect.
            OverrideFieldData.provider_classes = None

            with self.assertNumQueries(sql_queries, using='default'):
                with self.assertNumQueries(0, using='student_module_history'):
                    with self.assertMongoCallCount(mongo_reads):
                        with self.assertXBlockInstantiations(1):
                            self.grade_course(course_key)
Example #3
0
    def test_queries(self):
        """
        Verify that the view's query count doesn't regress.
        """
        # Pre-fill the course blocks cache
        get_course_in_cache(self.course.id)

        # Fetch the view and verify the query counts
        with self.assertNumQueries(36):
            with check_mongo_calls(3):
                url = course_home_url(self.course)
                self.client.get(url)
Example #4
0
    def test_queries(self):
        """
        Verify that the view's query count doesn't regress.
        """
        # Pre-fill the course blocks cache
        get_course_in_cache(self.course.id)

        # Fetch the view and verify the query counts
        with self.assertNumQueries(36):
            with check_mongo_calls(3):
                url = course_home_url(self.course)
                self.client.get(url)
Example #5
0
def recalculate_subsection_grade_handler(sender, **kwargs):  # pylint: disable=unused-argument
    """
    Consume the SCORE_CHANGED signal and trigger an update.
    This method expects that the kwargs dictionary will contain the following
    entries (See the definition of SCORE_CHANGED):
       - points_possible: Maximum score available for the exercise
       - points_earned: Score obtained by the user
       - user: User object
       - course_id: Unicode string representing the course
       - usage_id: Unicode string indicating the courseware instance
    """
    student = kwargs['user']
    course_key = CourseLocator.from_string(kwargs['course_id'])
    if not PersistentGradesEnabledFlag.feature_enabled(course_key):
        return

    scored_block_usage_key = UsageKey.from_string(kwargs['usage_id']).replace(course_key=course_key)
    collected_block_structure = get_course_in_cache(course_key)
    course = get_course_by_id(course_key, depth=0)

    subsections_to_update = collected_block_structure.get_transformer_block_field(
        scored_block_usage_key,
        GradesTransformer,
        'subsections',
        set()
    )
    for subsection_usage_key in subsections_to_update:
        transformed_subsection_structure = get_course_blocks(
            student,
            subsection_usage_key,
            collected_block_structure=collected_block_structure,
        )
        SubsectionGradeFactory(student).update(subsection_usage_key, transformed_subsection_structure, course)
Example #6
0
    def handle(self, *args, **options):

        if options.get('all'):
            course_keys = [
                course.id for course in modulestore().get_course_summaries()
            ]
        else:
            if len(args) < 1:
                raise CommandError(
                    'At least one course or --all must be specified.')
            try:
                course_keys = [CourseKey.from_string(arg) for arg in args]
            except InvalidKeyError:
                raise CommandError('Invalid key specified.')

        log.info('Generating course blocks for %d courses.', len(course_keys))
        log.debug('Generating course blocks for the following courses: %s',
                  course_keys)

        for course_key in course_keys:
            try:
                if options.get('force'):
                    block_structure = update_course_in_cache(course_key)
                else:
                    block_structure = get_course_in_cache(course_key)
                if options.get('dags'):
                    self._find_and_log_dags(block_structure, course_key)
            except Exception as ex:  # pylint: disable=broad-except
                log.exception(
                    'An error occurred while generating course blocks for %s: %s',
                    unicode(course_key),
                    ex.message,
                )

        log.info('Finished generating course blocks.')
Example #7
0
def recalculate_subsection_grade_handler(sender, **kwargs):  # pylint: disable=unused-argument
    """
    Consume the SCORE_CHANGED signal and trigger an update.
    This method expects that the kwargs dictionary will contain the following
    entries (See the definition of SCORE_CHANGED):
       - points_possible: Maximum score available for the exercise
       - points_earned: Score obtained by the user
       - user: User object
       - course_id: Unicode string representing the course
       - usage_id: Unicode string indicating the courseware instance
    """
    student = kwargs['user']
    course_key = CourseLocator.from_string(kwargs['course_id'])
    if not PersistentGradesEnabledFlag.feature_enabled(course_key):
        return

    scored_block_usage_key = UsageKey.from_string(
        kwargs['usage_id']).replace(course_key=course_key)
    collected_block_structure = get_course_in_cache(course_key)
    course = get_course_by_id(course_key, depth=0)

    subsections_to_update = collected_block_structure.get_transformer_block_field(
        scored_block_usage_key, GradesTransformer, 'subsections', set())
    subsection_grade_factory = SubsectionGradeFactory(
        student, course, collected_block_structure)
    for subsection_usage_key in subsections_to_update:
        transformed_subsection_structure = get_course_blocks(
            student,
            subsection_usage_key,
            collected_block_structure=collected_block_structure,
        )
        subsection_grade_factory.update(
            transformed_subsection_structure[subsection_usage_key],
            transformed_subsection_structure)
    def handle(self, *args, **options):

        if options.get('all'):
            course_keys = [course.id for course in modulestore().get_course_summaries()]
        else:
            if len(args) < 1:
                raise CommandError('At least one course or --all must be specified.')
            try:
                course_keys = [CourseKey.from_string(arg) for arg in args]
            except InvalidKeyError:
                raise CommandError('Invalid key specified.')

        log.info('Generating course blocks for %d courses.', len(course_keys))
        log.debug('Generating course blocks for the following courses: %s', course_keys)

        for course_key in course_keys:
            try:
                if options.get('force'):
                    block_structure = update_course_in_cache(course_key)
                else:
                    block_structure = get_course_in_cache(course_key)
                if options.get('dags'):
                    self._find_and_log_dags(block_structure, course_key)
            except Exception as ex:  # pylint: disable=broad-except
                log.exception(
                    'An error occurred while generating course blocks for %s: %s',
                    unicode(course_key),
                    ex.message,
                )

        log.info('Finished generating course blocks.')
Example #9
0
def recalculate_subsection_grade(user_id, course_id, usage_id):
    """
    Updates a saved subsection grade.
    This method expects the following parameters:
       - user_id: serialized id of applicable User object
       - course_id: Unicode string representing the course
       - usage_id: Unicode string indicating the courseware instance
    """
    course_key = CourseLocator.from_string(course_id)
    if not PersistentGradesEnabledFlag.feature_enabled(course_key):
        return

    student = User.objects.get(id=user_id)
    scored_block_usage_key = UsageKey.from_string(usage_id).replace(
        course_key=course_key)

    collected_block_structure = get_course_in_cache(course_key)
    course = get_course_by_id(course_key, depth=0)
    subsection_grade_factory = SubsectionGradeFactory(
        student, course, collected_block_structure)
    subsections_to_update = collected_block_structure.get_transformer_block_field(
        scored_block_usage_key, GradesTransformer, 'subsections', set())

    for subsection_usage_key in subsections_to_update:
        transformed_subsection_structure = get_course_blocks(
            student,
            subsection_usage_key,
            collected_block_structure=collected_block_structure,
        )
        subsection_grade_factory.update(
            transformed_subsection_structure[subsection_usage_key],
            transformed_subsection_structure)
Example #10
0
def recalculate_subsection_grade(user_id, course_id, usage_id, only_if_higher):
    """
    Updates a saved subsection grade.
    This method expects the following parameters:
       - user_id: serialized id of applicable User object
       - course_id: Unicode string representing the course
       - usage_id: Unicode string indicating the courseware instance
       - only_if_higher: boolean indicating whether grades should
        be updated only if the new grade is higher than the previous
        value.
    """
    if not PersistentGradesEnabledFlag.feature_enabled(course_id):
        return

    course_key = CourseLocator.from_string(course_id)
    student = User.objects.get(id=user_id)
    scored_block_usage_key = UsageKey.from_string(usage_id).replace(
        course_key=course_key)

    collected_block_structure = get_course_in_cache(course_key)
    course = modulestore().get_course(course_key, depth=0)
    subsection_grade_factory = SubsectionGradeFactory(
        student, course, collected_block_structure)
    subsections_to_update = collected_block_structure.get_transformer_block_field(
        scored_block_usage_key, GradesTransformer, 'subsections', set())

    try:
        for subsection_usage_key in subsections_to_update:
            transformed_subsection_structure = get_course_blocks(
                student,
                subsection_usage_key,
                collected_block_structure=collected_block_structure,
            )
            subsection_grade = subsection_grade_factory.update(
                transformed_subsection_structure[subsection_usage_key],
                transformed_subsection_structure,
                only_if_higher,
            )
            SUBSECTION_SCORE_CHANGED.send(
                sender=recalculate_subsection_grade,
                course=course,
                user=student,
                subsection_grade=subsection_grade,
            )

    except IntegrityError as exc:
        raise recalculate_subsection_grade.retry(
            args=[user_id, course_id, usage_id], exc=exc)
Example #11
0
    def handle(self, *args, **options):

        if options.get('all'):
            course_keys = [
                course.id for course in modulestore().get_course_summaries()
            ]
            if options.get('start'):
                end = options.get('end') or len(course_keys)
                course_keys = course_keys[options['start']:end]
        else:
            if len(args) < 1:
                raise CommandError(
                    'At least one course or --all must be specified.')
            try:
                course_keys = [CourseKey.from_string(arg) for arg in args]
            except InvalidKeyError:
                raise CommandError('Invalid key specified.')

        log.info('Generating course blocks for %d courses.', len(course_keys))

        if options.get('verbose'):
            log.setLevel(logging.DEBUG)
        else:
            log.setLevel(logging.CRITICAL)

        dag_info = _DAGInfo()
        for course_key in course_keys:
            try:
                if options.get('force'):
                    block_structure = update_course_in_cache(course_key)
                else:
                    block_structure = get_course_in_cache(course_key)
                if options.get('dags'):
                    self._find_and_log_dags(block_structure, course_key,
                                            dag_info)
            except Exception as ex:  # pylint: disable=broad-except
                log.exception(
                    'An error occurred while generating course blocks for %s: %s',
                    unicode(course_key),
                    ex.message,
                )

        log.info('Finished generating course blocks.')

        if options.get('dags'):
            log.critical('DAG data: %s', unicode(dag_info))
Example #12
0
 def setUp(self):
     super(CourseDataTest, self).setUp()
     with self.store.default_store(ModuleStoreEnum.Type.split):
         self.course = CourseFactory.create()
         # need to re-retrieve the course since the version on the original course isn't accurate.
         self.course = self.store.get_course(self.course.id)
     self.user = UserFactory.create()
     self.collected_structure = get_course_in_cache(self.course.id)
     self.one_true_structure = get_course_blocks(
         self.user, self.course.location, collected_block_structure=self.collected_structure,
     )
     self.expected_results = {
         'course': self.course,
         'collected_block_structure': self.collected_structure,
         'structure': self.one_true_structure,
         'course_key': self.course.id,
         'location': self.course.location,
     }
Example #13
0
 def setUp(self):
     super(CourseDataTest, self).setUp()
     with self.store.default_store(ModuleStoreEnum.Type.split):
         self.course = CourseFactory.create()
         # need to re-retrieve the course since the version on the original course isn't accurate.
         self.course = self.store.get_course(self.course.id)
     self.user = UserFactory.create()
     self.collected_structure = get_course_in_cache(self.course.id)
     self.one_true_structure = get_course_blocks(
         self.user, self.course.location, collected_block_structure=self.collected_structure,
     )
     self.expected_results = {
         'course': self.course,
         'collected_block_structure': self.collected_structure,
         'structure': self.one_true_structure,
         'course_key': self.course.id,
         'location': self.course.location,
     }
Example #14
0
def recalculate_subsection_grade_handler(sender, **kwargs):  # pylint: disable=unused-argument
    """
    Consume the SCORE_CHANGED signal and trigger an update.
    This method expects that the kwargs dictionary will contain the following
    entries (See the definition of SCORE_CHANGED):
       - points_possible: Maximum score available for the exercise
       - points_earned: Score obtained by the user
       - user: User object
       - course_id: Unicode string representing the course
       - usage_id: Unicode string indicating the courseware instance
    """
    try:
        course_id = kwargs['course_id']
        usage_id = kwargs['usage_id']
        student = kwargs['user']
    except KeyError:
        log.exception(
            u"Failed to process SCORE_CHANGED signal, some arguments were missing."
            "user: %s, course_id: %s, usage_id: %s.",
            kwargs.get('user', None),
            kwargs.get('course_id', None),
            kwargs.get('usage_id', None),
        )
        return

    course_key = CourseLocator.from_string(course_id)
    if not PersistentGradesEnabledFlag.feature_enabled(course_key):
        return

    usage_key = UsageKey.from_string(usage_id).replace(course_key=course_key)
    block_structure = get_course_in_cache(course_key)

    subsections_to_update = block_structure.get_transformer_block_field(
        usage_key,
        GradesTransformer,
        'subsections',
        set()
    )

    for subsection in subsections_to_update:
        SubsectionGradeFactory(student).update(subsection, course_key)
    def handle(self, *args, **options):

        if options.get("all"):
            course_keys = [course.id for course in modulestore().get_course_summaries()]
            if options.get("start"):
                end = options.get("end") or len(course_keys)
                course_keys = course_keys[options["start"] : end]
        else:
            if len(args) < 1:
                raise CommandError("At least one course or --all must be specified.")
            try:
                course_keys = [CourseKey.from_string(arg) for arg in args]
            except InvalidKeyError:
                raise CommandError("Invalid key specified.")

        log.info("Generating course blocks for %d courses.", len(course_keys))

        if options.get("verbose"):
            log.setLevel(logging.DEBUG)
        else:
            log.setLevel(logging.CRITICAL)

        dag_info = _DAGInfo()
        for course_key in course_keys:
            try:
                if options.get("force"):
                    block_structure = update_course_in_cache(course_key)
                else:
                    block_structure = get_course_in_cache(course_key)
                if options.get("dags"):
                    self._find_and_log_dags(block_structure, course_key, dag_info)
            except Exception as ex:  # pylint: disable=broad-except
                log.exception(
                    "An error occurred while generating course blocks for %s: %s", unicode(course_key), ex.message
                )

        log.info("Finished generating course blocks.")

        if options.get("dags"):
            log.critical("DAG data: %s", unicode(dag_info))
Example #16
0
def recalculate_subsection_grade_handler(sender, **kwargs):  # pylint: disable=unused-argument
    """
    Consume the SCORE_CHANGED signal and trigger an update.
    This method expects that the kwargs dictionary will contain the following
    entries (See the definition of SCORE_CHANGED):
       - points_possible: Maximum score available for the exercise
       - points_earned: Score obtained by the user
       - user: User object
       - course_id: Unicode string representing the course
       - usage_id: Unicode string indicating the courseware instance
    """
    try:
        course_id = kwargs['course_id']
        usage_id = kwargs['usage_id']
        student = kwargs['user']
    except KeyError:
        log.exception(
            u"Failed to process SCORE_CHANGED signal, some arguments were missing."
            "user: %s, course_id: %s, usage_id: %s.",
            kwargs.get('user', None),
            kwargs.get('course_id', None),
            kwargs.get('usage_id', None),
        )
        return

    course_key = CourseLocator.from_string(course_id)
    if not PersistentGradesEnabledFlag.feature_enabled(course_key):
        return

    usage_key = UsageKey.from_string(usage_id).replace(course_key=course_key)
    block_structure = get_course_in_cache(course_key)

    subsections_to_update = block_structure.get_transformer_block_field(
        usage_key, GradesTransformer, 'subsections', set())

    for subsection in subsections_to_update:
        SubsectionGradeFactory(student).update(subsection, course_key)
Example #17
0
 def course_structure(self):
     return get_course_in_cache(self.course_id)
Example #18
0
def get_user_grades(user_id, course_str):
    """
    Get a single user's grades for  course. 
    """
    user = USER_MODEL.objects.get(id=user_id)
    course_key = CourseKey.from_string(str(course_str))
    course = courses.get_course(course_key)
    course_grade = CourseGradeFactory().update(user, course)
    course_structure = get_course_in_cache(course.id)
    courseware_summary = course_grade.chapter_grades.values()
    grade_summary = course_grade.summary
    grades_schema = {}
    courseware_summary = course_grade.chapter_grades.items()
    chapter_schema = {}
    for key, chapter in courseware_summary:
        subsection_schema = {}
        for section in chapter['sections']:
            section_children = course_structure.get_children(section.location)
            verticals = course_structure.get_children(section.location)
            vertical_schema = {}
            for vertical_key in verticals:
                sections_scores = {}
                problem_keys = course_structure.get_children(vertical_key)
                for problem_key in problem_keys:
                    if problem_key in section.problem_scores:
                        problem_score = section.problem_scores[problem_key]
                        xblock_content_url = reverse(
                            'courseware.views.views.render_xblock',
                            kwargs={'usage_key_string': unicode(problem_key)},
                        )
                        xblock_structure_url = generate_xblock_structure_url(
                            course_str, problem_key, user)
                        sections_scores[str(problem_key)] = {
                            "date":
                            problem_score.first_attempted
                            if problem_score.first_attempted is not None else
                            "Not attempted",
                            "earned":
                            problem_score.earned,
                            "possible":
                            problem_score.possible,
                            "xblock_content_url":
                            "{}{}".format(settings.LMS_ROOT_URL,
                                          xblock_content_url),
                            "xblock_structure_url":
                            "{}{}".format(settings.LMS_ROOT_URL,
                                          xblock_structure_url)
                        }
                    else:
                        sections_scores[str(
                            problem_key)] = "This block has no grades"
                vertical_structure_url = generate_xblock_structure_url(
                    course_str, vertical_key, user)
                vertical_schema[str(vertical_key)] = {
                    'problem_blocks': sections_scores,
                    "vertical_structure_url": vertical_structure_url
                }
            subsection_structure_url = generate_xblock_structure_url(
                course_str, section.location, user)
            subsection_schema[str(section.location)] = {
                "verticals": vertical_schema,
                "section_score":
                course_grade.score_for_module(section.location),
                "subsection_structure_url": subsection_structure_url
            }
        chapter_structure_url = generate_xblock_structure_url(
            course_str, key, user)
        chapter_schema[str(key)] = {
            "sections": subsection_schema,
            "chapter_structure_url": chapter_structure_url
        }

    return chapter_schema
Example #19
0
def grading_context_for_course(course_key):
    """
    Same as grading_context, but takes in a course key.
    """
    course_structure = get_course_in_cache(course_key)
    return grading_context(course_structure)
Example #20
0
def grading_context_for_course(course):
    """
    Same as grading_context, but takes in a course key.
    """
    course_structure = get_course_in_cache(course.id)
    return grading_context(course, course_structure)
Example #21
0
def grading_context_for_course(course):
    """
    Same as grading_context, but takes in a course object.
    """
    course_structure = get_course_in_cache(course.id)
    return grading_context(course_structure)
Example #22
0
def grading_context_for_course(course_key):
    """
    Same as grading_context, but takes in a course object.
    """
    course_structure = get_course_in_cache(course_key)
    return grading_context(course_structure)