예제 #1
0
    def test_course_run_missing_overview_not_fulfillable(self):
        entitlement = CourseEntitlementFactory.create(mode=CourseMode.VERIFIED)

        assert not is_course_run_entitlement_fulfillable(
            CourseKey.from_string('course-v1:edx+FakeCourse+3T2017'),
            entitlement
        )
예제 #2
0
    def get_fulfillable_entitlement_for_user_course_run(
            cls, user, course_run_key):
        """
        Retrieves a fulfillable entitlement for the user and the given course run.

        Arguments:
            user (User): The user that we are inspecting the entitlements for.
            course_run_key (CourseKey): The course run Key.

        Returns:
            CourseEntitlement: The most recent fulfillable CourseEntitlement, None otherwise.
        """
        # Check if the User has any fulfillable entitlements.
        # Note: Wait to retrieve the Course UUID until we have confirmed the User has fulfillable entitlements.
        # This was done to avoid calling the APIs when the User does not have an entitlement.
        entitlements = cls.get_fulfillable_entitlements(user)
        if entitlements:
            course_uuid = get_course_uuid_for_course(course_run_key)
            if course_uuid:
                entitlement = entitlements.filter(
                    course_uuid=course_uuid).first()
                if (entitlement and is_course_run_entitlement_fulfillable(
                        course_run_key=course_run_key, entitlement=entitlement)
                        and entitlement.is_entitlement_redeemable()):
                    return entitlement
        return None
예제 #3
0
    def get_upgradeable_enrollments_for_entitlement(self, entitlement):
        """
        Retrieve all the CourseEnrollments that are upgradeable for a given CourseEntitlement

        Arguments:
            entitlement: CourseEntitlement that we are requesting the CourseEnrollments for.

        Returns:
            list: List of upgradeable CourseEnrollments
        """
        # find all course_runs within the course
        course_runs = get_course_runs_for_course(entitlement.course_uuid)

        # check if the user has enrollments for any of the course_runs
        upgradeable_enrollments = []
        for course_run in course_runs:
            course_run_id = CourseKey.from_string(course_run.get('key'))
            enrollment = CourseEnrollment.get_enrollment(
                entitlement.user, course_run_id)

            if (enrollment and enrollment.is_active
                    and is_course_run_entitlement_fulfillable(
                        course_run_id, entitlement)):
                upgradeable_enrollments.append(enrollment)

        return upgradeable_enrollments
예제 #4
0
    def test_course_run_not_fulfillable_enrollment_start_in_future(self):
        course_overview = self.create_course(start_from_now=-3,
                                             end_from_now=2,
                                             enrollment_start_from_now=2,
                                             enrollment_end_from_now=4)

        entitlement = CourseEntitlementFactory.create(mode=CourseMode.VERIFIED)

        assert not is_course_run_entitlement_fulfillable(
            course_overview.id, entitlement)
예제 #5
0
    def test_course_run_fulfillable_already_enrolled_course_ended(self):
        course_overview = self.create_course(
            start_from_now=-3,
            end_from_now=-1,
            enrollment_start_from_now=-2,
            enrollment_end_from_now=-1,
        )

        entitlement = CourseEntitlementFactory.create(mode=CourseMode.VERIFIED)
        CourseEnrollmentFactory.create(user=entitlement.user, course_id=course_overview.id)

        assert is_course_run_entitlement_fulfillable(course_overview.id, entitlement)
예제 #6
0
    def test_course_run_not_fulfillable_no_start_date(self):
        course_overview = self.create_course(start_from_now=-2,
                                             end_from_now=2,
                                             enrollment_start_from_now=-1,
                                             enrollment_end_from_now=1)
        course_overview.start = None
        course_overview.save()

        entitlement = CourseEntitlementFactory.create(mode=CourseMode.VERIFIED)

        assert not is_course_run_entitlement_fulfillable(
            course_overview.id, entitlement)
예제 #7
0
    def test_course_run_fulfillable_user_enrolled(self):
        course_overview = self.create_course(
            start_from_now=-3,
            end_from_now=2,
            enrollment_start_from_now=-2,
            enrollment_end_from_now=1
        )

        entitlement = CourseEntitlementFactory.create(mode=CourseMode.VERIFIED)
        # Enroll User in the Course, but do not update the entitlement
        CourseEnrollmentFactory.create(user=entitlement.user, course_id=course_overview.id)

        assert is_course_run_entitlement_fulfillable(course_overview.id, entitlement)
