Esempio n. 1
0
    def test_exam_authorization_when_not_passed_course(self):
        """
        test exam_authorization when user has not passed course but paid.
        """
        create_order(self.user, self.course_run)
        with patch('dashboard.utils.MMTrack.has_passed_course',
                   autospec=True,
                   return_value=False):
            mmtrack = get_mmtrack(self.user, self.program)
            expected_errors_message = MESSAGE_NOT_PASSED_OR_EXIST_TEMPLATE.format(
                user=mmtrack.user.username,
                course_id=self.course_run.edx_course_key)
            assert mmtrack.has_paid(self.course_run.edx_course_key) is True
            assert mmtrack.has_passed_course(
                self.course_run.edx_course_key) is False

            # Neither user has exam profile nor authorization.
            assert ExamProfile.objects.filter(
                profile=mmtrack.user.profile).exists() is False
            assert ExamAuthorization.objects.filter(
                user=mmtrack.user,
                course=self.course_run.course).exists() is False

            with self.assertRaises(ExamAuthorizationException) as eae:
                authorize_for_exam_run(self.user, self.course_run,
                                       self.exam_run)

            assert eae.exception.args[0] == expected_errors_message

            # assert exam profile created but user is not authorized
            assert ExamProfile.objects.filter(
                profile=mmtrack.user.profile).exists() is True
            assert ExamAuthorization.objects.filter(
                user=mmtrack.user,
                course=self.course_run.course).exists() is False
Esempio n. 2
0
def generate_program_letter(user, program):
    """
    Create a program letter if the user has a MM course certificate
    for each course in the program and program is non-fa.

    Args:
        user (User): a Django user.
        program (programs.models.Program): program where the user is enrolled.
    """
    if MicromastersProgramCommendation.objects.filter(user=user, program=program).exists():
        log.info('User [%s] already has a letter for program [%s]', user, program)
        return

    if (program.financial_aid_availability and
            MicromastersProgramCertificate.objects.filter(user=user, program=program).exists()):
        MicromastersProgramCommendation.objects.create(user=user, program=program)
        return

    mmtrack = get_mmtrack(user, program)
    courses_passed = mmtrack.count_courses_passed()
    program_course_count = (program.num_required_courses
                            if program.electives_set.exists()
                            else program.course_set.count())

    if courses_passed < program_course_count:
        return

    MicromastersProgramCommendation.objects.create(user=user, program=program)
    log.info(
        'Created MM program letter for [%s] in program [%s]',
        user.username,
        program.title
    )
Esempio n. 3
0
def update_or_create_combined_final_grade(user, course):
    """
    Update or create CombinedFinalGrade

    Args:
        user (User): a django User
        course (Course): a course model object
    """
    if not course.has_exam:
        return
    mmtrack = get_mmtrack(user, course.program)
    final_grade = mmtrack.get_best_final_grade_for_course(course)
    if final_grade is None:
        log.warning('User [%s] does not have a final for course [%s]', user, course)
        return

    best_exam = mmtrack.get_best_proctored_exam_grade(course)
    if best_exam is None:
        log.warning('User [%s] does not have a passing exam grade for course [%s]', user, course)
        return

    calculated_grade = round(final_grade.grade_percent * COURSE_GRADE_WEIGHT + best_exam.score * EXAM_GRADE_WEIGHT, 1)
    combined_grade, _ = CombinedFinalGrade.objects.update_or_create(
        user=user,
        course=course,
        defaults={'grade': calculated_grade}
    )
    combined_grade.save_and_log(None)
Esempio n. 4
0
    def test_exam_authorization_when_not_passed_course(self):
        """
        test exam_authorization when user has not passed course but paid.
        """
        create_order(self.user, self.course_run)
        with patch('dashboard.utils.MMTrack.has_passed_course', autospec=True, return_value=False):
            mmtrack = get_mmtrack(self.user, self.program)
            expected_errors_message = MESSAGE_NOT_PASSED_OR_EXIST_TEMPLATE.format(
                user=mmtrack.user.username,
                course_id=self.course_run.edx_course_key
            )
            assert mmtrack.has_paid(self.course_run.edx_course_key) is True
            assert mmtrack.has_passed_course(self.course_run.edx_course_key) is False

            # Neither user has exam profile nor authorization.
            assert ExamProfile.objects.filter(profile=mmtrack.user.profile).exists() is False
            assert ExamAuthorization.objects.filter(
                user=mmtrack.user,
                course=self.course_run.course
            ).exists() is False

            with self.assertRaises(ExamAuthorizationException) as eae:
                authorize_for_exam_run(mmtrack, self.course_run, self.exam_run)

            assert eae.exception.args[0] == expected_errors_message

            # assert exam profile created but user is not authorized
            assert ExamProfile.objects.filter(profile=mmtrack.user.profile).exists() is True
            assert ExamAuthorization.objects.filter(
                user=mmtrack.user,
                course=self.course_run.course
            ).exists() is False
