MST-187 return course staff role data for ProgramCourseEnrollment get API

This commit is contained in:
Simon Chen
2020-04-10 15:13:43 -04:00
parent 4fa970f962
commit fe1ef21bcd
5 changed files with 140 additions and 14 deletions

View File

@@ -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,

View File

@@ -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()

View File

@@ -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)

View File

@@ -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):
"""

View File

@@ -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']