Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [AXM-236] Add progress for other courses #2536

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 37 additions & 20 deletions lms/djangoapps/mobile_api/users/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ class CourseEnrollmentSerializer(serializers.ModelSerializer):
audit_access_expires = serializers.SerializerMethodField()
course_modes = serializers.SerializerMethodField()

BLOCK_STRUCTURE_CACHE_TIMEOUT = 60 * 60 # 1 hour

def get_audit_access_expires(self, model):
"""
Returns expiration date for a course audit expiration, if any or null
Expand Down Expand Up @@ -137,6 +139,40 @@ def get_course_modes(self, obj):
for mode in course_modes
]

def to_representation(self, instance):
"""
Override the to_representation method to add the course_status field to the serialized data.
"""
data = super().to_representation(instance)
if 'progress' in self.context.get('requested_fields', []):
data['progress'] = self.calculate_progress(instance)

return data

def calculate_progress(self, model: CourseEnrollment) -> Dict[str, int]:
"""
Calculate the progress of the user in the course.
:param model:
:return:
"""
is_staff = bool(has_access(model.user, 'staff', model.course.id))

cache_key = f'course_block_structure_{str(model.course.id)}_{model.user.id}'
collected_block_structure = cache.get(cache_key)
if not collected_block_structure:
collected_block_structure = get_block_structure_manager(model.course.id).get_collected()
cache.set(cache_key, collected_block_structure, self.BLOCK_STRUCTURE_CACHE_TIMEOUT)

course_grade = CourseGradeFactory().read(model.user, collected_block_structure=collected_block_structure)

# recalculate course grade from visible grades (stored grade was calculated over all grades, visible or not)
course_grade.update(visible_grades_only=True, has_staff_access=is_staff)
subsection_grades = list(course_grade.subsection_grades.values())
return {
'num_points_earned': sum(map(lambda x: x.graded_total.earned if x.graded else 0, subsection_grades)),
'num_points_possible': sum(map(lambda x: x.graded_total.possible if x.graded else 0, subsection_grades)),
}

class Meta:
model = CourseEnrollment
fields = ('audit_access_expires', 'created', 'mode', 'is_active', 'course', 'certificate', 'course_modes')
Expand Down Expand Up @@ -165,8 +201,6 @@ class CourseEnrollmentSerializerModifiedForPrimary(CourseEnrollmentSerializer):
progress = serializers.SerializerMethodField()
course_assignments = serializers.SerializerMethodField()

BLOCK_STRUCTURE_CACHE_TIMEOUT = 60 * 60 # 1 hour

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.course = modulestore().get_course(self.instance.course.id)
Expand Down Expand Up @@ -230,24 +264,7 @@ def get_progress(self, model: CourseEnrollment) -> Dict[str, int]:
"""
Returns the progress of the user in the course.
"""
assert isinstance(model, CourseEnrollment), f'Expected CourseEnrollment, got {type(model)}'
is_staff = bool(has_access(model.user, 'staff', model.course.id))

cache_key = f'course_block_structure_{str(model.course.id)}_{model.user.id}'
collected_block_structure = cache.get(cache_key)
if not collected_block_structure:
collected_block_structure = get_block_structure_manager(model.course.id).get_collected()
cache.set(cache_key, collected_block_structure, self.BLOCK_STRUCTURE_CACHE_TIMEOUT)

course_grade = CourseGradeFactory().read(model.user, collected_block_structure=collected_block_structure)

# recalculate course grade from visible grades (stored grade was calculated over all grades, visible or not)
course_grade.update(visible_grades_only=True, has_staff_access=is_staff)
subsection_grades = list(course_grade.subsection_grades.values())
return {
'num_points_earned': sum(map(lambda x: x.graded_total.earned if x.graded else 0, subsection_grades)),
'num_points_possible': sum(map(lambda x: x.graded_total.possible if x.graded else 0, subsection_grades)),
}
return self.calculate_progress(model)

def get_course_assignments(self, model: CourseEnrollment) -> Optional[Dict[str, List[Dict[str, str]]]]:
"""
Expand Down
3 changes: 3 additions & 0 deletions lms/djangoapps/mobile_api/users/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,10 @@ def is_org(self, check_org, course_org):

def get_serializer_context(self):
context = super().get_serializer_context()
requested_fields = self.request.GET.get('requested_fields', '')

context['api_version'] = self.kwargs.get('api_version')
context['requested_fields'] = requested_fields.split(',')
return context

def get_serializer_class(self):
Expand Down
Loading