Esempio n. 5
0
def update_or_create_combined_final_grade(user, course):
    """
    Update or create CombinedFinalGrade

    Args:
        user (User): a django User
        course (Course): a course model object
    """
    if not course.has_exam:
        return
    mmtrack = get_mmtrack(user, course.program)
    final_grade = mmtrack.get_best_final_grade_for_course(course)
    if final_grade is None:
        log.warning('User [%s] does not have a final for course [%s]', user, course)
        return

    best_exam = mmtrack.get_best_proctored_exam_grade(course)
    if best_exam is None:
        log.warning('User [%s] does not have a passing exam grade for course [%s]', user, course)
        return

    calculated_grade = round(final_grade.grade_percent * COURSE_GRADE_WEIGHT + best_exam.score * EXAM_GRADE_WEIGHT, 1)
    combined_grade, _ = CombinedFinalGrade.objects.update_or_create(
        user=user,
        course=course,
        defaults={'grade': calculated_grade}
    )
    combined_grade.save_and_log(None)
Esempio n. 6
0
def get_user_program_info(user, edx_client):
    """
    Provides a detailed serialization all of a User's enrolled Programs with enrollment/grade info

    Args:
        user (User): A User
        edx_client (EdxApi): An EdxApi instance

    Returns:
        list: Enrolled Program information
    """
    # update cache
    # NOTE: this part can be moved to an asynchronous task
    if edx_client is not None:
        try:
            for cache_type in CachedEdxDataApi.SUPPORTED_CACHES:
                CachedEdxDataApi.update_cache_if_expired(
                    user, edx_client, cache_type)
        except InvalidCredentialStored:
            # this needs to raise in order to force the user re-login
            raise
        except:  # pylint: disable=bare-except
            log.exception('Impossible to refresh edX cache')

    response_data = {
        "programs": [],
        "is_edx_data_fresh": CachedEdxDataApi.are_all_caches_fresh(user)
    }
    all_programs = (Program.objects.filter(
        live=True, programenrollment__user=user).prefetch_related(
            'course_set__courserun_set'))
    for program in all_programs:
        mmtrack_info = get_mmtrack(user, program)
        response_data['programs'].append(get_info_for_program(mmtrack_info))
    return response_data
Esempio n. 7
0
    def test_exam_authorization_when_not_paid(self):
        """
        test exam_authorization when user has passed course but not paid.
        """
        with mute_signals(post_save):
            self.final_grade.course_run_paid_on_edx = False
            self.final_grade.save()
        mmtrack = get_mmtrack(self.user, self.program)
        assert mmtrack.has_paid(self.course_run.edx_course_key) is False

        expected_errors_message = MESSAGE_NOT_ELIGIBLE_TEMPLATE.format(
            user=mmtrack.user.username,
            course_id=self.course_run.edx_course_key
        )

        # Neither user has exam profile nor authorization.
        assert ExamProfile.objects.filter(profile=mmtrack.user.profile).exists() is False
        assert ExamAuthorization.objects.filter(
            user=mmtrack.user,
            course=self.course_run.course
        ).exists() is False

        with self.assertRaises(ExamAuthorizationException) as eae:
            authorize_for_exam_run(mmtrack, self.course_run, self.exam_run)

        assert eae.exception.args[0] == expected_errors_message

        # Assert user has no exam profile and authorization after exception.
        assert ExamProfile.objects.filter(profile=mmtrack.user.profile).exists() is False
        assert ExamAuthorization.objects.filter(
            user=mmtrack.user,
            course=self.course_run.course
        ).exists() is False
Esempio n. 8
0
    def test_exam_authorization_attempts_consumed(self):
        """
        test exam_authorization when user passed and paid, but used all their attempts
        """
        create_order(self.user, self.course_run)
        mmtrack = get_mmtrack(self.user, self.program)
        self.assertTrue(mmtrack.has_paid(self.course_run.edx_course_key))
        self.assertTrue(mmtrack.has_passed_course(self.course_run.edx_course_key))
        old_run = ExamRunFactory.create(course=self.course_run.course)
        ExamAuthorizationFactory.create_batch(
            ATTEMPTS_PER_PAID_RUN,
            exam_run=old_run,
            user=mmtrack.user,
            course=self.course_run.course,
            exam_taken=True,
        )

        assert ExamAuthorization.objects.filter(
            user=mmtrack.user,
            course=self.course_run.course
        ).count() == 2

        with self.assertRaises(ExamAuthorizationException):
            authorize_for_exam_run(mmtrack, self.course_run, self.exam_run)

        # assert no new authorizations got created
        assert ExamAuthorization.objects.filter(
            user=mmtrack.user,
            course=self.course_run.course
        ).count() == 2
Esempio n. 9
0
def generate_program_letter(user, program):
    """
    Create a program letter if the user has a MM course certificate
    for each course in the program and program is non-fa.

    Args:
        user (User): a Django user.
        program (programs.models.Program): program where the user is enrolled.
    """
    if program.financial_aid_availability:
        log.error('Congratulation letter is only available for non-financial aid programs.')
        return

    if MicromastersProgramCommendation.objects.filter(user=user, program=program).exists():
        log.info('User [%s] already has a letter for program [%s]', user, program)
        return

    mmtrack = get_mmtrack(user, program)
    courses_passed = mmtrack.count_courses_passed()
    program_course_count = program.course_set.count()

    if courses_passed < program_course_count:
        return

    MicromastersProgramCommendation.objects.create(user=user, program=program)
    log.info(
        'Created MM program letter for [%s] in program [%s]',
        user.username,
        program.title
    )
