feat: Add EnrollmentsService in XBlockRuntime and block renderer (#34238)

* feat: Add EnrollmentsService in XBlockRuntime and block renderer

These changes give ability to use `EnrollmentsService` in XBlocks
Add `get_active_enrollments_by_course_and_user` method to `EnrollmentsService` which can be used to get active enrollment of user for a give course
This commit is contained in:
Zia Fazal
2024-03-19 09:41:11 +05:00
committed by GitHub
parent 762730ab6f
commit 1556be5851
4 changed files with 77 additions and 0 deletions

View File

@@ -71,6 +71,7 @@ from lms.djangoapps.verify_student.services import XBlockVerificationService
from openedx.core.djangoapps.bookmarks.api import BookmarksService
from openedx.core.djangoapps.crawlers.models import CrawlersConfig
from openedx.core.djangoapps.credit.services import CreditService
from openedx.core.djangoapps.enrollments.services import EnrollmentsService
from openedx.core.djangoapps.util.user_utils import SystemUser
from openedx.core.djangolib.markup import HTML
from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser
@@ -633,6 +634,7 @@ def prepare_runtime_for_user(
'teams_configuration': TeamsConfigurationService(),
'call_to_action': CallToActionService(),
'publish': EventPublishingService(user, course_id, track_function),
'enrollments': EnrollmentsService(),
}
runtime.get_block_for_descriptor = inner_get_block

View File

@@ -5,6 +5,7 @@ from functools import reduce
from operator import or_
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db.models import Q
from opaque_keys.edx.keys import CourseKey
@@ -12,6 +13,8 @@ from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.models import CourseEnrollment
from openedx.core.djangoapps.content.course_overviews.api import get_course_overview_or_none
USER_MODEL = get_user_model()
class EnrollmentsService:
"""
@@ -25,6 +28,34 @@ class EnrollmentsService:
"""
return CourseEnrollment.objects.filter(course_id=course_id, is_active=True)
def get_active_enrollments_by_course_and_user(self, course_id, user_id):
"""
Returns a list of active enrollments for a course and user.
Parameters:
* course_id: course ID for the course
* user_id: ID of User object
"""
user = self._get_user_by_id(user_id)
enrollment = CourseEnrollment.get_enrollment(user, course_id)
if not enrollment or not enrollment.is_active:
# not enrolled
return None
return enrollment
def _get_user_by_id(self, user_id):
"""
Returns s User object for give ID
Parameters:
* user_id: ID of User object
"""
try:
return USER_MODEL.objects.get(id=user_id)
except USER_MODEL.DoesNotExist:
return None
def _get_enrollments_for_course_proctoring_eligible_modes(self, course_id, allow_honor_mode=False):
"""
Return all enrollments for a course that are in a mode that makes the corresponding user

View File

@@ -28,6 +28,7 @@ class EnrollmentsServiceTests(ModuleStoreTestCase):
CourseMode.PROFESSIONAL,
CourseMode.VERIFIED
]
self.users = []
self.course = CourseOverviewFactory.create(enable_proctored_exams=True)
for index in range(len(self.course_modes)):
@@ -39,11 +40,51 @@ class EnrollmentsServiceTests(ModuleStoreTestCase):
username=f'user{index}',
email=f'LEARNER{index}@example.com'
)
self.users.append(user)
CourseEnrollment.enroll(user, course_id, mode=course_mode)
def enrollment_to_dict(self, enrollment):
return {'username': enrollment.username, 'mode': enrollment.mode}
def test_get_active_enrollments_by_course(self):
"""
Test that it returns a list of active enrollments for a course
"""
enrollments = self.service.get_active_enrollments_by_course(course_id=str(self.course.id))
self.assertEqual(len(self.course_modes), len(enrollments))
def test_get_active_enrollments_by_course_and_user(self):
"""
Test that it returns a list of active enrollments for a course and user
"""
enrollment = self.service.get_active_enrollments_by_course_and_user(
str(self.course.id),
self.users[0].id,
)
expected_values = {'username': 'user0', 'mode': 'audit'}
self.assertDictEqual(self.enrollment_to_dict(enrollment), expected_values)
def test_get_active_enrollments_by_course_and_user_none_course(self):
"""
Test that it returns a list of active enrollments for a course and user
for a non existing enrollment
"""
enrollments = self.service.get_active_enrollments_by_course_and_user(
'course-v1:testx+none+123',
self.users[0].id,
)
self.assertIsNone(enrollments)
def test_get_active_enrollments_by_course_and_user_none_user(self):
"""
Test getting enrollments for a course and non existing user raise error
"""
with self.assertRaises(AssertionError):
self.service.get_active_enrollments_by_course_and_user(
str(self.course.id),
0000,
)
def test_get_enrollments_can_take_proctored_exams_by_course(self):
"""
Test that it returns a list of active enrollments

View File

@@ -36,6 +36,7 @@ from common.djangoapps.xblock_django.user_service import DjangoXBlockUserService
from lms.djangoapps.courseware.model_data import DjangoKeyValueStore, FieldDataCache
from lms.djangoapps.grades.api import signals as grades_signals
from openedx.core.types import User as UserType
from openedx.core.djangoapps.enrollments.services import EnrollmentsService
from openedx.core.djangoapps.xblock.apps import get_xblock_app_config
from openedx.core.djangoapps.xblock.data import StudentDataMode
from openedx.core.djangoapps.xblock.runtime.ephemeral_field_data import EphemeralKeyValueStore
@@ -298,6 +299,8 @@ class XBlockRuntime(RuntimeShim, Runtime):
)
elif service_name == 'publish':
return EventPublishingService(self.user, context_key, make_track_function())
elif service_name == 'enrollments':
return EnrollmentsService()
# Check if the XBlockRuntimeSystem wants to handle this:
service = self.system.get_service(block, service_name)