コード例 #1
0
    def create(self, subsection, read_only=False):
        """
        Returns the SubsectionGrade object for the student and subsection.

        If read_only is True, doesn't save any updates to the grades.
        """
        self._log_event(
            log.debug,
            u"create, read_only: {0}, subsection: {1}".format(
                read_only, subsection.location),
            subsection,
        )

        subsection_grade = self._get_bulk_cached_grade(subsection)
        if not subsection_grade:
            if assume_zero_if_absent(self.course_data.course_key):
                subsection_grade = ZeroSubsectionGrade(subsection,
                                                       self.course_data)
            else:
                subsection_grade = CreateSubsectionGrade(
                    subsection,
                    self.course_data.structure,
                    self._submissions_scores,
                    self._csm_scores,
                )
                if should_persist_grades(self.course_data.course_key):
                    if read_only:
                        self._unsaved_subsection_grades[
                            subsection_grade.location] = subsection_grade
                    else:
                        grade_model = subsection_grade.update_or_create_model(
                            self.student)
                        self._update_saved_subsection_grade(
                            subsection.location, grade_model)
        return subsection_grade
コード例 #2
0
    def create(self, subsection, read_only=False, force_calculate=False):
        """
        Returns the SubsectionGrade object for the student and subsection.

        If read_only is True, doesn't save any updates to the grades.
        force_calculate - If true, will cause this function to return a `CreateSubsectionGrade` object if no cached
        grade currently exists, even if the assume_zero_if_absent flag is enabled for the course.
        """
        self._log_event(
            log.debug, u"create, read_only: {0}, subsection: {1}".format(read_only, subsection.location), subsection,
        )

        subsection_grade = self._get_bulk_cached_grade(subsection)
        if not subsection_grade:
            if assume_zero_if_absent(self.course_data.course_key) and not force_calculate:
                subsection_grade = ZeroSubsectionGrade(subsection, self.course_data)
            else:
                subsection_grade = CreateSubsectionGrade(
                    subsection, self.course_data.structure, self._submissions_scores, self._csm_scores,
                )
                if should_persist_grades(self.course_data.course_key):
                    if read_only:
                        self._unsaved_subsection_grades[subsection_grade.location] = subsection_grade
                    else:
                        grade_model = subsection_grade.update_or_create_model(self.student)
                        self._update_saved_subsection_grade(subsection.location, grade_model)
        return subsection_grade
コード例 #3
0
    def update(self, subsection, only_if_higher=None, score_deleted=False, force_update_subsections=False, persist_grade=True):
        """
        Updates the SubsectionGrade object for the student and subsection.
        """
        self._log_event(log.debug, u"update, subsection: {}".format(subsection.location), subsection)

        calculated_grade = CreateSubsectionGrade(
            subsection, self.course_data.structure, self._submissions_scores, self._csm_scores,
        )

        if persist_grade and should_persist_grades(self.course_data.course_key):
            if only_if_higher:
                try:
                    grade_model = PersistentSubsectionGrade.read_grade(self.student.id, subsection.location)
                except PersistentSubsectionGrade.DoesNotExist:
                    pass
                else:
                    orig_subsection_grade = ReadSubsectionGrade(subsection, grade_model, self)
                    if not is_score_higher_or_equal(
                        orig_subsection_grade.graded_total.earned,
                        orig_subsection_grade.graded_total.possible,
                        calculated_grade.graded_total.earned,
                        calculated_grade.graded_total.possible,
                        treat_undefined_as_zero=True,
                    ):
                        return orig_subsection_grade

            grade_model = calculated_grade.update_or_create_model(
                self.student,
                score_deleted,
                force_update_subsections
            )
            self._update_saved_subsection_grade(subsection.location, grade_model)

        return calculated_grade