Esempio n. 10
0
def authorize_for_exam_run(user, course_run, exam_run):
    """
    Authorize user for exam if he has paid for course and passed course.

    Args:
        mmtrack (dashboard.utils.MMTrack): a instance of all user information about a program.
        course_run (courses.models.CourseRun): A CourseRun object.
        exam_run (exams.models.ExamRun): the ExamRun we're authorizing for
    """

    mmtrack = get_mmtrack(user, course_run.course.program)
    if not mmtrack.user.is_active:
        raise ExamAuthorizationException(
            "Inactive user '{}' cannot be authorized for the exam for course id '{}'"
            .format(mmtrack.user.username, course_run.course))
    if course_run.course != exam_run.course:
        raise ExamAuthorizationException(
            "Course '{}' on CourseRun doesn't match Course '{}' on ExamRun".
            format(course_run.course, exam_run.course))
    if not exam_run.is_schedulable:
        raise ExamAuthorizationException(
            "Exam isn't schedulable currently: {}".format(exam_run))

    # If user has not paid for course then we dont need to process authorization
    if not mmtrack.has_paid(course_run.edx_course_key):
        errors_message = MESSAGE_NOT_ELIGIBLE_TEMPLATE.format(
            user=mmtrack.user.username, course_id=course_run.edx_course_key)
        raise ExamAuthorizationException(errors_message)

    # if user paid for a course then create his exam profile if it is not created yet
    ExamProfile.objects.get_or_create(profile=mmtrack.user.profile)

    # if they didn't pass, they don't get authorized
    if not mmtrack.has_passed_course(course_run.edx_course_key):
        errors_message = MESSAGE_NOT_PASSED_OR_EXIST_TEMPLATE.format(
            user=mmtrack.user.username, course_id=course_run.edx_course_key)
        raise ExamAuthorizationException(errors_message)

    # if they have run out of attempts, they don't get authorized
    if has_to_pay_for_exam(mmtrack, course_run.course):
        errors_message = MESSAGE_NO_ATTEMPTS_TEMPLATE.format(
            user=mmtrack.user.username, course_id=course_run.edx_course_key)
        raise ExamAuthorizationException(errors_message)
    # if they paid after deadline they don't get authorized for same term exam
    current_course_run = get_corresponding_course_run(exam_run)
    if current_course_run and mmtrack.paid_but_missed_deadline(
            current_course_run):
        errors_message = MESSAGE_MISSED_DEADLINE_TEMPLATE.format(
            user=mmtrack.user.username, course_id=course_run.edx_course_key)
        raise ExamAuthorizationException(errors_message)

    ExamAuthorization.objects.get_or_create(
        user=mmtrack.user,
        course=course_run.course,
        exam_run=exam_run,
        status=ExamAuthorization.STATUS_SUCCESS,
    )
    log.info(
        '[Exam authorization] user "%s" is authorized for the exam for course id "%s"',
        mmtrack.user.username, course_run.edx_course_key)
Esempio n. 11
0
    def test_exam_authorization_attempts_consumed(self):
        """
        test exam_authorization when user passed and paid, but used all their attempts
        """
        create_order(self.user, self.course_run)
        mmtrack = get_mmtrack(self.user, self.program)
        self.assertTrue(mmtrack.has_paid(self.course_run.edx_course_key))
        self.assertTrue(
            mmtrack.has_passed_course(self.course_run.edx_course_key))
        old_run = ExamRunFactory.create(course=self.course_run.course)
        ExamAuthorizationFactory.create_batch(
            ATTEMPTS_PER_PAID_RUN,
            exam_run=old_run,
            user=mmtrack.user,
            course=self.course_run.course,
            exam_taken=True,
        )

        assert ExamAuthorization.objects.filter(
            user=mmtrack.user, course=self.course_run.course).count() == 2

        with self.assertRaises(ExamAuthorizationException):
            authorize_for_exam_run(self.user, self.course_run, self.exam_run)

        # assert no new authorizations got created
        assert ExamAuthorization.objects.filter(
            user=mmtrack.user, course=self.course_run.course).count() == 2
Esempio n. 12
0
def get_user_program_info(user, edx_client):
    """
    Provides a detailed serialization all of a User's enrolled Programs with enrollment/grade info

    Args:
        user (User): A User
        edx_client (EdxApi): An EdxApi instance

    Returns:
        list: Enrolled Program information
    """
    # update cache
    # NOTE: this part can be moved to an asynchronous task
    if edx_client is not None:
        try:
            for cache_type in CachedEdxDataApi.SUPPORTED_CACHES:
                CachedEdxDataApi.update_cache_if_expired(user, edx_client, cache_type)
        except InvalidCredentialStored:
            # this needs to raise in order to force the user re-login
            raise
        except:  # pylint: disable=bare-except
            log.exception('Impossible to refresh edX cache')

    response_data = {
        "programs": [],
        "is_edx_data_fresh": CachedEdxDataApi.are_all_caches_fresh(user)
    }
    all_programs = (
        Program.objects.filter(live=True, programenrollment__user=user).prefetch_related('course_set__courserun_set')
    )
    for program in all_programs:
        mmtrack_info = get_mmtrack(user, program)
        response_data['programs'].append(get_info_for_program(mmtrack_info))
    return response_data