예제 #8
0
def get_fulfillable_course_runs_for_entitlement(entitlement, course_runs):
    """
    Looks through the list of course runs and returns the course runs that can
    be applied to the entitlement.

    Args:
        entitlement (CourseEntitlement): The CourseEntitlement to which a
        course run is to be applied.
        course_runs (list): List of course run that we would like to apply
        to the entitlement.

    Return:
        list: A list of sessions that a user can apply to the provided entitlement.
    """
    enrollable_sessions = []

    # Only retrieve list of published course runs that can still be enrolled and upgraded
    search_time = datetime.datetime.now(UTC)
    for course_run in course_runs:
        course_id = CourseKey.from_string(course_run.get('key'))
        (user_enrollment_mode,
         is_active) = CourseEnrollment.enrollment_mode_for_user(
             user=entitlement.user, course_id=course_id)
        is_enrolled_in_mode = is_active and (user_enrollment_mode
                                             == entitlement.mode)
        if (is_enrolled_in_mode and entitlement.enrollment_course_run
                and course_id == entitlement.enrollment_course_run.course_id):
            # User is enrolled in the course so we should include it in the list of enrollable sessions always
            # this will ensure it is available for the UI
            enrollable_sessions.append(course_run)
        elif not is_enrolled_in_mode and is_course_run_entitlement_fulfillable(
                course_id, entitlement, search_time):
            enrollable_sessions.append(course_run)

    enrollable_sessions.sort(key=lambda session: session.get('start'))
    return enrollable_sessions
예제 #9
0
    def create(self, request, uuid):
        """
        On POST this method will be called and will handle enrolling a user in the
        provided course_run_id from the data. This is called on a specific entitlement
        UUID so the course_run_id has to correspond to the Course that is assigned to
        the Entitlement.

        When this API is called for a user who is already enrolled in a run that User
        will be unenrolled from their current run and enrolled in the new run if it is
        available.
        """
        course_run_id = request.data.get('course_run_id', None)

        if not course_run_id:
            return Response(status=status.HTTP_400_BAD_REQUEST,
                            data='The Course Run ID was not provided.')

        # Verify that the user has an Entitlement for the provided Entitlement UUID.
        try:
            entitlement = CourseEntitlement.objects.get(uuid=uuid,
                                                        user=request.user,
                                                        expired_at=None)
        except CourseEntitlement.DoesNotExist:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data=
                'The Entitlement for this UUID does not exist or is Expired.')

        # Verify the course run ID is of the same Course as the Course entitlement.
        course_run_valid = self._verify_course_run_for_entitlement(
            entitlement, course_run_id)
        if not course_run_valid:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    'message':
                    'The Course Run ID is not a match for this Course Entitlement.'
                })

        try:
            course_run_key = CourseKey.from_string(course_run_id)
        except InvalidKeyError:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    'message':
                    'Invalid {course_id}'.format(course_id=course_run_id)
                })

        # Verify that the run is fullfillable
        if not is_course_run_entitlement_fulfillable(course_run_key,
                                                     entitlement):
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    'message':
                    'The User is unable to enroll in Course Run {course_id}, it is not available.'
                    .format(course_id=course_run_id)
                })

        # Determine if this is a Switch session or a simple enroll and handle both.
        if entitlement.enrollment_course_run is None:
            response = self._enroll_entitlement(entitlement=entitlement,
                                                course_run_key=course_run_key,
                                                user=request.user)
            if response:
                return response
        elif entitlement.enrollment_course_run.course_id != course_run_id:
            _unenroll_entitlement(
                course_entitlement=entitlement,
                course_run_key=entitlement.enrollment_course_run.course_id)
            response = self._enroll_entitlement(entitlement=entitlement,
                                                course_run_key=course_run_key,
                                                user=request.user)
            if response:
                return response

        return Response(status=status.HTTP_201_CREATED,
                        data={
                            'course_run_id': course_run_id,
                        })