Esempio n. 1
0
def test_fetch_user_case_sens():
    """fetch_user should be able to fetch a User with a case-insensitive filter"""
    email = "*****@*****.**"
    user = UserFactory.create(email=email)
    upper_email = email.upper()
    with pytest.raises(User.DoesNotExist):
        fetch_user(upper_email, ignore_case=False)
    assert fetch_user(upper_email, ignore_case=True) == user
Esempio n. 2
0
def test_fetch_user(prop, value, db_value):
    """
    fetch_user should return a User that matches a provided value which represents
    an id, email, or username
    """
    user = UserFactory.create(**{prop: db_value or value})
    found_user = fetch_user(value)
    assert user == found_user
Esempio n. 3
0
    def handle(self, *args, **options):
        """Handle command execution"""
        user = fetch_user(options["user"])
        keep_failed_enrollments = options["keep_failed_enrollments"]
        enrollment, _ = self.fetch_enrollment(user, options)

        if options["program"]:
            program_enrollment, run_enrollments = deactivate_program_enrollment(
                enrollment,
                change_status=ENROLL_CHANGE_STATUS_REFUNDED,
                keep_failed_enrollments=keep_failed_enrollments,
            )
        else:
            program_enrollment = None
            run_enrollments = []
            run_enrollment = deactivate_run_enrollment(
                enrollment,
                change_status=ENROLL_CHANGE_STATUS_REFUNDED,
                keep_failed_enrollments=keep_failed_enrollments,
            )
            if run_enrollment:
                run_enrollments.append(run_enrollment)

        if program_enrollment or run_enrollments:
            success_msg = "Refunded enrollments for user: {} ({})\nEnrollments affected: {}".format(
                enrollment.user.username,
                enrollment.user.email,
                enrollment_summaries(
                    filter(bool, [program_enrollment] + run_enrollments)),
            )

            if enrollment.order:
                enrollment.order.status = Order.REFUNDED
                enrollment.order.save_and_log(None)
                success_msg += "\nOrder status set to '{}' (order id: {})".format(
                    enrollment.order.status, enrollment.order.id)
            else:
                self.stdout.write(
                    self.style.WARNING(
                        "The given enrollment is not associated with an order, so no order status will be changed."
                    ))

            self.stdout.write(self.style.SUCCESS(success_msg))
        else:
            self.stdout.write(
                self.style.ERROR(
                    "Failed to refund the enrollment – 'for' user: {} ({}) from course / program ({})\n"
                    .format(user.username, user.email, options["run"]
                            or options["program"])))
Esempio n. 4
0
    def handle(self, *args, **options):
        """Handle command execution"""
        user = fetch_user(options["user"])
        from_courseware_id = options["from_run"]
        to_courseware_id = options["to_run"]

        try:
            from_enrollment, to_enrollment = defer_enrollment(
                user,
                from_courseware_id,
                to_courseware_id,
                keep_failed_enrollments=options["keep_failed_enrollments"],
                force=options["force"],
            )
        except ObjectDoesNotExist as exc:
            if isinstance(exc, CourseRunEnrollment.DoesNotExist):
                message = "'from' course run enrollment does not exist ({})".format(
                    from_courseware_id)
            elif isinstance(exc, CourseRun.DoesNotExist):
                message = "'to' course does not exist ({})".format(
                    to_courseware_id)
            else:
                message = str(exc)
            raise CommandError(message)
        except ValidationError as exc:
            raise CommandError("Invalid enrollment deferral - {}".format(exc))
        else:
            if not to_enrollment:
                raise CommandError(
                    "Failed to create/update the target enrollment ({})".
                    format(to_courseware_id))

        self.stdout.write(
            self.style.SUCCESS("Deferred enrollment for user: {}\n"
                               "Enrollment deactivated: {}\n"
                               "Enrollment created/updated: {}".format(
                                   user,
                                   enrollment_summary(from_enrollment),
                                   enrollment_summary(to_enrollment),
                               )))
Esempio n. 5
0
    def handle(self, *args, **options):  # pylint: disable=too-many-locals
        """Handle command execution"""

        user = fetch_user(options["user"]) if options["user"] else None
        program = options.get("program")
        run = options.get("run")
        revoke = options.get("revoke")
        include_program_courses = options.get("include_program_courses")

        if program and run:
            raise CommandError(
                "Either 'program' or 'run' should be provided, not both.")
        if not program and not run:
            raise CommandError("Either 'program' or 'run' must be provided.")

        if (program or run) and not user:
            raise CommandError("A valid user must be provided.")

        updated = False
        if program:
            updated = revoke_program_certificate(
                user=user,
                readable_id=program,
                revoke_state=revoke,
                include_program_courses=include_program_courses,
            )
        elif run:
            updated = revoke_course_run_certificate(user=user,
                                                    courseware_id=run,
                                                    revoke_state=revoke)

        if updated:
            msg = "Certificate for {} has been {}".format(
                "run: {}".format(run)
                if run else "program: {}".format(program),
                "revoked" if revoke else "un-revoked",
            )
            self.stdout.write(self.style.SUCCESS(msg))
        else:
            self.stdout.write(self.style.WARNING("No changes made."))
