feat: added support of multiple course ids in enrollment API and fixed failing case (#36700)

* feat: added support of multiple course ids in enrollment API and fixed failing case

* refactor: handled course IDs along with course run IDs

* refactor: added dosctring and renamed variable

* fix: added temp mixin

* test: added unit tests of added case
This commit is contained in:
Muhammad Abdullah Waheed
2025-05-14 17:22:48 +05:00
committed by GitHub
parent db49b2d0a3
commit 2d66047f7c
3 changed files with 98 additions and 1 deletions

View File

@@ -18,6 +18,7 @@ class CourseEnrollmentsApiListForm(Form):
MAX_INPUT_COUNT = 100
username = CharField(required=False)
course_id = CharField(required=False)
course_ids = CharField(required=False)
email = CharField(required=False)
def clean_course_id(self):
@@ -51,6 +52,24 @@ class CourseEnrollmentsApiListForm(Form):
return usernames
return usernames_csv_string
def clean_course_ids(self):
"""
Validate a string of comma-separated course IDs and return a list of course IDs.
"""
course_ids_csv_string = self.cleaned_data.get('course_ids')
if course_ids_csv_string:
course_ids = course_ids_csv_string.split(',')
if len(course_ids) > self.MAX_INPUT_COUNT:
raise ValidationError(
"Too many course_ids in a single request - {}. A maximum of {} is allowed".format(
len(course_ids),
self.MAX_INPUT_COUNT,
)
)
return course_ids
return course_ids_csv_string
def clean_email(self):
"""
Validate a string of comma-separated emails and return a list of emails.

View File

@@ -210,5 +210,69 @@
"created": "2018-01-01T00:00:01Z"
}
]
],
[
{
"course_ids": "course-v1:e+d+X,x+y+Z"
},
[
{
"course_id": "course-v1:e+d+X",
"is_active": true,
"mode": "honor",
"user": "student1",
"created": "2018-01-01T00:00:01Z"
},
{
"course_id": "course-v1:e+d+X",
"is_active": true,
"mode": "honor",
"user": "student2",
"created": "2018-01-01T00:00:01Z"
},
{
"course_id": "course-v1:x+y+Z",
"is_active": true,
"mode": "verified",
"user": "staff",
"created": "2018-01-01T00:00:01Z"
},
{
"course_id": "course-v1:x+y+Z",
"is_active": true,
"mode": "honor",
"user": "student2",
"created": "2018-01-01T00:00:01Z"
},
{
"course_id": "course-v1:x+y+Z",
"is_active": true,
"mode": "verified",
"user": "student3",
"created": "2018-01-01T00:00:01Z"
}
]
],
[
{
"course_ids": "course-v1:e+d+X,x+y+Z",
"username": "student2"
},
[
{
"course_id": "course-v1:e+d+X",
"is_active": true,
"mode": "honor",
"user": "student2",
"created": "2018-01-01T00:00:01Z"
},
{
"course_id": "course-v1:x+y+Z",
"is_active": true,
"mode": "honor",
"user": "student2",
"created": "2018-01-01T00:00:01Z"
}
]
]
]

View File

@@ -11,6 +11,7 @@ from django.core.exceptions import ( # lint-amnesty, pylint: disable=wrong-impo
ValidationError,
)
from django.db import IntegrityError # lint-amnesty, pylint: disable=wrong-import-order
from django.db.models import Q # lint-amnesty, pylint: disable=wrong-import-order
from django.utils.decorators import method_decorator # lint-amnesty, pylint: disable=wrong-import-order
from edx_rest_framework_extensions.auth.jwt.authentication import (
JwtAuthentication,
@@ -934,6 +935,8 @@ class CourseEnrollmentsApiListView(DeveloperErrorViewMixin, ListAPIView):
GET /api/enrollment/v1/enrollments?course_id={course_id}
GET /api/enrollment/v1/enrollments?course_ids={course_id},{course_id},{course_id}
GET /api/enrollment/v1/enrollments?username={username},{username},{username}
GET /api/enrollment/v1/enrollments?course_id={course_id}&username={username}
@@ -945,6 +948,10 @@ class CourseEnrollmentsApiListView(DeveloperErrorViewMixin, ListAPIView):
* course_id: Filters the result to course enrollments for the course corresponding to the
given course ID. The value must be URL encoded. Optional.
* course_ids: List of comma-separated course IDs. Filters the result to course enrollments
for the courses corresponding to the given course IDs. Course IDs could be course run IDs
or course IDs. The value must be URL encoded. Optional.
* username: List of comma-separated usernames. Filters the result to the course enrollments
of the given users. Optional.
@@ -1011,13 +1018,20 @@ class CourseEnrollmentsApiListView(DeveloperErrorViewMixin, ListAPIView):
if not form.is_valid():
raise ValidationError(form.errors)
queryset = CourseEnrollment.objects.all()
queryset = CourseEnrollment.objects.all().select_related("user", "course")
course_id = form.cleaned_data.get("course_id")
course_ids = form.cleaned_data.get("course_ids")
usernames = form.cleaned_data.get("username")
emails = form.cleaned_data.get("email")
if course_id:
queryset = queryset.filter(course__id=course_id)
if course_ids:
# Handles the case if parent course ID is sent rather than course run ID
query = Q()
for cid in course_ids:
query |= Q(course__id__icontains=cid)
queryset = queryset.filter(query)
if usernames:
queryset = queryset.filter(user__username__in=usernames)
if emails: