示例#1
0
def test_course_run_certificate_idempotent(user, course):
    """
    Test that the certificate generation is idempotent
    """
    grade = CourseRunGradeFactory.create(course_run__course=course,
                                         user=user,
                                         grade=0.25,
                                         passed=True)

    # Certificate is created the first time
    certificate, created, deleted = process_course_run_grade_certificate(grade)
    assert certificate
    assert created
    assert not deleted

    # Existing certificate is simply returned without any create/delete
    certificate, created, deleted = process_course_run_grade_certificate(grade)
    assert certificate
    assert not created
    assert not deleted
示例#2
0
def test_course_run_certificate_not_passing(user, course):
    """
    Test that the certificate is not generated if the grade is set to 0.0
    """
    grade = CourseRunGradeFactory.create(course_run__course=course,
                                         user=user,
                                         grade=1.0,
                                         passed=True)

    # Initially the certificate is created
    certificate, created, deleted = process_course_run_grade_certificate(grade)
    assert certificate
    assert created
    assert not deleted

    # Now that the grade indicates score 0.0, certificate should be deleted
    grade.grade = 0.0
    certificate, created, deleted = process_course_run_grade_certificate(grade)
    assert not certificate
    assert not created
    assert deleted
示例#3
0
def test_course_run_certificate(user, course, grade, passed, exp_certificate,
                                exp_created, exp_deleted):
    """
    Test that the certificate is generated correctly
    """
    certificate, created, deleted = process_course_run_grade_certificate(
        CourseRunGradeFactory.create(course_run__course=course,
                                     user=user,
                                     grade=grade,
                                     passed=passed))
    assert bool(certificate) is exp_certificate
    assert created is exp_created
    assert deleted is exp_deleted
示例#4
0
def generate_course_certificates():
    """
    Task to generate certificates for courses.
    """
    now = now_in_utc()
    course_runs = (CourseRun.objects.live().filter(
        end_date__lt=now -
        timedelta(hours=settings.CERTIFICATE_CREATION_DELAY_IN_HOURS)).exclude(
            id__in=CourseRunCertificate.objects.values_list("course_run__id",
                                                            flat=True)))

    for run in course_runs:
        edx_grade_user_iter = exception_logging_generator(
            get_edx_grades_with_users(run))
        created_grades_count, updated_grades_count, generated_certificates_count = (
            0,
            0,
            0,
        )
        for edx_grade, user in edx_grade_user_iter:
            course_run_grade, created, updated = ensure_course_run_grade(
                user=user,
                course_run=run,
                edx_grade=edx_grade,
                should_update=True)

            if created:
                created_grades_count += 1
            elif updated:
                updated_grades_count += 1

            _, created, deleted = process_course_run_grade_certificate(
                course_run_grade=course_run_grade)

            if deleted:
                log.warning(
                    "Certificate deleted for user %s and course_run %s", user,
                    run)
            elif created:
                generated_certificates_count += 1

        log.info(
            "Finished processing course run %s: created grades for %d users, "
            "updated grades for %d users, generated certificates for %d users",
            run,
            created_grades_count,
            updated_grades_count,
            generated_certificates_count,
        )
    def handle(self, *args, **options):  # pylint: disable=too-many-locals,too-many-branches
        """Handle command execution"""
        # Grade override for all users for the course run. Disallowed.
        if options["grade"] is not None and not options["user"]:
            raise CommandError(
                "No user supplied with override grade. Overwrite of grade is not supported for all users. Grade should only be supplied when a specific user is targeted."
            )
        try:
            run = CourseRun.objects.get(courseware_id=options["run"])
        except CourseRun.DoesNotExist:
            raise CommandError(
                "Could not find run with courseware_id={}".format(
                    options["run"]))
        now = now_in_utc()
        if not options.get("force") and (run.end_date is None
                                         or run.end_date > now):
            raise CommandError(
                "The given course run has not yet finished, so the course grades should not be "
                "considered final (courseware_id={}, end_date={}).\n"
                "Add the -f/--force flag if grades/certificates should be synced anyway."
                .format(
                    options["run"],
                    "None"
                    if run.end_date is None else run.end_date.isoformat(),
                ))

        user = fetch_user(options["user"]) if options["user"] else None
        override_grade = None
        should_update = options["update"]

        if options["grade"] is not None:
            override_grade = float(options["grade"])
            if override_grade and (override_grade < 0.0
                                   or override_grade > 1.0):
                raise CommandError(
                    "Invalid value for grade. Allowed range: 0.0 - 1.0")

        edx_grade_user_iter = get_edx_grades_with_users(run, user=user)

        results = []
        for edx_grade, user in edx_grade_user_iter:
            course_run_grade, created_grade, updated_grade = ensure_course_run_grade(
                user=user,
                course_run=run,
                edx_grade=edx_grade,
                should_update=should_update,
            )

            if override_grade is not None:
                course_run_grade.grade = override_grade
                course_run_grade.passed = bool(override_grade)
                course_run_grade.letter_grade = None
                course_run_grade.set_by_admin = True
                course_run_grade.save_and_log(None)

            _, created_cert, deleted_cert = process_course_run_grade_certificate(
                course_run_grade=course_run_grade)

            if created_grade:
                grade_status = "created"
            elif updated_grade:
                grade_status = "updated"
            else:
                grade_status = "already exists"

            grade_summary = ["passed: {}".format(course_run_grade.passed)]
            if override_grade is not None:
                grade_summary.append("value override: {}".format(
                    course_run_grade.grade))

            if created_cert:
                cert_status = "created"
            elif deleted_cert:
                cert_status = "deleted"
            elif course_run_grade.passed:
                cert_status = "already exists"
            else:
                cert_status = "ignored"

            result_summary = "Grade: {} ({}), Certificate: {}".format(
                grade_status, ", ".join(grade_summary), cert_status)

            results.append(
                "Processed user {} ({}) in course run {}. Result - {}".format(
                    user.username, user.email, run.courseware_id,
                    result_summary))

        for result in results:
            self.stdout.write(self.style.SUCCESS(result))