Esempio n. 6
0
    def handle(self, *args, **options):
        """Handle command execution"""

        user = fetch_user(options["user"])

        run = CourseRun.objects.filter(courseware_id=options["run"]).first()
        if run is None:
            raise CommandError(
                "Could not find course run with courseware_id={}".format(
                    options["run"]))

        product = Product.objects.filter(
            courseruns__courseware_id=options["run"]).first()
        if product is None:
            raise CommandError(
                "No product found for that course with courseware_id={}".
                format(options["run"]))

        coupon = Coupon.objects.filter(coupon_code=options["code"]).first()
        if not coupon:
            raise CommandError("That enrollment code {} does not exist".format(
                options["code"]))

        # Check if the coupon is valid for the product
        coupon_version = best_coupon_for_product(product,
                                                 user,
                                                 code=coupon.coupon_code)
        if coupon_version is None:
            raise CommandError({
                "coupons":
                "Enrollment code {} is invalid for course run {}".format(
                    options["code"], options["run"])
            })
        # Fetch the latest product version.
        product_version = latest_product_version(product)

        # Calculate the total paid price after applying coupon.
        total_price_paid = get_product_version_price_with_discount(
            coupon_version=coupon_version, product_version=product_version)

        with transaction.atomic():
            # Create an order.
            order = Order.objects.create(
                status=Order.FULFILLED,
                purchaser=user,
                total_price_paid=total_price_paid,
            )

            successful_enrollments, edx_request_success = create_run_enrollments(
                user,
                [run],
                keep_failed_enrollments=options["keep_failed_enrollments"],
                order=order,
            )
            if not successful_enrollments:
                raise CommandError("Failed to create the enrollment record")

        ProductCouponAssignment.objects.filter(
            email__iexact=user.email,
            redeemed=False,
            product_coupon__coupon=coupon).update(redeemed=True)

        self.stdout.write(
            self.style.SUCCESS(
                "Enrollment created for user {} in {} (edX enrollment success: {})"
                .format(user, options["run"], edx_request_success)))

        line = Line.objects.create(order=order,
                                   product_version=product_version,
                                   quantity=1)

        redeem_coupon(coupon_version=coupon_version, order=order)

        self.stdout.write(
            self.style.SUCCESS(
                "Order {} with line {} is created for user {} ".format(
                    order, line, user)))
Esempio n. 7
0
    def handle(self, *args, **options):
        from_user = fetch_user(options["from_user"])
        to_user = fetch_user(options["to_user"])
        keep_failed_enrollments = options["keep_failed_enrollments"]
        enrollment, enrolled_obj = self.fetch_enrollment(from_user, options)

        if options["program"]:
            to_user_existing_enrolled_run_ids = CourseRunEnrollment.get_program_run_enrollments(
                user=to_user,
                program=enrolled_obj).values_list("run__courseware_id",
                                                  flat=True)
            if len(to_user_existing_enrolled_run_ids) > 0:
                raise CommandError(
                    "'to' user is already enrolled in program runs ({})".
                    format(list(to_user_existing_enrolled_run_ids)))

            new_program_enrollment, new_run_enrollments = self.create_program_enrollment(
                enrollment,
                to_user=to_user,
                keep_failed_enrollments=keep_failed_enrollments,
            )
            if new_program_enrollment and new_run_enrollments:
                deactivate_program_enrollment(
                    enrollment,
                    change_status=ENROLL_CHANGE_STATUS_TRANSFERRED,
                    keep_failed_enrollments=keep_failed_enrollments,
                )
        else:
            new_program_enrollment = None
            new_run_enrollment = self.create_run_enrollment(
                enrollment,
                to_user=to_user,
                keep_failed_enrollments=keep_failed_enrollments,
            )
            new_run_enrollments = []
            if new_run_enrollment:
                new_run_enrollments.append(new_run_enrollment)
                deactivate_run_enrollment(
                    enrollment,
                    change_status=ENROLL_CHANGE_STATUS_TRANSFERRED,
                    keep_failed_enrollments=keep_failed_enrollments,
                )

        if new_program_enrollment or new_run_enrollments:
            self.stdout.write(
                self.style.SUCCESS(
                    "Transferred enrollment – 'from' user: {} ({}), 'to' user: {} ({})\n"
                    "Enrollments created/updated: {}".format(
                        from_user.username,
                        from_user.email,
                        to_user.username,
                        to_user.email,
                        enrollment_summaries(
                            filter(bool, [new_program_enrollment] +
                                   new_run_enrollments)),
                    )))
        else:
            self.stdout.write(
                self.style.ERROR(
                    "Failed to transfer enrollment – 'from' user: {} ({}), 'to' user: {} ({})\n"
                    .format(
                        from_user.username,
                        from_user.email,
                        to_user.username,
                        to_user.email,
                    )))
Esempio n. 8
0
def test_fetch_user_fail():
    """fetch_user should raise an exception if a matching User was not found"""
    with pytest.raises(User.DoesNotExist):
        fetch_user("*****@*****.**")
    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))