Example #1
0
def get_student_enrollments(user, edx_client):
    """
    Return cached enrollment data or fetch enrollment data first if necessary.
    All CourseRun will have an entry for the user: this entry will contain Null
    data if the user does not have an enrollment.

    Args:
        user (django.contrib.auth.models.User): A user
        edx_client (EdxApi): EdX client to retrieve enrollments
    Returns:
        Enrollments: an Enrollments object from edx_api.
            This may contain more enrollments than
            what we know about in MicroMasters if more exist from edX,
            or it may contain fewer enrollments if they don't exist for the course id in edX
    """
    # Data in database is refreshed after 5 minutes
    now = datetime.datetime.now(tz=pytz.utc)
    refresh_delta = now - datetime.timedelta(minutes=REFRESH_ENROLLMENT_CACHE_MINUTES)

    with transaction.atomic():
        course_ids = CourseRun.objects.filter(course__program__live=True).exclude(
            Q(edx_course_key__isnull=True) | Q(edx_course_key__exact='')
        ).values_list("edx_course_key", flat=True)

        enrollments_query = models.CachedEnrollment.objects.filter(
            user=user,
            last_request__gt=refresh_delta,
            course_run__edx_course_key__in=course_ids,
        )
        if enrollments_query.count() == len(course_ids):
            return Enrollments([enrollment.data for enrollment in enrollments_query.exclude(data__isnull=True)])

    # Data is not available in database or it's expired. Fetch new data.
    enrollments = edx_client.enrollments.get_student_enrollments()

    # Make sure all enrollments are updated atomically. It's still possible that this function executes twice and
    # we fetch the data from edX twice, but the data shouldn't be half modified at any point.
    with transaction.atomic():
        for course_id in course_ids:
            enrollment = enrollments.get_enrollment_for_course(course_id)
            # get the certificate data or None
            # None means we will cache the fact that the student
            # does not have an enrollment for the given course
            enrollment_data = enrollment.json if enrollment is not None else None
            course_run = CourseRun.objects.get(edx_course_key=course_id)
            updated_values = {
                'user': user,
                'course_run': course_run,
                'data': enrollment_data,
                'last_request': now,
            }
            models.CachedEnrollment.objects.update_or_create(
                user=user,
                course_run=course_run,
                defaults=updated_values
            )

    return enrollments
Example #2
0
    def deserialize_edx_data(data_iter):
        """
        Deserializes raw enrollment data

        Args:
            data_iter (iterable): Some iterable of raw data

        Returns: Enrollments: an edX Enrollments object
        """
        return Enrollments(data_iter)
Example #3
0
 def get_student_enrollments():
     """List of existing enrollments"""
     return Enrollments([{
         "course_details": {
             "course_id": self.line1.course_key
         }
     }, {
         "course_details": {
             "course_id": self.line2.course_key
         }
     }])
Example #4
0
 def get_student_enrollments():
     """List of existing enrollments"""
     return Enrollments([])