Esempio n. 13
0
    def test_exam_authorization_when_not_paid(self):
        """
        test exam_authorization when user has passed course but not paid.
        """
        with mute_signals(post_save):
            self.final_grade.course_run_paid_on_edx = False
            self.final_grade.save()
        mmtrack = get_mmtrack(self.user, self.program)
        assert mmtrack.has_paid(self.course_run.edx_course_key) is False

        expected_errors_message = MESSAGE_NOT_ELIGIBLE_TEMPLATE.format(
            user=mmtrack.user.username,
            course_id=self.course_run.edx_course_key)

        # Neither user has exam profile nor authorization.
        assert ExamProfile.objects.filter(
            profile=mmtrack.user.profile).exists() is False
        assert ExamAuthorization.objects.filter(
            user=mmtrack.user, course=self.course_run.course).exists() is False

        with self.assertRaises(ExamAuthorizationException) as eae:
            authorize_for_exam_run(self.user, self.course_run, self.exam_run)

        assert eae.exception.args[0] == expected_errors_message

        # Assert user has no exam profile and authorization after exception.
        assert ExamProfile.objects.filter(
            profile=mmtrack.user.profile).exists() is False
        assert ExamAuthorization.objects.filter(
            user=mmtrack.user, course=self.course_run.course).exists() is False
Esempio n. 14
0
def update_exam_authorization_cached_enrollment(sender, instance, **kwargs):  # pylint: disable=unused-argument
    """
    Signal handler to trigger an exam profile when user enroll in a course.
    """
    mmtrack = get_mmtrack(instance.user, instance.course_run.course.program)
    if is_eligible_for_exam(mmtrack, instance.course_run):
        # if user paid for a course then create his exam profile if it is not created yet.
        ExamProfile.objects.get_or_create(profile=mmtrack.user.profile)
Esempio n. 15
0
def update_exam_authorization_cached_enrollment(sender, instance, **kwargs):  # pylint: disable=unused-argument
    """
    Signal handler to trigger an exam profile when user enroll in a course.
    """
    mmtrack = get_mmtrack(instance.user, instance.course_run.course.program)
    if is_eligible_for_exam(mmtrack, instance.course_run):
        # if user paid for a course then create his exam profile if it is not created yet.
        ExamProfile.objects.get_or_create(profile=mmtrack.user.profile)
def populate_final_grade(apps, schema_editor):
    MicromastersCourseCertificate = apps.get_model('grades', 'MicromastersCourseCertificate')

    for certificate in MicromastersCourseCertificate.objects.select_related('final_grade').all():
        if not certificate.final_grade:
            mmtrack = get_mmtrack(certificate.user, certificate.course.program)
            certificate.final_grade = mmtrack.get_best_final_grade_for_course(certificate.course)
            certificate.save()
 def test_set_to_failed(self, course_run_program_type):
     """set_to_failed should set a CourseRun to failed for a given User"""
     course_run = self.course_runs[course_run_program_type]
     grade = Decimal('0.55')
     set_to_failed(user=self.user, course_run=course_run, grade=grade)
     mmtrack = get_mmtrack(self.user, course_run.course.program)
     assert not mmtrack.has_passed_course(course_run.edx_course_key)
     assert int(mmtrack.get_final_grade_percent(
         course_run.edx_course_key)) == (grade * 100)
Esempio n. 18
0
 def test_get_mmtrack(self):
     """
     test creation of  mmtrack(dashboard.utils.MMTrack) object.
     """
     self.pay_for_fa_course(self.crun_fa.edx_course_key)
     mmtrack = get_mmtrack(self.user, self.program_financial_aid)
     key = self.crun_fa.edx_course_key
     assert mmtrack.user == self.user
     assert mmtrack.has_paid(key) is True
Esempio n. 19
0
 def test_get_mmtrack(self):
     """
     test creation of  mmtrack(dashboard.utils.MMTrack) object.
     """
     self.pay_for_fa_course(self.crun_fa.edx_course_key)
     mmtrack = get_mmtrack(self.user, self.program_financial_aid)
     key = self.crun_fa.edx_course_key
     assert mmtrack.user == self.user
     assert mmtrack.has_paid(key) is True
 def test_set_payment_status(self, course_run_program_type):
     """Commands that set a User's payment status should work based on the audit flag value"""
     course_run = self.course_runs[course_run_program_type]
     for audit_setting in (True, False):
         set_to_enrolled(user=self.user,
                         course_run=course_run,
                         audit=audit_setting)
         mmtrack = get_mmtrack(self.user, course_run.course.program)
         assert mmtrack.has_paid(
             course_run.edx_course_key) is not audit_setting
def populate_final_grade(apps, schema_editor):
    MicromastersCourseCertificate = apps.get_model(
        'grades', 'MicromastersCourseCertificate')

    for certificate in MicromastersCourseCertificate.objects.select_related(
            'final_grade').all():
        if not certificate.final_grade:
            mmtrack = get_mmtrack(certificate.user, certificate.course.program)
            certificate.final_grade = mmtrack.get_best_final_grade_for_course(
                certificate.course)
            certificate.save()
Esempio n. 22
0
    def test_exam_authorization_multiple_runs(self):
        """Test that if the first enrollment is invalid it checks the second, but not the third"""
        exam_run = ExamRunFactory.create(course=self.course)
        mmtrack = get_mmtrack(self.user, self.program)

        with patch('exams.api.authorize_for_exam_run') as mock:
            mock.side_effect = [ExamAuthorizationException('invalid'), None, None]
            authorize_for_latest_passed_course(mmtrack, exam_run)

        assert mock.call_count == 2
        for enrollment in self.final_grades[:2]:  # two most recent runs
            mock.assert_any_call(mmtrack, enrollment.course_run, exam_run)
Esempio n. 23
0
def get_purchasable_course_run(course_key, user):
    """
    Gets a course run, or raises Http404 if not purchasable. To be purchasable a course run
    must not already be purchased, must be part of a live program, must be part of a program
    with financial aid enabled, with a financial aid object, and must have a valid price.

    Args:
        course_key (str):
            An edX course key
        user (User):
            The purchaser of the course run
    Returns:
        CourseRun: A course run
    """
    # Make sure it's connected to a live program, it has a valid price, and the user is enrolled in the program already
    try:
        course_run = get_object_or_404(
            CourseRun,
            edx_course_key=course_key,
            course__program__live=True,
            course__program__financial_aid_availability=True,
        )
    except Http404:
        log.warning("Course run %s is not purchasable", course_key)
        raise

    if not FinancialAid.objects.filter(
            tier_program__current=True,
            tier_program__program__course__courserun=course_run,
            user=user,
            status__in=FinancialAidStatus.TERMINAL_STATUSES,
    ).exists():
        log.warning("Course run %s has no attached financial aid for user %s",
                    course_key, get_social_username(user))
        raise ValidationError(
            "Course run {} does not have a current attached financial aid application"
            .format(course_key))

    # Make sure it's not already purchased
    if Line.objects.filter(
            order__status__in=Order.FULFILLED_STATUSES,
            order__user=user,
            course_key=course_run.edx_course_key,
    ).exists():
        mmtrack = get_mmtrack(user, course_run.course.program)
        if not has_to_pay_for_exam(mmtrack, course_run.course):
            log.warning("Course run %s is already purchased by user %s",
                        course_key, user)
            raise ValidationError(
                "Course run {} is already purchased".format(course_key))

    return course_run
Esempio n. 24
0
def bulk_authorize_for_exam_run(exam_run):
    """
    Authorize all eligible users for the given exam run

    Args:
        exam_run(exams.models.ExamRun): the exam run to authorize for
    """
    for program_enrollment in ProgramEnrollment.objects.filter(
            program=exam_run.course.program).iterator():
        mmtrack = get_mmtrack(program_enrollment.user,
                              program_enrollment.program)

        authorize_for_latest_passed_course(mmtrack, exam_run)
Esempio n. 25
0
def get_purchasable_course_run(course_key, user):
    """
    Gets a course run, or raises Http404 if not purchasable. To be purchasable a course run
    must not already be purchased, must be part of a live program, must be part of a program
    with financial aid enabled, with a financial aid object, and must have a valid price.

    Args:
        course_key (str):
            An edX course key
        user (User):
            The purchaser of the course run
    Returns:
        CourseRun: A course run
    """
    # Make sure it's connected to a live program, it has a valid price, and the user is enrolled in the program already
    try:
        course_run = get_object_or_404(
            CourseRun,
            edx_course_key=course_key,
            course__program__live=True,
            course__program__financial_aid_availability=True,
        )
    except Http404:
        log.warning("Course run %s is not purchasable", course_key)
        raise

    if not FinancialAid.objects.filter(
            tier_program__current=True,
            tier_program__program__course__courserun=course_run,
            user=user,
            status__in=FinancialAidStatus.TERMINAL_STATUSES,
    ).exists():
        log.warning("Course run %s has no attached financial aid for user %s", course_key, get_social_username(user))
        raise ValidationError(
            "Course run {} does not have a current attached financial aid application".format(course_key)
        )

    # Make sure it's not already purchased
    if Line.objects.filter(
            order__status__in=Order.FULFILLED_STATUSES,
            order__user=user,
            course_key=course_run.edx_course_key,
    ).exists():
        mmtrack = get_mmtrack(user, course_run.course.program)
        if not has_to_pay_for_exam(mmtrack, course_run.course):
            log.warning("Course run %s is already purchased by user %s", course_key, user)
            raise ValidationError("Course run {} is already purchased".format(course_key))

    return course_run
Esempio n. 26
0
def bulk_authorize_for_exam_run(exam_run):
    """
    Authorize all eligible users for the given exam run

    Args:
        exam_run(exams.models.ExamRun): the exam run to authorize for
    """
    for program_enrollment in ProgramEnrollment.objects.filter(
            program=exam_run.course.program
    ).iterator():
        mmtrack = get_mmtrack(
            program_enrollment.user,
            program_enrollment.program
        )

        authorize_for_latest_passed_course(mmtrack, exam_run)
Esempio n. 27
0
def authorize_user_for_schedulable_exam_runs(user, course_run):
    """
    Authorizes a user for all schedulable ExamRuns for a CourseRun

    Args:
        user (django.contib.auth.models.User): the user to authorize
        course_run (courses.models.CourseRun): the course run to check
    """
    mmtrack = get_mmtrack(user, course_run.course.program)

    # for each ExamRun for this course that is currently schedulable, attempt to authorize the user
    for exam_run in ExamRun.get_currently_schedulable(course_run.course):
        try:
            authorize_for_exam_run(mmtrack, course_run, exam_run)
        except ExamAuthorizationException:
            log.debug('Unable to authorize user: %s for exam on course_id: %s',
                      user.username, course_run.course.id)
Esempio n. 28
0
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        enrollment = get_object_or_404(ProgramEnrollment, hash=kwargs.get('record_hash'))
        user = enrollment.user
        authenticated = not user.is_anonymous
        js_settings = {
            "gaTrackingID": settings.GA_TRACKING_ID,
            "reactGaDebug": settings.REACT_GA_DEBUG,
            "edx_base_url": settings.EDXORG_BASE_URL,
            "authenticated": authenticated,
            "partner_schools": list(PartnerSchool.objects.values_list("id", "name")),
            "hash": enrollment.hash
        }
        context["js_settings_json"] = json.dumps(js_settings)
        context["is_public"] = True
        courses = enrollment.program.course_set.all()
        mmtrack = get_mmtrack(user, enrollment.program)
        combined_grade = CombinedFinalGrade.objects.filter(
            user=user,
            course__in=courses.values_list("id", flat=True)
        ).order_by("updated_on").last()
        context["program_title"] = enrollment.program.title
        context["program_status"] = "completed" if MicromastersProgramCertificate.objects.filter(
            user=user, program=enrollment.program).exists() else "partially"
        context["last_updated"] = combined_grade.updated_on if combined_grade else ""
        context["profile"] = {
            "username": user.username,
            "email": user.email,
            "full_name": user.profile.full_name
        }
        context['courses'] = []
        for course in courses:
            best_grade = mmtrack.get_best_final_grade_for_course(course)
            combined_grade = CombinedFinalGrade.objects.filter(user=user, course=course).first()
            context['courses'].append({
                "title": course.title,
                "edx_course_key": best_grade.course_run.edx_course_key if best_grade else "",
                "attempts": mmtrack.get_course_proctorate_exam_results(course).count(),
                "letter_grade": convert_to_letter(combined_grade.grade) if combined_grade else "",
                "status": "Earned" if get_certificate_url(mmtrack, course) else "Not Earned",
                "date_earned": combined_grade.created_on if combined_grade else "",
                "overall_grade": mmtrack.get_overall_final_grade_for_course(course)
            })

        return context
Esempio n. 29
0
    def serialize(cls, program_enrollment):
        """
        Serializes a ProgramEnrollment object
        """
        user = program_enrollment.user
        program = program_enrollment.program
        mmtrack = get_mmtrack(user, program)

        return {
            'id': program.id,
            'enrollments': cls.serialize_enrollments(mmtrack),
            'courses': cls.serialize_course_enrollments(mmtrack),
            'course_runs': cls.serialize_course_runs_enrolled(mmtrack),
            'grade_average': mmtrack.calculate_final_grade_average(),
            'is_learner': is_learner(user, program),
            'num_courses_passed': mmtrack.count_courses_passed(),
            'total_courses': program.course_set.count()
        }
Esempio n. 30
0
    def serialize(cls, program_enrollment):
        """
        Serializes a ProgramEnrollment object
        """
        user = program_enrollment.user
        program = program_enrollment.program
        mmtrack = get_mmtrack(user, program)

        return {
            'id': program.id,
            'enrollments': cls.serialize_enrollments(mmtrack),
            'courses': cls.serialize_course_enrollments(mmtrack),
            'course_runs': cls.serialize_course_runs_enrolled(mmtrack),
            'grade_average': mmtrack.calculate_final_grade_average(),
            'is_learner': is_learner(user, program),
            'num_courses_passed': mmtrack.count_courses_passed(),
            'total_courses': program.course_set.count()
        }
Esempio n. 31
0
def authorize_user_for_schedulable_exam_runs(user, course_run):
    """
    Authorizes a user for all schedulable ExamRuns for a CourseRun

    Args:
        user (django.contib.auth.models.User): the user to authorize
        course_run (courses.models.CourseRun): the course run to check
    """
    mmtrack = get_mmtrack(user, course_run.course.program)

    # for each ExamRun for this course that is currently schedulable, attempt to authorize the user
    for exam_run in ExamRun.get_currently_schedulable(course_run.course):
        try:
            authorize_for_exam_run(mmtrack, course_run, exam_run)
        except ExamAuthorizationException:
            log.debug(
                'Unable to authorize user: %s for exam on course_id: %s',
                user.username,
                course_run.course.id
            )
