Esempio n. 1
0
def get_eligibilities_for_user(username, course_key=None):
    """
    Retrieve all courses or particular course for which the user is eligible
    for credit.

    Arguments:
        username (unicode): Identifier of the user.
        course_key (unicode): Identifier of the course.

    Example:
        >>> get_eligibilities_for_user("ron")
        [
            {
                "course_key": "edX/Demo_101/Fall",
                "deadline": "2015-10-23"
            },
            {
                "course_key": "edX/Demo_201/Spring",
                "deadline": "2015-11-15"
            },
            ...
        ]

    Returns: list

    """
    eligibilities = CreditEligibility.get_user_eligibilities(username)
    if course_key:
        course_key = CourseKey.from_string(unicode(course_key))
        eligibilities = eligibilities.filter(course__course_key=course_key)

    return [{
        "course_key": unicode(eligibility.course.course_key),
        "deadline": eligibility.deadline,
    } for eligibility in eligibilities]
Esempio n. 2
0
    def post(self, request, provider_id):
        """ POST handler. """
        # Get the provider, or return HTTP 404 if it doesn't exist
        provider = generics.get_object_or_404(CreditProvider, provider_id=provider_id)

        # Validate the course key
        course_key = request.data.get('course_key')
        try:
            course_key = CourseKey.from_string(course_key)
        except InvalidKeyError:
            raise InvalidCourseKey(course_key)

        # Validate the username
        username = request.data.get('username')
        if not username:
            raise ValidationError({'detail': 'A username must be specified.'})

        # Ensure the user is actually eligible to receive credit
        if not CreditEligibility.is_user_eligible_for_credit(course_key, username):
            raise UserNotEligibleException(course_key, username)

        try:
            credit_request = create_credit_request(course_key, provider.provider_id, username)
            return Response(credit_request)
        except CreditApiBadRequest as ex:
            raise InvalidCreditRequest(text_type(ex))
Esempio n. 3
0
    def post(self, request, provider_id):
        """ POST handler. """
        # Get the provider, or return HTTP 404 if it doesn't exist
        provider = generics.get_object_or_404(CreditProvider,
                                              provider_id=provider_id)

        # Validate the course key
        course_key = request.data.get('course_key')
        try:
            course_key = CourseKey.from_string(course_key)
        except InvalidKeyError:
            raise InvalidCourseKey(course_key)

        # Validate the username
        username = request.data.get('username')
        if not username:
            raise ValidationError({'detail': 'A username must be specified.'})

        # Ensure the user is actually eligible to receive credit
        if not CreditEligibility.is_user_eligible_for_credit(
                course_key, username):
            raise UserNotEligibleException(course_key, username)

        try:
            credit_request = create_credit_request(course_key,
                                                   provider.provider_id,
                                                   username)
            return Response(credit_request)
        except CreditApiBadRequest as ex:
            raise InvalidCreditRequest(text_type(ex))
def get_eligibilities_for_user(username):
    """
    Retrieve all courses for which the user is eligible for credit.

    Arguments:
        username (unicode): Identifier of the user.

    Example:
        >>> get_eligibilities_for_user("ron")
        [
            {
                "course_key": "edX/Demo_101/Fall",
                "deadline": "2015-10-23"
            },
            {
                "course_key": "edX/Demo_201/Spring",
                "deadline": "2015-11-15"
            },
            ...
        ]

    Returns: list

    """
    return [
        {
            "course_key": eligibility.course.course_key,
            "deadline": eligibility.deadline,
        }
        for eligibility in CreditEligibility.get_user_eligibilities(username)
    ]
Esempio n. 5
0
def get_eligibilities_for_user(username):
    """
    Retrieve all courses for which the user is eligible for credit.

    Arguments:
        username (unicode): Identifier of the user.

    Example:
        >>> get_eligibilities_for_user("ron")
        [
            {
                "course_key": "edX/Demo_101/Fall",
                "deadline": "2015-10-23"
            },
            {
                "course_key": "edX/Demo_201/Spring",
                "deadline": "2015-11-15"
            },
            ...
        ]

    Returns: list

    """
    return [{
        "course_key": eligibility.course.course_key,
        "deadline": eligibility.deadline,
    } for eligibility in CreditEligibility.get_user_eligibilities(username)]
