feat: The API now returns learner_count and staff_count alongside the existing enrollment fields.

This commit is contained in:
Brian Buck
2026-02-19 16:09:50 -07:00
committed by Taylor Payne
parent 44521091aa
commit 15a252fdc3
3 changed files with 49 additions and 0 deletions

View File

@@ -254,6 +254,16 @@ definitions:
minimum: 0
description: Total number of enrollments across all modes
example: 150
learner_count:
type: integer
minimum: 0
description: Number of enrolled learners (excludes staff and admins)
example: 140
staff_count:
type: integer
minimum: 0
description: Number of enrolled staff and admins
example: 10
enrollment_counts:
type: object
description: |

View File

@@ -125,6 +125,11 @@ class CourseMetadataViewTest(SharedModuleStoreTestCase):
self.assertIn('total_enrollment', data)
self.assertGreaterEqual(data['total_enrollment'], 3)
# Verify role-based enrollment counts are present
self.assertIn('learner_count', data)
self.assertIn('staff_count', data)
self.assertEqual(data['total_enrollment'], data['learner_count'] + data['staff_count'])
# Verify permissions structure
self.assertIn('permissions', data)
permissions_data = data['permissions']
@@ -217,6 +222,28 @@ class CourseMetadataViewTest(SharedModuleStoreTestCase):
# Instructor should have instructor permission
self.assertTrue(permissions_data['instructor'])
def test_learner_and_staff_counts(self):
"""
Test that learner_count excludes staff/admins and staff_count is the difference.
"""
self.client.force_authenticate(user=self.instructor)
response = self.client.get(self._get_url())
self.assertEqual(response.status_code, status.HTTP_200_OK)
data = response.data
total = data['total_enrollment']
learner_count = data['learner_count']
staff_count = data['staff_count']
# Counts must be non-negative and sum to total
self.assertGreaterEqual(learner_count, 0)
self.assertGreaterEqual(staff_count, 0)
self.assertEqual(total, learner_count + staff_count)
# The student enrolled in setUp is not staff, so learner_count >= 1
self.assertGreaterEqual(learner_count, 1)
def test_enrollment_counts_by_mode(self):
"""
Test that enrollment counts include all configured modes,

View File

@@ -54,6 +54,10 @@ class CourseInformationSerializerV2(serializers.Serializer):
has_started = serializers.SerializerMethodField(help_text="Whether the course has started based on current time")
has_ended = serializers.SerializerMethodField(help_text="Whether the course has ended based on current time")
total_enrollment = serializers.SerializerMethodField(help_text="Total number of enrollments across all modes")
learner_count = serializers.SerializerMethodField(
help_text="Number of enrolled learners (excludes staff and admins)"
)
staff_count = serializers.SerializerMethodField(help_text="Number of enrolled staff and admins")
enrollment_counts = serializers.SerializerMethodField(help_text="Enrollment count breakdown by mode")
num_sections = serializers.SerializerMethodField(help_text="Number of sections/chapters in the course")
grade_cutoffs = serializers.SerializerMethodField(help_text="Formatted string of grade cutoffs")
@@ -268,6 +272,14 @@ class CourseInformationSerializerV2(serializers.Serializer):
"""Get total enrollment count."""
return self.get_enrollment_counts(data)['total']
def get_learner_count(self, data):
"""Get enrollment count excluding staff and admins."""
return CourseEnrollment.objects.num_enrolled_in_exclude_admins(data['course'].id)
def get_staff_count(self, data):
"""Get enrollment count for staff and admins only."""
return self.get_total_enrollment(data) - self.get_learner_count(data)
def get_enrollment_counts(self, data):
"""Get enrollment counts for all configured course modes."""
course_id = data['course'].id