コード例 #4
0
    def create(self, subsection, read_only=False):
        """
        Returns the SubsectionGrade object for the student and subsection.

        If read_only is True, doesn't save any updates to the grades.
        """
        self._log_event(
            log.debug, u"create, read_only: {0}, subsection: {1}".format(read_only, subsection.location), subsection,
        )

        subsection_grade = self._get_bulk_cached_grade(subsection)
        if not subsection_grade:
            if assume_zero_if_absent(self.course_data.course_key):
                subsection_grade = ZeroSubsectionGrade(subsection, self.course_data)
            else:
                subsection_grade = SubsectionGrade(subsection).init_from_structure(
                    self.student, self.course_data.structure, self._submissions_scores, self._csm_scores,
                )
                if should_persist_grades(self.course_data.course_key):
                    if read_only:
                        self._unsaved_subsection_grades[subsection_grade.location] = subsection_grade
                    else:
                        grade_model = subsection_grade.create_model(self.student)
                        self._update_saved_subsection_grade(subsection.location, grade_model)
        return subsection_grade
コード例 #5
0
    def update(self, subsection, only_if_higher=None):
        """
        Updates the SubsectionGrade object for the student and subsection.
        """
        # Save ourselves the extra queries if the course does not persist
        # subsection grades.
        self._log_event(log.warning, u"update, subsection: {}".format(subsection.location), subsection)

        calculated_grade = SubsectionGrade(subsection).init_from_structure(
            self.student, self.course_data.structure, self._submissions_scores, self._csm_scores,
        )

        if should_persist_grades(self.course_data.course_key):
            if only_if_higher:
                try:
                    grade_model = PersistentSubsectionGrade.read_grade(self.student.id, subsection.location)
                except PersistentSubsectionGrade.DoesNotExist:
                    pass
                else:
                    orig_subsection_grade = SubsectionGrade(subsection).init_from_model(
                        self.student, grade_model, self.course_data.structure, self._submissions_scores, self._csm_scores,
                    )
                    if not is_score_higher_or_equal(
                            orig_subsection_grade.graded_total.earned,
                            orig_subsection_grade.graded_total.possible,
                            calculated_grade.graded_total.earned,
                            calculated_grade.graded_total.possible,
                    ):
                        return orig_subsection_grade

            grade_model = calculated_grade.update_or_create_model(self.student)
            self._update_saved_subsection_grade(subsection.location, grade_model)

        return calculated_grade
コード例 #6
0
    def update(self, subsection, only_if_higher=None, score_deleted=False):
        """
        Updates the SubsectionGrade object for the student and subsection.
        """
        self._log_event(log.debug, u"update, subsection: {}".format(subsection.location), subsection)

        calculated_grade = CreateSubsectionGrade(
            subsection, self.course_data.structure, self._submissions_scores, self._csm_scores,
        )

        if should_persist_grades(self.course_data.course_key):
            if only_if_higher:
                try:
                    grade_model = PersistentSubsectionGrade.read_grade(self.student.id, subsection.location)
                except PersistentSubsectionGrade.DoesNotExist:
                    pass
                else:
                    orig_subsection_grade = ReadSubsectionGrade(subsection, grade_model, self)
                    if not is_score_higher_or_equal(
                            orig_subsection_grade.graded_total.earned,
                            orig_subsection_grade.graded_total.possible,
                            calculated_grade.graded_total.earned,
                            calculated_grade.graded_total.possible,
                    ):
                        return orig_subsection_grade

            grade_model = calculated_grade.update_or_create_model(self.student, score_deleted)
            self._update_saved_subsection_grade(subsection.location, grade_model)

        return calculated_grade
コード例 #7
0
 def _get_bulk_cached_grade(self, subsection):
     """
     Returns the student's SubsectionGrade for the subsection,
     while caching the results of a bulk retrieval for the
     course, for future access of other subsections.
     Returns None if not found.
     """
     if should_persist_grades(self.course_data.course_key):
         saved_subsection_grades = self._get_bulk_cached_subsection_grades()
         grade = saved_subsection_grades.get(subsection.location)
         if grade:
             return ReadSubsectionGrade(subsection, grade, self)
コード例 #8
0
 def _get_bulk_cached_grade(self, subsection):
     """
     Returns the student's SubsectionGrade for the subsection,
     while caching the results of a bulk retrieval for the
     course, for future access of other subsections.
     Returns None if not found.
     """
     if should_persist_grades(self.course_data.course_key):
         saved_subsection_grades = self._get_bulk_cached_subsection_grades()
         grade = saved_subsection_grades.get(subsection.location)
         if grade:
             return ReadSubsectionGrade(subsection, grade, self)
