MST-187 return course staff role data for ProgramCourseEnrollment get API
This commit is contained in:
@@ -28,7 +28,8 @@ from .reading import (
|
||||
get_saml_provider_for_organization,
|
||||
get_org_key_for_program,
|
||||
get_users_by_external_keys,
|
||||
get_users_by_external_keys_and_org_key
|
||||
get_users_by_external_keys_and_org_key,
|
||||
is_course_staff_enrollment
|
||||
)
|
||||
from .writing import (
|
||||
change_program_course_enrollment_status,
|
||||
|
||||
@@ -10,8 +10,10 @@ from organizations.models import Organization
|
||||
from social_django.models import UserSocialAuth
|
||||
|
||||
from openedx.core.djangoapps.catalog.utils import get_programs
|
||||
from student.roles import CourseStaffRole
|
||||
from third_party_auth.models import SAMLProviderConfig
|
||||
|
||||
from ..constants import ProgramCourseEnrollmentRoles
|
||||
from ..exceptions import (
|
||||
BadOrganizationShortNameException,
|
||||
ProgramDoesNotExistException,
|
||||
@@ -509,3 +511,21 @@ def get_provider_slug(provider_config):
|
||||
Returns: str
|
||||
"""
|
||||
return provider_config.provider_id.strip('saml-')
|
||||
|
||||
|
||||
def is_course_staff_enrollment(program_course_enrollment):
|
||||
"""
|
||||
Returns whether the provided program_course_enrollment have the
|
||||
course staff role on the course.
|
||||
|
||||
Arguments:
|
||||
program_course_enrollment: ProgramCourseEnrollment
|
||||
|
||||
returns: bool
|
||||
"""
|
||||
associated_user = program_course_enrollment.program_enrollment.user
|
||||
if associated_user:
|
||||
return CourseStaffRole(program_course_enrollment.course_key).has_user(associated_user)
|
||||
return program_course_enrollment.courseaccessroleassignment_set.filter(
|
||||
role=ProgramCourseEnrollmentRoles.COURSE_STAFF
|
||||
).exists()
|
||||
|
||||
@@ -22,13 +22,18 @@ from lms.djangoapps.program_enrollments.exceptions import (
|
||||
ProviderConfigurationException,
|
||||
ProviderDoesNotExistException
|
||||
)
|
||||
from lms.djangoapps.program_enrollments.models import ProgramEnrollment
|
||||
from lms.djangoapps.program_enrollments.tests.factories import ProgramCourseEnrollmentFactory, ProgramEnrollmentFactory
|
||||
from lms.djangoapps.program_enrollments.models import ProgramEnrollment, ProgramCourseEnrollment
|
||||
from lms.djangoapps.program_enrollments.tests.factories import (
|
||||
CourseAccessRoleAssignmentFactory,
|
||||
ProgramCourseEnrollmentFactory,
|
||||
ProgramEnrollmentFactory
|
||||
)
|
||||
from openedx.core.djangoapps.catalog.cache import PROGRAM_CACHE_KEY_TPL
|
||||
from openedx.core.djangoapps.catalog.tests.factories import OrganizationFactory as CatalogOrganizationFactory
|
||||
from openedx.core.djangoapps.catalog.tests.factories import ProgramFactory
|
||||
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
|
||||
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
|
||||
from student.roles import CourseStaffRole
|
||||
from student.tests.factories import CourseEnrollmentFactory, UserFactory
|
||||
from third_party_auth.tests.factories import SAMLProviderConfigFactory
|
||||
|
||||
@@ -40,7 +45,8 @@ from ..reading import (
|
||||
get_external_key_by_user_and_course,
|
||||
get_program_course_enrollment,
|
||||
get_program_enrollment,
|
||||
get_users_by_external_keys
|
||||
get_users_by_external_keys,
|
||||
is_course_staff_enrollment,
|
||||
)
|
||||
|
||||
User = get_user_model()
|
||||
@@ -612,3 +618,84 @@ class GetUsersByExternalKeysTests(CacheIsolationTestCase):
|
||||
)
|
||||
with self.assertRaises(ProviderConfigurationException):
|
||||
get_users_by_external_keys(self.program_uuid, [])
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class IsCourseStaffEnrollmentTest(TestCase):
|
||||
"""
|
||||
Tests for the is_course_staff_enrollment function
|
||||
"""
|
||||
program_uuid_x = UUID('dddddddd-5f48-493d-9410-84e1d36c657f')
|
||||
program_uuid_y = UUID('eeeeeeee-f803-43f6-bbf3-5ae15d393649')
|
||||
curriculum_uuid_a = UUID('aaaaaaaa-bd26-43d0-94b8-b0063858210b')
|
||||
curriculum_uuid_b = UUID('bbbbbbbb-145f-43db-ad05-f9ad65eec285')
|
||||
course_key_p = CourseKey.from_string('course-v1:TestX+ProEnroll+P')
|
||||
course_key_q = CourseKey.from_string('course-v1:TestX+ProEnroll+Q')
|
||||
username_0 = 'user-0'
|
||||
ext_3 = 'student-3'
|
||||
ext_4 = 'student-4'
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
super(IsCourseStaffEnrollmentTest, cls).setUpTestData()
|
||||
cls.user_0 = UserFactory(username=cls.username_0) # No enrollments
|
||||
CourseOverviewFactory(id=cls.course_key_p)
|
||||
CourseOverviewFactory(id=cls.course_key_q)
|
||||
enrollment_test_data = [ # ID
|
||||
(cls.user_0, None, cls.program_uuid_x, cls.curriculum_uuid_a, PEStatuses.ENROLLED), # 1
|
||||
(None, cls.ext_3, cls.program_uuid_x, cls.curriculum_uuid_b, PEStatuses.PENDING), # 2
|
||||
(None, cls.ext_4, cls.program_uuid_y, cls.curriculum_uuid_a, PEStatuses.ENROLLED), # 3
|
||||
(cls.user_0, None, cls.program_uuid_y, cls.curriculum_uuid_b, PEStatuses.SUSPENDED), # 4
|
||||
]
|
||||
for user, external_user_key, program_uuid, curriculum_uuid, status in enrollment_test_data:
|
||||
ProgramEnrollmentFactory(
|
||||
user=user,
|
||||
external_user_key=external_user_key,
|
||||
program_uuid=program_uuid,
|
||||
curriculum_uuid=curriculum_uuid,
|
||||
status=status,
|
||||
)
|
||||
course_enrollment_test_data = [ # ID
|
||||
(1, cls.course_key_p, PCEStatuses.ACTIVE, True), # 1
|
||||
(2, cls.course_key_q, PCEStatuses.ACTIVE, False), # 2
|
||||
(3, cls.course_key_p, PCEStatuses.ACTIVE, True), # 3
|
||||
(4, cls.course_key_q, PCEStatuses.ACTIVE, False), # 4
|
||||
]
|
||||
for program_enrollment_id, course_key, status, course_staff in course_enrollment_test_data:
|
||||
program_enrollment = ProgramEnrollment.objects.get(id=program_enrollment_id)
|
||||
course_enrollment = (
|
||||
CourseEnrollmentFactory(
|
||||
course_id=course_key,
|
||||
user=program_enrollment.user,
|
||||
mode=CourseMode.MASTERS,
|
||||
)
|
||||
if program_enrollment.user
|
||||
else None
|
||||
)
|
||||
|
||||
program_course_enrollment = ProgramCourseEnrollmentFactory(
|
||||
program_enrollment=program_enrollment,
|
||||
course_enrollment=course_enrollment,
|
||||
course_key=course_key,
|
||||
status=status,
|
||||
)
|
||||
if course_staff:
|
||||
if program_enrollment.user:
|
||||
CourseStaffRole(course_key).add_users(program_enrollment.user)
|
||||
else:
|
||||
CourseAccessRoleAssignmentFactory(
|
||||
enrollment=program_course_enrollment
|
||||
)
|
||||
|
||||
@ddt.data(
|
||||
(1, True),
|
||||
(2, False),
|
||||
(3, True),
|
||||
(4, False),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_is_course_staff_enrollment(self, program_course_enrollment_id, is_course_staff):
|
||||
program_course_enrollment = ProgramCourseEnrollment.objects.get(
|
||||
id=program_course_enrollment_id
|
||||
)
|
||||
assert is_course_staff == is_course_staff_enrollment(program_course_enrollment)
|
||||
|
||||
@@ -6,6 +6,7 @@ API Serializers
|
||||
from rest_framework import serializers
|
||||
from six import text_type
|
||||
|
||||
from lms.djangoapps.program_enrollments.api import is_course_staff_enrollment
|
||||
from lms.djangoapps.program_enrollments.models import ProgramCourseEnrollment, ProgramEnrollment
|
||||
|
||||
from .constants import CourseRunProgressStatuses
|
||||
@@ -78,6 +79,7 @@ class ProgramCourseEnrollmentSerializer(serializers.Serializer):
|
||||
status = serializers.CharField()
|
||||
account_exists = serializers.SerializerMethodField()
|
||||
curriculum_uuid = serializers.SerializerMethodField()
|
||||
course_staff = serializers.SerializerMethodField()
|
||||
|
||||
class Meta(object):
|
||||
model = ProgramCourseEnrollment
|
||||
@@ -91,6 +93,9 @@ class ProgramCourseEnrollmentSerializer(serializers.Serializer):
|
||||
def get_curriculum_uuid(self, obj):
|
||||
return text_type(obj.program_enrollment.curriculum_uuid)
|
||||
|
||||
def get_course_staff(self, obj):
|
||||
return is_course_staff_enrollment(obj)
|
||||
|
||||
|
||||
class ProgramCourseEnrollmentRequestSerializer(serializers.Serializer, InvalidStatusMixin):
|
||||
"""
|
||||
|
||||
@@ -35,7 +35,11 @@ from lms.djangoapps.program_enrollments.constants import ProgramCourseOperationS
|
||||
from lms.djangoapps.program_enrollments.constants import ProgramOperationStatuses as ProgramStatuses
|
||||
from lms.djangoapps.program_enrollments.exceptions import ProviderDoesNotExistException
|
||||
from lms.djangoapps.program_enrollments.models import ProgramCourseEnrollment, ProgramEnrollment
|
||||
from lms.djangoapps.program_enrollments.tests.factories import ProgramCourseEnrollmentFactory, ProgramEnrollmentFactory
|
||||
from lms.djangoapps.program_enrollments.tests.factories import (
|
||||
CourseAccessRoleAssignmentFactory,
|
||||
ProgramCourseEnrollmentFactory,
|
||||
ProgramEnrollmentFactory,
|
||||
)
|
||||
from openedx.core.djangoapps.catalog.cache import PROGRAM_CACHE_KEY_TPL, PROGRAMS_BY_ORGANIZATION_CACHE_KEY_TPL
|
||||
from openedx.core.djangoapps.catalog.tests.factories import (
|
||||
CourseFactory,
|
||||
@@ -890,18 +894,27 @@ class ProgramCourseEnrollmentsGetTests(EnrollmentsDataMixin, APITestCase):
|
||||
program_uuid=self.program_uuid, curriculum_uuid=self.curriculum_uuid, external_user_key='user-0',
|
||||
)
|
||||
program_enrollment_2 = ProgramEnrollmentFactory.create(
|
||||
program_uuid=self.program_uuid, curriculum_uuid=self.other_curriculum_uuid, external_user_key='user-0',
|
||||
program_uuid=self.program_uuid,
|
||||
curriculum_uuid=self.other_curriculum_uuid,
|
||||
external_user_key='user-0',
|
||||
user=None
|
||||
)
|
||||
|
||||
ProgramCourseEnrollmentFactory.create(
|
||||
program_enrollment=program_enrollment_1,
|
||||
course_key=self.course_id,
|
||||
status='active',
|
||||
)
|
||||
ProgramCourseEnrollmentFactory.create(
|
||||
CourseStaffRole(self.course_id).add_users(program_enrollment_1.user)
|
||||
|
||||
program_course_enrollment_2 = ProgramCourseEnrollmentFactory.create(
|
||||
program_enrollment=program_enrollment_2,
|
||||
course_key=self.course_id,
|
||||
status='inactive',
|
||||
)
|
||||
CourseAccessRoleAssignmentFactory.create(
|
||||
enrollment=program_course_enrollment_2
|
||||
)
|
||||
|
||||
self.addCleanup(self.destroy_course_enrollments)
|
||||
|
||||
@@ -959,11 +972,11 @@ class ProgramCourseEnrollmentsGetTests(EnrollmentsDataMixin, APITestCase):
|
||||
'results': [
|
||||
{
|
||||
'student_key': 'user-0', 'status': 'active', 'account_exists': True,
|
||||
'curriculum_uuid': text_type(self.curriculum_uuid),
|
||||
'curriculum_uuid': text_type(self.curriculum_uuid), 'course_staff': True
|
||||
},
|
||||
{
|
||||
'student_key': 'user-0', 'status': 'inactive', 'account_exists': True,
|
||||
'curriculum_uuid': text_type(self.other_curriculum_uuid),
|
||||
'student_key': 'user-0', 'status': 'inactive', 'account_exists': False,
|
||||
'curriculum_uuid': text_type(self.other_curriculum_uuid), 'course_staff': True
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -980,7 +993,7 @@ class ProgramCourseEnrollmentsGetTests(EnrollmentsDataMixin, APITestCase):
|
||||
expected_results = [
|
||||
{
|
||||
'student_key': 'user-0', 'status': 'active', 'account_exists': True,
|
||||
'curriculum_uuid': text_type(self.curriculum_uuid),
|
||||
'curriculum_uuid': text_type(self.curriculum_uuid), 'course_staff': True
|
||||
},
|
||||
]
|
||||
assert expected_results == response.data['results']
|
||||
@@ -994,12 +1007,12 @@ class ProgramCourseEnrollmentsGetTests(EnrollmentsDataMixin, APITestCase):
|
||||
assert status.HTTP_200_OK == next_response.status_code
|
||||
next_expected_results = [
|
||||
{
|
||||
'student_key': 'user-0', 'status': 'inactive', 'account_exists': True,
|
||||
'curriculum_uuid': text_type(self.other_curriculum_uuid),
|
||||
'student_key': 'user-0', 'status': 'inactive', 'account_exists': False,
|
||||
'curriculum_uuid': text_type(self.other_curriculum_uuid), 'course_staff': True
|
||||
},
|
||||
]
|
||||
assert next_expected_results == next_response.data['results']
|
||||
assert next_response.data['next'] is None
|
||||
|
||||
# there's going to be a 'cursor' query param, but we have no way of knowing it's value
|
||||
assert next_response.data['previous'] is not None
|
||||
assert self.get_url(course_id=self.course_id) in next_response.data['previous']
|
||||
|
||||
Reference in New Issue
Block a user