Esempio n. 32
0
    def test_exam_authorization_for_inactive_user(self):
        """
        test exam_authorization when inactive user passed and paid for course.
        """
        with mute_signals(post_save):
            profile = ProfileFactory.create()

        user = profile.user
        user.is_active = False
        user.save()
        with mute_signals(post_save):
            CachedEnrollmentFactory.create(user=user, course_run=self.course_run)

        with mute_signals(post_save):
            FinalGradeFactory.create(
                user=user,
                course_run=self.course_run,
                passed=True,
                course_run_paid_on_edx=False,
            )
        create_order(user, self.course_run)
        mmtrack = get_mmtrack(user, self.program)
        self.assertTrue(mmtrack.has_paid(self.course_run.edx_course_key))
        self.assertTrue(mmtrack.has_passed_course(self.course_run.edx_course_key))

        # Neither user has exam profile nor authorization.
        assert ExamProfile.objects.filter(profile=mmtrack.user.profile).exists() is False
        assert ExamAuthorization.objects.filter(
            user=mmtrack.user,
            course=self.course_run.course
        ).exists() is False

        with self.assertRaises(ExamAuthorizationException):
            authorize_for_exam_run(mmtrack, self.course_run, self.exam_run)

        # Assert user doesn't have exam profile and authorization
        assert ExamProfile.objects.filter(profile=mmtrack.user.profile).exists() is False
        assert ExamAuthorization.objects.filter(
            user=mmtrack.user,
            course=self.course_run.course
        ).exists() is False
Esempio n. 33
0
    def test_exam_authorization_for_inactive_user(self):
        """
        test exam_authorization when inactive user passed and paid for course.
        """
        with mute_signals(post_save):
            profile = ProfileFactory.create()

        user = profile.user
        user.is_active = False
        user.save()
        with mute_signals(post_save):
            CachedEnrollmentFactory.create(user=user,
                                           course_run=self.course_run)

        with mute_signals(post_save):
            FinalGradeFactory.create(
                user=user,
                course_run=self.course_run,
                passed=True,
                course_run_paid_on_edx=False,
            )
        create_order(user, self.course_run)
        mmtrack = get_mmtrack(user, self.program)
        self.assertTrue(mmtrack.has_paid(self.course_run.edx_course_key))
        self.assertTrue(
            mmtrack.has_passed_course(self.course_run.edx_course_key))

        # Neither user has exam profile nor authorization.
        assert ExamProfile.objects.filter(
            profile=mmtrack.user.profile).exists() is False
        assert ExamAuthorization.objects.filter(
            user=mmtrack.user, course=self.course_run.course).exists() is False

        with self.assertRaises(ExamAuthorizationException):
            authorize_for_exam_run(self.user, self.course_run, self.exam_run)

        # Assert user doesn't have exam profile and authorization
        assert ExamProfile.objects.filter(
            profile=mmtrack.user.profile).exists() is False
        assert ExamAuthorization.objects.filter(
            user=mmtrack.user, course=self.course_run.course).exists() is False
Esempio n. 34
0
    def test_exam_authorization(self):
        """
        test exam_authorization when user passed and paid for course.
        """
        create_order(self.user, self.course_run)
        mmtrack = get_mmtrack(self.user, self.program)
        self.assertTrue(mmtrack.has_paid(self.course_run.edx_course_key))
        self.assertTrue(
            mmtrack.has_passed_course(self.course_run.edx_course_key))

        # Neither user has exam profile nor authorization.
        assert ExamProfile.objects.filter(
            profile=mmtrack.user.profile).exists() is False
        assert ExamAuthorization.objects.filter(
            user=mmtrack.user, course=self.course_run.course).exists() is False

        authorize_for_exam_run(self.user, self.course_run, self.exam_run)

        # Assert user has exam profile and authorization.
        assert ExamProfile.objects.filter(
            profile=mmtrack.user.profile).exists() is True
        assert ExamAuthorization.objects.filter(
            user=mmtrack.user, course=self.course_run.course).exists() is True
Esempio n. 35
0
    def test_exam_authorization_for_missed_payment_deadline(self):
        """
        test exam_authorization when user paid, but only after deadline
        """
        create_order(self.user, self.course_run)
        mmtrack = get_mmtrack(self.user, self.program)
        course = self.course_run.course
        now = now_in_utc()
        exam_run = ExamRunFactory.create(course=course,
                                         authorized=True,
                                         date_first_schedulable=now,
                                         date_last_schedulable=now +
                                         datetime.timedelta(weeks=2))

        self.course_run.upgrade_deadline = exam_run.date_first_schedulable - datetime.timedelta(
            weeks=8)
        self.course_run.save()
        # paid after deadline
        order_qset = Order.objects.filter(
            user=self.user, line__course_key=self.course_run.edx_course_key)
        order_qset.update(modified_at=now - datetime.timedelta(weeks=5))

        with patch('exams.api.get_corresponding_course_run') as mock:
            mock.side_effect = [self.course_run]
            with self.assertRaises(ExamAuthorizationException):
                authorize_for_exam_run(self.user, self.course_run,
                                       self.exam_run)

        assert ExamAuthorization.objects.filter(
            user=mmtrack.user, course=course).exists() is False
        # paid before deadline
        order_qset.update(modified_at=exam_run.date_first_schedulable -
                          datetime.timedelta(weeks=9))
        authorize_for_exam_run(self.user, self.course_run, self.exam_run)

        assert ExamAuthorization.objects.filter(user=mmtrack.user,
                                                course=course).exists() is True