コード例 #9
0
    def update(self, subsection, only_if_higher=None, score_deleted=False, force_update_subsections=False, persist_grade=True):  # lint-amnesty, pylint: disable=line-too-long
        """
        Updates the SubsectionGrade object for the student and subsection.
        """
        self._log_event(log.debug,
                        u"update, subsection: {}".format(subsection.location),
                        subsection)

        calculated_grade = CreateSubsectionGrade(
            subsection,
            self.course_data.structure,
            self._submissions_scores,
            self._csm_scores,
        )

        if persist_grade and should_persist_grades(
                self.course_data.course_key):
            if only_if_higher:
                try:
                    grade_model = PersistentSubsectionGrade.read_grade(
                        self.student.id, subsection.location)
                except PersistentSubsectionGrade.DoesNotExist:
                    pass
                else:
                    orig_subsection_grade = ReadSubsectionGrade(
                        subsection, grade_model, self)
                    if not is_score_higher_or_equal(
                            orig_subsection_grade.graded_total.earned,
                            orig_subsection_grade.graded_total.possible,
                            calculated_grade.graded_total.earned,
                            calculated_grade.graded_total.possible,
                            treat_undefined_as_zero=True,
                    ):
                        return orig_subsection_grade

            grade_model = calculated_grade.update_or_create_model(
                self.student, score_deleted, force_update_subsections)
            self._update_saved_subsection_grade(subsection.location,
                                                grade_model)

            if settings.FEATURES.get(
                    'ENABLE_COURSE_ASSESSMENT_GRADE_CHANGE_SIGNAL'):
                COURSE_ASSESSMENT_GRADE_CHANGED.send(
                    sender=self,
                    course_id=self.course_data.course_key,
                    user=self.student,
                    subsection_id=calculated_grade.location,
                    subsection_grade=calculated_grade.graded_total.earned)

        return calculated_grade
コード例 #10
0
 def _get_bulk_cached_grade(self, subsection):
     """
     Returns the student's SubsectionGrade for the subsection,
     while caching the results of a bulk retrieval for the
     course, for future access of other subsections.
     Returns None if not found.
     """
     if should_persist_grades(self.course_data.course_key):
         saved_subsection_grades = self._get_bulk_cached_subsection_grades()
         subsection_grade = saved_subsection_grades.get(subsection.location)
         if subsection_grade:
             return SubsectionGrade(subsection).init_from_model(
                 self.student, subsection_grade, self.course_data.structure, self._submissions_scores, self._csm_scores,
             )
コード例 #11
0
    def update(self, subsection, only_if_higher=None, score_deleted=False):
        """
        Updates the SubsectionGrade object for the student and subsection.
        """
        # Save ourselves the extra queries if the course does not persist
        # subsection grades.
        self._log_event(log.warning,
                        u"update, subsection: {}".format(subsection.location),
                        subsection)

        calculated_grade = SubsectionGrade(subsection).init_from_structure(
            self.student,
            self.course_data.structure,
            self._submissions_scores,
            self._csm_scores,
        )

        if should_persist_grades(self.course_data.course_key):
            if only_if_higher:
                try:
                    grade_model = PersistentSubsectionGrade.read_grade(
                        self.student.id, subsection.location)
                except PersistentSubsectionGrade.DoesNotExist:
                    pass
                else:
                    orig_subsection_grade = SubsectionGrade(
                        subsection).init_from_model(
                            self.student,
                            grade_model,
                            self.course_data.structure,
                            self._submissions_scores,
                            self._csm_scores,
                        )
                    if not is_score_higher_or_equal(
                            orig_subsection_grade.graded_total.earned,
                            orig_subsection_grade.graded_total.possible,
                            calculated_grade.graded_total.earned,
                            calculated_grade.graded_total.possible,
                    ):
                        return orig_subsection_grade

            grade_model = calculated_grade.update_or_create_model(
                self.student, score_deleted)
            self._update_saved_subsection_grade(subsection.location,
                                                grade_model)

        return calculated_grade
コード例 #12
0
 def _get_bulk_cached_grade(self, subsection):
     """
     Returns the student's SubsectionGrade for the subsection,
     while caching the results of a bulk retrieval for the
     course, for future access of other subsections.
     Returns None if not found.
     """
     if should_persist_grades(self.course_data.course_key):
         saved_subsection_grades = self._get_bulk_cached_subsection_grades()
         subsection_grade = saved_subsection_grades.get(subsection.location)
         if subsection_grade:
             return SubsectionGrade(subsection).init_from_model(
                 self.student,
                 subsection_grade,
                 self.course_data.structure,
                 self._submissions_scores,
                 self._csm_scores,
             )
コード例 #13
0
    def handle(self, *args, **options):

        # build a list of CourseKeys from any course IDs given
        course_key_list = []
        for course_id in options["course_id"]:
            try:
                course_key_list.append(CourseKey.from_string(course_id))
            except (InvalidKeyError, ValueError):
                log.error("Invalid course ID: %s", course_id)
                sys.exit(1)

        # get the Learndot:edX course mappings
        course_mappings = CourseMapping.objects.all()
        if course_key_list:
            course_mappings = course_mappings.filter(
                edx_course_key__in=course_key_list)

        if not course_mappings.exists():
            if options["course_id"]:
                log.error(
                    "No course mappings were found for your specified course IDs."
                )
            else:
                log.error("No course mappings were found.")
            sys.exit(1)

        learndot_client = LearndotAPIClient()

        # for each mapped course, go through its enrollments, get the
        # course grade for each enrolled user, and if the user has passed,
        # update the Learndot enrolment

        date_settings = {
            'TIMEZONE': settings.TIME_ZONE,
            'RETURN_AS_TIMEZONE_AWARE': True
        }
        end_enrollments_date = dateparser.parse(options["end"],
                                                settings=date_settings)
        start_enrolments_date = dateparser.parse(options["start"],
                                                 settings=date_settings)

        for cm in course_mappings:
            try:
                course = get_course(cm.edx_course_key)
            except (InvalidKeyError, ValueError):
                log.error("Invalid edX course found in map: %s",
                          cm.edx_course_key)
                continue

            log.info("Processing enrollments in course %s", cm.edx_course_key)

            enrollments = CourseEnrollment.objects.filter(
                course_id=cm.edx_course_key,
                created__range=[start_enrolments_date, end_enrollments_date],
            )

            if options["users"]:
                enrollments = enrollments.filter(
                    user__username__in=options["users"])

            for enrollment in enrollments:
                contact_id = learndot_client.get_contact_id(enrollment.user)
                if not contact_id:
                    log.info(
                        "Not setting enrolment status for user %s in course %s, because contact_id is None .",
                        enrollment.user, cm.edx_course_key)
                    continue
                #
                # Disturbingly enough, if persistent grades are not
                # enabled, it just takes looking up the grade to get
                # the Learndot enrolment updated, because when
                # CourseGradeFactory constructs the CourseGrade in its
                # read() method, it will actually call its _update()
                # method, which sends the COURSE_GRADE_NOW_PASSED
                # signal, which of course fires
                # edxlearndot.signals.listen_for_passing_grade.
                #
                # However, if the edX instance has persistent course
                # grades enabled, the CourseGrade doesn't have to be
                # constructed, so the signal isn't fired, and we have
                # to explicitly update Learndot.
                #
                course_grade = CourseGradeFactory().read(
                    enrollment.user, course)
                if not course_grade:
                    log.info(
                        "Not setting enrolment status for user %s in course %s, because no grade is available.",
                        enrollment.user, cm.edx_course_key)
                elif course_grade.passed and should_persist_grades(
                        cm.edx_course_key):
                    log.info(
                        "Grades are persistent; explicitly updating Learndot enrolment."
                    )
                    learndot_client.check_if_enrolment_and_set_status_to_passed(
                        contact_id,
                        cm.learndot_component_id,
                        unconditional=options["unconditional"])