Esempio n. 6
0
def is_user_eligible_for_credit(username, course_key):
    """
    Returns a boolean indicating if the user is eligible for credit for
    the given course

    Args:
        username(str): The identifier for user
        course_key (CourseKey): The identifier for course

    Returns:
        True if user is eligible for the course else False
    """
    return CreditEligibility.is_user_eligible_for_credit(course_key, username)
Esempio n. 7
0
def is_user_eligible_for_credit(username, course_key):
    """
    Returns a boolean indicating if the user is eligible for credit for
    the given course

    Args:
        username(str): The identifier for user
        course_key (CourseKey): The identifier for course

    Returns:
        True if user is eligible for the course else False
    """
    return CreditEligibility.is_user_eligible_for_credit(course_key, username)
Esempio n. 8
0
def get_eligibilities_for_user(username, course_key=None):
    """
    Retrieve all courses or particular course for which the user is eligible
    for credit.

    Arguments:
        username (unicode): Identifier of the user.
        course_key (unicode): Identifier of the course.

    Example:
        >>> get_eligibilities_for_user("ron")
        [
            {
                "course_key": "edX/Demo_101/Fall",
                "deadline": "2015-10-23"
            },
            {
                "course_key": "edX/Demo_201/Spring",
                "deadline": "2015-11-15"
            },
            ...
        ]

    Returns: list

    """
    eligibilities = CreditEligibility.get_user_eligibilities(username)
    if course_key:
        course_key = CourseKey.from_string(unicode(course_key))
        eligibilities = eligibilities.filter(course__course_key=course_key)

    return [
        {
            "course_key": unicode(eligibility.course.course_key),
            "deadline": eligibility.deadline,
        }
        for eligibility in eligibilities
    ]
Esempio n. 9
0
def set_credit_requirement_status(user,
                                  course_key,
                                  req_namespace,
                                  req_name,
                                  status="satisfied",
                                  reason=None):
    """
    Update the user's requirement status.

    This will record whether the user satisfied or failed a particular requirement
    in a course.  If the user has satisfied all requirements, the user will be marked
    as eligible for credit in the course.

    Args:
        user(User): User object to set credit requirement for.
        course_key (CourseKey): Identifier for the course associated with the requirement.
        req_namespace (str): Namespace of the requirement (e.g. "grade" or "reverification")
        req_name (str): Name of the requirement (e.g. "grade" or the location of the ICRV XBlock)

    Keyword Arguments:
        status (str): Status of the requirement (either "satisfied" or "failed")
        reason (dict): Reason of the status
    """
    # Check whether user has credit eligible enrollment.
    enrollment_mode, is_active = CourseEnrollment.enrollment_mode_for_user(
        user, course_key)
    has_credit_eligible_enrollment = (
        CourseMode.is_credit_eligible_slug(enrollment_mode) and is_active)

    # Refuse to set status of requirement if the user enrollment is not credit eligible.
    if not has_credit_eligible_enrollment:
        return

    # Do not allow students who have requested credit to change their eligibility
    if CreditRequest.get_user_request_status(user.username, course_key):
        log.info(
            u'Refusing to set status of requirement with namespace "%s" and name "%s" because the '
            u'user "%s" has already requested credit for the course "%s".',
            req_namespace, req_name, user.username, course_key)
        return

    # Do not allow a student who has earned eligibility to un-earn eligibility
    eligible_before_update = CreditEligibility.is_user_eligible_for_credit(
        course_key, user.username)
    if eligible_before_update and status == 'failed':
        log.info(
            u'Refusing to set status of requirement with namespace "%s" and name "%s" to "failed" because the '
            u'user "%s" is already eligible for credit in the course "%s".',
            req_namespace, req_name, user.username, course_key)
        return

    # Retrieve all credit requirements for the course
    # We retrieve all of them to avoid making a second query later when
    # we need to check whether all requirements have been satisfied.
    reqs = CreditRequirement.get_course_requirements(course_key)

    # Find the requirement we're trying to set
    req_to_update = next(
        (req for req in reqs
         if req.namespace == req_namespace and req.name == req_name), None)

    # If we can't find the requirement, then the most likely explanation
    # is that there was a lag updating the credit requirements after the course
    # was published.  We *could* attempt to create the requirement here,
    # but that could cause serious performance issues if many users attempt to
    # lock the row at the same time.
    # Instead, we skip updating the requirement and log an error.
    if req_to_update is None:
        log.error(
            (u'Could not update credit requirement in course "%s" '
             u'with namespace "%s" and name "%s" '
             u'because the requirement does not exist. '
             u'The user "%s" should have had his/her status updated to "%s".'),
            unicode(course_key), req_namespace, req_name, user.username,
            status)
        return

    # Update the requirement status
    CreditRequirementStatus.add_or_update_requirement_status(user.username,
                                                             req_to_update,
                                                             status=status,
                                                             reason=reason)

    # If we're marking this requirement as "satisfied", there's a chance that the user has met all eligibility
    # requirements, and should be notified. However, if the user was already eligible, do not send another notification.
    if status == "satisfied" and not eligible_before_update:
        is_eligible, eligibility_record_created = CreditEligibility.update_eligibility(
            reqs, user.username, course_key)
        if eligibility_record_created and is_eligible:
            try:
                send_credit_notifications(user.username, course_key)
            except Exception:  # pylint: disable=broad-except
                log.exception("Error sending email")
Esempio n. 10
0
def set_credit_requirement_status(username, course_key, req_namespace, req_name, status="satisfied", reason=None):
    """
    Update the user's requirement status.

    This will record whether the user satisfied or failed a particular requirement
    in a course.  If the user has satisfied all requirements, the user will be marked
    as eligible for credit in the course.

    Args:
        username (str): Username of the user
        course_key (CourseKey): Identifier for the course associated with the requirement.
        req_namespace (str): Namespace of the requirement (e.g. "grade" or "reverification")
        req_name (str): Name of the requirement (e.g. "grade" or the location of the ICRV XBlock)

    Keyword Arguments:
        status (str): Status of the requirement (either "satisfied" or "failed")
        reason (dict): Reason of the status

    Example:
        >>> set_credit_requirement_status(
                "staff",
                CourseKey.from_string("course-v1-edX-DemoX-1T2015"),
                "reverification",
                "i4x://edX/DemoX/edx-reverification-block/assessment_uuid",
                status="satisfied",
                reason={}
            )

    """
    # Check if we're already eligible for credit.
    # If so, short-circuit this process.
    if CreditEligibility.is_user_eligible_for_credit(course_key, username):
        log.info(
            u'Skipping update of credit requirement with namespace "%s" '
            u'and name "%s" because the user "%s" is already eligible for credit '
            u'in the course "%s".',
            req_namespace, req_name, username, course_key
        )
        return

    # Retrieve all credit requirements for the course
    # We retrieve all of them to avoid making a second query later when
    # we need to check whether all requirements have been satisfied.
    reqs = CreditRequirement.get_course_requirements(course_key)

    # Find the requirement we're trying to set
    req_to_update = next((
        req for req in reqs
        if req.namespace == req_namespace and req.name == req_name
    ), None)

    # If we can't find the requirement, then the most likely explanation
    # is that there was a lag updating the credit requirements after the course
    # was published.  We *could* attempt to create the requirement here,
    # but that could cause serious performance issues if many users attempt to
    # lock the row at the same time.
    # Instead, we skip updating the requirement and log an error.
    if req_to_update is None:
        log.error(
            (
                u'Could not update credit requirement in course "%s" '
                u'with namespace "%s" and name "%s" '
                u'because the requirement does not exist. '
                u'The user "%s" should have had his/her status updated to "%s".'
            ),
            unicode(course_key), req_namespace, req_name, username, status
        )
        return

    # Update the requirement status
    CreditRequirementStatus.add_or_update_requirement_status(
        username, req_to_update, status=status, reason=reason
    )

    # If we're marking this requirement as "satisfied", there's a chance
    # that the user has met all eligibility requirements.
    if status == "satisfied":
        is_eligible, eligibility_record_created = CreditEligibility.update_eligibility(reqs, username, course_key)
        if eligibility_record_created and is_eligible:
            try:
                send_credit_notifications(username, course_key)
            except Exception:  # pylint: disable=broad-except
                log.error("Error sending email")
Esempio n. 11
0
def set_credit_requirement_status(user, course_key, req_namespace, req_name, status="satisfied", reason=None):
    """
    Update the user's requirement status.

    This will record whether the user satisfied or failed a particular requirement
    in a course.  If the user has satisfied all requirements, the user will be marked
    as eligible for credit in the course.

    Args:
        user(User): User object to set credit requirement for.
        course_key (CourseKey): Identifier for the course associated with the requirement.
        req_namespace (str): Namespace of the requirement (e.g. "grade" or "reverification")
        req_name (str): Name of the requirement (e.g. "grade" or the location of the ICRV XBlock)

    Keyword Arguments:
        status (str): Status of the requirement (either "satisfied" or "failed")
        reason (dict): Reason of the status
    """
    # Check whether user has credit eligible enrollment.
    enrollment_mode, is_active = CourseEnrollment.enrollment_mode_for_user(user, course_key)
    has_credit_eligible_enrollment = (CourseMode.is_credit_eligible_slug(enrollment_mode) and is_active)

    # Refuse to set status of requirement if the user enrollment is not credit eligible.
    if not has_credit_eligible_enrollment:
        return

    # Do not allow students who have requested credit to change their eligibility
    if CreditRequest.get_user_request_status(user.username, course_key):
        log.info(
            u'Refusing to set status of requirement with namespace "%s" and name "%s" because the '
            u'user "%s" has already requested credit for the course "%s".',
            req_namespace, req_name, user.username, course_key
        )
        return

    # Do not allow a student who has earned eligibility to un-earn eligibility
    eligible_before_update = CreditEligibility.is_user_eligible_for_credit(course_key, user.username)
    if eligible_before_update and status == 'failed':
        log.info(
            u'Refusing to set status of requirement with namespace "%s" and name "%s" to "failed" because the '
            u'user "%s" is already eligible for credit in the course "%s".',
            req_namespace, req_name, user.username, course_key
        )
        return

    # Retrieve all credit requirements for the course
    # We retrieve all of them to avoid making a second query later when
    # we need to check whether all requirements have been satisfied.
    reqs = CreditRequirement.get_course_requirements(course_key)

    # Find the requirement we're trying to set
    req_to_update = next((
        req for req in reqs
        if req.namespace == req_namespace and req.name == req_name
    ), None)

    # If we can't find the requirement, then the most likely explanation
    # is that there was a lag updating the credit requirements after the course
    # was published.  We *could* attempt to create the requirement here,
    # but that could cause serious performance issues if many users attempt to
    # lock the row at the same time.
    # Instead, we skip updating the requirement and log an error.
    if req_to_update is None:
        log.error(
            (
                u'Could not update credit requirement in course "%s" '
                u'with namespace "%s" and name "%s" '
                u'because the requirement does not exist. '
                u'The user "%s" should have had his/her status updated to "%s".'
            ),
            unicode(course_key), req_namespace, req_name, user.username, status
        )
        return

    # Update the requirement status
    CreditRequirementStatus.add_or_update_requirement_status(
        user.username, req_to_update, status=status, reason=reason
    )

    # If we're marking this requirement as "satisfied", there's a chance that the user has met all eligibility
    # requirements, and should be notified. However, if the user was already eligible, do not send another notification.
    if status == "satisfied" and not eligible_before_update:
        is_eligible, eligibility_record_created = CreditEligibility.update_eligibility(reqs, user.username, course_key)
        if eligibility_record_created and is_eligible:
            try:
                send_credit_notifications(user.username, course_key)
            except Exception:  # pylint: disable=broad-except
                log.exception("Error sending email")