Esempio n. 36
0
    def test_exam_authorization(self):
        """
        test exam_authorization when user passed and paid for course.
        """
        create_order(self.user, self.course_run)
        mmtrack = get_mmtrack(self.user, self.program)
        self.assertTrue(mmtrack.has_paid(self.course_run.edx_course_key))
        self.assertTrue(mmtrack.has_passed_course(self.course_run.edx_course_key))

        # Neither user has exam profile nor authorization.
        assert ExamProfile.objects.filter(profile=mmtrack.user.profile).exists() is False
        assert ExamAuthorization.objects.filter(
            user=mmtrack.user,
            course=self.course_run.course
        ).exists() is False

        authorize_for_exam_run(mmtrack, self.course_run, self.exam_run)

        # Assert user has exam profile and authorization.
        assert ExamProfile.objects.filter(profile=mmtrack.user.profile).exists() is True
        assert ExamAuthorization.objects.filter(
            user=mmtrack.user,
            course=self.course_run.course
        ).exists() is True
Esempio n. 37
0
    def test_exam_authorization_course_mismatch(self):
        """
        test exam_authorization fails if course_run and exam_run courses mismatch
        """
        mmtrack = get_mmtrack(self.user, self.program)

        # Neither user has exam profile nor authorization.
        assert ExamProfile.objects.filter(profile=mmtrack.user.profile).exists() is False
        assert ExamAuthorization.objects.filter(
            user=mmtrack.user,
            course=self.course_run.course
        ).exists() is False

        exam_run = ExamRunFactory.create()

        with self.assertRaises(ExamAuthorizationException):
            authorize_for_exam_run(mmtrack, self.course_run, exam_run)

        # Assert user has exam profile and authorization.
        assert ExamProfile.objects.filter(profile=mmtrack.user.profile).exists() is False
        assert ExamAuthorization.objects.filter(
            user=mmtrack.user,
            course=self.course_run.course
        ).exists() is False
Esempio n. 38
0
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        enrollment = self.get_program_enrollment(**kwargs)
        user = enrollment.user

        authenticated = not user.is_anonymous
        share_hash_absolute_url = self.request.build_absolute_uri(
            reverse("shared_grade_records",
                    kwargs=dict(enrollment_id=enrollment.id,
                                record_share_hash=enrollment.share_hash)))
        js_settings = {
            "gaTrackingID":
            settings.GA_TRACKING_ID,
            "reactGaDebug":
            settings.REACT_GA_DEBUG,
            "edx_base_url":
            settings.EDXORG_BASE_URL,
            "authenticated":
            authenticated,
            "partner_schools":
            list(PartnerSchool.objects.values_list("id", "name")),
            "hash":
            enrollment.share_hash,
            "enrollment_id":
            enrollment.id,
            "absolute_record_share_hash":
            "" if not enrollment.share_hash else share_hash_absolute_url
        }
        context["js_settings_json"] = json.dumps(js_settings)
        courses = enrollment.program.course_set.prefetch_related(
            'electivecourse')
        mmtrack = get_mmtrack(user, enrollment.program)
        combined_grade = CombinedFinalGrade.objects.filter(
            user=user, course__in=courses.values_list(
                "id", flat=True)).order_by("updated_on").last()
        context["program_title"] = enrollment.program.title
        context[
            "program_status"] = "completed" if MicromastersProgramCertificate.objects.filter(
                user=user,
                program=enrollment.program).exists() else "partially"
        context[
            "last_updated"] = combined_grade.updated_on if combined_grade else ""
        context["has_electives"] = mmtrack.program.electives_set.exists()
        context["is_owner"] = self.request.user == user
        context["public_jquery"] = True
        context["profile"] = {
            "username": user.username,
            "email": user.email,
            "full_name": user.profile.full_name
        }
        context['courses'] = []
        for course in courses:
            best_grade = mmtrack.get_best_final_grade_for_course(course)
            combined_grade = CombinedFinalGrade.objects.filter(
                user=user, course=course).first()
            context['courses'].append({
                "title":
                course.title,
                "edx_course_key":
                best_grade.course_run.edx_course_key if best_grade else "",
                "attempts":
                mmtrack.get_course_proctorate_exam_results(course).count(),
                "letter_grade":
                convert_to_letter(combined_grade.grade)
                if combined_grade else "",
                "status":
                "Earned"
                if get_certificate_url(mmtrack, course) else "Not Earned",
                "date_earned":
                combined_grade.created_on if combined_grade else "",
                "overall_grade":
                mmtrack.get_overall_final_grade_for_course(course),
                "elective_tag":
                "elective" if (getattr(course, "electivecourse", None)
                               is not None) else "core"
            })

        return context